Skip to content

Commit 5cbb76a

Browse files
feat(chore): comments fix
comments fix GH-27
1 parent 41d4720 commit 5cbb76a

9 files changed

Lines changed: 456 additions & 376 deletions

File tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
export * from './customer.adapter';
22
export * from './invoice.adapter';
3+
export * from './payment-intent.adapter';
34
export * from './payment-source.adapter';
45
export * from './subscription.adapter';

src/providers/sdk/chargebee/adapter/invoice.adapter.ts

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
import {
2+
TInvoicePdf,
3+
TInvoicePaymentDetails,
4+
TPaymentMethod,
5+
} from '../../../../types';
6+
import {ChargebeeInvoice} from '../type';
17
import {AnyObject} from '@loopback/repository';
28
import {ICharge, IChargeBeeInvoice, IDiscount} from '../type';
39
export class InvoiceAdapter {
@@ -38,4 +44,62 @@ export class InvoiceAdapter {
3844
};
3945
return res;
4046
}
47+
48+
/**
49+
* Adapts a ChargeBee invoice download result to TInvoicePdf format.
50+
*
51+
* @param download - ChargeBee download object
52+
* @param invoiceId - The invoice ID
53+
* @returns TInvoicePdf - Invoice PDF information
54+
*/
55+
adaptToInvoicePdf(
56+
download: Record<string, unknown>,
57+
invoiceId: string,
58+
): TInvoicePdf {
59+
return {
60+
invoiceId: invoiceId,
61+
pdfUrl: String(download['download_url'] ?? ''),
62+
generatedAt: Math.floor(Date.now() / 1000), // Current timestamp in seconds
63+
expiresAt: download['expires_at'] as number | undefined,
64+
};
65+
}
66+
67+
/**
68+
* Adapts ChargeBee invoice and payment method data to TInvoicePaymentDetails format.
69+
*
70+
* @param invoice - ChargeBee invoice object
71+
* @param paymentMethod - Payment method details
72+
* @returns TInvoicePaymentDetails - Payment details for the invoice
73+
*/
74+
adaptToPaymentDetails(
75+
invoice: ChargebeeInvoice,
76+
paymentMethod: TPaymentMethod,
77+
): TInvoicePaymentDetails {
78+
const id = invoice.invoiceId ?? invoice.id ?? '';
79+
return {
80+
invoiceId: id,
81+
paymentMethod: paymentMethod,
82+
paymentDate: invoice.paidAt
83+
? Math.floor(new Date(invoice.paidAt).getTime() / 1000)
84+
: undefined,
85+
amount: invoice.total ?? 0,
86+
currency: invoice.currencyCode ?? 'USD',
87+
status: invoice.status ?? 'unknown',
88+
transactionId: id,
89+
description: `Payment for invoice ${id}`,
90+
};
91+
}
92+
93+
/**
94+
* Extracts customer ID from invoice.
95+
*
96+
* @param invoice - The ChargeBee invoice
97+
* @returns Customer ID or empty string if not found
98+
*/
99+
getCustomerIdFromInvoice(invoice: ChargebeeInvoice): string {
100+
const customerId =
101+
((invoice as Record<string, unknown>)['customer_id'] as string) ||
102+
invoice.customerId;
103+
return customerId ?? '';
104+
}
41105
}
Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
import {TPaymentIntent, TPaymentMethod} from '../../../../types';
2+
import {
3+
ChargebeeCard,
4+
ChargebeePaymentSource,
5+
ChargebeeTransaction,
6+
} from '../type';
7+
8+
// Payment method default values
9+
const DEFAULT_EXPIRY_MONTH = 12;
10+
const DEFAULT_EXPIRY_YEAR = 2025;
11+
const DEFAULT_FUNDING_TYPE = 'credit';
12+
const DEFAULT_CARD_BRAND = 'unknown';
13+
14+
export class ChargebeePaymentIntentAdapter {
15+
constructor() {}
16+
17+
/**
18+
* Adapts a ChargeBee transaction to the generic TPaymentIntent format.
19+
*
20+
* @param transaction - ChargeBee transaction object
21+
* @param paymentMethod - Optional payment method details
22+
* @returns TPaymentIntent - Normalized payment intent format
23+
*/
24+
adaptToModel(
25+
transaction: ChargebeeTransaction,
26+
paymentMethod?: TPaymentMethod,
27+
): TPaymentIntent {
28+
const currencyCode =
29+
((transaction as Record<string, unknown>)['currency_code'] as
30+
| string
31+
| undefined) ??
32+
transaction.currencyCode ??
33+
'usd';
34+
const customerId =
35+
((transaction as Record<string, unknown>)['customer_id'] as
36+
| string
37+
| undefined) ?? transaction.customerId;
38+
const amountCapturable = (transaction as Record<string, unknown>)[
39+
'amount_capturable'
40+
] as number | undefined;
41+
const transactionType =
42+
((transaction as Record<string, unknown>)['type'] as
43+
| string
44+
| undefined) ?? 'transaction';
45+
46+
return {
47+
id: transaction.id ?? '',
48+
amount: transaction.amount ?? 0,
49+
currency: String(currencyCode).toLowerCase(),
50+
status: this.mapTransactionStatusToPaymentIntentStatus(
51+
transaction.status ?? 'in_progress',
52+
),
53+
created:
54+
typeof transaction.date === 'string'
55+
? Math.floor(new Date(transaction.date).getTime() / 1000)
56+
: (transaction.date ?? 0),
57+
customer: customerId,
58+
paymentMethod: paymentMethod,
59+
description: `ChargeBee ${transactionType} transaction`,
60+
latestCharge: transaction.id ?? '', // In ChargeBee, transaction is the charge
61+
clientSecret: undefined, // ChargeBee doesn't have client secret concept
62+
amountCapturable: amountCapturable,
63+
captureMethod: 'automatic', // ChargeBee default behavior
64+
};
65+
}
66+
67+
/**
68+
* Maps ChargeBee transaction status to PaymentIntent status.
69+
*
70+
* ChargeBee transaction statuses: in_progress, success, voided, failure, timeout, needs_attention, late_failure
71+
* PaymentIntent statuses: requires_payment_method, requires_confirmation, requires_action, processing, requires_capture, canceled, succeeded
72+
*
73+
* @param transactionStatus - ChargeBee transaction status
74+
* @returns Corresponding PaymentIntent status
75+
*/
76+
private mapTransactionStatusToPaymentIntentStatus(
77+
transactionStatus: string,
78+
): string {
79+
switch (transactionStatus) {
80+
case 'in_progress':
81+
return 'processing';
82+
case 'success':
83+
return 'succeeded';
84+
case 'voided':
85+
return 'canceled';
86+
case 'failure':
87+
return 'canceled';
88+
case 'timeout':
89+
return 'canceled';
90+
case 'needs_attention':
91+
return 'requires_action';
92+
case 'late_failure':
93+
return 'canceled';
94+
default:
95+
return 'requires_payment_method';
96+
}
97+
}
98+
99+
/**
100+
* Adapts a ChargeBee payment source to the generic TPaymentMethod format.
101+
*/
102+
adaptPaymentSource(source: ChargebeePaymentSource): TPaymentMethod {
103+
if (source.type === 'card' && source.card) {
104+
return {
105+
type: 'card',
106+
id: source.id ?? '',
107+
customer: source.customerId,
108+
card: this.buildCardDetails(source.card),
109+
};
110+
}
111+
112+
return {
113+
type: source.type ?? 'unknown',
114+
id: source.id ?? '',
115+
customer: source.customerId,
116+
};
117+
}
118+
119+
/**
120+
* Builds card details object from ChargeBee card data.
121+
*
122+
* @param card - ChargeBee card information
123+
* @returns Formatted card details
124+
*/
125+
private buildCardDetails(card: ChargebeeCard): {
126+
brand: string;
127+
last4: string;
128+
expMonth: number;
129+
expYear: number;
130+
funding: string;
131+
} {
132+
return {
133+
brand: this.getCardBrand(card),
134+
last4: card.last4 ?? '****',
135+
expMonth: card.expiryMonth ?? DEFAULT_EXPIRY_MONTH,
136+
expYear: card.expiryYear ?? DEFAULT_EXPIRY_YEAR,
137+
funding: card.funding ?? DEFAULT_FUNDING_TYPE,
138+
};
139+
}
140+
141+
/**
142+
* Gets card brand from first six digits.
143+
*
144+
* @param card - ChargeBee card information
145+
* @returns Card brand
146+
*/
147+
private getCardBrand(card: ChargebeeCard): string {
148+
if (card.firstSixDigits) {
149+
return this.detectCardBrand(card.firstSixDigits);
150+
}
151+
return DEFAULT_CARD_BRAND;
152+
}
153+
154+
/**
155+
* Detects card brand from first six digits.
156+
*/
157+
private detectCardBrand(firstSix: string): string {
158+
if (firstSix.startsWith('4')) return 'visa';
159+
if (firstSix.startsWith('5') || firstSix.startsWith('2'))
160+
return 'mastercard';
161+
if (firstSix.startsWith('3')) return 'amex';
162+
return 'unknown';
163+
}
164+
165+
/**
166+
* Creates a pending payment method object.
167+
*
168+
* @returns Payment method with pending status
169+
*/
170+
createPendingPaymentMethod(): TPaymentMethod {
171+
return {
172+
type: 'pending',
173+
description: 'Payment not yet processed',
174+
} as TPaymentMethod;
175+
}
176+
177+
/**
178+
* Creates an unknown payment method object.
179+
*
180+
* @param description - Description for the unknown payment method
181+
* @returns Payment method with unknown status
182+
*/
183+
createUnknownPaymentMethod(description: string): TPaymentMethod {
184+
return {
185+
type: 'unknown',
186+
description,
187+
} as TPaymentMethod;
188+
}
189+
}

0 commit comments

Comments
 (0)