x
This commit is contained in:
1 parent
037ee775db
commit
abee5249ca
14 files changed
+128241
-2
No files matched your search
@@ -1,5 +1,6 @@
|
||||
import { Elysia, t } from "elysia";
|
||||
import prisma from "../lib/prisma";
|
||||
import { THAILAND_PROVINCES, findProvince, cleanDistrictName } from "../utils/thaiProvinces";
|
||||
|
||||
const toNum = (val: any): number => {
|
||||
if (val === null || val === undefined || val === "") return 0;
|
||||
@@ -390,4 +391,211 @@ export const tiktokOrderRoute = new Elysia({ prefix: "/tiktok-order" })
|
||||
aov: completedOrders > 0 ? totalRevenue / completedOrders : 0,
|
||||
}
|
||||
};
|
||||
})
|
||||
|
||||
// ── GET Thailand Sales Map (77 Provinces & Top 20) ──────────────────────
|
||||
.get("/sales-map", async ({ query }) => {
|
||||
const shop = (query.shop as string) || "hom-aroma";
|
||||
const dateFrom = query.dateFrom as string | undefined;
|
||||
const dateTo = query.dateTo as string | undefined;
|
||||
|
||||
const where: any = {};
|
||||
if (shop && shop !== "all") {
|
||||
where.shop = shop;
|
||||
}
|
||||
if (dateFrom || dateTo) {
|
||||
where.createdTime = {};
|
||||
if (dateFrom) where.createdTime.gte = dateFrom;
|
||||
if (dateTo) where.createdTime.lte = dateTo + " 23:59";
|
||||
}
|
||||
|
||||
const orders = await prisma.tiktokOrder.findMany({
|
||||
where,
|
||||
select: {
|
||||
orderId: true,
|
||||
province: true,
|
||||
district: true,
|
||||
orderAmount: true,
|
||||
status: true,
|
||||
createdTime: true,
|
||||
},
|
||||
});
|
||||
|
||||
// Map each order to standard province
|
||||
const provSalesMap = new Map<string, { code: string; nameTh: string; nameEn: string; region: string; regionTh: string; revenue: number; orders: number }>();
|
||||
|
||||
// Initialize with all 77 provinces
|
||||
for (const p of THAILAND_PROVINCES) {
|
||||
provSalesMap.set(p.nameTh, {
|
||||
code: p.code,
|
||||
nameTh: p.nameTh,
|
||||
nameEn: p.nameEn,
|
||||
region: p.region,
|
||||
regionTh: p.regionTh,
|
||||
revenue: 0,
|
||||
orders: 0,
|
||||
});
|
||||
}
|
||||
|
||||
let totalRevenue = 0;
|
||||
let totalOrders = orders.length;
|
||||
let unmappedOrders = 0;
|
||||
let unmappedRevenue = 0;
|
||||
|
||||
for (const o of orders) {
|
||||
totalRevenue += o.orderAmount;
|
||||
const matched = findProvince(o.province);
|
||||
if (matched) {
|
||||
const p = provSalesMap.get(matched.nameTh)!;
|
||||
p.revenue += o.orderAmount;
|
||||
p.orders += 1;
|
||||
} else {
|
||||
unmappedOrders += 1;
|
||||
unmappedRevenue += o.orderAmount;
|
||||
}
|
||||
}
|
||||
|
||||
const provinceList = Array.from(provSalesMap.values());
|
||||
const activeProvinces = provinceList.filter(p => p.orders > 0);
|
||||
const coverageCount = activeProvinces.length;
|
||||
|
||||
// Top 20 provinces by revenue
|
||||
const topProvinces = [...provinceList]
|
||||
.sort((a, b) => b.revenue - a.revenue)
|
||||
.slice(0, 20)
|
||||
.map((p, idx) => ({
|
||||
rank: idx + 1,
|
||||
...p,
|
||||
aov: p.orders > 0 ? p.revenue / p.orders : 0,
|
||||
}));
|
||||
|
||||
// Region Breakdown
|
||||
const regionMap = new Map<string, { region: string; regionTh: string; revenue: number; orders: number }>();
|
||||
for (const p of provinceList) {
|
||||
if (!regionMap.has(p.region)) {
|
||||
regionMap.set(p.region, { region: p.region, regionTh: p.regionTh, revenue: 0, orders: 0 });
|
||||
}
|
||||
const r = regionMap.get(p.region)!;
|
||||
r.revenue += p.revenue;
|
||||
r.orders += p.orders;
|
||||
}
|
||||
const regionBreakdown = Array.from(regionMap.values())
|
||||
.map(r => ({
|
||||
...r,
|
||||
percentage: totalRevenue > 0 ? (r.revenue / totalRevenue) * 100 : 0,
|
||||
}))
|
||||
.sort((a, b) => b.revenue - a.revenue);
|
||||
|
||||
const topRegion = regionBreakdown[0] || { region: 'Northeast', regionTh: 'ภาคอีสาน', revenue: 0, orders: 0 };
|
||||
const aov = totalOrders > 0 ? totalRevenue / totalOrders : 0;
|
||||
|
||||
return {
|
||||
kpi: {
|
||||
totalRevenue,
|
||||
totalOrders,
|
||||
coverageCount,
|
||||
coverageTotal: 77,
|
||||
coveragePercent: (coverageCount / 77) * 100,
|
||||
aov,
|
||||
topRegion: {
|
||||
name: topRegion.regionTh,
|
||||
orders: topRegion.orders,
|
||||
revenue: topRegion.revenue,
|
||||
},
|
||||
unmappedOrders,
|
||||
unmappedRevenue,
|
||||
},
|
||||
provinces: provinceList,
|
||||
topProvinces,
|
||||
regionBreakdown,
|
||||
};
|
||||
})
|
||||
|
||||
// ── GET District Level Details & Orders ──────────────────────────────────
|
||||
.get("/sales-map/district", async ({ query, set }) => {
|
||||
const provinceQuery = query.province as string;
|
||||
if (!provinceQuery) {
|
||||
set.status = 400;
|
||||
return { error: "Province is required" };
|
||||
}
|
||||
|
||||
const targetProv = findProvince(provinceQuery);
|
||||
const provNameTh = targetProv ? targetProv.nameTh : provinceQuery;
|
||||
|
||||
const shop = query.shop as string | undefined;
|
||||
const dateFrom = query.dateFrom as string | undefined;
|
||||
const dateTo = query.dateTo as string | undefined;
|
||||
|
||||
const where: any = {};
|
||||
if (shop && shop !== "all") {
|
||||
where.shop = shop;
|
||||
}
|
||||
if (dateFrom || dateTo) {
|
||||
where.createdTime = {};
|
||||
if (dateFrom) where.createdTime.gte = dateFrom;
|
||||
if (dateTo) where.createdTime.lte = dateTo + " 23:59";
|
||||
}
|
||||
|
||||
// Fetch all orders matching filter
|
||||
const allOrders = await prisma.tiktokOrder.findMany({
|
||||
where,
|
||||
include: {
|
||||
items: true,
|
||||
},
|
||||
orderBy: { createdTime: "desc" },
|
||||
});
|
||||
|
||||
// Filter in JS using findProvince to match variants
|
||||
const matchedOrders = allOrders.filter(o => {
|
||||
const p = findProvince(o.province);
|
||||
return p ? p.nameTh === provNameTh : (o.province?.includes(provNameTh) || provNameTh.includes(o.province || ''));
|
||||
});
|
||||
|
||||
// Group by cleaned district name
|
||||
const districtMap = new Map<string, { districtName: string; revenue: number; orders: number }>();
|
||||
let provRevenue = 0;
|
||||
|
||||
for (const o of matchedOrders) {
|
||||
provRevenue += o.orderAmount;
|
||||
const dName = cleanDistrictName(o.district) || "ไม่ระบุอำเภอ";
|
||||
if (!districtMap.has(dName)) {
|
||||
districtMap.set(dName, { districtName: dName, revenue: 0, orders: 0 });
|
||||
}
|
||||
const d = districtMap.get(dName)!;
|
||||
d.revenue += o.orderAmount;
|
||||
d.orders += 1;
|
||||
}
|
||||
|
||||
const districts = Array.from(districtMap.values()).sort((a, b) => b.revenue - a.revenue);
|
||||
|
||||
return {
|
||||
province: targetProv || { nameTh: provNameTh, nameEn: provNameTh, region: 'Central', regionTh: 'ภาคกลาง', code: '' },
|
||||
summary: {
|
||||
totalRevenue: provRevenue,
|
||||
totalOrders: matchedOrders.length,
|
||||
districtCount: districts.length,
|
||||
},
|
||||
districts,
|
||||
orders: matchedOrders.map(o => ({
|
||||
orderId: o.orderId,
|
||||
shop: o.shop,
|
||||
status: o.status,
|
||||
subStatus: o.subStatus,
|
||||
buyerUsername: o.buyerUsername,
|
||||
createdTime: o.createdTime,
|
||||
orderAmount: o.orderAmount,
|
||||
shippingFee: o.shippingFee,
|
||||
province: o.province,
|
||||
district: cleanDistrictName(o.district) || o.district || 'ไม่ระบุอำเภอ',
|
||||
itemsCount: o.items.reduce((s, i) => s + i.quantity, 0),
|
||||
items: o.items.map(i => ({
|
||||
productName: i.productName,
|
||||
variation: i.variation,
|
||||
sellerSku: i.sellerSku,
|
||||
quantity: i.quantity,
|
||||
subtotalAfterDiscount: i.subtotalAfterDiscount,
|
||||
unitOriginalPrice: i.unitOriginalPrice,
|
||||
})),
|
||||
})),
|
||||
};
|
||||
});
|
||||
@@ -0,0 +1,146 @@
|
||||
export interface ProvinceMeta {
|
||||
code: string;
|
||||
nameTh: string;
|
||||
nameEn: string;
|
||||
region: 'North' | 'Northeast' | 'Central' | 'East' | 'West' | 'South';
|
||||
regionTh: string;
|
||||
}
|
||||
|
||||
export const REGION_TH_MAP: Record<string, string> = {
|
||||
North: 'ภาคเหนือ',
|
||||
Northeast: 'ภาคอีสาน',
|
||||
Central: 'ภาคกลาง',
|
||||
East: 'ภาคตะวันออก',
|
||||
West: 'ภาคตะวันตก',
|
||||
South: 'ภาคใต้',
|
||||
};
|
||||
|
||||
export const THAILAND_PROVINCES: ProvinceMeta[] = [
|
||||
{ code: '10', nameTh: 'กรุงเทพมหานคร', nameEn: 'Bangkok', region: 'Central', regionTh: 'ภาคกลาง' },
|
||||
{ code: '11', nameTh: 'สมุทรปราการ', nameEn: 'Samut Prakan', region: 'Central', regionTh: 'ภาคกลาง' },
|
||||
{ code: '12', nameTh: 'นนทบุรี', nameEn: 'Nonthaburi', region: 'Central', regionTh: 'ภาคกลาง' },
|
||||
{ code: '13', nameTh: 'ปทุมธานี', nameEn: 'Pathum Thani', region: 'Central', regionTh: 'ภาคกลาง' },
|
||||
{ code: '14', nameTh: 'พระนครศรีอยุธยา', nameEn: 'Phra Nakhon Si Ayutthaya', region: 'Central', regionTh: 'ภาคกลาง' },
|
||||
{ code: '15', nameTh: 'อ่างทอง', nameEn: 'Ang Thong', region: 'Central', regionTh: 'ภาคกลาง' },
|
||||
{ code: '16', nameTh: 'ลพบุรี', nameEn: 'Lop Buri', region: 'Central', regionTh: 'ภาคกลาง' },
|
||||
{ code: '17', nameTh: 'สิงห์บุรี', nameEn: 'Sing Buri', region: 'Central', regionTh: 'ภาคกลาง' },
|
||||
{ code: '18', nameTh: 'ชัยนาท', nameEn: 'Chai Nat', region: 'Central', regionTh: 'ภาคกลาง' },
|
||||
{ code: '19', nameTh: 'สระบุรี', nameEn: 'Saraburi', region: 'Central', regionTh: 'ภาคกลาง' },
|
||||
{ code: '20', nameTh: 'ชลบุรี', nameEn: 'Chon Buri', region: 'East', regionTh: 'ภาคตะวันออก' },
|
||||
{ code: '21', nameTh: 'ระยอง', nameEn: 'Rayong', region: 'East', regionTh: 'ภาคตะวันออก' },
|
||||
{ code: '22', nameTh: 'จันทบุรี', nameEn: 'Chanthaburi', region: 'East', regionTh: 'ภาคตะวันออก' },
|
||||
{ code: '23', nameTh: 'ตราด', nameEn: 'Trat', region: 'East', regionTh: 'ภาคตะวันออก' },
|
||||
{ code: '24', nameTh: 'ฉะเชิงเทรา', nameEn: 'Chachoengsao', region: 'East', regionTh: 'ภาคตะวันออก' },
|
||||
{ code: '25', nameTh: 'ปราจีนบุรี', nameEn: 'Prachin Buri', region: 'East', regionTh: 'ภาคตะวันออก' },
|
||||
{ code: '26', nameTh: 'นครนายก', nameEn: 'Nakhon Nayok', region: 'Central', regionTh: 'ภาคกลาง' },
|
||||
{ code: '27', nameTh: 'สระแก้ว', nameEn: 'Sa Kaeo', region: 'East', regionTh: 'ภาคตะวันออก' },
|
||||
{ code: '30', nameTh: 'นครราชสีมา', nameEn: 'Nakhon Ratchasima', region: 'Northeast', regionTh: 'ภาคอีสาน' },
|
||||
{ code: '31', nameTh: 'บุรีรัมย์', nameEn: 'Buri Ram', region: 'Northeast', regionTh: 'ภาคอีสาน' },
|
||||
{ code: '32', nameTh: 'สุรินทร์', nameEn: 'Surin', region: 'Northeast', regionTh: 'ภาคอีสาน' },
|
||||
{ code: '33', nameTh: 'ศรีสะเกษ', nameEn: 'Si Sa Ket', region: 'Northeast', regionTh: 'ภาคอีสาน' },
|
||||
{ code: '34', nameTh: 'อุบลราชธานี', nameEn: 'Ubon Ratchathani', region: 'Northeast', regionTh: 'ภาคอีสาน' },
|
||||
{ code: '35', nameTh: 'ยโสธร', nameEn: 'Yasothon', region: 'Northeast', regionTh: 'ภาคอีสาน' },
|
||||
{ code: '36', nameTh: 'ชัยภูมิ', nameEn: 'Chaiyaphum', region: 'Northeast', regionTh: 'ภาคอีสาน' },
|
||||
{ code: '37', nameTh: 'อำนาจเจริญ', nameEn: 'Amnat Charoen', region: 'Northeast', regionTh: 'ภาคอีสาน' },
|
||||
{ code: '38', nameTh: 'บึงกาฬ', nameEn: 'Bueng Kan', region: 'Northeast', regionTh: 'ภาคอีสาน' },
|
||||
{ code: '39', nameTh: 'หนองบัวลำภู', nameEn: 'Nong Bua Lam Phu', region: 'Northeast', regionTh: 'ภาคอีสาน' },
|
||||
{ code: '40', nameTh: 'ขอนแก่น', nameEn: 'Khon Kaen', region: 'Northeast', regionTh: 'ภาคอีสาน' },
|
||||
{ code: '41', nameTh: 'อุดรธานี', nameEn: 'Udon Thani', region: 'Northeast', regionTh: 'ภาคอีสาน' },
|
||||
{ code: '42', nameTh: 'เลย', nameEn: 'Loei', region: 'Northeast', regionTh: 'ภาคอีสาน' },
|
||||
{ code: '43', nameTh: 'หนองคาย', nameEn: 'Nong Khai', region: 'Northeast', regionTh: 'ภาคอีสาน' },
|
||||
{ code: '44', nameTh: 'มหาสารคาม', nameEn: 'Maha Sarakham', region: 'Northeast', regionTh: 'ภาคอีสาน' },
|
||||
{ code: '45', nameTh: 'ร้อยเอ็ด', nameEn: 'Roi Et', region: 'Northeast', regionTh: 'ภาคอีสาน' },
|
||||
{ code: '46', nameTh: 'กาฬสินธุ์', nameEn: 'Kalasin', region: 'Northeast', regionTh: 'ภาคอีสาน' },
|
||||
{ code: '47', nameTh: 'สกลนคร', nameEn: 'Sakon Nakhon', region: 'Northeast', regionTh: 'ภาคอีสาน' },
|
||||
{ code: '48', nameTh: 'นครพนม', nameEn: 'Nakhon Phanom', region: 'Northeast', regionTh: 'ภาคอีสาน' },
|
||||
{ code: '49', nameTh: 'มุกดาหาร', nameEn: 'Mukdahan', region: 'Northeast', regionTh: 'ภาคอีสาน' },
|
||||
{ code: '50', nameTh: 'เชียงใหม่', nameEn: 'Chiang Mai', region: 'North', regionTh: 'ภาคเหนือ' },
|
||||
{ code: '51', nameTh: 'ลำพูน', nameEn: 'Lamphun', region: 'North', regionTh: 'ภาคเหนือ' },
|
||||
{ code: '52', nameTh: 'ลำปาง', nameEn: 'Lampang', region: 'North', regionTh: 'ภาคเหนือ' },
|
||||
{ code: '53', nameTh: 'อุตรดิตถ์', nameEn: 'Uttaradit', region: 'North', regionTh: 'ภาคเหนือ' },
|
||||
{ code: '54', nameTh: 'แพร่', nameEn: 'Phrae', region: 'North', regionTh: 'ภาคเหนือ' },
|
||||
{ code: '55', nameTh: 'น่าน', nameEn: 'Nan', region: 'North', regionTh: 'ภาคเหนือ' },
|
||||
{ code: '56', nameTh: 'พะเยา', nameEn: 'Phayao', region: 'North', regionTh: 'ภาคเหนือ' },
|
||||
{ code: '57', nameTh: 'เชียงราย', nameEn: 'Chiang Rai', region: 'North', regionTh: 'ภาคเหนือ' },
|
||||
{ code: '58', nameTh: 'แม่ฮ่องสอน', nameEn: 'Mae Hong Son', region: 'North', regionTh: 'ภาคเหนือ' },
|
||||
{ code: '60', nameTh: 'นครสวรรค์', nameEn: 'Nakhon Sawan', region: 'Central', regionTh: 'ภาคกลาง' },
|
||||
{ code: '61', nameTh: 'อุทัยธานี', nameEn: 'Uthai Thani', region: 'Central', regionTh: 'ภาคกลาง' },
|
||||
{ code: '62', nameTh: 'กำแพงเพชร', nameEn: 'Kamphaeng Phet', region: 'Central', regionTh: 'ภาคกลาง' },
|
||||
{ code: '63', nameTh: 'ตาก', nameEn: 'Tak', region: 'West', regionTh: 'ภาคตะวันตก' },
|
||||
{ code: '64', nameTh: 'สุโขทัย', nameEn: 'Sukhothai', region: 'Central', regionTh: 'ภาคกลาง' },
|
||||
{ code: '65', nameTh: 'พิษณุโลก', nameEn: 'Phitsanulok', region: 'Central', regionTh: 'ภาคกลาง' },
|
||||
{ code: '66', nameTh: 'พิจิตร', nameEn: 'Phichit', region: 'Central', regionTh: 'ภาคกลาง' },
|
||||
{ code: '67', nameTh: 'เพชรบูรณ์', nameEn: 'Phetchabun', region: 'Central', regionTh: 'ภาคกลาง' },
|
||||
{ code: '70', nameTh: 'ราชบุรี', nameEn: 'Ratchaburi', region: 'West', regionTh: 'ภาคตะวันตก' },
|
||||
{ code: '71', nameTh: 'กาญจนบุรี', nameEn: 'Kanchanaburi', region: 'West', regionTh: 'ภาคตะวันตก' },
|
||||
{ code: '72', nameTh: 'สุพรรณบุรี', nameEn: 'Suphan Buri', region: 'Central', regionTh: 'ภาคกลาง' },
|
||||
{ code: '73', nameTh: 'นครปฐม', nameEn: 'Nakhon Pathom', region: 'Central', regionTh: 'ภาคกลาง' },
|
||||
{ code: '74', nameTh: 'สมุทรสาคร', nameEn: 'Samut Sakhon', region: 'Central', regionTh: 'ภาคกลาง' },
|
||||
{ code: '75', nameTh: 'สมุทรสงคราม', nameEn: 'Samut Songkhram', region: 'Central', regionTh: 'ภาคกลาง' },
|
||||
{ code: '76', nameTh: 'เพชรบุรี', nameEn: 'Phetchaburi', region: 'West', regionTh: 'ภาคตะวันตก' },
|
||||
{ code: '77', nameTh: 'ประจวบคีรีขันธ์', nameEn: 'Prachuap Khiri Khan', region: 'West', regionTh: 'ภาคตะวันตก' },
|
||||
{ code: '80', nameTh: 'นครศรีธรรมราช', nameEn: 'Nakhon Si Thammarat', region: 'South', regionTh: 'ภาคใต้' },
|
||||
{ code: '81', nameTh: 'กระบี่', nameEn: 'Krabi', region: 'South', regionTh: 'ภาคใต้' },
|
||||
{ code: '82', nameTh: 'พังงา', nameEn: 'Phangnga', region: 'South', regionTh: 'ภาคใต้' },
|
||||
{ code: '83', nameTh: 'ภูเก็ต', nameEn: 'Phuket', region: 'South', regionTh: 'ภาคใต้' },
|
||||
{ code: '84', nameTh: 'สุราษฎร์ธานี', nameEn: 'Surat Thani', region: 'South', regionTh: 'ภาคใต้' },
|
||||
{ code: '85', nameTh: 'ระนอง', nameEn: 'Ranong', region: 'South', regionTh: 'ภาคใต้' },
|
||||
{ code: '86', nameTh: 'ชุมพร', nameEn: 'Chumphon', region: 'South', regionTh: 'ภาคใต้' },
|
||||
{ code: '90', nameTh: 'สงขลา', nameEn: 'Songkhla', region: 'South', regionTh: 'ภาคใต้' },
|
||||
{ code: '91', nameTh: 'สตูล', nameEn: 'Satun', region: 'South', regionTh: 'ภาคใต้' },
|
||||
{ code: '92', nameTh: 'ตรัง', nameEn: 'Trang', region: 'South', regionTh: 'ภาคใต้' },
|
||||
{ code: '93', nameTh: 'พัทลุง', nameEn: 'Phatthalung', region: 'South', regionTh: 'ภาคใต้' },
|
||||
{ code: '94', nameTh: 'ปัตตานี', nameEn: 'Pattani', region: 'South', regionTh: 'ภาคใต้' },
|
||||
{ code: '95', nameTh: 'ยะลา', nameEn: 'Yala', region: 'South', regionTh: 'ภาคใต้' },
|
||||
{ code: '96', nameTh: 'นราธิวาส', nameEn: 'Narathiwat', region: 'South', regionTh: 'ภาคใต้' },
|
||||
];
|
||||
|
||||
const ALIAS_MAP: Record<string, string> = {
|
||||
'กทม': 'กรุงเทพมหานคร',
|
||||
'กทม.': 'กรุงเทพมหานคร',
|
||||
'กรุงเทพ': 'กรุงเทพมหานคร',
|
||||
'กรุงเทพฯ': 'กรุงเทพมหานคร',
|
||||
'bangkok': 'กรุงเทพมหานคร',
|
||||
'bkk': 'กรุงเทพมหานคร',
|
||||
'korat': 'นครราชสีมา',
|
||||
'โคราช': 'นครราชสีมา',
|
||||
'ayutthaya': 'พระนครศรีอยุธยา',
|
||||
'อยุธยา': 'พระนครศรีอยุธยา',
|
||||
};
|
||||
|
||||
const cleanStr = (s: string) => s.toLowerCase().replace(/[\s\-_.,()จ\.\/\\]/g, '').trim();
|
||||
|
||||
const PROVINCE_LOOKUP = new Map<string, ProvinceMeta>();
|
||||
|
||||
for (const p of THAILAND_PROVINCES) {
|
||||
PROVINCE_LOOKUP.set(cleanStr(p.nameTh), p);
|
||||
PROVINCE_LOOKUP.set(cleanStr(p.nameEn), p);
|
||||
PROVINCE_LOOKUP.set(p.code, p);
|
||||
}
|
||||
|
||||
for (const [alias, targetName] of Object.entries(ALIAS_MAP)) {
|
||||
const target = THAILAND_PROVINCES.find(p => p.nameTh === targetName);
|
||||
if (target) {
|
||||
PROVINCE_LOOKUP.set(cleanStr(alias), target);
|
||||
}
|
||||
}
|
||||
|
||||
export function findProvince(input: string | null | undefined): ProvinceMeta | null {
|
||||
if (!input) return null;
|
||||
const cleaned = cleanStr(input);
|
||||
if (PROVINCE_LOOKUP.has(cleaned)) return PROVINCE_LOOKUP.get(cleaned)!;
|
||||
|
||||
for (const [key, val] of PROVINCE_LOOKUP.entries()) {
|
||||
if (key.length >= 3 && (cleaned.includes(key) || key.includes(cleaned))) {
|
||||
return val;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export function cleanDistrictName(input: string | null | undefined): string {
|
||||
if (!input) return '';
|
||||
return input
|
||||
.replace(/^(อำเภอ|อ\.|เขต|แขวง|ตำบล|ต\.)\s*/, '')
|
||||
.trim();
|
||||
}
|
||||
Reference in new issue
Block a user