Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ export async function POST(_request: Request, context: RouteContext) {
try {
const { orderId } = await context.params;

const order = await OrderService.confirm(orderId);
const result = await OrderService.confirm(orderId);

return NextResponse.json({
data: order,
data: result,
});
} catch (error) {
return createApiErrorResponse(error);
Expand Down
24 changes: 24 additions & 0 deletions apps/commerce-api/src/app/api/payments/by-order/[orderId]/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { NextResponse } from "next/server";

import { createApiErrorResponse } from "@/lib/api-error";
import { PaymentService } from "@/services/PaymentService";

type RouteContext = {
params: Promise<{
orderId: string;
}>;
};

export async function GET(_request: Request, context: RouteContext) {
try {
const { orderId } = await context.params;

const payment = await PaymentService.findByOrderId(orderId);

return NextResponse.json({
data: payment,
});
} catch (error) {
return createApiErrorResponse(error);
}
}
9 changes: 2 additions & 7 deletions apps/commerce-api/src/db/seed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -173,9 +173,9 @@ const orderSeed = [
discount: 8_000_000,
total: 160_000_000,
currency: "IDR",
status: "PENDING",
status: "CONFIRMED",
createdAt: new Date("2026-08-27T03:00:00.000Z"),
updatedAt: new Date("2026-08-27T03:00:00.000Z"),
updatedAt: new Date("2026-08-27T03:15:00.000Z"),
},
{
id: "ORD-2026-0180",
Expand Down Expand Up @@ -418,15 +418,10 @@ async function seedDatabase() {
console.log("");

console.log(` Customers: ${customerSeed.length}`);

console.log(` Quotations: ${quotationSeed.length}`);

console.log(` Quotation items: ${quotationItemSeed.length}`);

console.log(` Orders: ${orderSeed.length}`);

console.log(` Order items: ${orderItemSeed.length}`);

console.log(` Payments: ${paymentSeed.length}`);
} finally {
await pool.end();
Expand Down
22 changes: 20 additions & 2 deletions apps/commerce-api/src/db/verify-persistence.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,9 @@ async function verifyPersistence() {
throw new Error("Expected ORD-2026-0181 to exist.");
}

if (order.status !== "PENDING") {
if (order.status !== "CONFIRMED") {
throw new Error(
`Expected ORD-2026-0181 to be PENDING, received ${order.status}.`,
`Expected ORD-2026-0181 to be CONFIRMED, received ${order.status}.`,
);
}

Expand All @@ -113,12 +113,30 @@ async function verifyPersistence() {
throw new Error("Expected PAY-2026-0091 to exist.");
}

if (payment.orderId !== order.id) {
throw new Error(
`Expected PAY-2026-0091 to belong to ${order.id}, received ${payment.orderId}.`,
);
}

if (payment.amount !== order.total) {
throw new Error(
`Expected PAY-2026-0091 amount to equal order total ${order.total}, received ${payment.amount}.`,
);
}

if (payment.status !== "PENDING") {
throw new Error(
`Expected PAY-2026-0091 to be PENDING, received ${payment.status}.`,
);
}

if (payment.reference !== "INV-2026-0181") {
throw new Error(
`Expected PAY-2026-0091 reference to be INV-2026-0181, received ${payment.reference}.`,
);
}

if (payment.paidAt !== null) {
throw new Error("Expected PAY-2026-0091 paidAt to be null.");
}
Expand Down
13 changes: 12 additions & 1 deletion apps/commerce-api/src/lib/payments.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
export type PaymentStatus = "PENDING" | "PAID" | "FAILED" | "REFUNDED";
export type PaymentStatus =
| "PENDING"
| "PAID"
| "FAILED"
| "REFUNDED"
| "CANCELLED";

export type PaymentMethod = "BANK_TRANSFER" | "VIRTUAL_ACCOUNT" | "CARD";

Expand All @@ -18,6 +23,12 @@ export type Payment = {
refundedAt: string | null;
};

export type CreatePaymentForOrderInput = {
orderId: string;
amount: number;
currency: Currency;
};

export class PaymentDomainError extends Error {
statusCode: number;

Expand Down
28 changes: 28 additions & 0 deletions apps/commerce-api/src/repositories/OrderRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,33 @@ async function insertInTransaction(
}
}

async function updateStatusInTransaction(
transaction: DatabaseTransaction,
orderId: string,
expectedStatuses: OrderStatus[],
nextStatus: OrderStatus,
updatedAt: string,
): Promise<boolean> {
if (expectedStatuses.length === 0) {
return false;
}

const result = await transaction
.update(orders)
.set({
status: nextStatus,
updatedAt: new Date(updatedAt),
})
.where(
and(eq(orders.id, orderId), inArray(orders.status, expectedStatuses)),
)
.returning({
id: orders.id,
});

return result.length > 0;
}

async function updateStatus(
orderId: string,
expectedStatuses: OrderStatus[],
Expand Down Expand Up @@ -272,5 +299,6 @@ export const OrderRepository = {
findBySourceQuotationIdInTransaction,
allocateIdentityInTransaction,
insertInTransaction,
updateStatusInTransaction,
updateStatus,
};
Loading
Loading