This commit is contained in:
Your Name committed 2026-10-08 08:08:37 +07:00
1 parent d13dedd215
commit dba82b26a8
17 files changed
+427 -71

No files matched your search

+82 -12
View File
@@ -15,7 +15,7 @@ export const ordersRoute = new Elysia({ prefix: "/orders" })
include: { items: true, customer: true }
});
})
.get("/:id", async ({ params: { id }, set }) => {
.get("/:id", async ({ params: { id }, query, set }) => {
const order = await prisma.order.findUnique({
where: { id: Number(id) },
include: { items: true, customer: true }
@@ -24,6 +24,42 @@ export const ordersRoute = new Elysia({ prefix: "/orders" })
set.status = 404;
return { error: "Order not found" };
}
const lang = (query as any)?.lang;
if (lang && lang !== 'all') {
const missingProductIds = order.items
.filter((item: any) => !item.translations || !(item.translations as any)?.name)
.map((item: any) => item.productId)
.filter(Boolean);
let legacyTranslationMap = new Map<number, Record<string, string>>();
if (missingProductIds.length > 0) {
const legacyTranslations = await prisma.productTranslation.findMany({
where: { productId: { in: missingProductIds } },
select: { productId: true, langCode: true, name: true }
});
for (const pt of legacyTranslations) {
if (!legacyTranslationMap.has(pt.productId)) legacyTranslationMap.set(pt.productId, {});
legacyTranslationMap.get(pt.productId)![pt.langCode] = pt.name;
}
}
const localizedItems = order.items.map((item: any) => {
const snapshotName = (item.translations as any)?.name?.[lang];
const legacyName = legacyTranslationMap.get(item.productId)?.[lang];
const localizedName = snapshotName || legacyName || item.productName;
return {
...item,
productName: localizedName,
};
});
return {
...order,
items: localizedItems,
};
}
return order;
})
.post("/", async ({ body, set }) => {
@@ -31,8 +67,9 @@ export const ordersRoute = new Elysia({ prefix: "/orders" })
const data = body as any;
const settings = await prisma.storeSettings.findFirst()
const earnRate = settings?.pointsEarnRate || 1.0
const netAmount = data.totalAmount - data.shippingFee
const pointsEarned = Math.floor(Math.max(0, netAmount) * earnRate)
const shippingFee = data.shippingFee || 0
const netAmount = (data.totalAmount || 0) - shippingFee
const pointsEarned = Number.isFinite(netAmount) ? Math.floor(Math.max(0, netAmount) * earnRate) : 0
if (data.customerId && data.pointsUsed && data.pointsUsed > 0) {
// Verify customer has enough points
@@ -51,6 +88,33 @@ export const ordersRoute = new Elysia({ prefix: "/orders" })
const isPos = data.channel === "POS";
const initialStatus = isPos ? "COMPLETED" : "PENDING_PAYMENT";
// Pre-fetch product names across all languages for immutable snapshotting
const productIds = Array.from(new Set((data.items || []).map((item: any) => Number(item.productId)).filter(Boolean))) as number[];
const [productRecords, productTranslations] = await Promise.all([
productIds.length > 0 ? prisma.product.findMany({
where: { id: { in: productIds } },
select: { id: true, name: true }
}) : [],
productIds.length > 0 ? prisma.productTranslation.findMany({
where: { productId: { in: productIds } },
select: { productId: true, langCode: true, name: true }
}) : []
]);
const translationMap = new Map<number, Record<string, string>>();
for (const p of productRecords) {
if (p.name) {
if (!translationMap.has(p.id)) translationMap.set(p.id, {});
translationMap.get(p.id)!['th'] = p.name;
}
}
for (const pt of productTranslations) {
if (pt.name) {
if (!translationMap.has(pt.productId)) translationMap.set(pt.productId, {});
translationMap.get(pt.productId)![pt.langCode] = pt.name;
}
}
const order = await prisma.order.create({
data: {
channel: data.channel || "ONLINE",
@@ -77,20 +141,26 @@ export const ordersRoute = new Elysia({ prefix: "/orders" })
changeAmount: data.changeAmount,
cashierId: data.cashierId,
items: {
create: data.items.map((item: any) => ({
productId: item.productId,
variantId: item.variantId,
quantity: item.quantity,
priceAtPurchase: item.priceAtPurchase,
productName: item.productName,
variantName: item.variantName,
productImage: item.productImage
}))
create: data.items.map((item: any) => {
const names = translationMap.get(Number(item.productId)) || {};
const translationsSnapshot = Object.keys(names).length > 0 ? { name: names } : undefined;
return {
productId: item.productId,
variantId: item.variantId,
quantity: item.quantity,
priceAtPurchase: item.priceAtPurchase,
productName: item.productName,
variantName: item.variantName,
productImage: item.productImage,
translations: translationsSnapshot,
};
})
}
},
include: { items: true }
});
// For POS orders: Deduct stock immediately and credit points
if (isPos) {
for (const item of data.items) {