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
@@ -20,8 +20,10 @@ import {
isValidDocumentNotes,
isValidImageDescription,
isValidImageUrl,
isAllowedStatusTransition,
parseCsvRecord,
SALES_PAYMENT_STATUSES,
SALES_PAYMENT_USER_TRANSITIONS,
} from '../shared/sales-fields';
import type {
CreateSalesPaymentInput,
@@ -152,6 +154,15 @@ export class SalesPaymentsService {
if (!existing) {
throw new NotFoundException('Sales payment not found');
}
if (
!isAllowedStatusTransition(
existing.status.value,
next.value,
SALES_PAYMENT_USER_TRANSITIONS,
)
) {
throw new BadRequestException('Invalid status transition');
}
const becomingApproved =
next.value === 'approved' && existing.status.value !== 'approved';
const leavingApproved =
@@ -180,13 +191,10 @@ export class SalesPaymentsService {
statusRaw: string,
userId: string,
): Promise<{ updated: number }> {
const status = this.assertStatus(statusRaw);
const updated = await this.salesPaymentsRepository.bulkUpdateStatus(
ids,
status,
userId,
);
return { updated };
for (const id of ids) {
await this.updateStatus(id, statusRaw, userId);
}
return { updated: ids.length };
}
async delete(id: string): Promise<void> {