diff --git a/src/orders/dto/order.dto.ts b/src/orders/dto/order.dto.ts index 1a39775..7936626 100644 --- a/src/orders/dto/order.dto.ts +++ b/src/orders/dto/order.dto.ts @@ -2,6 +2,7 @@ import { ArrayMinSize, IsDateString, IsEnum, + IsIn, IsInt, IsNumber, IsOptional, @@ -166,4 +167,9 @@ export class ListOrdersDto { @Min(0) @Type(() => Number) maxTotal?: number; + + /** Filter by payment outcome derived from transactions. */ + @IsOptional() + @IsIn(['paid', 'unpaid', 'failed']) + paymentStatus?: 'paid' | 'unpaid' | 'failed'; } diff --git a/src/orders/orders.service.ts b/src/orders/orders.service.ts index b57ddd6..7e486c5 100644 --- a/src/orders/orders.service.ts +++ b/src/orders/orders.service.ts @@ -155,6 +155,7 @@ export class OrdersService { customer: this.buildCustomerSearchFilter(query.customerQuery.trim()), } : {}), + ...this.paymentStatusWhere(query.paymentStatus), }; const [items, total] = await Promise.all([ @@ -762,6 +763,43 @@ export class OrdersService { return { OR: or }; } + private paymentStatusWhere( + paymentStatus: 'paid' | 'unpaid' | 'failed' | undefined, + ): Prisma.OrderWhereInput { + if (paymentStatus === 'paid') { + return { + transactions: { some: { status: 'completed' } }, + }; + } + if (paymentStatus === 'failed') { + return { + AND: [ + { transactions: { some: { status: 'failed' } } }, + { transactions: { none: { status: 'completed' } } }, + ], + }; + } + if (paymentStatus === 'unpaid') { + return { + transactions: { none: { status: 'completed' } }, + }; + } + return {}; + } + + private derivePaymentStatus( + transactions: Array<{ status: string }>, + ): 'paid' | 'unpaid' | 'failed' { + if (transactions.some((tx) => tx.status === 'completed')) return 'paid'; + if ( + transactions.length > 0 && + transactions.every((tx) => tx.status === 'failed') + ) { + return 'failed'; + } + return 'unpaid'; + } + private async defaultProcessStepId(businessId: bigint) { const steps = await this.businessSettings.getOrderProcessSteps(businessId); return steps[0]?.id ?? 'processing'; @@ -873,6 +911,7 @@ export class OrdersService { processStepLabel: processStep?.label ?? null, processStepLabelFa: processStep?.labelFa?.trim() || null, processStepColor: processStep?.color ?? null, + paymentStatus: this.derivePaymentStatus(order.transactions ?? []), source: order.source, subtotal: Number(order.subtotal), shippingTotal: Number(order.shippingTotal),