Compare commits

...

2 commits

Author SHA1 Message Date
HAM
61825309d1 feat: sync data from data to flowAccount
All checks were successful
Spell Check / Spell Check with Typos (push) Successful in 5s
2025-09-12 15:20:20 +07:00
HAM
250bbca226 feat: create product for flowAccount service 2025-09-12 15:19:51 +07:00
2 changed files with 215 additions and 0 deletions

View file

@ -30,6 +30,7 @@ import { deleteFile, deleteFolder, fileLocation, getFile, listFile, setFile } fr
import { isUsedError, notFoundError, relationError } from "../utils/error";
import { queryOrNot, whereDateQuery } from "../utils/relation";
import spreadsheet from "../utils/spreadsheet";
import flowAccount from "../services/flowaccount";
const MANAGE_ROLES = [
"system",
@ -299,6 +300,9 @@ export class ProductController extends Controller {
},
update: { value: { increment: 1 } },
});
const listId = await flowAccount.createProducts(body);
return await prisma.product.create({
include: {
createdBy: true,
@ -306,6 +310,8 @@ export class ProductController extends Controller {
},
data: {
...body,
flowAccountProductIdAgentPrice: `${listId.data.productIdAgentPrice}`,
flowAccountProductIdSellPrice: `${listId.data.productIdSellPrice}`,
document: body.document
? {
createMany: { data: body.document.map((v) => ({ name: v })) },
@ -379,6 +385,19 @@ export class ProductController extends Controller {
await permissionCheck(req.user, productGroup.registeredBranch);
}
if (
product.flowAccountProductIdSellPrice !== null &&
product.flowAccountProductIdAgentPrice !== null
) {
await flowAccount.editProducts(
product.flowAccountProductIdSellPrice,
product.flowAccountProductIdAgentPrice,
body,
);
} else {
throw notFoundError("FlowAccountProductId");
}
const record = await prisma.product.update({
include: {
productGroup: true,
@ -441,6 +460,18 @@ export class ProductController extends Controller {
if (record.status !== Status.CREATED) throw isUsedError("Product");
if (
record.flowAccountProductIdSellPrice !== null &&
record.flowAccountProductIdAgentPrice !== null
) {
await Promise.all([
flowAccount.deleteProduct(record.flowAccountProductIdSellPrice),
flowAccount.deleteProduct(record.flowAccountProductIdAgentPrice),
]);
} else {
throw notFoundError("FlowAccountProductId");
}
await deleteFolder(fileLocation.product.img(productId));
return await prisma.product.delete({

View file

@ -3,6 +3,7 @@ import config from "../config.json";
import { CustomerType, PayCondition } from "@prisma/client";
import { convertTemplate } from "../utils/string-template";
import { htmlToText } from "html-to-text";
import { JsonObject } from "@prisma/client/runtime/library";
if (!process.env.FLOW_ACCOUNT_URL) throw new Error("Require FLOW_ACCOUNT_URL");
if (!process.env.FLOW_ACCOUNT_CLIENT_ID) throw new Error("Require FLOW_ACCOUNT_CLIENT_ID");
@ -388,6 +389,189 @@ const flowAccount = {
}
return null;
},
// flowAccount GET Product list
async getProducts() {
const { token } = await flowAccountAPI.auth();
const res = await fetch(api + "/products", {
method: "GET",
headers: {
["Content-Type"]: `application/json`,
["Authorization"]: `Bearer ${token}`,
},
});
return {
ok: res.ok,
status: res.status,
body: await res.json(),
};
},
// flowAccount GET Product by id
async getProductsById(recordId: string) {
const { token } = await flowAccountAPI.auth();
const res = await fetch(api + `/products/${recordId}`, {
method: "GET",
headers: {
["Content-Type"]: `application/json`,
["Authorization"]: `Bearer ${token}`,
},
});
const data = await res.json();
return {
ok: res.ok,
status: res.status,
list: data.data.list,
total: data.data.total,
};
},
// flowAccount POST create Product
async createProducts(body: JsonObject) {
const { token } = await flowAccountAPI.auth();
const commonBody = {
productStructureType: null,
type: "3",
name: body.name,
sellDescription: body.detail,
sellVatType: 3,
unitName: "Unit",
categoryName: "Car",
}; // helper function สำหรับสร้าง product
const createProduct = async (price: any, vatIncluded: boolean) => {
try {
const res = await fetch(api + "/products", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${token}`,
},
body: JSON.stringify({
...commonBody,
sellPrice: price,
sellVatType: vatIncluded ? 1 : 3,
}),
});
if (!res.ok) {
throw new Error(`Request failed with status ${res.status}`);
} // ป้องกัน response ที่ไม่ใช่ JSON หรือว่าง
let json: any = null;
try {
json = await res.json();
} catch {
throw new Error("Response is not valid JSON");
}
return json?.data?.list?.[0]?.id ?? null;
} catch (err) {
console.error("createProduct error:", err);
return null;
}
};
const [sellId, agentId] = await Promise.all([
createProduct(body.price, /true/.test(`${body.vatIncluded}`)),
createProduct(body.agentPrice, /true/.test(`${body.agentPriceVatIncluded}`)),
]);
return {
ok: !!(agentId && sellId),
status: agentId && sellId ? 200 : 500,
data: {
productIdAgentPrice: agentId,
productIdSellPrice: sellId,
},
};
},
// flowAccount PUT edit Product
async editProducts(sellPriceId: String, agentPriceId: String, body: JsonObject) {
console.log("body: ", body);
const { token } = await flowAccountAPI.auth();
const commonBody = {
productStructureType: null,
type: "3",
name: body.name,
sellDescription: body.detail,
sellVatType: 3,
unitName: "Unit",
categoryName: "Car",
}; // helper function สำหรับสร้าง product
const editProduct = async (id: String, price: any, vatIncluded: boolean) => {
try {
const res = await fetch(api + `/products/${id}`, {
method: "PUT",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${token}`,
},
body: JSON.stringify({
...commonBody,
sellPrice: price,
sellVatType: vatIncluded ? 1 : 3,
}),
});
if (!res.ok) {
throw new Error(`Request failed with status ${res.status}`);
} // ป้องกัน response ที่ไม่ใช่ JSON หรือว่าง
let json: any = null;
try {
json = await res.json();
} catch {
throw new Error("Response is not valid JSON");
}
return json?.data?.list?.[0]?.id ?? null;
} catch (err) {
console.error("createProduct error:", err);
return null;
}
};
const [agentId, sellId] = await Promise.all([
editProduct(sellPriceId, body.price, /true/.test(`${body.vatIncluded}`)),
editProduct(agentPriceId, body.agentPrice, /true/.test(`${body.agentPriceVatIncluded}`)),
]);
return {
ok: !!(agentId && sellId),
status: agentId && sellId ? 200 : 500,
data: {
productIdAgentPrice: agentId,
productIdSellPrice: sellId,
},
};
},
// flowAccount DELETE Product
async deleteProduct(recordId: string) {
const { token } = await flowAccountAPI.auth();
const res = await fetch(api + `/products/${recordId}`, {
method: "DELETE",
headers: {
["Authorization"]: `Bearer ${token}`,
},
});
return {
ok: res.ok,
status: res.status,
};
},
};
export default flowAccount;