x
This commit is contained in:
1 parent
d13dedd215
commit
dba82b26a8
17 files changed
+427
-71
No files matched your search
+2
@@ -0,0 +1,2 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE "OrderItem" ADD COLUMN "translations" JSONB;
|
||||
@@ -432,8 +432,10 @@ model OrderItem {
|
||||
productName String
|
||||
variantName String?
|
||||
productImage String?
|
||||
translations Json?
|
||||
}
|
||||
|
||||
|
||||
model Article {
|
||||
id Int @id @default(autoincrement())
|
||||
slug String @unique
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in new issue
Block a user