x
This commit is contained in:
1 parent
c23a4723ed
commit
07e9413a6b
13 files changed
+497
-94
No files matched your search
@@ -1 +1,9 @@
|
||||
DATABASE_URL="postgresql://postgres:postgres@localhost:5550/homaroma_db?schema=public"
|
||||
PORT=3051
|
||||
OMISE_SECRET_KEY="skey_test_67xsxzvrku2w9bc11rq"
|
||||
APP_URL="https://api.homaroma.shop"
|
||||
APP_URL="https://api.homaroma.shop"
|
||||
BACKEND_PUBLIC_URL="https://api.homaroma.shop"
|
||||
LINE_CHANNEL_SECRET="f003b6def9f33e44c7ef27c60823c392"
|
||||
LINE_CHANNEL_ACCESS_TOKEN="HdKPnnebRILkn9L73CwssVKL7sPI5MeAFP7rI6eEtY6tm7SVD34KaYZPCPy7sn1Wj4NY0yq2d9nqSYqaIqBZMP/bPc8ZqT861sgk9dt2l9k9KvvlbDI7eISP5y/1f4xI6+l5uLHK08koxD0djiUCxQdB04t89/1O/w1cDnyilFU="
|
||||
ti@pc-server:~/projects/homaroma-api
|
||||
@@ -0,0 +1,24 @@
|
||||
import prisma from './src/lib/prisma';
|
||||
|
||||
async function main() {
|
||||
console.log('Starting deletion process...');
|
||||
|
||||
try {
|
||||
// Delete all product variants first to avoid foreign key constraint errors
|
||||
const deletedVariants = await prisma.productVariant.deleteMany({});
|
||||
console.log(`Deleted ${deletedVariants.count} ProductVariants.`);
|
||||
|
||||
// Delete all products
|
||||
const deletedProducts = await prisma.product.deleteMany({});
|
||||
console.log(`Deleted ${deletedProducts.count} Products.`);
|
||||
|
||||
console.log('Deletion completed successfully.');
|
||||
} catch (error) {
|
||||
console.error('Error deleting products:', error);
|
||||
process.exit(1);
|
||||
} finally {
|
||||
await prisma.$disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
@@ -0,0 +1,10 @@
|
||||
import prisma from './src/lib/prisma';
|
||||
async function main() {
|
||||
const brand = await prisma.productBrand.findFirst({ where: { name: 'DDC' } });
|
||||
let cat = await prisma.category.findFirst({ where: { name: 'Sprockets' } });
|
||||
if (!cat) {
|
||||
cat = await prisma.category.create({ data: { name: 'Sprockets' } });
|
||||
}
|
||||
console.log(JSON.stringify({brandId: brand?.id, catId: cat.id}));
|
||||
}
|
||||
main().catch(console.error).finally(() => process.exit(0));
|
||||
@@ -0,0 +1,16 @@
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
const prisma = new PrismaClient();
|
||||
prisma.product.findMany({
|
||||
include: {
|
||||
category: { include: { translations: true } },
|
||||
brand: true,
|
||||
translations: true,
|
||||
variants: {
|
||||
include: {
|
||||
bomItems: { include: { rawMaterial: true } }
|
||||
},
|
||||
orderBy: { price: "asc" }
|
||||
},
|
||||
images: { orderBy: { order: "asc" } },
|
||||
}
|
||||
}).then(console.log).catch(console.error).finally(() => prisma.$disconnect());
|
||||
@@ -0,0 +1,5 @@
|
||||
import prisma from './src/lib/prisma';
|
||||
prisma.storeSettingsTranslation.findMany({ select: { langCode: true } })
|
||||
.then(x => console.log([...new Set(x.map(r => r.langCode))]))
|
||||
.catch(console.error)
|
||||
.finally(() => prisma.$disconnect());
|
||||
@@ -0,0 +1,2 @@
|
||||
import prisma from './src/lib/prisma';
|
||||
prisma.menu.findMany().then(console.log).catch(console.error).finally(() => prisma.$disconnect());
|
||||
@@ -0,0 +1,14 @@
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
const prisma = new PrismaClient();
|
||||
prisma.page.findUnique({
|
||||
where: { slug: 'home' },
|
||||
include: {
|
||||
translations: true,
|
||||
sections: {
|
||||
include: {
|
||||
translations: true
|
||||
},
|
||||
orderBy: { order: "asc" }
|
||||
}
|
||||
}
|
||||
}).then(console.log).catch(console.error).finally(() => prisma.$disconnect());
|
||||
@@ -0,0 +1,10 @@
|
||||
import prisma from './src/lib/prisma';
|
||||
prisma.page.findUnique({
|
||||
where: { slug: 'home' },
|
||||
include: {
|
||||
translations: true,
|
||||
sections: {
|
||||
orderBy: { order: "asc" }
|
||||
}
|
||||
}
|
||||
}).then(console.log).catch(console.error).finally(() => prisma.$disconnect());
|
||||
@@ -4,15 +4,35 @@ import prisma from "../lib/prisma";
|
||||
export const productsRoute = new Elysia({ prefix: "/products" })
|
||||
.decorate("validateVariants", (options: any[] = [], variants: any[] = []) => {
|
||||
if (options.length > 3) throw new Error("Options array length cannot exceed 3.");
|
||||
|
||||
const getPrimaryValues = (values: any[]) => {
|
||||
return values.map(val => {
|
||||
if (typeof val === 'string') return val;
|
||||
if (typeof val === 'object' && val !== null) {
|
||||
return val.th || Object.values(val)[0];
|
||||
}
|
||||
return String(val);
|
||||
});
|
||||
};
|
||||
|
||||
for (const v of variants) {
|
||||
if (v.option1 && options[0] && !options[0].values.includes(v.option1)) {
|
||||
throw new Error(`Variant option1 '${v.option1}' is not found in options[0].values [${options[0].values.join(', ')}]`);
|
||||
if (v.option1 && options[0]) {
|
||||
const validValues = getPrimaryValues(options[0].values);
|
||||
if (!validValues.includes(v.option1)) {
|
||||
throw new Error(`Variant option1 '${v.option1}' is not found in options[0].values [${validValues.join(', ')}]`);
|
||||
}
|
||||
}
|
||||
if (v.option2 && options[1] && !options[1].values.includes(v.option2)) {
|
||||
throw new Error(`Variant option2 '${v.option2}' is not found in options[1].values [${options[1].values.join(', ')}]`);
|
||||
if (v.option2 && options[1]) {
|
||||
const validValues = getPrimaryValues(options[1].values);
|
||||
if (!validValues.includes(v.option2)) {
|
||||
throw new Error(`Variant option2 '${v.option2}' is not found in options[1].values [${validValues.join(', ')}]`);
|
||||
}
|
||||
}
|
||||
if (v.option3 && options[2] && !options[2].values.includes(v.option3)) {
|
||||
throw new Error(`Variant option3 '${v.option3}' is not found in options[2].values [${options[2].values.join(', ')}]`);
|
||||
if (v.option3 && options[2]) {
|
||||
const validValues = getPrimaryValues(options[2].values);
|
||||
if (!validValues.includes(v.option3)) {
|
||||
throw new Error(`Variant option3 '${v.option3}' is not found in options[2].values [${validValues.join(', ')}]`);
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -369,10 +389,28 @@ export const productsRoute = new Elysia({ prefix: "/products" })
|
||||
validateVariants(payload.options || [], payload.variants);
|
||||
}
|
||||
const product = await prisma.$transaction(async (tx) => {
|
||||
let categoryId = payload.categoryId;
|
||||
if (!categoryId && payload.categoryName) {
|
||||
let cat = await tx.category.findUnique({ where: { name: payload.categoryName } });
|
||||
if (!cat) {
|
||||
cat = await tx.category.create({ data: { name: payload.categoryName } });
|
||||
}
|
||||
categoryId = cat.id;
|
||||
}
|
||||
|
||||
let brandId = payload.brandId;
|
||||
if (!brandId && payload.brandName) {
|
||||
let brand = await tx.productBrand.findUnique({ where: { name: payload.brandName } });
|
||||
if (!brand) {
|
||||
brand = await tx.productBrand.create({ data: { name: payload.brandName } });
|
||||
}
|
||||
brandId = brand.id;
|
||||
}
|
||||
|
||||
const prod = await tx.product.create({
|
||||
data: {
|
||||
categoryId: payload.categoryId,
|
||||
brandId: payload.brandId,
|
||||
categoryId: categoryId,
|
||||
brandId: brandId,
|
||||
name: payload.name || "New Product",
|
||||
price: payload.price || 0,
|
||||
description: payload.description || "",
|
||||
@@ -381,15 +419,29 @@ export const productsRoute = new Elysia({ prefix: "/products" })
|
||||
}
|
||||
});
|
||||
|
||||
await tx.productTranslation.create({
|
||||
data: {
|
||||
productId: prod.id,
|
||||
langCode: 'th',
|
||||
name: payload.name || "New Product",
|
||||
description: payload.description || "",
|
||||
details: payload.details || "",
|
||||
if (payload.translations && typeof payload.translations === 'object') {
|
||||
for (const [lang, trans] of Object.entries(payload.translations)) {
|
||||
await tx.productTranslation.create({
|
||||
data: {
|
||||
productId: prod.id,
|
||||
langCode: lang,
|
||||
name: (trans as any).name || payload.name || "New Product",
|
||||
description: (trans as any).description || payload.description || "",
|
||||
details: (trans as any).details || payload.details || "",
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
await tx.productTranslation.create({
|
||||
data: {
|
||||
productId: prod.id,
|
||||
langCode: 'th',
|
||||
name: payload.name || "New Product",
|
||||
description: payload.description || "",
|
||||
details: payload.details || "",
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (payload.variants && payload.variants.length > 0) {
|
||||
for (const v of payload.variants) {
|
||||
@@ -437,6 +489,124 @@ export const productsRoute = new Elysia({ prefix: "/products" })
|
||||
},
|
||||
}
|
||||
)
|
||||
.post(
|
||||
"/bulk",
|
||||
async ({ body, status, validateVariants }) => {
|
||||
const payloadArray = body as any[];
|
||||
if (!Array.isArray(payloadArray)) {
|
||||
return status(400, { success: false, message: "Payload must be an array of products" });
|
||||
}
|
||||
|
||||
try {
|
||||
const createdProducts = await prisma.$transaction(async (tx) => {
|
||||
const results = [];
|
||||
|
||||
for (const payload of payloadArray) {
|
||||
if (payload.variants && Array.isArray(payload.variants)) {
|
||||
validateVariants(payload.options || [], payload.variants);
|
||||
}
|
||||
|
||||
let categoryId = payload.categoryId;
|
||||
if (!categoryId && payload.categoryName) {
|
||||
let cat = await tx.category.findUnique({ where: { name: payload.categoryName } });
|
||||
if (!cat) {
|
||||
cat = await tx.category.create({ data: { name: payload.categoryName } });
|
||||
}
|
||||
categoryId = cat.id;
|
||||
}
|
||||
|
||||
let brandId = payload.brandId;
|
||||
if (!brandId && payload.brandName) {
|
||||
let brand = await tx.productBrand.findUnique({ where: { name: payload.brandName } });
|
||||
if (!brand) {
|
||||
brand = await tx.productBrand.create({ data: { name: payload.brandName } });
|
||||
}
|
||||
brandId = brand.id;
|
||||
}
|
||||
|
||||
const prod = await tx.product.create({
|
||||
data: {
|
||||
categoryId: categoryId,
|
||||
brandId: brandId,
|
||||
name: payload.name || "New Product",
|
||||
price: payload.price || 0,
|
||||
description: payload.description || "",
|
||||
details: payload.details || "",
|
||||
options: payload.options || [],
|
||||
}
|
||||
});
|
||||
|
||||
if (payload.translations && typeof payload.translations === 'object') {
|
||||
for (const [lang, trans] of Object.entries(payload.translations)) {
|
||||
await tx.productTranslation.create({
|
||||
data: {
|
||||
productId: prod.id,
|
||||
langCode: lang,
|
||||
name: (trans as any).name || payload.name || "New Product",
|
||||
description: (trans as any).description || payload.description || "",
|
||||
details: (trans as any).details || payload.details || "",
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
await tx.productTranslation.create({
|
||||
data: {
|
||||
productId: prod.id,
|
||||
langCode: 'th',
|
||||
name: payload.name || "New Product",
|
||||
description: payload.description || "",
|
||||
details: payload.details || "",
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (payload.variants && payload.variants.length > 0) {
|
||||
for (const v of payload.variants) {
|
||||
await tx.productVariant.create({
|
||||
data: {
|
||||
productId: prod.id,
|
||||
sku: v.sku || null,
|
||||
barcode: v.barcode || null,
|
||||
stock: v.stock || 0,
|
||||
option1: v.option1 || "",
|
||||
option2: v.option2 || "",
|
||||
option3: v.option3 || "",
|
||||
price: v.price || 0,
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (payload.images && payload.images.length > 0) {
|
||||
for (const [idx, img] of payload.images.entries()) {
|
||||
await tx.productImage.create({
|
||||
data: {
|
||||
productId: prod.id,
|
||||
url: img.url,
|
||||
order: img.order ?? idx,
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
results.push(prod);
|
||||
}
|
||||
return results;
|
||||
});
|
||||
|
||||
return { success: true, products: createdProducts };
|
||||
} catch (err: any) {
|
||||
console.error("Bulk create products error:", err);
|
||||
return status(500, { success: false, message: err?.message || "Failed to bulk create products" });
|
||||
}
|
||||
},
|
||||
{
|
||||
body: t.Array(t.Any()),
|
||||
detail: {
|
||||
summary: "Bulk Create Products",
|
||||
tags: ["products"],
|
||||
},
|
||||
}
|
||||
)
|
||||
.patch(
|
||||
"/:id",
|
||||
async ({ params, body, status }) => {
|
||||
|
||||
Reference in new issue
Block a user