Skip to content

Commit ce9a2db

Browse files
committed
fix: calculate payment result amount
1 parent 2f10aaf commit ce9a2db

File tree

4 files changed

+43
-11
lines changed

4 files changed

+43
-11
lines changed

src/infra/payment/payment.service.ts

+5
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,11 @@ export class PaymentService {
4949
frontendAmount: number | string;
5050
calculatedBackendAmount: number | string;
5151
}): void {
52+
this.logger.log(`[Payment Verification]`, {
53+
pgAmount,
54+
frontendAmount,
55+
calculatedBackendAmount,
56+
});
5257
if (!decimal.isSame(pgAmount, frontendAmount)) {
5358
throw new Error(
5459
`Payment amount mismatch. Reserved: ${frontendAmount} | Amount: ${pgAmount}`,

src/infra/payment/portone-api.types.ts

+13-11
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,17 @@ export type PortonePaymentResult = {
2323
* https://developers.portone.io/api/rest-v2/payment?v=v2#post%20%2Fpayments%2F%7BpaymentId%7D%2Fcancel
2424
*/
2525
export type PortoneSucceededPaymentCancellation = {
26-
status: 'SUCCEEDED' | 'FAILED' | 'REQUESTED';
27-
id: string;
28-
pgCancellationId?: string;
29-
reason: string;
30-
totalAmount: number;
31-
taxFreeAmount: number;
32-
vatAmount: number;
33-
easyPayDiscountAmount?: number;
34-
cancelledAt?: string;
35-
requestedAt: string;
36-
receiptUrl?: string; // 취소 영수증 URL. status 가 SUCCEEDED 일 때만 존재.
26+
cancellation: {
27+
status: 'SUCCEEDED' | 'FAILED' | 'REQUESTED';
28+
id: string;
29+
pgCancellationId?: string;
30+
reason: string;
31+
totalAmount: number;
32+
taxFreeAmount: number;
33+
vatAmount: number;
34+
easyPayDiscountAmount?: number;
35+
cancelledAt?: string;
36+
requestedAt: string;
37+
receiptUrl?: string; // 취소 영수증 URL. status 가 SUCCEEDED 일 때만 존재.
38+
};
3739
};

src/shared/utils/decimal.ts

+10
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,13 @@ export const divide = (a: number | string, b: number | string): Price => {
4747
const y = new BigNumber(b);
4848
return typia.assert<Price>(x.dividedBy(y).toString());
4949
};
50+
51+
export const floor = (a: number | string): Price => {
52+
const x = new BigNumber(a);
53+
return typia.assert<Price>(x.integerValue(BigNumber.ROUND_FLOOR).toString());
54+
};
55+
56+
export const ceil = (a: number | string): Price => {
57+
const x = new BigNumber(a);
58+
return typia.assert<Price>(x.integerValue(BigNumber.ROUND_CEIL).toString());
59+
};

src/v1/order/course/course-order-purchase.service.ts

+15
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ export class CourseOrderPurchaseService {
168168
'pricing' | 'discount'
169169
>,
170170
coupon: ICoupon | null,
171+
rounding: 'floor' | 'ceil' = 'floor',
171172
): Price {
172173
const { pricing, discount } = product;
173174
let calculatedAmount = pricing.amount;
@@ -186,6 +187,13 @@ export class CourseOrderPurchaseService {
186187
}
187188

188189
if (!coupon) {
190+
// Apply rounding if necessary
191+
if (rounding === 'floor') {
192+
calculatedAmount = decimal.floor(calculatedAmount);
193+
} else if (rounding === 'ceil') {
194+
calculatedAmount = decimal.ceil(calculatedAmount);
195+
}
196+
189197
return calculatedAmount;
190198
}
191199

@@ -223,6 +231,13 @@ export class CourseOrderPurchaseService {
223231
calculatedAmount = '0';
224232
}
225233

234+
// Apply rounding if necessary
235+
if (rounding === 'floor') {
236+
calculatedAmount = decimal.floor(calculatedAmount);
237+
} else if (rounding === 'ceil') {
238+
calculatedAmount = decimal.ceil(calculatedAmount);
239+
}
240+
226241
return calculatedAmount;
227242
}
228243

0 commit comments

Comments
 (0)