Merge branch 'develop'
This commit is contained in:
commit
06c54780d3
5 changed files with 146 additions and 16 deletions
|
|
@ -0,0 +1,17 @@
|
||||||
|
/*
|
||||||
|
Warnings:
|
||||||
|
|
||||||
|
- Made the column `vatIncluded` on table `Product` required. This step will fail if there are existing NULL values in that column.
|
||||||
|
|
||||||
|
*/
|
||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "Product" ADD COLUMN "agentPriceCalcVat" BOOLEAN,
|
||||||
|
ADD COLUMN "agentPriceVatIncluded" BOOLEAN,
|
||||||
|
ADD COLUMN "serviceChargeCalcVat" BOOLEAN,
|
||||||
|
ADD COLUMN "serviceChargeVatIncluded" BOOLEAN,
|
||||||
|
ALTER COLUMN "vatIncluded" SET NOT NULL,
|
||||||
|
ALTER COLUMN "vatIncluded" SET DEFAULT true;
|
||||||
|
UPDATE "Product" SET "agentPriceCalcVat" = "Product"."calcVat" WHERE "agentPriceCalcVat" IS NULL;
|
||||||
|
UPDATE "Product" SET "agentPriceVatIncluded" = "Product"."vatIncluded" WHERE "agentPriceVatIncluded" IS NULL;
|
||||||
|
UPDATE "Product" SET "serviceChargeCalcVat" = "Product"."calcVat" WHERE "serviceChargeCalcVat" IS NULL;
|
||||||
|
UPDATE "Product" SET "serviceChargeVatIncluded" = "Product"."vatIncluded" WHERE "serviceChargeVatIncluded" IS NULL;
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "Product" ALTER COLUMN "agentPriceCalcVat" SET DEFAULT true,
|
||||||
|
ALTER COLUMN "agentPriceVatIncluded" SET DEFAULT true,
|
||||||
|
ALTER COLUMN "serviceChargeCalcVat" SET DEFAULT true,
|
||||||
|
ALTER COLUMN "serviceChargeVatIncluded" SET DEFAULT true;
|
||||||
|
|
@ -1103,10 +1103,16 @@ model Product {
|
||||||
price Float
|
price Float
|
||||||
agentPrice Float
|
agentPrice Float
|
||||||
serviceCharge Float
|
serviceCharge Float
|
||||||
vatIncluded Boolean?
|
|
||||||
expenseType String?
|
expenseType String?
|
||||||
|
|
||||||
calcVat Boolean @default(true)
|
vatIncluded Boolean @default(true)
|
||||||
|
calcVat Boolean @default(true)
|
||||||
|
|
||||||
|
agentPriceVatIncluded Boolean? @default(true)
|
||||||
|
agentPriceCalcVat Boolean? @default(true)
|
||||||
|
|
||||||
|
serviceChargeVatIncluded Boolean? @default(true)
|
||||||
|
serviceChargeCalcVat Boolean? @default(true)
|
||||||
|
|
||||||
status Status @default(CREATED)
|
status Status @default(CREATED)
|
||||||
statusOrder Int @default(0)
|
statusOrder Int @default(0)
|
||||||
|
|
|
||||||
|
|
@ -58,6 +58,10 @@ type ProductCreate = {
|
||||||
serviceCharge: number;
|
serviceCharge: number;
|
||||||
vatIncluded?: boolean;
|
vatIncluded?: boolean;
|
||||||
calcVat?: boolean;
|
calcVat?: boolean;
|
||||||
|
agentPriceVatIncluded?: boolean;
|
||||||
|
agentPriceCalcVat?: boolean;
|
||||||
|
serviceChargeVatIncluded?: boolean;
|
||||||
|
serviceChargeCalcVat?: boolean;
|
||||||
expenseType?: string;
|
expenseType?: string;
|
||||||
selectedImage?: string;
|
selectedImage?: string;
|
||||||
shared?: boolean;
|
shared?: boolean;
|
||||||
|
|
@ -77,6 +81,10 @@ type ProductUpdate = {
|
||||||
remark?: string;
|
remark?: string;
|
||||||
vatIncluded?: boolean;
|
vatIncluded?: boolean;
|
||||||
calcVat?: boolean;
|
calcVat?: boolean;
|
||||||
|
agentPriceVatIncluded?: boolean;
|
||||||
|
agentPriceCalcVat?: boolean;
|
||||||
|
serviceChargeVatIncluded?: boolean;
|
||||||
|
serviceChargeCalcVat?: boolean;
|
||||||
expenseType?: string;
|
expenseType?: string;
|
||||||
selectedImage?: string;
|
selectedImage?: string;
|
||||||
shared?: boolean;
|
shared?: boolean;
|
||||||
|
|
|
||||||
|
|
@ -478,9 +478,11 @@ export class QuotationController extends Controller {
|
||||||
const list = body.productServiceList.map((v, i) => {
|
const list = body.productServiceList.map((v, i) => {
|
||||||
const p = product.find((p) => p.id === v.productId)!;
|
const p = product.find((p) => p.id === v.productId)!;
|
||||||
|
|
||||||
|
const vatIncluded = body.agentPrice ? p.agentPriceVatIncluded : p.vatIncluded;
|
||||||
|
|
||||||
const originalPrice = body.agentPrice ? p.agentPrice : p.price;
|
const originalPrice = body.agentPrice ? p.agentPrice : p.price;
|
||||||
const finalPriceWithVat = precisionRound(
|
const finalPriceWithVat = precisionRound(
|
||||||
originalPrice + (p.vatIncluded ? 0 : originalPrice * VAT_DEFAULT),
|
originalPrice + (vatIncluded ? 0 : originalPrice * VAT_DEFAULT),
|
||||||
);
|
);
|
||||||
|
|
||||||
const price = finalPriceWithVat;
|
const price = finalPriceWithVat;
|
||||||
|
|
@ -743,9 +745,11 @@ export class QuotationController extends Controller {
|
||||||
const list = body.productServiceList?.map((v, i) => {
|
const list = body.productServiceList?.map((v, i) => {
|
||||||
const p = product.find((p) => p.id === v.productId)!;
|
const p = product.find((p) => p.id === v.productId)!;
|
||||||
|
|
||||||
|
const vatIncluded = record.agentPrice ? p.agentPriceVatIncluded : p.vatIncluded;
|
||||||
|
|
||||||
const originalPrice = record.agentPrice ? p.agentPrice : p.price;
|
const originalPrice = record.agentPrice ? p.agentPrice : p.price;
|
||||||
const finalPriceWithVat = precisionRound(
|
const finalPriceWithVat = precisionRound(
|
||||||
originalPrice + (p.vatIncluded ? 0 : originalPrice * VAT_DEFAULT),
|
originalPrice + (vatIncluded ? 0 : originalPrice * VAT_DEFAULT),
|
||||||
);
|
);
|
||||||
|
|
||||||
const price = finalPriceWithVat;
|
const price = finalPriceWithVat;
|
||||||
|
|
@ -919,14 +923,63 @@ export class QuotationActionController extends Controller {
|
||||||
@Request() req: RequestWithUser,
|
@Request() req: RequestWithUser,
|
||||||
@Path() quotationId: string,
|
@Path() quotationId: string,
|
||||||
@Body()
|
@Body()
|
||||||
body: {
|
body: (
|
||||||
workerId: string;
|
| {
|
||||||
productServiceId: string[];
|
workerId: string;
|
||||||
}[],
|
productServiceId: string[];
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
workerData: {
|
||||||
|
dateOfBirth: Date;
|
||||||
|
gender: string;
|
||||||
|
nationality: string;
|
||||||
|
namePrefix?: string;
|
||||||
|
firstName: string;
|
||||||
|
firstNameEN: string;
|
||||||
|
middleName?: string;
|
||||||
|
middleNameEN?: string;
|
||||||
|
lastName: string;
|
||||||
|
lastNameEN: string;
|
||||||
|
};
|
||||||
|
productServiceId: string[];
|
||||||
|
}
|
||||||
|
)[],
|
||||||
) {
|
) {
|
||||||
|
const { existsEmployee, newEmployee } = body.reduce<{
|
||||||
|
existsEmployee: {
|
||||||
|
workerId: string;
|
||||||
|
productServiceId: string[];
|
||||||
|
}[];
|
||||||
|
newEmployee: {
|
||||||
|
workerData: {
|
||||||
|
dateOfBirth: Date;
|
||||||
|
gender: string;
|
||||||
|
nationality: string;
|
||||||
|
namePrefix?: string;
|
||||||
|
firstName: string;
|
||||||
|
firstNameEN: string;
|
||||||
|
middleName?: string;
|
||||||
|
middleNameEN?: string;
|
||||||
|
lastName: string;
|
||||||
|
lastNameEN: string;
|
||||||
|
};
|
||||||
|
productServiceId: string[];
|
||||||
|
}[];
|
||||||
|
}>(
|
||||||
|
(acc, current) => {
|
||||||
|
if ("workerId" in current) {
|
||||||
|
acc.existsEmployee.push(current);
|
||||||
|
} else {
|
||||||
|
acc.newEmployee.push(current);
|
||||||
|
}
|
||||||
|
return acc;
|
||||||
|
},
|
||||||
|
{ existsEmployee: [], newEmployee: [] },
|
||||||
|
);
|
||||||
|
|
||||||
const ids = {
|
const ids = {
|
||||||
employee: body.map((v) => v.workerId),
|
employee: existsEmployee.map((v) => v.workerId),
|
||||||
productService: body
|
productService: existsEmployee
|
||||||
.flatMap((v) => v.productServiceId)
|
.flatMap((v) => v.productServiceId)
|
||||||
.filter((lhs, i, a) => a.findIndex((rhs) => lhs === rhs) === i),
|
.filter((lhs, i, a) => a.findIndex((rhs) => lhs === rhs) === i),
|
||||||
};
|
};
|
||||||
|
|
@ -936,6 +989,7 @@ export class QuotationActionController extends Controller {
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
tx.quotation.findFirst({
|
tx.quotation.findFirst({
|
||||||
include: {
|
include: {
|
||||||
|
customerBranch: true,
|
||||||
worker: true,
|
worker: true,
|
||||||
_count: {
|
_count: {
|
||||||
select: {
|
select: {
|
||||||
|
|
@ -961,11 +1015,13 @@ export class QuotationActionController extends Controller {
|
||||||
if (ids.productService.length !== productService.length) throw relationError("Product");
|
if (ids.productService.length !== productService.length) throw relationError("Product");
|
||||||
if (
|
if (
|
||||||
quotation._count.worker +
|
quotation._count.worker +
|
||||||
body.filter((lhs) => !quotation.worker.find((rhs) => rhs.employeeId === lhs.workerId))
|
existsEmployee.filter(
|
||||||
.length >
|
(lhs) => !quotation.worker.find((rhs) => rhs.employeeId === lhs.workerId),
|
||||||
|
).length +
|
||||||
|
newEmployee.length >
|
||||||
(quotation.workerMax || 0)
|
(quotation.workerMax || 0)
|
||||||
) {
|
) {
|
||||||
if (body.length === 0) return;
|
if (existsEmployee.length === 0) return;
|
||||||
throw new HttpError(
|
throw new HttpError(
|
||||||
HttpStatus.PRECONDITION_FAILED,
|
HttpStatus.PRECONDITION_FAILED,
|
||||||
"Worker exceed current quotation max worker.",
|
"Worker exceed current quotation max worker.",
|
||||||
|
|
@ -974,8 +1030,46 @@ export class QuotationActionController extends Controller {
|
||||||
}
|
}
|
||||||
|
|
||||||
await prisma.$transaction(async (tx) => {
|
await prisma.$transaction(async (tx) => {
|
||||||
|
const customerBranch = quotation.customerBranch;
|
||||||
|
const lastEmployee = await tx.runningNo.upsert({
|
||||||
|
where: {
|
||||||
|
key: `EMPLOYEE_${customerBranch.id}-${`${new Date().getFullYear()}`.slice(-2).padStart(2, "0")}`,
|
||||||
|
},
|
||||||
|
create: {
|
||||||
|
key: `EMPLOYEE_${customerBranch.id}-${`${new Date().getFullYear()}`.slice(-2).padStart(2, "0")}`,
|
||||||
|
value: newEmployee.length,
|
||||||
|
},
|
||||||
|
update: { value: { increment: newEmployee.length } },
|
||||||
|
});
|
||||||
|
|
||||||
|
const newEmployeeWithId = await Promise.all(
|
||||||
|
newEmployee.map(async (v, i) => {
|
||||||
|
const data = await tx.employee.create({
|
||||||
|
data: {
|
||||||
|
...v.workerData,
|
||||||
|
code: `${customerBranch.code}-${`${new Date().getFullYear()}`.slice(-2).padStart(2, "0")}${`${lastEmployee.value - nonExistEmployee.length + i + 1}`.padStart(7, "0")}`,
|
||||||
|
customerBranchId: customerBranch.id,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return { workerId: data.id, productServiceId: v.productServiceId };
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
const rearrange: typeof existsEmployee = [];
|
||||||
|
|
||||||
|
while (body.length > 0) {
|
||||||
|
const item = body.shift();
|
||||||
|
if (item && "workerId" in item) {
|
||||||
|
rearrange.push(item);
|
||||||
|
} else {
|
||||||
|
const popNew = newEmployeeWithId.shift();
|
||||||
|
popNew && rearrange.push(popNew);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
await tx.quotationProductServiceWorker.createMany({
|
await tx.quotationProductServiceWorker.createMany({
|
||||||
data: body
|
data: existsEmployee
|
||||||
.filter((lhs) => !quotation.worker.find((rhs) => rhs.employeeId === lhs.workerId))
|
.filter((lhs) => !quotation.worker.find((rhs) => rhs.employeeId === lhs.workerId))
|
||||||
.flatMap((lhs) =>
|
.flatMap((lhs) =>
|
||||||
lhs.productServiceId.map((rhs) => ({
|
lhs.productServiceId.map((rhs) => ({
|
||||||
|
|
@ -1006,7 +1100,7 @@ export class QuotationActionController extends Controller {
|
||||||
quotationStatus: QuotationStatus.PaymentSuccess, // NOTE: change back if already complete or canceled
|
quotationStatus: QuotationStatus.PaymentSuccess, // NOTE: change back if already complete or canceled
|
||||||
worker: {
|
worker: {
|
||||||
createMany: {
|
createMany: {
|
||||||
data: body
|
data: rearrange
|
||||||
.filter((lhs) => !quotation.worker.find((rhs) => rhs.employeeId === lhs.workerId))
|
.filter((lhs) => !quotation.worker.find((rhs) => rhs.employeeId === lhs.workerId))
|
||||||
.map((v, i) => ({
|
.map((v, i) => ({
|
||||||
no: quotation._count.worker + i + 1,
|
no: quotation._count.worker + i + 1,
|
||||||
|
|
@ -1018,7 +1112,7 @@ export class QuotationActionController extends Controller {
|
||||||
quotation.quotationStatus === "PaymentInProcess" ||
|
quotation.quotationStatus === "PaymentInProcess" ||
|
||||||
quotation.quotationStatus === "PaymentSuccess"
|
quotation.quotationStatus === "PaymentSuccess"
|
||||||
? {
|
? {
|
||||||
create: body
|
create: rearrange
|
||||||
.filter(
|
.filter(
|
||||||
(lhs) =>
|
(lhs) =>
|
||||||
!quotation.worker.find((rhs) => rhs.employeeId === lhs.workerId) &&
|
!quotation.worker.find((rhs) => rhs.employeeId === lhs.workerId) &&
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue