Enhance sales document flow with new service and related functionalities

- Introduced `SalesDocumentFlowService` to manage the lifecycle of sales documents, including packing slips and invoices.
- Implemented methods for processing orders, generating invoices, and handling packing slips based on order status.
- Updated `SalesOrdersService`, `PackingSlipsService`, and `SalesInvoicesService` to integrate with the new document flow service.
- Added new methods for marking drafts processed and checking if invoices are on sales plans.
- Enhanced existing services and repositories to support new functionalities, including status transitions and related document management.
- Updated DTOs to include new fields for packing slip and invoice IDs in sales order responses.
- Added unit tests for the new service and updated existing tests to cover new functionalities.
This commit is contained in:
shancheas
2026-08-31 09:35:18 +07:00
parent 627aeac4a0
commit afed5ff0f5
24 changed files with 950 additions and 53 deletions
@@ -36,7 +36,10 @@ describe('PlansService', () => {
const employeesService = { findById: jest.fn() };
const branchesService = { findById: jest.fn() };
const customersService = { findById: jest.fn() };
const salesInvoicesService = { findById: jest.fn() };
const salesInvoicesService = {
findById: jest.fn(),
markDraftsProcessed: jest.fn(),
};
const packingSlipsService = { findById: jest.fn() };
const privilegesService = { checkPermission: jest.fn() };
+29
View File
@@ -136,6 +136,12 @@ export class PlansService {
const created = await this.plansRepository.create(
await this.toWritePayload(input),
);
await this.processAttachedInvoices(
created.purpose,
[],
created.invoiceIds,
input.userId,
);
return this.toItem(created);
}
@@ -201,6 +207,12 @@ export class PlansService {
packingSlipIds: attachments.packingSlipIds,
userId: input.userId,
});
await this.processAttachedInvoices(
purpose,
existing.invoiceIds,
attachments.invoiceIds,
input.userId,
);
return this.toItem(updated);
}
@@ -515,6 +527,23 @@ export class PlansService {
};
}
private async processAttachedInvoices(
purpose: FieldPurpose,
previousIds: readonly string[],
nextIds: readonly string[],
userId: string,
): Promise<void> {
if (purpose !== 'sales') {
return;
}
const previous = new Set(previousIds);
const newlyAttached = nextIds.filter((id) => !previous.has(id));
if (newlyAttached.length === 0) {
return;
}
await this.salesInvoicesService.markDraftsProcessed(newlyAttached, userId);
}
private async assertInvoices(ids: readonly string[]): Promise<void> {
for (const id of ids) {
await this.salesInvoicesService.findById(id);