Ship deploy build for multi-company order items.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-08-15 10:38:10 +03:30
co-authored by Cursor
parent 551fd6f06a
commit 0903a1c1e9
17 changed files with 203 additions and 46 deletions
+12 -3
View File
@@ -105,9 +105,16 @@ let CartsService = class CartsService {
if (!item) if (!item)
throw new common_1.NotFoundException('آیتم سبد یافت نشد'); throw new common_1.NotFoundException('آیتم سبد یافت نشد');
await this.prisma.cartItem.delete({ where: { id: itemId } }); await this.prisma.cartItem.delete({ where: { id: itemId } });
const remaining = await this.prisma.cartItem.findMany({
where: { cartId: cart.id },
take: 1,
});
await this.prisma.cart.update({ await this.prisma.cart.update({
where: { id: cart.id }, where: { id: cart.id },
data: { updatedAt: new Date() }, data: {
companyId: remaining[0]?.companyId ?? null,
updatedAt: new Date(),
},
}); });
return this.getCart(userId); return this.getCart(userId);
} }
@@ -151,12 +158,14 @@ let CartsService = class CartsService {
return cart; return cart;
} }
mapCart(cart) { mapCart(cart) {
const companyName = cart.items[0]?.companyName; const companyNames = [
...new Set(cart.items.map((item) => item.companyName).filter(Boolean)),
];
return { return {
id: cart.id, id: cart.id,
userId: cart.userId, userId: cart.userId,
companyId: cart.companyId ?? cart.items[0]?.companyId, companyId: cart.companyId ?? cart.items[0]?.companyId,
companyName: companyName ?? '', companyName: companyNames.join('، '),
notes: cart.notes ?? undefined, notes: cart.notes ?? undefined,
items: cart.items.map((item) => ({ items: cart.items.map((item) => ({
id: item.id, id: item.id,
+1 -1
View File
File diff suppressed because one or more lines are too long
+8 -2
View File
@@ -32,7 +32,7 @@ let CashPaymentsService = class CashPaymentsService {
async submitReceipt(userId, orderId, dto) { async submitReceipt(userId, orderId, dto) {
const order = await this.prisma.order.findUnique({ const order = await this.prisma.order.findUnique({
where: { id: orderId }, where: { id: orderId },
include: { cashReceipt: true }, include: { cashReceipt: true, items: true },
}); });
if (!order) if (!order)
throw new common_1.NotFoundException('سفارش یافت نشد'); throw new common_1.NotFoundException('سفارش یافت نشد');
@@ -49,10 +49,16 @@ let CashPaymentsService = class CashPaymentsService {
order.cashInvoiceExpiresAt.getTime() < Date.now()) { order.cashInvoiceExpiresAt.getTime() < Date.now()) {
throw new common_1.BadRequestException('مهلت پرداخت فاکتور نقدی به پایان رسیده است'); throw new common_1.BadRequestException('مهلت پرداخت فاکتور نقدی به پایان رسیده است');
} }
const companyIds = [
...new Set([
order.companyId,
...order.items.map((item) => item.companyId).filter(Boolean),
].filter(Boolean)),
];
const account = await this.prisma.bankAccount.findFirst({ const account = await this.prisma.bankAccount.findFirst({
where: { where: {
id: dto.destinationAccountId, id: dto.destinationAccountId,
companyId: order.companyId, companyId: { in: companyIds },
isActive: true, isActive: true,
}, },
}); });
File diff suppressed because one or more lines are too long
+4
View File
@@ -2,3 +2,7 @@ export declare function computeCashInvoiceExpiry(company: {
cashInvoiceValidUntilHour: number | null; cashInvoiceValidUntilHour: number | null;
cashInvoiceValidityHours: number; cashInvoiceValidityHours: number;
}): Date; }): Date;
export declare function earliestCashInvoiceExpiry(companies: Array<{
cashInvoiceValidUntilHour: number | null;
cashInvoiceValidityHours: number;
}>): Date;
+9
View File
@@ -1,6 +1,7 @@
"use strict"; "use strict";
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.computeCashInvoiceExpiry = computeCashInvoiceExpiry; exports.computeCashInvoiceExpiry = computeCashInvoiceExpiry;
exports.earliestCashInvoiceExpiry = earliestCashInvoiceExpiry;
const tehran_time_1 = require("./tehran-time"); const tehran_time_1 = require("./tehran-time");
function computeCashInvoiceExpiry(company) { function computeCashInvoiceExpiry(company) {
const now = new Date(); const now = new Date();
@@ -14,4 +15,12 @@ function computeCashInvoiceExpiry(company) {
} }
return new Date(now.getTime() + company.cashInvoiceValidityHours * 60 * 60 * 1000); return new Date(now.getTime() + company.cashInvoiceValidityHours * 60 * 60 * 1000);
} }
function earliestCashInvoiceExpiry(companies) {
if (!companies.length) {
return new Date(Date.now() + 8 * 60 * 60 * 1000);
}
return companies
.map((company) => computeCashInvoiceExpiry(company))
.reduce((earliest, current) => current.getTime() < earliest.getTime() ? current : earliest);
}
//# sourceMappingURL=cash-expiry.js.map //# sourceMappingURL=cash-expiry.js.map
+1 -1
View File
@@ -1 +1 @@
{"version":3,"file":"cash-expiry.js","sourceRoot":"","sources":["../../../src/common/utils/cash-expiry.ts"],"names":[],"mappings":";;AAEA,4DAmBC;AArBD,+CAAsD;AAEtD,SAAgB,wBAAwB,CAAC,OAGxC;IACC,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;IACvB,IACE,OAAO,CAAC,yBAAyB,IAAI,IAAI;QACzC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,yBAAyB,CAAC,EAClD,CAAC;QACD,MAAM,OAAO,GAAG,IAAA,0BAAY,EAAC,GAAG,EAAE,OAAO,CAAC,yBAAyB,CAAC,CAAC;QACrE,IAAI,OAAO,CAAC,OAAO,EAAE,IAAI,GAAG,CAAC,OAAO,EAAE,EAAE,CAAC;YACvC,OAAO,IAAA,0BAAY,EAAC,IAAA,qBAAO,EAAC,GAAG,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,yBAAyB,CAAC,CAAC;QAC1E,CAAC;QACD,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,OAAO,IAAI,IAAI,CACb,GAAG,CAAC,OAAO,EAAE,GAAG,OAAO,CAAC,wBAAwB,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAClE,CAAC;AACJ,CAAC"} {"version":3,"file":"cash-expiry.js","sourceRoot":"","sources":["../../../src/common/utils/cash-expiry.ts"],"names":[],"mappings":";;AAEA,4DAmBC;AAGD,8DAcC;AAtCD,+CAAsD;AAEtD,SAAgB,wBAAwB,CAAC,OAGxC;IACC,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;IACvB,IACE,OAAO,CAAC,yBAAyB,IAAI,IAAI;QACzC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,yBAAyB,CAAC,EAClD,CAAC;QACD,MAAM,OAAO,GAAG,IAAA,0BAAY,EAAC,GAAG,EAAE,OAAO,CAAC,yBAAyB,CAAC,CAAC;QACrE,IAAI,OAAO,CAAC,OAAO,EAAE,IAAI,GAAG,CAAC,OAAO,EAAE,EAAE,CAAC;YACvC,OAAO,IAAA,0BAAY,EAAC,IAAA,qBAAO,EAAC,GAAG,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,yBAAyB,CAAC,CAAC;QAC1E,CAAC;QACD,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,OAAO,IAAI,IAAI,CACb,GAAG,CAAC,OAAO,EAAE,GAAG,OAAO,CAAC,wBAAwB,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAClE,CAAC;AACJ,CAAC;AAGD,SAAgB,yBAAyB,CACvC,SAGE;IAEF,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC;QACtB,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;IACnD,CAAC;IACD,OAAO,SAAS;SACb,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,wBAAwB,CAAC,OAAO,CAAC,CAAC;SACnD,MAAM,CAAC,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,CAC5B,OAAO,CAAC,OAAO,EAAE,GAAG,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAC5D,CAAC;AACN,CAAC"}
+2
View File
@@ -57,6 +57,8 @@ export declare class DashboardController {
lineTotal: number | null; lineTotal: number | null;
totalAmount: number | null; totalAmount: number | null;
notes: string | undefined; notes: string | undefined;
companyId: string;
companyName: string;
}[]; }[];
checks: { checks: {
id: string; id: string;
+2
View File
@@ -59,6 +59,8 @@ export declare class DashboardService {
lineTotal: number | null; lineTotal: number | null;
totalAmount: number | null; totalAmount: number | null;
notes: string | undefined; notes: string | undefined;
companyId: string;
companyName: string;
}[]; }[];
checks: { checks: {
id: string; id: string;
+1
View File
@@ -34,6 +34,7 @@ export declare class ChooseSettlementDto {
checkMode?: CheckRegistrationMode; checkMode?: CheckRegistrationMode;
} }
export declare class AdminCreateOrderDto { export declare class AdminCreateOrderDto {
customerId?: string;
userId?: string; userId?: string;
customerPhone?: string; customerPhone?: string;
customerName?: string; customerName?: string;
+6
View File
@@ -185,6 +185,7 @@ __decorate([
__metadata("design:type", String) __metadata("design:type", String)
], ChooseSettlementDto.prototype, "checkMode", void 0); ], ChooseSettlementDto.prototype, "checkMode", void 0);
class AdminCreateOrderDto { class AdminCreateOrderDto {
customerId;
userId; userId;
customerPhone; customerPhone;
customerName; customerName;
@@ -196,6 +197,11 @@ class AdminCreateOrderDto {
items; items;
} }
exports.AdminCreateOrderDto = AdminCreateOrderDto; exports.AdminCreateOrderDto = AdminCreateOrderDto;
__decorate([
(0, class_validator_1.IsOptional)(),
(0, class_validator_1.IsString)(),
__metadata("design:type", String)
], AdminCreateOrderDto.prototype, "customerId", void 0);
__decorate([ __decorate([
(0, class_validator_1.IsOptional)(), (0, class_validator_1.IsOptional)(),
(0, class_validator_1.IsString)(), (0, class_validator_1.IsString)(),
+1 -1
View File
File diff suppressed because one or more lines are too long
+20
View File
@@ -49,6 +49,8 @@ export declare class CustomerOrdersController {
lineTotal: number | null; lineTotal: number | null;
totalAmount: number | null; totalAmount: number | null;
notes: string | undefined; notes: string | undefined;
companyId: string;
companyName: string;
}[]; }[];
checks: { checks: {
id: string; id: string;
@@ -152,6 +154,8 @@ export declare class CustomerOrdersController {
lineTotal: number | null; lineTotal: number | null;
totalAmount: number | null; totalAmount: number | null;
notes: string | undefined; notes: string | undefined;
companyId: string;
companyName: string;
}[]; }[];
checks: { checks: {
id: string; id: string;
@@ -255,6 +259,8 @@ export declare class CustomerOrdersController {
lineTotal: number | null; lineTotal: number | null;
totalAmount: number | null; totalAmount: number | null;
notes: string | undefined; notes: string | undefined;
companyId: string;
companyName: string;
}[]; }[];
checks: { checks: {
id: string; id: string;
@@ -358,6 +364,8 @@ export declare class CustomerOrdersController {
lineTotal: number | null; lineTotal: number | null;
totalAmount: number | null; totalAmount: number | null;
notes: string | undefined; notes: string | undefined;
companyId: string;
companyName: string;
}[]; }[];
checks: { checks: {
id: string; id: string;
@@ -461,6 +469,8 @@ export declare class CustomerOrdersController {
lineTotal: number | null; lineTotal: number | null;
totalAmount: number | null; totalAmount: number | null;
notes: string | undefined; notes: string | undefined;
companyId: string;
companyName: string;
}[]; }[];
checks: { checks: {
id: string; id: string;
@@ -568,6 +578,8 @@ export declare class AdminOrdersController {
lineTotal: number | null; lineTotal: number | null;
totalAmount: number | null; totalAmount: number | null;
notes: string | undefined; notes: string | undefined;
companyId: string;
companyName: string;
}[]; }[];
checks: { checks: {
id: string; id: string;
@@ -671,6 +683,8 @@ export declare class AdminOrdersController {
lineTotal: number | null; lineTotal: number | null;
totalAmount: number | null; totalAmount: number | null;
notes: string | undefined; notes: string | undefined;
companyId: string;
companyName: string;
}[]; }[];
checks: { checks: {
id: string; id: string;
@@ -774,6 +788,8 @@ export declare class AdminOrdersController {
lineTotal: number | null; lineTotal: number | null;
totalAmount: number | null; totalAmount: number | null;
notes: string | undefined; notes: string | undefined;
companyId: string;
companyName: string;
}[]; }[];
checks: { checks: {
id: string; id: string;
@@ -877,6 +893,8 @@ export declare class AdminOrdersController {
lineTotal: number | null; lineTotal: number | null;
totalAmount: number | null; totalAmount: number | null;
notes: string | undefined; notes: string | undefined;
companyId: string;
companyName: string;
}[]; }[];
checks: { checks: {
id: string; id: string;
@@ -980,6 +998,8 @@ export declare class AdminOrdersController {
lineTotal: number | null; lineTotal: number | null;
totalAmount: number | null; totalAmount: number | null;
notes: string | undefined; notes: string | undefined;
companyId: string;
companyName: string;
}[]; }[];
checks: { checks: {
id: string; id: string;
+23
View File
@@ -71,6 +71,8 @@ export declare class OrdersService {
lineTotal: number | null; lineTotal: number | null;
totalAmount: number | null; totalAmount: number | null;
notes: string | undefined; notes: string | undefined;
companyId: string;
companyName: string;
}[]; }[];
checks: { checks: {
id: string; id: string;
@@ -174,6 +176,8 @@ export declare class OrdersService {
lineTotal: number | null; lineTotal: number | null;
totalAmount: number | null; totalAmount: number | null;
notes: string | undefined; notes: string | undefined;
companyId: string;
companyName: string;
}[]; }[];
checks: { checks: {
id: string; id: string;
@@ -280,6 +284,8 @@ export declare class OrdersService {
lineTotal: number | null; lineTotal: number | null;
totalAmount: number | null; totalAmount: number | null;
notes: string | undefined; notes: string | undefined;
companyId: string;
companyName: string;
}[]; }[];
checks: { checks: {
id: string; id: string;
@@ -383,6 +389,8 @@ export declare class OrdersService {
lineTotal: number | null; lineTotal: number | null;
totalAmount: number | null; totalAmount: number | null;
notes: string | undefined; notes: string | undefined;
companyId: string;
companyName: string;
}[]; }[];
checks: { checks: {
id: string; id: string;
@@ -486,6 +494,8 @@ export declare class OrdersService {
lineTotal: number | null; lineTotal: number | null;
totalAmount: number | null; totalAmount: number | null;
notes: string | undefined; notes: string | undefined;
companyId: string;
companyName: string;
}[]; }[];
checks: { checks: {
id: string; id: string;
@@ -589,6 +599,8 @@ export declare class OrdersService {
lineTotal: number | null; lineTotal: number | null;
totalAmount: number | null; totalAmount: number | null;
notes: string | undefined; notes: string | undefined;
companyId: string;
companyName: string;
}[]; }[];
checks: { checks: {
id: string; id: string;
@@ -692,6 +704,8 @@ export declare class OrdersService {
lineTotal: number | null; lineTotal: number | null;
totalAmount: number | null; totalAmount: number | null;
notes: string | undefined; notes: string | undefined;
companyId: string;
companyName: string;
}[]; }[];
checks: { checks: {
id: string; id: string;
@@ -795,6 +809,8 @@ export declare class OrdersService {
lineTotal: number | null; lineTotal: number | null;
totalAmount: number | null; totalAmount: number | null;
notes: string | undefined; notes: string | undefined;
companyId: string;
companyName: string;
}[]; }[];
checks: { checks: {
id: string; id: string;
@@ -898,6 +914,8 @@ export declare class OrdersService {
lineTotal: number | null; lineTotal: number | null;
totalAmount: number | null; totalAmount: number | null;
notes: string | undefined; notes: string | undefined;
companyId: string;
companyName: string;
}[]; }[];
checks: { checks: {
id: string; id: string;
@@ -1001,6 +1019,8 @@ export declare class OrdersService {
lineTotal: number | null; lineTotal: number | null;
totalAmount: number | null; totalAmount: number | null;
notes: string | undefined; notes: string | undefined;
companyId: string;
companyName: string;
}[]; }[];
checks: { checks: {
id: string; id: string;
@@ -1062,6 +1082,7 @@ export declare class OrdersService {
private mapCheckCreate; private mapCheckCreate;
private nextOrderNumber; private nextOrderNumber;
private createWithUniqueOrderNumber; private createWithUniqueOrderNumber;
private companiesForOrder;
private getOrder; private getOrder;
mapOrder(order: OrderFull, adminView?: boolean): { mapOrder(order: OrderFull, adminView?: boolean): {
id: string; id: string;
@@ -1108,6 +1129,8 @@ export declare class OrdersService {
lineTotal: number | null; lineTotal: number | null;
totalAmount: number | null; totalAmount: number | null;
notes: string | undefined; notes: string | undefined;
companyId: string;
companyName: string;
}[]; }[];
checks: { checks: {
id: string; id: string;
+111 -36
View File
@@ -101,26 +101,53 @@ let OrdersService = class OrdersService {
return this.mapOrder(order, true); return this.mapOrder(order, true);
} }
async submitOrder(userId, dto) { async submitOrder(userId, dto) {
const [company, settings] = await Promise.all([ const settings = await this.prisma.systemSettings.findUnique({
this.prisma.company.findUnique({ where: { id: dto.companyId } }), where: { id: 'default' },
this.prisma.systemSettings.findUnique({ select: { maxMeteragePerInvoice: true },
where: { id: 'default' },
select: { maxMeteragePerInvoice: true },
}),
]);
if (!company || !company.isActive) {
throw new common_1.NotFoundException('شرکت یافت نشد یا غیرفعال است');
}
const maxMeterage = (0, meterage_1.resolveMaxMeterage)(company.maxMeteragePerInvoice, settings?.maxMeteragePerInvoice);
const productIds = dto.items.map((i) => i.productId);
const products = await this.prisma.product.findMany({
where: { id: { in: productIds }, companyId: company.id, isActive: true },
include: { catalog: true },
}); });
if (products.length !== productIds.length) { const productIds = dto.items.map((i) => i.productId);
throw new common_1.BadRequestException('یک یا چند محصول نامعتبر است'); const uniqueProductIds = [...new Set(productIds)];
if (uniqueProductIds.length !== productIds.length) {
throw new common_1.BadRequestException('محصول تکراری در سفارش مجاز نیست');
} }
const products = await this.prisma.product.findMany({
where: { id: { in: uniqueProductIds } },
include: { catalog: true, company: true },
});
const productMap = new Map(products.map((p) => [p.id, p])); const productMap = new Map(products.map((p) => [p.id, p]));
for (const item of dto.items) {
const product = productMap.get(item.productId);
if (!product) {
throw new common_1.BadRequestException('یک یا چند محصول نامعتبر است یا دیگر در سیستم وجود ندارد. سبد را خالی کنید و دوباره اضافه کنید.');
}
if (!product.isActive) {
throw new common_1.BadRequestException(`محصول «${product.name}» غیرفعال است و قابل سفارش نیست`);
}
if (!product.company?.isActive) {
throw new common_1.BadRequestException(`شرکت محصول «${product.name}» غیرفعال است`);
}
}
const meterageByCompany = new Map();
for (const item of dto.items) {
const product = productMap.get(item.productId);
const current = meterageByCompany.get(product.companyId);
if (current) {
current.meterage += item.meterage;
}
else {
meterageByCompany.set(product.companyId, {
name: product.company.name,
meterage: item.meterage,
max: product.company.maxMeteragePerInvoice,
});
}
}
for (const row of meterageByCompany.values()) {
const maxMeterageResolved = (0, meterage_1.resolveMaxMeterage)(row.max, settings?.maxMeteragePerInvoice);
if (row.meterage > maxMeterageResolved) {
throw new common_1.BadRequestException(`حداکثر متراژ مجاز فاکتور برای «${row.name}» برابر ${maxMeterageResolved} متر است`);
}
}
let totalMeterage = 0; let totalMeterage = 0;
const itemsData = dto.items.map((item) => { const itemsData = dto.items.map((item) => {
const product = productMap.get(item.productId); const product = productMap.get(item.productId);
@@ -140,18 +167,28 @@ let OrdersService = class OrdersService {
color: product.color, color: product.color,
requestedMeterage: item.meterage, requestedMeterage: item.meterage,
notes: item.notes?.trim() || null, notes: item.notes?.trim() || null,
companyId: product.companyId,
companyName: product.company.name,
}; };
}); });
if (totalMeterage > maxMeterage) { const companyNames = [
throw new common_1.BadRequestException(`حداکثر متراژ مجاز هر فاکتور ${maxMeterage} متر است`); ...new Set(itemsData.map((item) => item.companyName).filter(Boolean)),
];
const preferredCompanyId = itemsData.some((item) => item.companyId === dto.companyId)
? dto.companyId
: itemsData[0].companyId;
const primaryCompany = products.find((p) => p.companyId === preferredCompanyId)
?.company;
if (!primaryCompany) {
throw new common_1.NotFoundException('شرکت محصولات یافت نشد یا غیرفعال است');
} }
const order = await this.createWithUniqueOrderNumber((orderNumber) => this.prisma.$transaction(async (tx) => { const order = await this.createWithUniqueOrderNumber((orderNumber) => this.prisma.$transaction(async (tx) => {
const created = await tx.order.create({ const created = await tx.order.create({
data: { data: {
orderNumber, orderNumber,
userId, userId,
companyId: company.id, companyId: primaryCompany.id,
companyName: company.name, companyName: companyNames.join('، '),
settlementType: null, settlementType: null,
checkMode: null, checkMode: null,
status: client_1.OrderStatus.awaiting_review, status: client_1.OrderStatus.awaiting_review,
@@ -174,7 +211,17 @@ let OrdersService = class OrdersService {
const cart = await tx.cart.findFirst({ where: { userId } }); const cart = await tx.cart.findFirst({ where: { userId } });
if (cart) { if (cart) {
await tx.cartItem.deleteMany({ await tx.cartItem.deleteMany({
where: { cartId: cart.id, companyId: company.id }, where: {
cartId: cart.id,
productId: { in: uniqueProductIds },
},
});
const remaining = await tx.cartItem.findFirst({
where: { cartId: cart.id },
});
await tx.cart.update({
where: { id: cart.id },
data: { companyId: remaining?.companyId ?? null },
}); });
} }
return created; return created;
@@ -200,6 +247,9 @@ let OrdersService = class OrdersService {
? client_1.OrderStatus.awaiting_cash_payment ? client_1.OrderStatus.awaiting_cash_payment
: client_1.OrderStatus.check_in_progress; : client_1.OrderStatus.check_in_progress;
(0, order_transitions_1.assertTransition)(order.status, nextStatus); (0, order_transitions_1.assertTransition)(order.status, nextStatus);
const cashCompanies = isCash
? await this.companiesForOrder(order)
: [];
await this.prisma.$transaction(async (tx) => { await this.prisma.$transaction(async (tx) => {
await tx.order.update({ await tx.order.update({
where: { id }, where: { id },
@@ -209,7 +259,7 @@ let OrdersService = class OrdersService {
? null ? null
: (dto.checkMode ?? client_1.CheckRegistrationMode.full), : (dto.checkMode ?? client_1.CheckRegistrationMode.full),
cashInvoiceExpiresAt: isCash cashInvoiceExpiresAt: isCash
? (0, cash_expiry_1.computeCashInvoiceExpiry)(order.company) ? (0, cash_expiry_1.earliestCashInvoiceExpiry)(cashCompanies)
: null, : null,
cashReminderSentAt: null, cashReminderSentAt: null,
status: nextStatus, status: nextStatus,
@@ -235,8 +285,16 @@ let OrdersService = class OrdersService {
}); });
if (!company) if (!company)
throw new common_1.NotFoundException('شرکت یافت نشد'); throw new common_1.NotFoundException('شرکت یافت نشد');
let userId = dto.userId; let userId = dto.customerId || dto.userId;
if (!userId && dto.customerPhone) { if (userId) {
const existing = await this.prisma.customer.findUnique({
where: { id: userId },
});
if (!existing) {
throw new common_1.BadRequestException('مشتری انتخاب‌شده یافت نشد');
}
}
else if (dto.customerPhone) {
const phone = (0, phone_1.normalizePhone)((0, phone_1.toEnglishDigits)(dto.customerPhone)); const phone = (0, phone_1.normalizePhone)((0, phone_1.toEnglishDigits)(dto.customerPhone));
if (!(0, phone_1.isValidPhone)(phone)) { if (!(0, phone_1.isValidPhone)(phone)) {
throw new common_1.BadRequestException('شماره موبایل نامعتبر است'); throw new common_1.BadRequestException('شماره موبایل نامعتبر است');
@@ -257,7 +315,7 @@ let OrdersService = class OrdersService {
userId = customer.id; userId = customer.id;
} }
if (!userId) { if (!userId) {
throw new common_1.BadRequestException('شناسه یا شماره مشتری الزامی است'); throw new common_1.BadRequestException('انتخاب مشتری الزامی است');
} }
const totalMeterage = dto.meterage ?? 0; const totalMeterage = dto.meterage ?? 0;
const ownerId = userId; const ownerId = userId;
@@ -372,6 +430,12 @@ let OrdersService = class OrdersService {
(order.finalAmount ?? 0) <= 0) { (order.finalAmount ?? 0) <= 0) {
throw new common_1.BadRequestException('ابتدا سفارش را قیمت‌گذاری کنید تا فاکتور قابل ارسال باشد'); throw new common_1.BadRequestException('ابتدا سفارش را قیمت‌گذاری کنید تا فاکتور قابل ارسال باشد');
} }
const needsCashExpiry = (dto.status === client_1.OrderStatus.cash_invoice_issued ||
dto.status === client_1.OrderStatus.awaiting_cash_payment) &&
!order.cashInvoiceExpiresAt;
const cashExpiry = needsCashExpiry
? (0, cash_expiry_1.earliestCashInvoiceExpiry)(await this.companiesForOrder(order))
: null;
await this.prisma.$transaction(async (tx) => { await this.prisma.$transaction(async (tx) => {
await tx.order.update({ await tx.order.update({
where: { id }, where: { id },
@@ -389,16 +453,11 @@ let OrdersService = class OrdersService {
reason: dto.reason || null, reason: dto.reason || null,
}, },
}); });
if (dto.status === client_1.OrderStatus.cash_invoice_issued || if (cashExpiry) {
dto.status === client_1.OrderStatus.awaiting_cash_payment) { await tx.order.update({
if (!order.cashInvoiceExpiresAt) { where: { id },
await tx.order.update({ data: { cashInvoiceExpiresAt: cashExpiry },
where: { id }, });
data: {
cashInvoiceExpiresAt: (0, cash_expiry_1.computeCashInvoiceExpiry)(order.company),
},
});
}
} }
}); });
const event = (0, notification_events_1.eventForStatus)(dto.status); const event = (0, notification_events_1.eventForStatus)(dto.status);
@@ -515,6 +574,20 @@ let OrdersService = class OrdersService {
} }
} }
} }
async companiesForOrder(order) {
const companyIds = [
...new Set([
order.companyId,
...order.items.map((item) => item.companyId).filter(Boolean),
].filter(Boolean)),
];
if (!companyIds.length)
return order.company ? [order.company] : [];
const companies = await this.prisma.company.findMany({
where: { id: { in: companyIds } },
});
return companies.length ? companies : order.company ? [order.company] : [];
}
async getOrder(id) { async getOrder(id) {
const order = await this.prisma.order.findUnique({ const order = await this.prisma.order.findUnique({
where: { id }, where: { id },
@@ -572,6 +645,8 @@ let OrdersService = class OrdersService {
lineTotal: hidePrices ? null : item.lineTotal, lineTotal: hidePrices ? null : item.lineTotal,
totalAmount: hidePrices ? null : item.lineTotal, totalAmount: hidePrices ? null : item.lineTotal,
notes: item.notes ?? undefined, notes: item.notes ?? undefined,
companyId: item.companyId,
companyName: item.companyName,
})), })),
checks: order.checks.map((c) => ({ checks: order.checks.map((c) => ({
id: c.id, id: c.id,
+1 -1
View File
File diff suppressed because one or more lines are too long
Binary file not shown.