refactor: update quotation
This commit is contained in:
parent
353d372dd8
commit
8ae8ec7002
2 changed files with 73 additions and 58 deletions
|
|
@ -1,8 +1,3 @@
|
||||||
{
|
{
|
||||||
"branch": {
|
"vat": 0.07
|
||||||
"maxHeadOfficeBranch": 10
|
|
||||||
},
|
|
||||||
"personnel": {
|
|
||||||
"type": ["USER", "MESSENGER", "DELEGATE", "AGENCY"]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import { PayCondition, Prisma, Status } from "@prisma/client";
|
import { PayCondition, Prisma, Status } from "@prisma/client";
|
||||||
|
import config from "../config.json";
|
||||||
import {
|
import {
|
||||||
Body,
|
Body,
|
||||||
Controller,
|
Controller,
|
||||||
|
|
@ -63,6 +64,7 @@ type QuotationCreate = {
|
||||||
urgent?: boolean;
|
urgent?: boolean;
|
||||||
|
|
||||||
agentPrice?: boolean;
|
agentPrice?: boolean;
|
||||||
|
discount?: number;
|
||||||
|
|
||||||
productServiceList: {
|
productServiceList: {
|
||||||
serviceId?: string;
|
serviceId?: string;
|
||||||
|
|
@ -74,12 +76,7 @@ type QuotationCreate = {
|
||||||
* @minimum 0
|
* @minimum 0
|
||||||
*/
|
*/
|
||||||
discount?: number;
|
discount?: number;
|
||||||
pricePerUnit?: number;
|
workerIndex?: number[];
|
||||||
/**
|
|
||||||
* @maximum 1
|
|
||||||
* @minimum 0
|
|
||||||
*/
|
|
||||||
vat?: number;
|
|
||||||
}[];
|
}[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -122,6 +119,8 @@ type QuotationUpdate = {
|
||||||
|
|
||||||
urgent?: boolean;
|
urgent?: boolean;
|
||||||
|
|
||||||
|
discount?: number;
|
||||||
|
|
||||||
productServiceList?: {
|
productServiceList?: {
|
||||||
serviceId?: string;
|
serviceId?: string;
|
||||||
workId?: string;
|
workId?: string;
|
||||||
|
|
@ -132,15 +131,12 @@ type QuotationUpdate = {
|
||||||
* @minimum 0
|
* @minimum 0
|
||||||
*/
|
*/
|
||||||
discount: number;
|
discount: number;
|
||||||
pricePerUnit?: number;
|
workerIndex?: number[];
|
||||||
/**
|
|
||||||
* @maximum 1
|
|
||||||
* @minimum 0
|
|
||||||
*/
|
|
||||||
vat?: number;
|
|
||||||
}[];
|
}[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const VAT_DEFAULT = config.vat;
|
||||||
|
|
||||||
const MANAGE_ROLES = [
|
const MANAGE_ROLES = [
|
||||||
"system",
|
"system",
|
||||||
"head_of_admin",
|
"head_of_admin",
|
||||||
|
|
@ -150,7 +146,6 @@ const MANAGE_ROLES = [
|
||||||
"head_of_sale",
|
"head_of_sale",
|
||||||
"sale",
|
"sale",
|
||||||
];
|
];
|
||||||
const VAT_DEFAULT = 0.07;
|
|
||||||
|
|
||||||
function globalAllow(user: RequestWithUser["user"]) {
|
function globalAllow(user: RequestWithUser["user"]) {
|
||||||
const allowList = ["system", "head_of_admin", "head_of_account", "head_of_sale"];
|
const allowList = ["system", "head_of_admin", "head_of_account", "head_of_sale"];
|
||||||
|
|
@ -322,28 +317,38 @@ export class QuotationController extends Controller {
|
||||||
update: { value: { increment: 1 } },
|
update: { value: { increment: 1 } },
|
||||||
});
|
});
|
||||||
|
|
||||||
const list = body.productServiceList.map((v, i) => ({
|
const list = body.productServiceList.map((v, i) => {
|
||||||
order: i + 1,
|
const p = product.find((p) => p.id === v.productId)!;
|
||||||
productId: v.productId,
|
const price = body.agentPrice ? p.agentPrice : p.price;
|
||||||
workId: v.workId,
|
const pricePerUnit = p.vatIncluded ? precisionRound(price / 1 + VAT_DEFAULT) : price;
|
||||||
serviceId: v.serviceId,
|
const vat = precisionRound(p.vatIncluded ? price - pricePerUnit : price * VAT_DEFAULT);
|
||||||
pricePerUnit:
|
|
||||||
product.find((p) => p.id === v.productId)?.[body.agentPrice ? "agentPrice" : "price"] ||
|
return {
|
||||||
0,
|
order: i + 1,
|
||||||
amount: v.amount,
|
productId: v.productId,
|
||||||
discount: v.discount || 0,
|
workId: v.workId,
|
||||||
vat: v.vat || VAT_DEFAULT,
|
serviceId: v.serviceId,
|
||||||
}));
|
pricePerUnit:
|
||||||
|
product.find((p) => p.id === v.productId)?.[body.agentPrice ? "agentPrice" : "price"] ||
|
||||||
|
0,
|
||||||
|
amount: v.amount,
|
||||||
|
discount: v.discount || 0,
|
||||||
|
vat,
|
||||||
|
worker: {
|
||||||
|
create: sortedEmployeeId
|
||||||
|
.filter((_, i) => !v.workerIndex || i in v.workerIndex)
|
||||||
|
.map((employeeId) => ({ employeeId })),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
const price = list.reduce(
|
const price = list.reduce(
|
||||||
(a, c) => {
|
(a, c) => {
|
||||||
const price = precisionRound(c.pricePerUnit * c.amount);
|
const multiply = precisionRound(c.pricePerUnit * c.amount);
|
||||||
const discount = precisionRound(price - (c.discount || 0));
|
|
||||||
const vat = precisionRound((price - discount) * c.vat);
|
|
||||||
|
|
||||||
a.totalPrice = precisionRound(a.totalPrice + price);
|
a.totalPrice = precisionRound(a.totalPrice + multiply);
|
||||||
a.totalDiscount = precisionRound(a.totalDiscount + discount);
|
a.totalDiscount = precisionRound(a.totalDiscount + c.discount);
|
||||||
a.vat = precisionRound(a.vat + vat);
|
a.vat = precisionRound(a.vat + c.vat);
|
||||||
a.finalPrice = precisionRound(a.totalPrice - a.totalDiscount + a.vat);
|
a.finalPrice = precisionRound(a.totalPrice - a.totalDiscount + a.vat);
|
||||||
|
|
||||||
return a;
|
return a;
|
||||||
|
|
@ -352,7 +357,8 @@ export class QuotationController extends Controller {
|
||||||
totalPrice: 0,
|
totalPrice: 0,
|
||||||
totalDiscount: 0,
|
totalDiscount: 0,
|
||||||
vat: 0,
|
vat: 0,
|
||||||
finalPrice: 0,
|
discount: body.discount,
|
||||||
|
finalPrice: -(body.discount || 0),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -397,7 +403,9 @@ export class QuotationController extends Controller {
|
||||||
})),
|
})),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
productServiceList: { create: list },
|
productServiceList: {
|
||||||
|
create: list,
|
||||||
|
},
|
||||||
createdByUserId: req.user.sub,
|
createdByUserId: req.user.sub,
|
||||||
updatedByUserId: req.user.sub,
|
updatedByUserId: req.user.sub,
|
||||||
},
|
},
|
||||||
|
|
@ -517,28 +525,39 @@ export class QuotationController extends Controller {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const list = body.productServiceList?.map((v, i) => ({
|
const list = body.productServiceList?.map((v, i) => {
|
||||||
order: i + 1,
|
const p = product.find((p) => p.id === v.productId)!;
|
||||||
productId: v.productId,
|
const price = record.agentPrice ? p.agentPrice : p.price;
|
||||||
workId: v.workId,
|
const pricePerUnit = p.vatIncluded ? precisionRound(price / 1 + VAT_DEFAULT) : price;
|
||||||
serviceId: v.serviceId,
|
const vat = precisionRound(p.vatIncluded ? price - pricePerUnit : price * VAT_DEFAULT);
|
||||||
pricePerUnit:
|
|
||||||
product.find((p) => p.id === v.productId)?.[record.agentPrice ? "agentPrice" : "price"] ||
|
return {
|
||||||
0,
|
order: i + 1,
|
||||||
amount: v.amount,
|
productId: v.productId,
|
||||||
discount: v.discount || 0,
|
workId: v.workId,
|
||||||
vat: v.vat || VAT_DEFAULT,
|
serviceId: v.serviceId,
|
||||||
}));
|
pricePerUnit:
|
||||||
|
product.find((p) => p.id === v.productId)?.[
|
||||||
|
record.agentPrice ? "agentPrice" : "price"
|
||||||
|
] || 0,
|
||||||
|
amount: v.amount,
|
||||||
|
discount: v.discount || 0,
|
||||||
|
vat,
|
||||||
|
worker: {
|
||||||
|
create: sortedEmployeeId
|
||||||
|
.filter((_, i) => !v.workerIndex || i in v.workerIndex)
|
||||||
|
.map((employeeId) => ({ employeeId })),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
const price = list?.reduce(
|
const price = list?.reduce(
|
||||||
(a, c) => {
|
(a, c) => {
|
||||||
const price = precisionRound(c.pricePerUnit * c.amount);
|
const multiply = precisionRound(c.pricePerUnit * c.amount);
|
||||||
const discount = precisionRound(price - (c.discount || 0));
|
|
||||||
const vat = precisionRound((price - discount) * c.vat);
|
|
||||||
|
|
||||||
a.totalPrice = precisionRound(a.totalPrice + price);
|
a.totalPrice = precisionRound(a.totalPrice + multiply);
|
||||||
a.totalDiscount = precisionRound(a.totalDiscount + discount);
|
a.totalDiscount = precisionRound(a.totalDiscount + c.discount);
|
||||||
a.vat = precisionRound(a.vat + vat);
|
a.vat = precisionRound(a.vat + c.vat);
|
||||||
a.finalPrice = precisionRound(a.totalPrice - a.totalDiscount + a.vat);
|
a.finalPrice = precisionRound(a.totalPrice - a.totalDiscount + a.vat);
|
||||||
|
|
||||||
return a;
|
return a;
|
||||||
|
|
@ -547,7 +566,8 @@ export class QuotationController extends Controller {
|
||||||
totalPrice: 0,
|
totalPrice: 0,
|
||||||
totalDiscount: 0,
|
totalDiscount: 0,
|
||||||
vat: 0,
|
vat: 0,
|
||||||
finalPrice: 0,
|
discount: body.discount,
|
||||||
|
finalPrice: -(body.discount || 0),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue