@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.
Files changed (36) hide show
  1. package/.turbo/turbo-build.log +4 -0
  2. package/CHANGELOG.md +1 -0
  3. package/LICENSE.md +230 -0
  4. package/README.md +1 -0
  5. package/assets/onload-expression.js +38 -0
  6. package/assets/onload-expression.min.js +1 -0
  7. package/events.js +1 -0
  8. package/lib/index.d.ts +1 -0
  9. package/lib/index.js +2 -0
  10. package/lib/index.js.map +1 -0
  11. package/lib/pagarme-v5-events.d.ts +6 -0
  12. package/lib/pagarme-v5-events.js +21 -0
  13. package/lib/pagarme-v5-events.js.map +1 -0
  14. package/lib/pagarme-v5.d.ts +4 -0
  15. package/lib/pagarme-v5.js +12 -0
  16. package/lib/pagarme-v5.js.map +1 -0
  17. package/lib-mjs/create-pagarme5-transaction.mjs +208 -0
  18. package/lib-mjs/events-to-pagarme5.mjs +209 -0
  19. package/lib-mjs/functions-lib/api-utils.mjs +220 -0
  20. package/lib-mjs/functions-lib/firestore-utils.mjs +24 -0
  21. package/lib-mjs/functions-lib/pagarme/create-axios.mjs +12 -0
  22. package/lib-mjs/functions-lib/pagarme/handle-plans.mjs +69 -0
  23. package/lib-mjs/functions-lib/pagarme/parses-utils.mjs +61 -0
  24. package/lib-mjs/functions-lib/pagarme/payment-subscription.mjs +244 -0
  25. package/lib-mjs/functions-lib/payments/add-installments.mjs +45 -0
  26. package/lib-mjs/list-pagarme5-payments.mjs +218 -0
  27. package/lib-mjs/pagarme5-webhooks.mjs +343 -0
  28. package/package.json +38 -0
  29. package/scripts/build.sh +4 -0
  30. package/scripts/tests.sh +9 -0
  31. package/src/index.ts +1 -0
  32. package/src/pagarme-v5-events.ts +27 -0
  33. package/src/pagarme-v5.ts +12 -0
  34. package/tests/1-list-payments.test.mjs +37 -0
  35. package/tests/2-create-transaction.test.mjs +56 -0
  36. 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
+ };