@cloudcommerce/app-paypal 2.48.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +1 -0
- package/assets/onload-expression.js +60 -0
- package/assets/onload-expression.min.js +1 -0
- package/events.js +1 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.js +3 -0
- package/lib/index.js.map +1 -0
- package/lib/paypal-create-transaction.d.ts +83 -0
- package/lib/paypal-create-transaction.js +262 -0
- package/lib/paypal-create-transaction.js.map +1 -0
- package/lib/paypal-events.d.ts +5 -0
- package/lib/paypal-events.js +117 -0
- package/lib/paypal-events.js.map +1 -0
- package/lib/paypal-list-payments.d.ts +11 -0
- package/lib/paypal-list-payments.js +216 -0
- package/lib/paypal-list-payments.js.map +1 -0
- package/lib/paypal.d.ts +92 -0
- package/lib/paypal.js +12 -0
- package/lib/paypal.js.map +1 -0
- package/lib/util/parse-to-paypal-payment.d.ts +33 -0
- package/lib/util/parse-to-paypal-payment.js +100 -0
- package/lib/util/parse-to-paypal-payment.js.map +1 -0
- package/lib/util/paypal-api.d.ts +11 -0
- package/lib/util/paypal-api.js +149 -0
- package/lib/util/paypal-api.js.map +1 -0
- package/package.json +43 -0
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import * as path from 'node:path';
|
|
2
|
+
import * as fs from 'node:fs';
|
|
3
|
+
import url from 'node:url';
|
|
4
|
+
import { getFirestore } from 'firebase-admin/firestore';
|
|
5
|
+
import { logger } from '@cloudcommerce/firebase/lib/config';
|
|
6
|
+
import parseToPaypalPayment from './util/parse-to-paypal-payment.js';
|
|
7
|
+
import { createPaypalProfile, createPaypalWebhook, createPaypalPayment } from './util/paypal-api.js';
|
|
8
|
+
|
|
9
|
+
const __dirname = url.fileURLToPath(new URL('.', import.meta.url));
|
|
10
|
+
|
|
11
|
+
export const paypalListPayments = async (modBody) => {
|
|
12
|
+
const { application, params } = modBody;
|
|
13
|
+
const appData = {
|
|
14
|
+
...application.data,
|
|
15
|
+
...application.hidden_data,
|
|
16
|
+
};
|
|
17
|
+
if (appData.paypal_client_id) {
|
|
18
|
+
process.env.PAYPAL_CLIENT_ID = appData.paypal_client_id;
|
|
19
|
+
}
|
|
20
|
+
if (appData.paypal_secret) {
|
|
21
|
+
process.env.PAYPAL_CLIENT_SECRET = appData.paypal_secret;
|
|
22
|
+
}
|
|
23
|
+
process.env.PAYPAL_ENV = appData.paypal_sandbox
|
|
24
|
+
? 'sandbox'
|
|
25
|
+
: process.env.PAYPAL_ENV || 'live';
|
|
26
|
+
const { PAYPAL_CLIENT_ID, PAYPAL_CLIENT_SECRET, PAYPAL_ENV } = process.env;
|
|
27
|
+
if (!PAYPAL_CLIENT_ID || !PAYPAL_CLIENT_SECRET) {
|
|
28
|
+
return {
|
|
29
|
+
error: 'NO_PAYPAL_KEYS',
|
|
30
|
+
message: 'Client ID ou Secret não configurado (lojista deve configurar o aplicativo)',
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
const { lang = 'pt_br', amount = { total: 0 } } = params;
|
|
34
|
+
const response = {
|
|
35
|
+
payment_gateways: [],
|
|
36
|
+
};
|
|
37
|
+
const { discount } = appData;
|
|
38
|
+
if (discount && discount.value > 0) {
|
|
39
|
+
if (discount.apply_at !== 'freight') {
|
|
40
|
+
const { value } = discount;
|
|
41
|
+
response.discount_option = {
|
|
42
|
+
label: appData.discount_option_label,
|
|
43
|
+
value,
|
|
44
|
+
};
|
|
45
|
+
['type', 'min_amount'].forEach((prop) => {
|
|
46
|
+
if (discount[prop]) {
|
|
47
|
+
response.discount_option[prop] = discount[prop];
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
if (amount.total) {
|
|
52
|
+
if (amount.total < discount.min_amount) {
|
|
53
|
+
discount.value = 0;
|
|
54
|
+
} else {
|
|
55
|
+
delete discount.min_amount;
|
|
56
|
+
const maxDiscount = amount[discount.apply_at || 'subtotal'];
|
|
57
|
+
let discountValue;
|
|
58
|
+
if (discount.type === 'percentage') {
|
|
59
|
+
discountValue = maxDiscount * (discount.value / 100);
|
|
60
|
+
} else {
|
|
61
|
+
discountValue = discount.value;
|
|
62
|
+
if (discountValue && discountValue > maxDiscount) {
|
|
63
|
+
discountValue = maxDiscount;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
if (discountValue) {
|
|
67
|
+
amount.discount = (amount.discount || 0) + discountValue;
|
|
68
|
+
amount.total -= discountValue;
|
|
69
|
+
if (amount.total < 0) {
|
|
70
|
+
amount.total = 0;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
let paypalPayment;
|
|
77
|
+
try {
|
|
78
|
+
if (params.customer && params.items && !params.is_checkout_confirmation
|
|
79
|
+
&& (params.payment_method || !params.can_fetch_when_selected)) {
|
|
80
|
+
try {
|
|
81
|
+
const docRef = getFirestore().doc(`paypalProfiles/${PAYPAL_CLIENT_ID}`);
|
|
82
|
+
if (!(await docRef.get()).exists) {
|
|
83
|
+
await Promise.all([
|
|
84
|
+
createPaypalWebhook(),
|
|
85
|
+
createPaypalProfile(),
|
|
86
|
+
]);
|
|
87
|
+
}
|
|
88
|
+
paypalPayment = await createPaypalPayment(parseToPaypalPayment(params));
|
|
89
|
+
} catch (_err) {
|
|
90
|
+
const err = _err;
|
|
91
|
+
if (err.response?.status === 401) {
|
|
92
|
+
throw err;
|
|
93
|
+
}
|
|
94
|
+
logger.error(err);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
} catch (_err) {
|
|
98
|
+
const err = _err;
|
|
99
|
+
return {
|
|
100
|
+
status: err.response?.status || 400,
|
|
101
|
+
error: 'PAYPAL_SETUP_ERROR',
|
|
102
|
+
message: (err.response?.data?.error_description) || err.message,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
const addPaymentGateway = () => {
|
|
106
|
+
const label = lang === 'pt_br' ? 'Cartão de crédito' : 'Credit card';
|
|
107
|
+
const iconSrc = 'https://paypal.ecomplus.biz/assets/paypal-plus/icon.png';
|
|
108
|
+
const paymentGateway = {
|
|
109
|
+
label,
|
|
110
|
+
payment_method: {
|
|
111
|
+
code: 'credit_card',
|
|
112
|
+
name: label,
|
|
113
|
+
},
|
|
114
|
+
intermediator: {
|
|
115
|
+
name: 'PayPal',
|
|
116
|
+
link: 'https://www.paypal.com/',
|
|
117
|
+
code: 'paypal',
|
|
118
|
+
},
|
|
119
|
+
icon: iconSrc,
|
|
120
|
+
js_client: {
|
|
121
|
+
onload_expression: fs.readFileSync(path.join(__dirname, '../assets/onload-expression.min.js'), 'utf8'),
|
|
122
|
+
container_html: '<div id="pppLoading" class="p-2">'
|
|
123
|
+
+ '<div class="spinner-border" role="status">'
|
|
124
|
+
+ '<span class="sr-only">Loading...</span></div></div>'
|
|
125
|
+
+ '<div id="ppplus"></div>'
|
|
126
|
+
+ '<button class="btn btn-success btn-lg btn-block" type="submit" id="pppContinue" '
|
|
127
|
+
+ 'onclick="_pppApp.doContinue(); return false;"> '
|
|
128
|
+
+ '<i class="fas fa-lock mr-1"></i> '
|
|
129
|
+
+ `${(lang === 'pt_br' ? 'Finalizar compra' : 'Checkout')} </button>`,
|
|
130
|
+
transaction_promise: '_pppContinue',
|
|
131
|
+
script_uri: 'https://www.paypalobjects.com/webstatic/ppplusdcc/ppplusdcc.min.js',
|
|
132
|
+
},
|
|
133
|
+
};
|
|
134
|
+
if (params.payment_method?.code !== paymentGateway.payment_method.code) {
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
response.payment_gateways.unshift(paymentGateway);
|
|
138
|
+
['label', 'text', 'icon'].forEach((prop) => {
|
|
139
|
+
if (appData[prop]) {
|
|
140
|
+
paymentGateway[prop] = appData[prop];
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
if (appData.ppp_label) {
|
|
144
|
+
paymentGateway.label = appData.ppp_label;
|
|
145
|
+
}
|
|
146
|
+
if (discount && discount.value > 0) {
|
|
147
|
+
paymentGateway.discount = discount;
|
|
148
|
+
if (response.discount_option && !response.discount_option.label) {
|
|
149
|
+
response.discount_option.label = paymentGateway.label;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
const installmentsOption = appData.installments_option;
|
|
153
|
+
if (installmentsOption && installmentsOption.max_number) {
|
|
154
|
+
response.installments_option = installmentsOption;
|
|
155
|
+
if (amount.total) {
|
|
156
|
+
paymentGateway.installment_options = [];
|
|
157
|
+
const minInstallment = installmentsOption.min_installment || 5;
|
|
158
|
+
for (let number = 2; number <= installmentsOption.max_number; number++) {
|
|
159
|
+
const value = amount.total / number;
|
|
160
|
+
if (value >= minInstallment) {
|
|
161
|
+
paymentGateway.installment_options.push({
|
|
162
|
+
number,
|
|
163
|
+
value,
|
|
164
|
+
// PayPal only supports interest-free installments
|
|
165
|
+
tax: false,
|
|
166
|
+
});
|
|
167
|
+
} else {
|
|
168
|
+
break;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
const jsClient = paymentGateway.js_client;
|
|
174
|
+
const locales = lang.split('_');
|
|
175
|
+
const paypalLocale = `${locales[0]}_${(locales[1] || locales[0]).toUpperCase()}`;
|
|
176
|
+
if (!paypalPayment && params.can_fetch_when_selected) {
|
|
177
|
+
// Refetch for JS Client with onload expression (and Payment ID) when payment selected
|
|
178
|
+
paymentGateway.fetch_when_selected = true;
|
|
179
|
+
delete jsClient.onload_expression;
|
|
180
|
+
} else {
|
|
181
|
+
let onloadExpression = `window._paypalEnv="${PAYPAL_ENV}";`
|
|
182
|
+
+ `window._paypalLocale="${paypalLocale}";`;
|
|
183
|
+
if (paypalPayment) {
|
|
184
|
+
// Payment request ID and approval URL for PayPal Plus
|
|
185
|
+
// https://developer.paypal.com/docs/integration/paypal-plus/mexico-brazil/create-a-payment-request/
|
|
186
|
+
onloadExpression += `window._paypalPaymentId="${paypalPayment.id}";`
|
|
187
|
+
+ `window._paypalInvoiceNumber="${paypalPayment.transactions[0].invoice_number}";`;
|
|
188
|
+
if (Array.isArray(paypalPayment.links)) {
|
|
189
|
+
const linkObj = paypalPayment.links.find(({ rel }) => rel === 'approval_url');
|
|
190
|
+
if (linkObj) {
|
|
191
|
+
onloadExpression += `window._paypalApprovalUrl="${linkObj.href}";`;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
if (appData.disable_remembered_cards) {
|
|
196
|
+
onloadExpression += 'window._paypalDisallowRemembered=true;';
|
|
197
|
+
}
|
|
198
|
+
const paypalOrder = {};
|
|
199
|
+
if (amount.total) {
|
|
200
|
+
paypalOrder.purchase_units = [{
|
|
201
|
+
amount: {
|
|
202
|
+
value: amount.total.toFixed(2),
|
|
203
|
+
},
|
|
204
|
+
}];
|
|
205
|
+
}
|
|
206
|
+
jsClient.onload_expression = onloadExpression
|
|
207
|
+
+ `window._paypalOrderObj=${JSON.stringify(paypalOrder)};`
|
|
208
|
+
+ jsClient.onload_expression;
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
addPaymentGateway();
|
|
212
|
+
return response;
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
export default paypalListPayments;
|
|
216
|
+
// # sourceMappingURL=paypal-list-payments.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paypal-list-payments.js","sourceRoot":"","sources":["../src/paypal-list-payments.ts"],"names":[],"mappings":"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"}
|
package/lib/paypal.d.ts
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import '@cloudcommerce/firebase/lib/init';
|
|
2
|
+
import type { AppModuleBody } from '@cloudcommerce/types';
|
|
3
|
+
export declare const listPayments: (modBody: AppModuleBody<"list_payments">) => Promise<import("@cloudcommerce/types").ListPaymentsResponse | {
|
|
4
|
+
error: string;
|
|
5
|
+
message: string;
|
|
6
|
+
status?: undefined;
|
|
7
|
+
} | {
|
|
8
|
+
status: number;
|
|
9
|
+
error: string;
|
|
10
|
+
message: any;
|
|
11
|
+
}>;
|
|
12
|
+
export declare const createTransaction: (modBody: AppModuleBody<"create_transaction">) => Promise<{
|
|
13
|
+
error: string;
|
|
14
|
+
message: string;
|
|
15
|
+
status?: undefined;
|
|
16
|
+
transaction?: undefined;
|
|
17
|
+
} | {
|
|
18
|
+
status: number;
|
|
19
|
+
error: string;
|
|
20
|
+
message: string;
|
|
21
|
+
transaction?: undefined;
|
|
22
|
+
} | {
|
|
23
|
+
transaction: {
|
|
24
|
+
payment_link?: string;
|
|
25
|
+
payment_instructions?: string;
|
|
26
|
+
intermediator?: {
|
|
27
|
+
transaction_id?: string;
|
|
28
|
+
transaction_code?: string;
|
|
29
|
+
transaction_reference?: string;
|
|
30
|
+
payment_method?: {
|
|
31
|
+
code: string;
|
|
32
|
+
name?: string;
|
|
33
|
+
};
|
|
34
|
+
buyer_id?: string;
|
|
35
|
+
};
|
|
36
|
+
credit_card?: {
|
|
37
|
+
holder_name?: string;
|
|
38
|
+
avs_result_code?: string | null;
|
|
39
|
+
cvv_result_code?: string | null;
|
|
40
|
+
bin?: number;
|
|
41
|
+
company?: string;
|
|
42
|
+
last_digits?: string;
|
|
43
|
+
token?: string;
|
|
44
|
+
error_code?: "incorrect_number" | "invalid_number" | "invalid_expiry_date" | "invalid_cvc" | "expired_card" | "incorrect_cvc" | "incorrect_zip" | "incorrect_address" | "card_declined" | "processing_error" | "call_issuer" | "pick_up_card";
|
|
45
|
+
};
|
|
46
|
+
banking_billet?: {
|
|
47
|
+
code?: string;
|
|
48
|
+
valid_thru?: string;
|
|
49
|
+
text_lines?: string[];
|
|
50
|
+
link?: string;
|
|
51
|
+
};
|
|
52
|
+
loyalty_points?: {
|
|
53
|
+
name?: string;
|
|
54
|
+
program_id: string;
|
|
55
|
+
points_value: number;
|
|
56
|
+
ratio?: number;
|
|
57
|
+
};
|
|
58
|
+
account_deposit?: {
|
|
59
|
+
valid_thru?: string;
|
|
60
|
+
text_lines?: string[];
|
|
61
|
+
};
|
|
62
|
+
currency_id?: string;
|
|
63
|
+
currency_symbol?: string;
|
|
64
|
+
discount?: number;
|
|
65
|
+
amount: number;
|
|
66
|
+
installments?: {
|
|
67
|
+
number: number;
|
|
68
|
+
value?: number;
|
|
69
|
+
tax?: boolean;
|
|
70
|
+
total?: number;
|
|
71
|
+
};
|
|
72
|
+
creditor_fees?: {
|
|
73
|
+
installment?: number;
|
|
74
|
+
operational?: number;
|
|
75
|
+
intermediation?: number;
|
|
76
|
+
other?: number;
|
|
77
|
+
};
|
|
78
|
+
status?: {
|
|
79
|
+
updated_at?: string;
|
|
80
|
+
current: "pending" | "under_analysis" | "authorized" | "unauthorized" | "paid" | "in_dispute" | "refunded" | "voided" | "unknown";
|
|
81
|
+
};
|
|
82
|
+
flags?: string[];
|
|
83
|
+
custom_fields?: {
|
|
84
|
+
field: string;
|
|
85
|
+
value: string;
|
|
86
|
+
}[];
|
|
87
|
+
notes?: string;
|
|
88
|
+
};
|
|
89
|
+
error?: undefined;
|
|
90
|
+
message?: undefined;
|
|
91
|
+
status?: undefined;
|
|
92
|
+
}>;
|
package/lib/paypal.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import '@cloudcommerce/firebase/lib/init';
|
|
2
|
+
import handleListPayments from './paypal-list-payments.js';
|
|
3
|
+
import handleCreateTransaction from './paypal-create-transaction.js';
|
|
4
|
+
|
|
5
|
+
export const listPayments = async (modBody) => {
|
|
6
|
+
return handleListPayments(modBody);
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export const createTransaction = async (modBody) => {
|
|
10
|
+
return handleCreateTransaction(modBody);
|
|
11
|
+
};
|
|
12
|
+
// # sourceMappingURL=paypal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paypal.js","sourceRoot":"","sources":["../src/paypal.ts"],"names":[],"mappings":"AAAA,OAAO,kCAAkC,CAAC;AAE1C,OAAO,kBAAkB,MAAM,wBAAwB,CAAC;AACxD,OAAO,uBAAuB,MAAM,6BAA6B,CAAC;AAElE,MAAM,CAAC,MAAM,YAAY,GAAG,KAAK,EAAE,OAAuC,EAAE,EAAE;IAC5E,OAAO,kBAAkB,CAAC,OAAO,CAAC,CAAC;AACrC,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,iBAAiB,GAAG,KAAK,EAAE,OAA4C,EAAE,EAAE;IACtF,OAAO,uBAAuB,CAAC,OAAO,CAAC,CAAC;AAC1C,CAAC,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { ListPaymentsParams } from '@cloudcommerce/types';
|
|
2
|
+
export declare const parseToPaypalPayment: (body: ListPaymentsParams) => {
|
|
3
|
+
intent: string;
|
|
4
|
+
payer: {
|
|
5
|
+
payment_method: string;
|
|
6
|
+
};
|
|
7
|
+
application_context: {
|
|
8
|
+
brand_name: string | undefined;
|
|
9
|
+
locale: string;
|
|
10
|
+
shipping_preference: string;
|
|
11
|
+
};
|
|
12
|
+
transactions: {
|
|
13
|
+
invoice_number: string;
|
|
14
|
+
amount: {
|
|
15
|
+
currency: string | undefined;
|
|
16
|
+
total: string;
|
|
17
|
+
details: {
|
|
18
|
+
shipping: string;
|
|
19
|
+
subtotal: string;
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
description: string;
|
|
23
|
+
payment_options: {
|
|
24
|
+
allowed_payment_method: string;
|
|
25
|
+
};
|
|
26
|
+
item_list: Record<string, any>;
|
|
27
|
+
}[];
|
|
28
|
+
redirect_urls: {
|
|
29
|
+
return_url: string;
|
|
30
|
+
cancel_url: string;
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
export default parseToPaypalPayment;
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { price as getPrice } from '@ecomplus/utils';
|
|
2
|
+
|
|
3
|
+
export const parseToPaypalPayment = (body) => {
|
|
4
|
+
const {
|
|
5
|
+
lang = 'pt_br', customer, amount = { total: 0 }, items, domain,
|
|
6
|
+
} = body;
|
|
7
|
+
let currency = body.currency_id;
|
|
8
|
+
if (!currency && items) {
|
|
9
|
+
currency = (items[0]?.currency_id) || 'BRL';
|
|
10
|
+
}
|
|
11
|
+
const round = (n) => (n ? Math.round(n * 100) / 100 : 0);
|
|
12
|
+
const total = round(amount.total) || 1;
|
|
13
|
+
const freight = round(amount.freight);
|
|
14
|
+
const subtotal = total - freight;
|
|
15
|
+
// https://developer.paypal.com/docs/integration/paypal-plus/mexico-brazil/create-a-payment-request/
|
|
16
|
+
const paypalPayment = {
|
|
17
|
+
intent: 'sale',
|
|
18
|
+
payer: {
|
|
19
|
+
payment_method: 'paypal',
|
|
20
|
+
},
|
|
21
|
+
application_context: {
|
|
22
|
+
brand_name: domain,
|
|
23
|
+
locale: lang ? lang.slice(-2).toUpperCase() : 'BR',
|
|
24
|
+
shipping_preference: 'SET_PROVIDED_ADDRESS',
|
|
25
|
+
},
|
|
26
|
+
transactions: [{
|
|
27
|
+
invoice_number: `INVOICE${Date.now().toString()}`,
|
|
28
|
+
amount: {
|
|
29
|
+
currency,
|
|
30
|
+
total: total.toFixed(2),
|
|
31
|
+
details: {
|
|
32
|
+
shipping: freight.toFixed(2),
|
|
33
|
+
subtotal: subtotal.toFixed(2),
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
description: lang === 'pt_br'
|
|
37
|
+
? `Pagamento na loja ${domain}`
|
|
38
|
+
: `Payment in store ${domain}`,
|
|
39
|
+
payment_options: {
|
|
40
|
+
allowed_payment_method: 'IMMEDIATE_PAY',
|
|
41
|
+
},
|
|
42
|
+
item_list: {
|
|
43
|
+
items: [],
|
|
44
|
+
},
|
|
45
|
+
}],
|
|
46
|
+
redirect_urls: {
|
|
47
|
+
return_url: `https://${domain}/app/#/confirmation`,
|
|
48
|
+
cancel_url: `https://${domain}/app/#/cancel`,
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
const paypalItemsList = paypalPayment.transactions[0].item_list;
|
|
52
|
+
const address = customer?.addresses?.find((addr) => addr.default);
|
|
53
|
+
if (address) {
|
|
54
|
+
paypalItemsList.shipping_address = {
|
|
55
|
+
recipient_name: address.name,
|
|
56
|
+
line1: address.line_address
|
|
57
|
+
|| (address.street ? address.street + ' ' + (address.number || 'S/N') : ''),
|
|
58
|
+
line2: address.complement || '',
|
|
59
|
+
city: address.city,
|
|
60
|
+
country_code: address.country_code || 'BR',
|
|
61
|
+
postal_code: address.zip,
|
|
62
|
+
state: address.province_code || address.province || '',
|
|
63
|
+
};
|
|
64
|
+
const phone = customer?.phones?.[0];
|
|
65
|
+
if (phone) {
|
|
66
|
+
paypalItemsList.shipping_address.phone = phone.number;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
let itemsAmount = 0;
|
|
70
|
+
items?.forEach((item) => {
|
|
71
|
+
const price = round(getPrice(item));
|
|
72
|
+
itemsAmount += price * item.quantity;
|
|
73
|
+
paypalItemsList.items.push({
|
|
74
|
+
name: item.name,
|
|
75
|
+
quantity: item.quantity,
|
|
76
|
+
price: price.toFixed(2),
|
|
77
|
+
sku: item.sku,
|
|
78
|
+
currency: item.currency_id || currency,
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
const diffSubtotal = round(subtotal) - round(itemsAmount);
|
|
82
|
+
if (diffSubtotal) {
|
|
83
|
+
// Apply discount or subtotal hardfix
|
|
84
|
+
// https://github.com/paypal/PayPal-PHP-SDK/issues/908
|
|
85
|
+
const name = amount.discount
|
|
86
|
+
? (lang === 'pt_br' && 'Desconto') || 'Discount'
|
|
87
|
+
: 'fix';
|
|
88
|
+
paypalItemsList.items.push({
|
|
89
|
+
name,
|
|
90
|
+
quantity: 1,
|
|
91
|
+
price: diffSubtotal.toFixed(2),
|
|
92
|
+
sku: name.toUpperCase(),
|
|
93
|
+
currency,
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
return paypalPayment;
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
export default parseToPaypalPayment;
|
|
100
|
+
// # sourceMappingURL=parse-to-paypal-payment.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse-to-paypal-payment.js","sourceRoot":"","sources":["../../src/util/parse-to-paypal-payment.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { AxiosInstance } from 'axios';
|
|
2
|
+
export declare const getPaypalAxios: () => Promise<AxiosInstance>;
|
|
3
|
+
export declare const createPaypalPayment: (paypalPayment: Record<string, any>) => Promise<Record<string, any>>;
|
|
4
|
+
export declare const readPaypalPayment: (paymentId: string) => Promise<Record<string, any>>;
|
|
5
|
+
export declare const editPaypalPayment: (paymentId: string, paypalPaymentEdit: Array<Record<string, any>>) => Promise<Record<string, any>>;
|
|
6
|
+
export declare const executePaypalPayment: (paymentId: string, paypalPaymentExecute: Record<string, any> & {
|
|
7
|
+
payer_id: string;
|
|
8
|
+
}) => Promise<Record<string, any>>;
|
|
9
|
+
export declare const createPaypalProfile: () => Promise<void>;
|
|
10
|
+
export declare const createPaypalWebhook: () => Promise<void>;
|
|
11
|
+
export declare const readPaypalWebhookEvent: (eventId: string) => Promise<Record<string, any>>;
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { getFirestore, Timestamp } from 'firebase-admin/firestore';
|
|
2
|
+
import axios from 'axios';
|
|
3
|
+
import config, { logger } from '@cloudcommerce/firebase/lib/config';
|
|
4
|
+
|
|
5
|
+
let _paypalAxios;
|
|
6
|
+
let _tokenExpiresAt;
|
|
7
|
+
|
|
8
|
+
export const getPaypalAxios = async () => {
|
|
9
|
+
if (_tokenExpiresAt && Date.now() > _tokenExpiresAt - 9000) {
|
|
10
|
+
_paypalAxios = undefined;
|
|
11
|
+
_tokenExpiresAt = undefined;
|
|
12
|
+
}
|
|
13
|
+
if (_paypalAxios) return _paypalAxios;
|
|
14
|
+
const { PAYPAL_CLIENT_ID, PAYPAL_CLIENT_SECRET, PAYPAL_ENV } = process.env;
|
|
15
|
+
const baseURL = PAYPAL_ENV === 'sandbox'
|
|
16
|
+
? 'https://api-m.sandbox.paypal.com/'
|
|
17
|
+
: 'https://api-m.paypal.com/';
|
|
18
|
+
let token;
|
|
19
|
+
const docRef = getFirestore().doc(`paypalTokens/${PAYPAL_CLIENT_ID}`);
|
|
20
|
+
const docSnap = await docRef.get();
|
|
21
|
+
if (docSnap.exists) {
|
|
22
|
+
const { data, expiresAt } = (docSnap.data() || {});
|
|
23
|
+
_tokenExpiresAt = expiresAt && expiresAt.toMillis();
|
|
24
|
+
if (_tokenExpiresAt && _tokenExpiresAt > Date.now() + 9000) {
|
|
25
|
+
token = data?.access_token;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
if (!token) {
|
|
29
|
+
const { data } = await axios.post('/v1/oauth2/token', 'grant_type=client_credentials', {
|
|
30
|
+
baseURL,
|
|
31
|
+
headers: {
|
|
32
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
33
|
+
},
|
|
34
|
+
auth: {
|
|
35
|
+
username: PAYPAL_CLIENT_ID,
|
|
36
|
+
password: PAYPAL_CLIENT_SECRET,
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
if (data?.access_token) {
|
|
40
|
+
_tokenExpiresAt = data.expires_in
|
|
41
|
+
? Date.now() + (data.expires_in * 1000)
|
|
42
|
+
: Date.now() + (9 * 60 * 60 * 1000);
|
|
43
|
+
docRef.set({
|
|
44
|
+
data,
|
|
45
|
+
expiresAt: Timestamp.fromMillis(_tokenExpiresAt),
|
|
46
|
+
}).catch(logger.warn);
|
|
47
|
+
token = data.access_token;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
if (!token) {
|
|
51
|
+
throw new Error('Missing PayPal access token');
|
|
52
|
+
}
|
|
53
|
+
_paypalAxios = axios.create({
|
|
54
|
+
baseURL,
|
|
55
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
56
|
+
});
|
|
57
|
+
return _paypalAxios;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export const createPaypalPayment = async (paypalPayment) => {
|
|
61
|
+
const paypalAxios = await getPaypalAxios();
|
|
62
|
+
const { data } = await paypalAxios.post('/v1/payments/payment', paypalPayment);
|
|
63
|
+
return data;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export const readPaypalPayment = async (paymentId) => {
|
|
67
|
+
const paypalAxios = await getPaypalAxios();
|
|
68
|
+
const { data } = await paypalAxios.get(`/v1/payments/payment/${paymentId}`);
|
|
69
|
+
return data;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
export const editPaypalPayment = async (paymentId, paypalPaymentEdit) => {
|
|
73
|
+
const paypalAxios = await getPaypalAxios();
|
|
74
|
+
const { data } = await paypalAxios
|
|
75
|
+
.patch(`/v1/payments/payment/${paymentId}`, paypalPaymentEdit);
|
|
76
|
+
return data;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
export const executePaypalPayment = async (paymentId, paypalPaymentExecute) => {
|
|
80
|
+
const paypalAxios = await getPaypalAxios();
|
|
81
|
+
const { data } = await paypalAxios
|
|
82
|
+
.post(`/v1/payments/payment/${paymentId}/execute/`, paypalPaymentExecute);
|
|
83
|
+
return data;
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
export const createPaypalProfile = async () => {
|
|
87
|
+
const { settingsContent } = config.get();
|
|
88
|
+
(await getPaypalAxios()).post('/v1/payment-experience/web-profiles/', {
|
|
89
|
+
name: `EComPlus_${Date.now()}`,
|
|
90
|
+
presentation: {
|
|
91
|
+
brand_name: settingsContent.name || 'Loja Virtual',
|
|
92
|
+
logo_image: settingsContent.logo
|
|
93
|
+
|| 'https://www.paypalobjects.com/webstatic/mktg/logo/AM_SbyPP_mc_vs_dc_ae.jpg',
|
|
94
|
+
locale_code: settingsContent.countryCode || 'BR',
|
|
95
|
+
},
|
|
96
|
+
input_fields: {
|
|
97
|
+
allow_note: true,
|
|
98
|
+
no_shipping: 1,
|
|
99
|
+
address_override: 1,
|
|
100
|
+
},
|
|
101
|
+
flow_config: {
|
|
102
|
+
landing_page_type: 'billing',
|
|
103
|
+
bank_txn_pending_url: settingsContent.domain
|
|
104
|
+
? `https://${settingsContent.domain}/app/#/confirmation/`
|
|
105
|
+
: 'http://www.yeowza.com',
|
|
106
|
+
},
|
|
107
|
+
});
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
export const createPaypalWebhook = async () => {
|
|
111
|
+
const locationId = config.get().httpsFunctionOptions.region;
|
|
112
|
+
const appBaseUri = `https://${locationId}-${process.env.GCLOUD_PROJECT}.cloudfunctions.net`;
|
|
113
|
+
(await getPaypalAxios()).post('/v1/notifications/webhooks', {
|
|
114
|
+
url: `${appBaseUri}/paypal-webhook`,
|
|
115
|
+
event_types: [
|
|
116
|
+
// v2
|
|
117
|
+
'PAYMENT.AUTHORIZATION.CREATED',
|
|
118
|
+
'PAYMENT.AUTHORIZATION.VOIDED',
|
|
119
|
+
'PAYMENT.CAPTURE.COMPLETED',
|
|
120
|
+
'PAYMENT.CAPTURE.DENIED',
|
|
121
|
+
'PAYMENT.CAPTURE.PENDING',
|
|
122
|
+
'PAYMENT.CAPTURE.REFUNDED',
|
|
123
|
+
'PAYMENT.CAPTURE.REVERSED',
|
|
124
|
+
// v1
|
|
125
|
+
'PAYMENT.SALE.PENDING',
|
|
126
|
+
'PAYMENT.SALE.DENIED',
|
|
127
|
+
'PAYMENT.SALE.COMPLETED',
|
|
128
|
+
'PAYMENT.SALE.REFUNDED',
|
|
129
|
+
'PAYMENT.SALE.REVERSED',
|
|
130
|
+
'PAYMENT.PAYOUTSBATCH.PROCESSING',
|
|
131
|
+
'PAYMENT.PAYOUTSBATCH.SUCCESS',
|
|
132
|
+
'PAYMENT.PAYOUTSBATCH.DENIED',
|
|
133
|
+
'RISK.DISPUTE.CREATED',
|
|
134
|
+
].map((name) => ({ name })),
|
|
135
|
+
}).catch((_err) => {
|
|
136
|
+
const err = _err;
|
|
137
|
+
if (err.response?.data?.name === 'WEBHOOK_URL_ALREADY_EXISTS') {
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
throw err;
|
|
141
|
+
});
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
export const readPaypalWebhookEvent = async (eventId) => {
|
|
145
|
+
const paypalAxios = await getPaypalAxios();
|
|
146
|
+
const { data } = await paypalAxios.get(`/v1/notifications/webhooks-events/${eventId}`);
|
|
147
|
+
return data;
|
|
148
|
+
};
|
|
149
|
+
// # sourceMappingURL=paypal-api.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paypal-api.js","sourceRoot":"","sources":["../../src/util/paypal-api.ts"],"names":[],"mappings":"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"}
|