create branch dev and commit code

This commit is contained in:
thanawat saiyota 2026-06-09 10:50:59 +07:00
parent 3b70cc9fe8
commit ea68fa5cc4
44 changed files with 12421 additions and 214 deletions

View file

@ -0,0 +1,162 @@
import { get } from 'svelte/store';
import { existingProductCodes } from '../stores/sheetStore';
// Country code mapping (country short from Android -> 2-digit product code prefix)
// Country short is read from /sdcard/coffeevending/country/short
export const countryCodeMap: Record<string, string> = {
// Thailand
THAI: '12',
tha: '12',
// Malaysia
MYS: '12',
mys: '12',
// Indonesia
IDR: '13',
idr: '13',
// Australia
AUS: '51',
aus: '51',
// Singapore
SGP: '52',
sgp: '52',
SG: '52', // obsolete
// UAE Dubai
UAE_DUBAI: '53',
uae_dubai: '53',
dubai: '53',
// Hong Kong
HKG: '54',
hkg: '54',
// UK
GBR: '55',
gbr: '55',
// Romania
ROU: '56',
rou: '56',
// Latvia
LVA: '57',
lva: '57',
// Estonia
EST: '58',
est: '58',
// Lithuania
LTU: '59',
ltu: '59',
// USA Pepsi (uses Thai prefix)
USA_PEPSI: '12',
usa_pepsi: '12',
// Counter machines
counter01: '19'
};
// Temperature codes
export const tempCodes: Record<TempType, string> = {
hot: '01',
cold: '02',
blend: '03'
};
// Category/Drink type codes
export const categoryOptions = [
{ value: '01', label: 'Coffee V1' },
{ value: '21', label: 'Coffee V2' },
{ value: '02', label: 'Tea' },
{ value: '03', label: 'Milk' },
{ value: '04', label: 'Whey' },
{ value: '05', label: 'Soda & Other' }
] as const;
export type TempType = 'hot' | 'cold' | 'blend';
export type CategoryCode = (typeof categoryOptions)[number]['value'];
/**
* Get all existing product code suffixes (last 4 digits)
* @param category - Optional category code to filter by (e.g., '01' for Coffee V1)
*/
export function getExistingCodeSuffixes(category?: string): Set<string> {
const codes = get(existingProductCodes);
if (category) {
// Filter codes by category (2nd segment: XX-[category]-XX-XXXX)
return new Set(
[...codes]
.filter((code) => {
const parts = code.split('-');
return parts[1] === category;
})
.map((code) => code.split('-')[3])
);
}
return new Set([...codes].map((code) => code.split('-')[3]));
}
/**
* Generate next suffix by finding max existing + 1 for a specific category
* @param category - Optional category code to find max within (e.g., '01' for Coffee V1)
*/
export function generateNextSuffix(category?: string): string {
const suffixes = getExistingCodeSuffixes(category);
let maxSuffix = 0;
for (const suffix of suffixes) {
const num = parseInt(suffix, 10);
if (!isNaN(num) && num > maxSuffix) {
maxSuffix = num;
}
}
const nextSuffix = maxSuffix + 1;
if (nextSuffix > 9999) {
throw new Error('Product code suffix exceeded 9999');
}
return String(nextSuffix).padStart(4, '0');
}
/**
* Generate a complete product code
* @param country - Country code (e.g., 'tha')
* @param category - Category code (e.g., '01' for Coffee V1)
* @param temp - Temperature type ('hot', 'cold', 'blend')
* @param suffix - Optional specific suffix, otherwise auto-generate
* @returns Product code like '12-01-01-0006'
*/
export function generateProductCode(
country: string,
category: string,
temp: TempType,
suffix?: string
): string {
const countryCode = countryCodeMap[country] || '99';
const tempCode = tempCodes[temp];
const codeSuffix = suffix ?? generateNextSuffix();
return `${countryCode}-${category}-${tempCode}-${codeSuffix}`;
}
/**
* Check if a product code already exists
*/
export function isProductCodeExists(code: string): boolean {
const codes = get(existingProductCodes);
return codes.has(code);
}
/**
* Generate a unique product code (auto-retry if exists)
*/
export function generateUniqueProductCode(
country: string,
category: string,
temp: TempType
): string {
const code = generateProductCode(country, category, temp);
if (isProductCodeExists(code)) {
throw new Error(`Product code already exists: ${code}`);
}
return code;
}