Merge branch 'INDA-330-pii-update' into 'main'
[ProtonMail-WebClient.git] / packages / payments / core / payment-processors / savedPayment.ts
blob92dd15f0dcaca733d1b5405c1ee11390d55fc912
1 import { type Api } from '@proton/shared/lib/interfaces';
3 import { PAYMENT_METHOD_TYPES } from '../constants';
4 import { type PaymentVerificator, createPaymentTokenForExistingPayment } from '../createPaymentToken';
5 import type {
6     AmountAndCurrency,
7     ChargeablePaymentParameters,
8     ChargeablePaymentToken,
9     NonChargeablePaymentToken,
10     SavedPaymentMethod,
11     SavedPaymentMethodExternal,
12     SavedPaymentMethodInternal,
13     V5PaymentToken,
14 } from '../interface';
15 import { PaymentProcessor } from './paymentProcessor';
17 interface SavedPaymentState {
18     method: {
19         paymentMethodId: string;
20         type:
21             | PAYMENT_METHOD_TYPES.CARD
22             | PAYMENT_METHOD_TYPES.PAYPAL
23             | PAYMENT_METHOD_TYPES.CHARGEBEE_SEPA_DIRECT_DEBIT;
24     };
27 function convertType(
28     type:
29         | PAYMENT_METHOD_TYPES.CARD
30         | PAYMENT_METHOD_TYPES.PAYPAL
31         | PAYMENT_METHOD_TYPES.CHARGEBEE_CARD
32         | PAYMENT_METHOD_TYPES.CHARGEBEE_PAYPAL
33         | PAYMENT_METHOD_TYPES.CHARGEBEE_SEPA_DIRECT_DEBIT
34 ): PAYMENT_METHOD_TYPES.CARD | PAYMENT_METHOD_TYPES.PAYPAL | PAYMENT_METHOD_TYPES.CHARGEBEE_SEPA_DIRECT_DEBIT {
35     switch (type) {
36         case PAYMENT_METHOD_TYPES.CARD:
37         case PAYMENT_METHOD_TYPES.PAYPAL:
38             return type;
39         case PAYMENT_METHOD_TYPES.CHARGEBEE_CARD:
40             return PAYMENT_METHOD_TYPES.CARD;
41         case PAYMENT_METHOD_TYPES.CHARGEBEE_PAYPAL:
42             return PAYMENT_METHOD_TYPES.PAYPAL;
43         case PAYMENT_METHOD_TYPES.CHARGEBEE_SEPA_DIRECT_DEBIT:
44             return PAYMENT_METHOD_TYPES.CHARGEBEE_SEPA_DIRECT_DEBIT;
45     }
48 export class SavedPaymentProcessor extends PaymentProcessor<SavedPaymentState> {
49     public fetchedPaymentToken: ChargeablePaymentToken | NonChargeablePaymentToken | null = null;
51     constructor(
52         public verifyPayment: PaymentVerificator,
53         public api: Api,
54         amountAndCurrency: AmountAndCurrency,
55         savedMethod: SavedPaymentMethodInternal | SavedPaymentMethodExternal | SavedPaymentMethod,
56         public onTokenIsChargeable?: (data: ChargeablePaymentParameters) => Promise<unknown>
57     ) {
58         super(
59             {
60                 method: {
61                     paymentMethodId: savedMethod.ID,
62                     type: convertType(savedMethod.Type),
63                 },
64             },
65             amountAndCurrency
66         );
67     }
69     async fetchPaymentToken(): Promise<ChargeablePaymentToken | NonChargeablePaymentToken | null> {
70         if (this.amountAndCurrency.Amount === 0) {
71             return null;
72         }
74         this.fetchedPaymentToken = await createPaymentTokenForExistingPayment(
75             this.state.method.paymentMethodId,
76             this.state.method.type,
77             this.api,
78             this.amountAndCurrency
79         );
81         return this.fetchedPaymentToken;
82     }
84     async verifyPaymentToken(): Promise<ChargeablePaymentParameters> {
85         if (this.amountAndCurrency.Amount === 0) {
86             return this.tokenCreated();
87         }
89         if (this.fetchedPaymentToken === null) {
90             throw new Error('Payment token was not fetched. Please call fetchPaymentToken() first.');
91         }
93         if (this.fetchedPaymentToken.chargeable) {
94             return this.tokenCreated(this.fetchedPaymentToken);
95         }
97         const token: V5PaymentToken = await this.verifyPayment({
98             Token: this.fetchedPaymentToken.PaymentToken,
99             ApprovalURL: this.fetchedPaymentToken.approvalURL,
100             ReturnHost: this.fetchedPaymentToken.returnHost,
101         });
103         return this.tokenCreated(token);
104     }
106     updateSavedMethod(savedMethod: SavedPaymentMethodInternal | SavedPaymentMethodExternal | SavedPaymentMethod) {
107         this.state.method = {
108             paymentMethodId: savedMethod.ID,
109             type: convertType(savedMethod.Type),
110         };
111     }
113     reset() {
114         this.fetchedPaymentToken = null;
115     }
117     private tokenCreated(token?: V5PaymentToken): ChargeablePaymentParameters {
118         const result: ChargeablePaymentParameters = {
119             type: PAYMENT_METHOD_TYPES.CARD,
120             chargeable: true,
121             ...this.amountAndCurrency,
122             ...token,
123         };
125         void this.onTokenIsChargeable?.(result);
127         return result;
128     }