Add paymentStatus filter and field on order list API.

Support paid/unpaid/failed filtering from completed transactions for dashboard order tabs.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Alireza Hassani
2026-10-02 22:22:23 +03:30
co-authored by Cursor
parent 0d9e866a57
commit 7f6fa3672d
2 changed files with 45 additions and 0 deletions
+6
View File
@@ -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';
}
+39
View File
@@ -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),