@cloudcommerce/app-pagarme-v5 0.32.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/.turbo/turbo-build.log +4 -0
- package/CHANGELOG.md +1 -0
- package/LICENSE.md +230 -0
- package/README.md +1 -0
- package/assets/onload-expression.js +38 -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 +2 -0
- package/lib/index.js.map +1 -0
- package/lib/pagarme-v5-events.d.ts +6 -0
- package/lib/pagarme-v5-events.js +21 -0
- package/lib/pagarme-v5-events.js.map +1 -0
- package/lib/pagarme-v5.d.ts +4 -0
- package/lib/pagarme-v5.js +12 -0
- package/lib/pagarme-v5.js.map +1 -0
- package/lib-mjs/create-pagarme5-transaction.mjs +208 -0
- package/lib-mjs/events-to-pagarme5.mjs +209 -0
- package/lib-mjs/functions-lib/api-utils.mjs +220 -0
- package/lib-mjs/functions-lib/firestore-utils.mjs +24 -0
- package/lib-mjs/functions-lib/pagarme/create-axios.mjs +12 -0
- package/lib-mjs/functions-lib/pagarme/handle-plans.mjs +69 -0
- package/lib-mjs/functions-lib/pagarme/parses-utils.mjs +61 -0
- package/lib-mjs/functions-lib/pagarme/payment-subscription.mjs +244 -0
- package/lib-mjs/functions-lib/payments/add-installments.mjs +45 -0
- package/lib-mjs/list-pagarme5-payments.mjs +218 -0
- package/lib-mjs/pagarme5-webhooks.mjs +343 -0
- package/package.json +38 -0
- package/scripts/build.sh +4 -0
- package/scripts/tests.sh +9 -0
- package/src/index.ts +1 -0
- package/src/pagarme-v5-events.ts +27 -0
- package/src/pagarme-v5.ts +12 -0
- package/tests/1-list-payments.test.mjs +37 -0
- package/tests/2-create-transaction.test.mjs +56 -0
- package/tsconfig.json +6 -0
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import api from '@cloudcommerce/api';
|
|
2
|
+
import logger from 'firebase-functions/logger';
|
|
3
|
+
// import config from '@cloudcommerce/firebase/lib/config';
|
|
4
|
+
import { getFirestore } from 'firebase-admin/firestore';
|
|
5
|
+
import ecomUtils from '@ecomplus/utils';
|
|
6
|
+
import axios from './functions-lib/pagarme/create-axios.mjs';
|
|
7
|
+
import { getOrderWithQueryString } from './functions-lib/api-utils.mjs';
|
|
8
|
+
import { getDocFirestore } from './functions-lib/firestore-utils.mjs';
|
|
9
|
+
|
|
10
|
+
const colletionFirebase = getFirestore().collection('pagarmeV5Subscriptions');
|
|
11
|
+
|
|
12
|
+
const eventOrderCancelled = async (
|
|
13
|
+
apiDoc,
|
|
14
|
+
pagarmeAxios,
|
|
15
|
+
) => {
|
|
16
|
+
const order = apiDoc;
|
|
17
|
+
if (order?.transactions[0]?.type === 'recurrence') {
|
|
18
|
+
const { data: { data: subcriptions } } = await pagarmeAxios.get(`/subscriptions?code=${order._id}`);
|
|
19
|
+
if (subcriptions && subcriptions[0].status !== 'canceled') {
|
|
20
|
+
try {
|
|
21
|
+
logger.log(`> (App PagarMe V5): Try cancel subscription: #${order._id}`);
|
|
22
|
+
await pagarmeAxios.delete(`/subscriptions/${subcriptions[0].id}`);
|
|
23
|
+
logger.log('> (App PagarMe V5): Successfully canceled');
|
|
24
|
+
await colletionFirebase.doc(order._id)
|
|
25
|
+
.set({
|
|
26
|
+
status: 'cancelled',
|
|
27
|
+
updatedAt: new Date().toISOString(),
|
|
28
|
+
}, { merge: true })
|
|
29
|
+
.catch(logger.error);
|
|
30
|
+
|
|
31
|
+
logger.log('>> SUCESSS');
|
|
32
|
+
return null;
|
|
33
|
+
} catch (err) {
|
|
34
|
+
logger.error('> (App PagarMe V5): Error when canceling in Pagar.Me, return the status');
|
|
35
|
+
await api.patch(order._id, { status: 'open' })
|
|
36
|
+
.catch(logger.error);
|
|
37
|
+
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
} else {
|
|
41
|
+
logger.log('> (App PagarMe V5): Subscription already canceled or does not exist');
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
// edit items order order Original
|
|
46
|
+
return null;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const eventProducts = async (
|
|
50
|
+
apiDoc,
|
|
51
|
+
pagarmeAxios,
|
|
52
|
+
) => {
|
|
53
|
+
// console.log('> Edit product ', resourceId, 's: ', storeId);
|
|
54
|
+
const product = apiDoc;
|
|
55
|
+
|
|
56
|
+
let query = 'status!=cancelled&transactions.type=recurrence';
|
|
57
|
+
query += '&transactions.app.intermediator.code=pagarme';
|
|
58
|
+
query += `&items.product_id=${product._id}`;
|
|
59
|
+
|
|
60
|
+
const result = await getOrderWithQueryString(query);
|
|
61
|
+
|
|
62
|
+
if (result && result.length) {
|
|
63
|
+
let i = 0;
|
|
64
|
+
while (i < result.length) {
|
|
65
|
+
const updateItemPagarme = [];
|
|
66
|
+
// eslint-disable-next-line no-await-in-loop
|
|
67
|
+
const order = (await api.get(`orders/${result[i]._id}`)).data;
|
|
68
|
+
// eslint-disable-next-line no-await-in-loop
|
|
69
|
+
const docSubscription = await getDocFirestore(colletionFirebase, result[i]._id);
|
|
70
|
+
logger.log('> (App PagarMe v5): Order ', JSON.stringify(order), ' ', JSON.stringify(docSubscription));
|
|
71
|
+
if (order && docSubscription) {
|
|
72
|
+
const itemsUpdate = [];
|
|
73
|
+
order.items.forEach((orderItem) => {
|
|
74
|
+
if (orderItem.product_id === product._id) {
|
|
75
|
+
if (orderItem.variation_id) {
|
|
76
|
+
const variation = product.variations
|
|
77
|
+
.find((itemFind) => itemFind.sku === orderItem.sku);
|
|
78
|
+
|
|
79
|
+
let quantity = orderItem.quantity;
|
|
80
|
+
if (variation && variation.quantity < orderItem.quantity) {
|
|
81
|
+
quantity = variation.quantity;
|
|
82
|
+
} else if (!variation) {
|
|
83
|
+
quantity = 0;
|
|
84
|
+
}
|
|
85
|
+
const newItem = {
|
|
86
|
+
sku: variation.sku,
|
|
87
|
+
price: ecomUtils.price({ ...product, ...variation }),
|
|
88
|
+
quantity,
|
|
89
|
+
};
|
|
90
|
+
if ((orderItem.final_price && orderItem.final_price !== newItem.price)
|
|
91
|
+
|| orderItem.price !== newItem.price || orderItem.quantity !== newItem.quantity) {
|
|
92
|
+
itemsUpdate.push(newItem);
|
|
93
|
+
}
|
|
94
|
+
} else {
|
|
95
|
+
const newItem = {
|
|
96
|
+
sku: product.sku,
|
|
97
|
+
price: ecomUtils.price(product),
|
|
98
|
+
quantity: product.quantity < orderItem.quantity
|
|
99
|
+
? product.quantity : orderItem.quantity,
|
|
100
|
+
};
|
|
101
|
+
if ((orderItem.final_price && orderItem.final_price !== newItem.price)
|
|
102
|
+
|| orderItem.price !== newItem.price || orderItem.quantity !== newItem.quantity) {
|
|
103
|
+
itemsUpdate.push(newItem);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
if (itemsUpdate.length) {
|
|
110
|
+
docSubscription?.items?.forEach((itemPagarme) => {
|
|
111
|
+
const itemToEdit = itemsUpdate.find((itemFind) => itemPagarme.id === `pi_${itemFind.sku}`);
|
|
112
|
+
if (itemToEdit && !itemPagarme.cycles) {
|
|
113
|
+
itemPagarme.quantity = itemToEdit.quantity;
|
|
114
|
+
itemPagarme.pricing_scheme.price = Math.floor((itemToEdit.price) * 100);
|
|
115
|
+
updateItemPagarme.push({
|
|
116
|
+
subscription_id: docSubscription.subscriptionPagarmeId,
|
|
117
|
+
item: itemPagarme,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
// order not found or error
|
|
124
|
+
if (updateItemPagarme.length) {
|
|
125
|
+
logger.log('> (App PagarMe V5): Try update item in Pagar.Me');
|
|
126
|
+
try {
|
|
127
|
+
// eslint-disable-next-line no-await-in-loop
|
|
128
|
+
await Promise.all(updateItemPagarme.map((itemPagarme) => {
|
|
129
|
+
return pagarmeAxios.put(
|
|
130
|
+
`/subscriptions/${itemPagarme.subscription_id}/items/${itemPagarme.item.id}`,
|
|
131
|
+
{
|
|
132
|
+
...itemPagarme.item,
|
|
133
|
+
},
|
|
134
|
+
);
|
|
135
|
+
}));
|
|
136
|
+
} catch (err) {
|
|
137
|
+
logger.error(err);
|
|
138
|
+
/* When creating a new order, check the items saved in Pagar.Me
|
|
139
|
+
with the original order items
|
|
140
|
+
|
|
141
|
+
No need to save to firestore
|
|
142
|
+
*/
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
i += 1;
|
|
146
|
+
}
|
|
147
|
+
logger.log('>> SUCESSS');
|
|
148
|
+
return null;
|
|
149
|
+
}
|
|
150
|
+
logger.log('>> Orders not found ');
|
|
151
|
+
return null;
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
const handleApiEvent = async ({
|
|
155
|
+
evName,
|
|
156
|
+
apiEvent,
|
|
157
|
+
apiDoc,
|
|
158
|
+
app,
|
|
159
|
+
}) => {
|
|
160
|
+
const resourceId = apiEvent.resource_id;
|
|
161
|
+
logger.info('>> ', resourceId, ' - Action: ', apiEvent.action);
|
|
162
|
+
const key = `${evName}_${resourceId}`;
|
|
163
|
+
const configApp = { ...app.data, ...app.hidden_data };
|
|
164
|
+
if (
|
|
165
|
+
Array.isArray(configApp.ignore_events)
|
|
166
|
+
&& configApp.ignore_events.includes(evName)
|
|
167
|
+
) {
|
|
168
|
+
logger.info('>> ', key, ' - Ignored event');
|
|
169
|
+
return null;
|
|
170
|
+
}
|
|
171
|
+
logger.info(`> Webhook ${resourceId} [${evName}] => ${apiDoc}`);
|
|
172
|
+
|
|
173
|
+
if (!process.env.PAGARMEV5_API_TOKEN) {
|
|
174
|
+
const pagarmeApiToken = configApp.pagarme_api_token;
|
|
175
|
+
if (pagarmeApiToken && typeof pagarmeApiToken === 'string') {
|
|
176
|
+
process.env.PAGARMEV5_API_TOKEN = pagarmeApiToken;
|
|
177
|
+
} else {
|
|
178
|
+
logger.warn('Missing PAGARMEV5 API TOKEN');
|
|
179
|
+
return null;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
try {
|
|
184
|
+
const pagarmeAxios = axios(process.env.PAGARMEV5_API_TOKEN);
|
|
185
|
+
|
|
186
|
+
if (evName === 'orders-cancelled') {
|
|
187
|
+
return eventOrderCancelled(apiDoc, pagarmeAxios);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (evName.startsWith('products-') && evName !== 'products-new') {
|
|
191
|
+
return eventProducts(apiDoc, pagarmeAxios);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return null;
|
|
195
|
+
} catch (error) {
|
|
196
|
+
const statusCode = error.response?.status;
|
|
197
|
+
if (statusCode === 404) {
|
|
198
|
+
logger.warn('> (App PagarMe V5): Subscription not found in PagarMe');
|
|
199
|
+
return null;
|
|
200
|
+
}
|
|
201
|
+
if (statusCode === 401 || statusCode === 403) {
|
|
202
|
+
logger.warn('> (App PagarMe V5): Unauthorized subscription deletion request');
|
|
203
|
+
return null;
|
|
204
|
+
}
|
|
205
|
+
throw error;
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
export default handleApiEvent;
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import ecomUtils from '@ecomplus/utils';
|
|
2
|
+
import api from '@cloudcommerce/api';
|
|
3
|
+
|
|
4
|
+
const getOrderById = async (orderId) => {
|
|
5
|
+
const { data } = await api.get(`orders/${orderId}`);
|
|
6
|
+
return data;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
const addPaymentHistory = async (orderId, body) => {
|
|
10
|
+
return api.post(`orders/${orderId}/payments_history`, body);
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const updateTransaction = (orderId, body, transactionId) => {
|
|
14
|
+
const urlTransaction = transactionId ? `/${transactionId}` : '';
|
|
15
|
+
const method = transactionId ? 'PATCH' : 'POST';
|
|
16
|
+
|
|
17
|
+
return api[method](`orders/${orderId}/transactions${urlTransaction}`, body);
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const getOrderIntermediatorTransactionId = async (invoiceId) => {
|
|
21
|
+
let queryString = `?transactions.intermediator.transaction_id=${invoiceId}`;
|
|
22
|
+
queryString += '&fields=transactions,financial_status.current,status';
|
|
23
|
+
const data = await api.get(`orders${queryString}`);
|
|
24
|
+
|
|
25
|
+
return data?.result.length ? data?.result[0] : null;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const checkItemsAndRecalculeteOrder = (amount, items, plan, itemsPagarme) => {
|
|
29
|
+
let subtotal = 0;
|
|
30
|
+
let item;
|
|
31
|
+
let i = 0;
|
|
32
|
+
while (i < items.length) {
|
|
33
|
+
item = items[i];
|
|
34
|
+
|
|
35
|
+
if (item.flags && (item.flags.includes('freebie') || item.flags.includes('discount-set-free'))) {
|
|
36
|
+
items.splice(i, 1);
|
|
37
|
+
} else {
|
|
38
|
+
// eslint-disable-next-line no-loop-func
|
|
39
|
+
const itemFound = itemsPagarme.find((itemFind) => itemFind.id === `pi_${item.sku}`);
|
|
40
|
+
|
|
41
|
+
if (itemFound) {
|
|
42
|
+
item.quantity = itemFound.quantity;
|
|
43
|
+
if (item.final_price) {
|
|
44
|
+
item.final_price = (itemFound.pricing_scheme.price / 100);
|
|
45
|
+
}
|
|
46
|
+
item.price = (itemFound.pricing_scheme.price / 100);
|
|
47
|
+
subtotal += item.quantity * (item.final_price || item.price);
|
|
48
|
+
i += 1;
|
|
49
|
+
} else {
|
|
50
|
+
items.splice(i, 1);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (subtotal > 0) {
|
|
56
|
+
amount.subtotal = subtotal;
|
|
57
|
+
amount.total = amount.subtotal + (amount.tax || 0)
|
|
58
|
+
+ (amount.freight || 0) + (amount.extra || 0);
|
|
59
|
+
|
|
60
|
+
let planDiscount;
|
|
61
|
+
if (plan && plan.discount) {
|
|
62
|
+
if (plan.discount.type === 'percentage') {
|
|
63
|
+
planDiscount = amount[plan.discount.apply_at];
|
|
64
|
+
planDiscount *= ((plan.discount.value) / 100);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
// if the plan doesn't exist, because it's subscription before the update
|
|
68
|
+
amount.discount = plan ? ((plan.discount && plan.discount.type !== 'percentage' ? plan.discount.value : planDiscount) || 0) : (amount.discount || 0);
|
|
69
|
+
|
|
70
|
+
amount.total -= amount.discount;
|
|
71
|
+
amount.total = amount.total > 0 ? amount.total : 0;
|
|
72
|
+
|
|
73
|
+
return amount.total > 0 ? Math.floor((amount.total).toFixed(2) * 1000) / 10 : 0;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return 0;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const createNewOrderBasedOld = (oldOrder, plan, status, charge, subscriptionPagarme) => {
|
|
80
|
+
const {
|
|
81
|
+
buyers, items, domain, amount,
|
|
82
|
+
} = oldOrder;
|
|
83
|
+
const channelType = oldOrder.channel_type;
|
|
84
|
+
const shippingLines = oldOrder.shipping_lines;
|
|
85
|
+
const shippingMethodLabel = oldOrder.shipping_method_label;
|
|
86
|
+
const paymentMethodLabel = oldOrder.payment_method_label;
|
|
87
|
+
const originalTransaction = oldOrder.transactions[0];
|
|
88
|
+
|
|
89
|
+
const portion = charge.code?.replace(`${oldOrder._id}-`, '');
|
|
90
|
+
const itemsPagarme = subscriptionPagarme.items;
|
|
91
|
+
|
|
92
|
+
checkItemsAndRecalculeteOrder(amount, items, plan, itemsPagarme);
|
|
93
|
+
if (amount.balance) {
|
|
94
|
+
delete amount.balance;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
items.forEach((item) => {
|
|
98
|
+
if (item.stock_status && item.stock_status !== 'unmanaged') {
|
|
99
|
+
item.stock_status = 'pending';
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
const transactionPagarme = charge.last_transaction;
|
|
103
|
+
|
|
104
|
+
const transactions = [
|
|
105
|
+
{
|
|
106
|
+
amount: amount.total,
|
|
107
|
+
status: {
|
|
108
|
+
updated_at: transactionPagarme.updated_at || new Date().toISOString(),
|
|
109
|
+
current: status,
|
|
110
|
+
},
|
|
111
|
+
intermediator: {
|
|
112
|
+
transaction_id: `${charge.invoice.id}`,
|
|
113
|
+
transaction_code: `${transactionPagarme.acquirer_auth_code || ''}`,
|
|
114
|
+
transaction_reference: `${transactionPagarme.acquirer_tid || ''}`,
|
|
115
|
+
},
|
|
116
|
+
payment_method: originalTransaction.payment_method,
|
|
117
|
+
app: originalTransaction.app,
|
|
118
|
+
_id: ecomUtils.randomObjectId(),
|
|
119
|
+
notes: `Parcela #${portion} referente à ${plan?.label || 'Assinatura'}`,
|
|
120
|
+
custom_fields: originalTransaction.custom_fields,
|
|
121
|
+
},
|
|
122
|
+
];
|
|
123
|
+
|
|
124
|
+
transactions[0].payment_link = transactionPagarme.url;
|
|
125
|
+
|
|
126
|
+
const financialStatus = {
|
|
127
|
+
updated_at: transactionPagarme.updated_at || new Date().toISOString(),
|
|
128
|
+
current: status,
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
let notes = `Parcela #${portion} desconto de ${plan.discount.type === 'percentage' ? '' : 'R$'}`;
|
|
132
|
+
notes += ` ${plan.discount.value} ${plan.discount.type === 'percentage' ? '%' : ''}`;
|
|
133
|
+
notes += ` sobre ${plan.discount.apply_at}`;
|
|
134
|
+
|
|
135
|
+
const body = {
|
|
136
|
+
opened_at: new Date().toISOString(),
|
|
137
|
+
items,
|
|
138
|
+
shipping_lines: shippingLines,
|
|
139
|
+
buyers,
|
|
140
|
+
channel_type: channelType,
|
|
141
|
+
domain,
|
|
142
|
+
amount,
|
|
143
|
+
shipping_method_label: shippingMethodLabel,
|
|
144
|
+
payment_method_label: paymentMethodLabel,
|
|
145
|
+
transactions,
|
|
146
|
+
financial_status: financialStatus,
|
|
147
|
+
subscription_order: {
|
|
148
|
+
_id: oldOrder._id,
|
|
149
|
+
number: oldOrder.number,
|
|
150
|
+
},
|
|
151
|
+
notes,
|
|
152
|
+
staff_notes: `Valor cobrado no Pagar.Me R$${(charge.amount) / 100}`,
|
|
153
|
+
};
|
|
154
|
+
return api.post('orders', body);
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
// const updateOrder = async (orderId, body) => {
|
|
158
|
+
// return api.patch(`orders/${orderId}`, body);
|
|
159
|
+
// };
|
|
160
|
+
|
|
161
|
+
const getOrderWithQueryString = async (query) => {
|
|
162
|
+
const { data } = await api.get(`orders?${query}`);
|
|
163
|
+
|
|
164
|
+
return data?.result.length ? data?.result : null;
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
const getProductById = async (productId) => {
|
|
168
|
+
const { data } = await api.get(`products/${productId}`);
|
|
169
|
+
return data;
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
const checkItemCategory = async (categoryIds, itemsPagarme, itemsApi) => {
|
|
173
|
+
let i = 0;
|
|
174
|
+
|
|
175
|
+
const itemsIdPagarmeDelete = [];
|
|
176
|
+
while (i < itemsPagarme.length) {
|
|
177
|
+
const itemPagarme = itemsPagarme[i];
|
|
178
|
+
// Obs.: freight is one item, initially do not remove freight
|
|
179
|
+
const isItemFreigth = itemPagarme?.id?.startsWith('pi_freight_');
|
|
180
|
+
const itemFound = itemsApi.find((itemFind) => itemPagarme.id === `pi_${itemFind.sku}`);
|
|
181
|
+
const itemFoundIndex = itemsApi.indexOf(itemFound);
|
|
182
|
+
|
|
183
|
+
if (itemFound && !isItemFreigth) {
|
|
184
|
+
// eslint-disable-next-line no-await-in-loop
|
|
185
|
+
const product = await getProductById(itemFound.product_id);
|
|
186
|
+
if (product.categories) {
|
|
187
|
+
let canSign = false;
|
|
188
|
+
product.categories.forEach((category) => {
|
|
189
|
+
if (categoryIds.includes(category._id)) {
|
|
190
|
+
canSign = true;
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
if (!canSign) {
|
|
195
|
+
itemsIdPagarmeDelete.push(itemPagarme.id);
|
|
196
|
+
itemsApi.splice(itemFoundIndex, 1);
|
|
197
|
+
}
|
|
198
|
+
} else {
|
|
199
|
+
itemsIdPagarmeDelete.push(itemPagarme.id);
|
|
200
|
+
itemsApi.splice(itemFoundIndex, 1);
|
|
201
|
+
}
|
|
202
|
+
} else if (!isItemFreigth) {
|
|
203
|
+
itemsIdPagarmeDelete.push(itemPagarme.id);
|
|
204
|
+
}
|
|
205
|
+
i += 1;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
return itemsIdPagarmeDelete;
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
export {
|
|
212
|
+
getOrderById,
|
|
213
|
+
addPaymentHistory,
|
|
214
|
+
updateTransaction,
|
|
215
|
+
getOrderIntermediatorTransactionId,
|
|
216
|
+
createNewOrderBasedOld,
|
|
217
|
+
getOrderWithQueryString,
|
|
218
|
+
getProductById,
|
|
219
|
+
checkItemCategory,
|
|
220
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import logger from 'firebase-functions/logger';
|
|
2
|
+
|
|
3
|
+
const getDocFirestore = async (collection, documentId) => {
|
|
4
|
+
const documentSnapshot = await collection.doc(documentId).get();
|
|
5
|
+
let data;
|
|
6
|
+
if (documentSnapshot) {
|
|
7
|
+
data = documentSnapshot.data();
|
|
8
|
+
}
|
|
9
|
+
return data;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const updateDocFirestore = async (collection, documentId, body) => {
|
|
13
|
+
const updatedAt = new Date().toISOString();
|
|
14
|
+
body.updatedAt = updatedAt;
|
|
15
|
+
|
|
16
|
+
await collection.doc(documentId)
|
|
17
|
+
.set(body, { merge: true })
|
|
18
|
+
.catch(logger.error);
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export {
|
|
22
|
+
getDocFirestore,
|
|
23
|
+
updateDocFirestore,
|
|
24
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
|
|
3
|
+
export default (apiSecretKey) => {
|
|
4
|
+
return axios.create({
|
|
5
|
+
baseURL: 'https://api.pagar.me/core/v5',
|
|
6
|
+
headers: {
|
|
7
|
+
accept: 'application/json',
|
|
8
|
+
'content-type': 'application/json',
|
|
9
|
+
Authorization: 'Basic ' + Buffer.from(`${apiSecretKey}:`).toString('base64'),
|
|
10
|
+
},
|
|
11
|
+
});
|
|
12
|
+
};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
const discountPlanPayment = (planName, plan, amount) => {
|
|
2
|
+
let discount;
|
|
3
|
+
// console.log('>>Plan ', plan)
|
|
4
|
+
if (plan.discount_first_installment
|
|
5
|
+
&& !plan.discount_first_installment.disable) {
|
|
6
|
+
discount = plan.discount_first_installment;
|
|
7
|
+
} else {
|
|
8
|
+
discount = plan.discount;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
if (discount && discount.value > 0) {
|
|
12
|
+
// default discount option
|
|
13
|
+
const { value } = discount;
|
|
14
|
+
const discountOption = {
|
|
15
|
+
label: planName,
|
|
16
|
+
value,
|
|
17
|
+
type: discount.type,
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
if (amount.total) {
|
|
21
|
+
// check amount value to apply discount
|
|
22
|
+
if (amount.total < discount.min_amount) {
|
|
23
|
+
discount.value = 0;
|
|
24
|
+
} else {
|
|
25
|
+
delete discount.min_amount;
|
|
26
|
+
|
|
27
|
+
// fix local amount object
|
|
28
|
+
const applyDiscount = discount.apply_at;
|
|
29
|
+
|
|
30
|
+
const maxDiscount = amount[applyDiscount || 'subtotal'];
|
|
31
|
+
let discountValue;
|
|
32
|
+
if (discount.type === 'percentage') {
|
|
33
|
+
discountValue = (maxDiscount * discount.value) / 100;
|
|
34
|
+
} else {
|
|
35
|
+
discountValue = discount.value;
|
|
36
|
+
if (discountValue > maxDiscount) {
|
|
37
|
+
discountValue = maxDiscount;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
if (discountValue > 0) {
|
|
41
|
+
amount.discount = (amount.discount || 0) + discountValue;
|
|
42
|
+
amount.total -= discountValue;
|
|
43
|
+
if (amount.total < 0) {
|
|
44
|
+
amount.total = 0;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return { amount, discountOption };
|
|
50
|
+
}
|
|
51
|
+
return null;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const getPlanInTransction = (label, plans) => {
|
|
55
|
+
// find plan by name (label)
|
|
56
|
+
const plan = plans.find((planFind) => {
|
|
57
|
+
const planLabel = `Assinatura ${planFind.periodicity} ${planFind.label || 'Plano'}`;
|
|
58
|
+
|
|
59
|
+
label = label.trim();
|
|
60
|
+
return label === planLabel;
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
return plan;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export {
|
|
67
|
+
discountPlanPayment,
|
|
68
|
+
getPlanInTransction,
|
|
69
|
+
};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// pending, paid, canceled, scheduled ou failed.
|
|
2
|
+
const parserInvoiceStatusToEcom = (status) => {
|
|
3
|
+
// pending, paid, canceled, scheduled ou failed
|
|
4
|
+
switch (status) {
|
|
5
|
+
case 'pending':
|
|
6
|
+
case 'paid':
|
|
7
|
+
return status;
|
|
8
|
+
case 'scheduled':
|
|
9
|
+
return 'under_analysis';
|
|
10
|
+
case 'canceled':
|
|
11
|
+
return 'voided';
|
|
12
|
+
case 'failed':
|
|
13
|
+
return 'unauthorized';
|
|
14
|
+
default:
|
|
15
|
+
return 'unknown';
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const parserChangeStatusToEcom = (status) => {
|
|
20
|
+
// overpaid paid partial_canceled payment_failed pending processing refunded underpaid
|
|
21
|
+
switch (status) {
|
|
22
|
+
case 'pending':
|
|
23
|
+
case 'paid':
|
|
24
|
+
case 'refunded':
|
|
25
|
+
return status;
|
|
26
|
+
|
|
27
|
+
case 'overpaid':
|
|
28
|
+
return 'paid';
|
|
29
|
+
|
|
30
|
+
case 'processing':
|
|
31
|
+
return 'under_analysis';
|
|
32
|
+
|
|
33
|
+
case 'canceled':
|
|
34
|
+
return 'voided';
|
|
35
|
+
|
|
36
|
+
case 'payment_failed':
|
|
37
|
+
case 'failed':
|
|
38
|
+
return 'unauthorized';
|
|
39
|
+
|
|
40
|
+
case 'underpaid':
|
|
41
|
+
return 'partially_paid';
|
|
42
|
+
|
|
43
|
+
default:
|
|
44
|
+
return 'unknown';
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const parseAddress = (to) => ({
|
|
49
|
+
city: to.city,
|
|
50
|
+
state: to.province || to.province_code,
|
|
51
|
+
country: to.country_code ? to.country_code.toLowerCase() : 'br',
|
|
52
|
+
zip_code: to.zip.replace(/\D/g, '').padStart(8, '0'),
|
|
53
|
+
line_1: `${String(to.number) || 's/n'},${to.street},${to.borough}`,
|
|
54
|
+
line_2: to.complement || '',
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
export {
|
|
58
|
+
parserInvoiceStatusToEcom,
|
|
59
|
+
parserChangeStatusToEcom,
|
|
60
|
+
parseAddress,
|
|
61
|
+
};
|