Skip to content

Commit 205fb06

Browse files
committed
feat: Enhance order and payment transaction handling
- Updated OrderDTO to include payment_transactions as an array of PaymentTransactionDTO. - Introduced PaymentTransactionDTO and related types for better payment transaction management. - Modified Order interface to accommodate paymentTransactions. - Updated payment.ts to define PaymentTransaction interface and related types. - Enhanced admin order management UI to display payment transactions history. - Added functionality for capturing, refunding, and canceling payments with improved error handling. - Implemented Mark as Shipped action for orders. - Cleaned up console logs in product management routes.
1 parent 503234e commit 205fb06

12 files changed

Lines changed: 595 additions & 246 deletions

File tree

src/lib/server/api/commercify.ts

Lines changed: 215 additions & 69 deletions
Large diffs are not rendered by default.

src/lib/server/api/dtos.ts

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,9 +179,9 @@ export interface OrderDTO {
179179
currency: string;
180180
shipping_address: AddressDTO;
181181
billing_address: AddressDTO;
182-
payment_details?: PaymentDetails;
183182
shipping_details: ShippingOptionDTO;
184183
discount_details?: AppliedDiscountDTO;
184+
payment_transactions?: PaymentTransactionDTO[];
185185
customer: CustomerDetailsDTO;
186186
action_required: boolean; // Indicates if action is needed (e.g., payment)
187187
action_url?: string; // URL for payment or order actions
@@ -262,6 +262,36 @@ export const PaymentStatusCaptured: PaymentStatus = 'captured';
262262
export const PaymentStatusRefunded: PaymentStatus = 'refunded';
263263
export const PaymentStatusCancelled: PaymentStatus = 'cancelled';
264264
export const PaymentStatusFailed: PaymentStatus = 'failed';
265+
/**
266+
* PaymentTransactionDTO represents a payment transaction
267+
*/
268+
export interface PaymentTransactionDTO {
269+
id: number /* uint */;
270+
transaction_id: string;
271+
external_id?: string;
272+
type: TransactionType;
273+
status: TransactionStatus;
274+
amount: number /* float64 */;
275+
currency: string;
276+
provider: string;
277+
created_at: string;
278+
updated_at: string;
279+
}
280+
/**
281+
* TransactionType represents the type of payment transaction
282+
*/
283+
export type TransactionType = string;
284+
export const TransactionTypeAuthorize: TransactionType = 'authorize';
285+
export const TransactionTypeCapture: TransactionType = 'capture';
286+
export const TransactionTypeRefund: TransactionType = 'refund';
287+
export const TransactionTypeCancel: TransactionType = 'cancel';
288+
/**
289+
* TransactionStatus represents the status of a payment transaction
290+
*/
291+
export type TransactionStatus = string;
292+
export const TransactionStatusSuccessful: TransactionStatus = 'successful';
293+
export const TransactionStatusFailed: TransactionStatus = 'failed';
294+
export const TransactionStatusPending: TransactionStatus = 'pending';
265295

266296
//////////
267297
// source: product.go

src/lib/types/order.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { Checkout, CheckoutItem } from './checkout';
22
import type { Price } from './common';
3-
import type { PaymentDetails, PaymentStatus } from './payment';
3+
import type { PaymentDetails, PaymentStatus, PaymentTransaction } from './payment';
44

55
export interface OrderItem extends CheckoutItem {}
66

@@ -10,6 +10,7 @@ export interface Order extends Checkout {
1010
checkoutId: string; // Reference to the original checkout session
1111
status: OrderStatus;
1212
paymentDetails?: PaymentDetails;
13+
paymentTransactions?: PaymentTransaction[];
1314
createdAt: string; // ISO date string
1415
}
1516

src/lib/types/payment.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ export type PaymentStatus =
1010
| 'failed';
1111
export type PaymentProvider = 'stripe' | 'mobilepay';
1212

13+
export type TransactionStatus = 'pending' | 'successful' | 'failed';
14+
1315
export interface PaymentDetails {
1416
paymentId: string; // Optional payment ID if available
1517
method: PaymentMethod; // e.g., 'credit_card', 'wallet'
@@ -26,3 +28,34 @@ export interface PaymentDetails {
2628
createdAt: string; // ISO date string for when the payment was created
2729
updatedAt?: string; // Optional ISO date string for when the payment was last updated
2830
}
31+
32+
export interface PaymentTransaction {
33+
id: string;
34+
transactionId: string;
35+
externalId?: string;
36+
type: 'authorize' | 'capture' | 'refund' | 'cancel';
37+
status: TransactionStatus;
38+
amount: number;
39+
currency: string;
40+
provider: string;
41+
createdAt: string;
42+
updatedAt: string;
43+
}
44+
45+
export interface PaymentTransactionDTO {
46+
id: number /* uint */;
47+
transaction_id: string;
48+
external_id?: string;
49+
type: PaymentStatus;
50+
status: TransactionStatus;
51+
amount: number /* float64 */;
52+
currency: string;
53+
provider: string;
54+
created_at: string;
55+
updated_at: string;
56+
}
57+
58+
export interface PaymentEventInput {
59+
amount?: number;
60+
isFull: boolean;
61+
}

src/routes/admin/orders/+page.svelte

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -133,16 +133,16 @@
133133
View Details
134134
</a>
135135
</DropdownMenu.Item>
136-
<DropdownMenu.Item>
136+
<!-- <DropdownMenu.Item>
137137
<Package class="mr-2 h-4 w-4" />
138138
Ship Order
139-
</DropdownMenu.Item>
140-
<DropdownMenu.Item>
139+
</DropdownMenu.Item> -->
140+
<!-- <DropdownMenu.Item>
141141
<CreditCard class="mr-2 h-4 w-4" />
142142
Process Payment
143143
</DropdownMenu.Item>
144144
<DropdownMenu.Separator />
145-
<DropdownMenu.Item class="text-red-600">Cancel Order</DropdownMenu.Item>
145+
<DropdownMenu.Item class="text-red-600">Cancel Order</DropdownMenu.Item> -->
146146
</DropdownMenu.Content>
147147
</DropdownMenu.Root>
148148
</Table.Cell>

src/routes/admin/orders/[id]/+page.server.ts

Lines changed: 74 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -12,113 +12,113 @@ export const load: PageServerLoad = async ({ params, locals, depends }) => {
1212
return fail(404, { error: 'Order ID is required' });
1313
}
1414

15-
try {
16-
const orderResult = await commercify.getOrderById(orderId);
15+
const orderResult = await commercify.getOrderById(orderId);
1716

18-
if (!orderResult.success || !orderResult.data) {
19-
console.error('Error fetching order:', orderResult.error);
20-
return fail(404, {
21-
error: orderResult.error || 'Order not found'
17+
if (!orderResult.success || !orderResult.data) {
18+
console.error('Error fetching order:', orderResult.error);
19+
return fail(404, {
20+
error: orderResult.error || 'Order not found'
21+
});
22+
}
23+
24+
return {
25+
order: orderResult.data,
26+
orderId
27+
};
28+
};
29+
30+
export const actions: Actions = {
31+
capture: async ({ request, locals }) => {
32+
const { commercify } = locals;
33+
const data = await request.formData();
34+
const paymentId = data.get('paymentId') as string;
35+
36+
if (!paymentId) {
37+
return fail(400, { error: 'Payment ID is required' });
38+
}
39+
40+
// Note: The API captures payment by orderId, but we validate paymentId from the form
41+
const result = await commercify.captureOrderPayment(paymentId, {
42+
isFull: true
43+
});
44+
45+
if (!result.success) {
46+
return fail(400, {
47+
error: result.error || 'Failed to capture payment'
2248
});
2349
}
2450

2551
return {
26-
order: orderResult.data,
27-
orderId
52+
success: true,
53+
message: 'Payment captured successfully'
2854
};
29-
} catch (error) {
30-
console.error('Error loading order:', error);
31-
return fail(500, {
32-
error: 'Failed to load order. Please try again later.'
33-
});
34-
}
35-
};
55+
},
3656

37-
export const actions: Actions = {
38-
capture: async ({ params, locals }) => {
57+
refund: async ({ locals, request }) => {
3958
const { commercify } = locals;
40-
const orderId = params.id;
59+
const data = await request.formData();
60+
const paymentId = data.get('paymentId') as string;
4161

42-
if (!orderId) {
62+
if (!paymentId) {
4363
return fail(400, { error: 'Order ID is required' });
4464
}
4565

46-
try {
47-
const result = await commercify.captureOrderPayment(orderId);
48-
49-
if (!result.success) {
50-
return fail(400, {
51-
error: result.error || 'Failed to capture payment'
52-
});
53-
}
54-
55-
return {
56-
success: true,
57-
message: 'Payment captured successfully'
58-
};
59-
} catch (error) {
60-
console.error('Error capturing payment:', error);
61-
return fail(500, {
62-
error: 'Failed to capture payment'
66+
const result = await commercify.refundOrderPayment(paymentId, { isFull: true });
67+
68+
if (!result.success) {
69+
return fail(400, {
70+
error: result.error || 'Failed to refund payment'
6371
});
6472
}
73+
74+
return {
75+
success: true,
76+
message: 'Payment refunded successfully'
77+
};
6578
},
6679

67-
refund: async ({ params, locals }) => {
80+
cancel: async ({ request, locals }) => {
6881
const { commercify } = locals;
69-
const orderId = params.id;
82+
const data = await request.formData();
83+
const paymentId = data.get('paymentId') as string;
7084

71-
if (!orderId) {
85+
if (!paymentId) {
7286
return fail(400, { error: 'Order ID is required' });
7387
}
7488

75-
try {
76-
const result = await commercify.refundOrderPayment(orderId);
77-
78-
if (!result.success) {
79-
return fail(400, {
80-
error: result.error || 'Failed to refund payment'
81-
});
82-
}
83-
84-
return {
85-
success: true,
86-
message: 'Payment refunded successfully'
87-
};
88-
} catch (error) {
89-
console.error('Error refunding payment:', error);
90-
return fail(500, {
91-
error: 'Failed to refund payment'
89+
const result = await commercify.cancelOrderPayment(paymentId);
90+
91+
if (!result.success) {
92+
return fail(400, {
93+
error: result.error || 'Failed to cancel payment'
9294
});
9395
}
96+
97+
return {
98+
success: true,
99+
message: 'Payment cancelled successfully'
100+
};
94101
},
95102

96-
cancel: async ({ params, locals }) => {
103+
ship: async ({ params, locals }) => {
97104
const { commercify } = locals;
98105
const orderId = params.id;
99106

100107
if (!orderId) {
101108
return fail(400, { error: 'Order ID is required' });
102109
}
103110

104-
try {
105-
const result = await commercify.cancelOrder(orderId);
106-
107-
if (!result.success) {
108-
return fail(400, {
109-
error: result.error || 'Failed to cancel order'
110-
});
111-
}
112-
113-
return {
114-
success: true,
115-
message: 'Order cancelled successfully'
116-
};
117-
} catch (error) {
118-
console.error('Error cancelling order:', error);
119-
return fail(500, {
120-
error: 'Failed to cancel order'
111+
const result = await commercify.updateOrderStatus(orderId, 'shipped');
112+
113+
if (!result.success) {
114+
return fail(400, {
115+
error: result.error || 'Failed to mark order as shipped'
121116
});
122117
}
118+
119+
return {
120+
success: true,
121+
message: 'Order marked as shipped successfully'
122+
};
123123
}
124124
};

0 commit comments

Comments
 (0)