@cloudcommerce/app-tiny-erp 0.0.59 → 0.0.62

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 (54) hide show
  1. package/.turbo/turbo-build.log +30 -4
  2. package/lib/event-to-tiny.js +117 -0
  3. package/lib/event-to-tiny.js.map +1 -0
  4. package/lib/index.js +2 -0
  5. package/lib/index.js.map +1 -0
  6. package/lib/integration/after-tiny-queue.js +79 -0
  7. package/lib/integration/after-tiny-queue.js.map +1 -0
  8. package/lib/integration/export-order-to-tiny.js +81 -0
  9. package/lib/integration/export-order-to-tiny.js.map +1 -0
  10. package/lib/integration/export-product-to-tiny.js +58 -0
  11. package/lib/integration/export-product-to-tiny.js.map +1 -0
  12. package/lib/integration/helpers/format-tiny-date.js +7 -0
  13. package/lib/integration/helpers/format-tiny-date.js.map +1 -0
  14. package/lib/integration/import-order-from-tiny.js +92 -0
  15. package/lib/integration/import-order-from-tiny.js.map +1 -0
  16. package/lib/integration/import-product-from-tiny.js +158 -0
  17. package/lib/integration/import-product-from-tiny.js.map +1 -0
  18. package/lib/integration/parsers/order-from-tiny.js +46 -0
  19. package/lib/integration/parsers/order-from-tiny.js.map +1 -0
  20. package/lib/integration/parsers/order-to-tiny.js +193 -0
  21. package/lib/integration/parsers/order-to-tiny.js.map +1 -0
  22. package/lib/integration/parsers/product-from-tiny.js +199 -0
  23. package/lib/integration/parsers/product-from-tiny.js.map +1 -0
  24. package/lib/integration/parsers/product-to-tiny.js +129 -0
  25. package/lib/integration/parsers/product-to-tiny.js.map +1 -0
  26. package/lib/integration/parsers/status-from-tiny.js +34 -0
  27. package/lib/integration/parsers/status-from-tiny.js.map +1 -0
  28. package/lib/integration/parsers/status-to-tiny.js +39 -0
  29. package/lib/integration/parsers/status-to-tiny.js.map +1 -0
  30. package/lib/integration/post-tiny-erp.js +47 -0
  31. package/lib/integration/post-tiny-erp.js.map +1 -0
  32. package/lib/tiny-erp.js +17 -0
  33. package/lib/tiny-erp.js.map +1 -0
  34. package/lib/tiny-webhook.js +92 -0
  35. package/lib/tiny-webhook.js.map +1 -0
  36. package/package.json +13 -6
  37. package/src/event-to-tiny.ts +136 -0
  38. package/src/index.ts +1 -0
  39. package/src/integration/after-tiny-queue.ts +80 -0
  40. package/src/integration/export-order-to-tiny.ts +86 -0
  41. package/src/integration/export-product-to-tiny.ts +60 -0
  42. package/src/integration/helpers/format-tiny-date.ts +6 -0
  43. package/src/integration/import-order-from-tiny.ts +102 -0
  44. package/src/integration/import-product-from-tiny.ts +162 -0
  45. package/src/integration/parsers/order-from-tiny.ts +49 -0
  46. package/src/integration/parsers/order-to-tiny.ts +205 -0
  47. package/src/integration/parsers/product-from-tiny.ts +215 -0
  48. package/src/integration/parsers/product-to-tiny.ts +138 -0
  49. package/src/integration/parsers/status-from-tiny.ts +35 -0
  50. package/src/integration/parsers/status-to-tiny.ts +42 -0
  51. package/src/integration/post-tiny-erp.ts +52 -0
  52. package/src/tiny-erp.ts +23 -0
  53. package/src/tiny-webhook.ts +100 -0
  54. package/src/firebase.ts +0 -0
@@ -0,0 +1,86 @@
1
+ import type { Orders } from '@cloudcommerce/types';
2
+ import logger from 'firebase-functions/lib/logger';
3
+ import api from '@cloudcommerce/api';
4
+ import postTiny from './post-tiny-erp';
5
+ import parseStatus from './parsers/status-to-tiny';
6
+ import parseOrder from './parsers/order-to-tiny';
7
+
8
+ export default async (apiDoc, queueEntry, appData, canCreateNew) => {
9
+ const orderId = queueEntry.nextId;
10
+ let order: Orders;
11
+ if (orderId === apiDoc._id) {
12
+ order = apiDoc;
13
+ } else {
14
+ try {
15
+ order = (await api.get(`orders/${orderId}`)).data;
16
+ } catch (err: any) {
17
+ if (err.statusCode === 404) {
18
+ const msg = `O pedido ${orderId} não existe (:${err.statusCode})`;
19
+ const error: any = new Error(msg);
20
+ error.isConfigError = true;
21
+ return error;
22
+ }
23
+ throw err;
24
+ }
25
+ }
26
+ if (!order.financial_status) {
27
+ logger.info(`${orderId} skipped with no financial status`);
28
+ return null;
29
+ }
30
+ logger.info(`${orderId} searching order ${order.number}`);
31
+
32
+ let tinyData: { pedidos?: any };
33
+ try {
34
+ tinyData = await postTiny('/pedidos.pesquisa.php', {
35
+ numeroEcommerce: String(order.number),
36
+ });
37
+ } catch (err: any) {
38
+ const status = err.response && err.response.status;
39
+ if (status === 404) {
40
+ tinyData = {};
41
+ } else {
42
+ logger.info(`${orderId} search on tiny ends with status ${status}`);
43
+ throw err;
44
+ }
45
+ }
46
+
47
+ const { pedidos } = tinyData;
48
+ const tinyStatus = parseStatus(order);
49
+ let originalTinyOrder;
50
+ if (Array.isArray(pedidos)) {
51
+ originalTinyOrder = pedidos.find(({ pedido }) => {
52
+ return order.number === Number(pedido.numero_ecommerce);
53
+ });
54
+ if (originalTinyOrder) {
55
+ originalTinyOrder = originalTinyOrder.pedido;
56
+ }
57
+ }
58
+ if (!originalTinyOrder) {
59
+ if (!canCreateNew) {
60
+ return null;
61
+ }
62
+ if (
63
+ appData.approved_orders_only
64
+ && (tinyStatus === 'aberto' || tinyStatus === 'cancelado')
65
+ ) {
66
+ logger.info(`${orderId} skipped with status "${tinyStatus}"`);
67
+ return null;
68
+ }
69
+ const tinyOrder = parseOrder(order, appData);
70
+ logger.info(`${orderId} ${JSON.stringify(tinyOrder)}`);
71
+ return postTiny('/pedido.incluir.php', {
72
+ pedido: {
73
+ pedido: tinyOrder,
74
+ },
75
+ });
76
+ }
77
+
78
+ logger.info(`${orderId} found with tiny status ${tinyStatus}`);
79
+ if (tinyStatus) {
80
+ return postTiny('/pedido.alterar.situacao', {
81
+ id: originalTinyOrder.id,
82
+ situacao: tinyStatus,
83
+ });
84
+ }
85
+ return null;
86
+ };
@@ -0,0 +1,60 @@
1
+ import type { Products } from '@cloudcommerce/types';
2
+ import api from '@cloudcommerce/api';
3
+ import postTiny from './post-tiny-erp';
4
+ import parseProduct from './parsers/product-to-tiny';
5
+
6
+ export default async (apiDoc, queueEntry, appData, canCreateNew) => {
7
+ const productId = queueEntry.nextId;
8
+ let product: Products;
9
+ if (productId === apiDoc._id) {
10
+ product = apiDoc;
11
+ } else {
12
+ try {
13
+ product = (await api.get(`products/${productId}`)).data;
14
+ } catch (err: any) {
15
+ if (err.statusCode === 404) {
16
+ const msg = `O produto ${productId} não existe (:${err.statusCode})`;
17
+ const error: any = new Error(msg);
18
+ error.isConfigError = true;
19
+ return error;
20
+ }
21
+ throw err;
22
+ }
23
+ }
24
+
25
+ let tinyData: { produtos?: any };
26
+ try {
27
+ tinyData = await postTiny('/produtos.pesquisa.php', {
28
+ pesquisa: product.sku,
29
+ });
30
+ } catch (err: any) {
31
+ if (err.response && err.response.status === 404) {
32
+ tinyData = {};
33
+ } else {
34
+ throw err;
35
+ }
36
+ }
37
+
38
+ const { produtos } = tinyData;
39
+ let originalTinyProduct;
40
+ if (Array.isArray(produtos)) {
41
+ originalTinyProduct = produtos.find(({ produto }) => {
42
+ return product.sku === String(produto.codigo);
43
+ });
44
+ if (originalTinyProduct) {
45
+ originalTinyProduct = originalTinyProduct.produto;
46
+ } else if (!canCreateNew) {
47
+ return null;
48
+ }
49
+ }
50
+ const tinyProduct = parseProduct(product, originalTinyProduct, appData);
51
+ return tinyProduct
52
+ ? postTiny(originalTinyProduct ? '/produto.alterar.php' : '/produto.incluir.php', {
53
+ produto: {
54
+ produtos: [{
55
+ produto: tinyProduct,
56
+ }],
57
+ },
58
+ })
59
+ : null;
60
+ };
@@ -0,0 +1,6 @@
1
+ export default (d: Date) => {
2
+ /* eslint-disable prefer-template */
3
+ return d.getDate().toString().padStart(2, '0') + '/'
4
+ + (d.getMonth() + 1).toString().padStart(2, '0') + '/'
5
+ + d.getFullYear();
6
+ };
@@ -0,0 +1,102 @@
1
+ import type { Orders } from '@cloudcommerce/types';
2
+ // eslint-disable-next-line import/no-unresolved
3
+ import { getFirestore } from 'firebase-admin/firestore';
4
+ import logger from 'firebase-functions/lib/logger';
5
+ import api from '@cloudcommerce/api';
6
+ import postTiny from './post-tiny-erp';
7
+ import parseOrder from './parsers/order-from-tiny';
8
+ import parseStatus from './parsers/status-from-tiny';
9
+
10
+ const getLastStatus = (records) => {
11
+ let statusRecord;
12
+ records.forEach((record) => {
13
+ if (
14
+ record
15
+ && (!statusRecord || !record.date_time || record.date_time >= statusRecord.date_time)
16
+ ) {
17
+ statusRecord = record;
18
+ }
19
+ });
20
+ return statusRecord && statusRecord.status;
21
+ };
22
+
23
+ export default async (apiDoc, queueEntry) => {
24
+ const getTinyOrder = async (tinyOrderId) => {
25
+ const { pedido } = await postTiny('/pedido.obter.php', {
26
+ id: Number(tinyOrderId),
27
+ });
28
+ const situacao = typeof pedido.situacao === 'string'
29
+ ? pedido.situacao.toLowerCase()
30
+ : null;
31
+ const orderNumber = pedido.numero_ecommerce;
32
+ logger.info(`Import order n${orderNumber} ${tinyOrderId} => ${situacao}`);
33
+
34
+ const documentRef = getFirestore().doc(`tinyErpOrders/${tinyOrderId}`);
35
+ const documentSnapshot = await documentRef.get();
36
+ if (
37
+ documentSnapshot.exists
38
+ && documentSnapshot.get('situacao') === situacao
39
+ ) {
40
+ logger.info(`>> Ignoring Tiny order n${orderNumber} ${tinyOrderId} with same status`);
41
+ return null;
42
+ }
43
+
44
+ let listEndpoint = 'orders?limit=1&fields=_id,payments_history,fulfillments,shipping_lines';
45
+ if (orderNumber) {
46
+ listEndpoint += `&number=${orderNumber}`;
47
+ } else {
48
+ listEndpoint += `&hidden_metafields.value=${tinyOrderId}_tiny`;
49
+ }
50
+ const { data: { result } } = await api.get(listEndpoint as 'orders');
51
+ if (!result.length) {
52
+ return null;
53
+ }
54
+ const order = result[0];
55
+ const partialOrder = await parseOrder(pedido, order.shipping_lines) as Orders;
56
+ const promises: Promise<any>[] = [];
57
+ if (partialOrder && Object.keys(partialOrder).length) {
58
+ promises.push(api.patch(`orders/${order._id}`, partialOrder));
59
+ }
60
+ const { fulfillmentStatus, financialStatus } = parseStatus(situacao);
61
+ const data: Record<string, any> = {
62
+ date_time: new Date().toISOString(),
63
+ flags: ['from-tiny'],
64
+ };
65
+ [
66
+ [financialStatus, 'payments_history'],
67
+ [fulfillmentStatus, 'fulfillments'],
68
+ ].forEach(([newStatus, subresource]) => {
69
+ if (
70
+ newStatus
71
+ // @ts-ignore
72
+ && (!order[subresource] || getLastStatus(order[subresource]) !== newStatus)
73
+ ) {
74
+ data.status = newStatus;
75
+ promises.push(api.post(`orders/${order._id}/${subresource}`, data as any));
76
+ logger.info(`${order._id} updated to ${newStatus} from Tiny ${tinyOrderId}`);
77
+ }
78
+ });
79
+
80
+ return Promise.all(promises)
81
+ .then(([firstResult]) => {
82
+ documentRef.set({ situacao }).catch(logger.error);
83
+ return (firstResult && firstResult.response) || firstResult;
84
+ });
85
+ };
86
+
87
+ const tinyOrderNumber = queueEntry.nextId;
88
+ if (typeof tinyOrderNumber === 'string' && tinyOrderNumber.startsWith('id:')) {
89
+ return getTinyOrder(tinyOrderNumber.substring(3));
90
+ }
91
+ return postTiny('/pedidos.pesquisa.php', {
92
+ numero: tinyOrderNumber,
93
+ }).then(({ pedidos }) => {
94
+ const tinyOrder = pedidos.find(({ pedido }) => {
95
+ return Number(tinyOrderNumber) === Number(pedido.numero);
96
+ });
97
+ if (tinyOrder) {
98
+ return getTinyOrder(tinyOrder.pedido.id);
99
+ }
100
+ return null;
101
+ });
102
+ };
@@ -0,0 +1,162 @@
1
+ import type { Products } from '@cloudcommerce/types';
2
+ import logger from 'firebase-functions/lib/logger';
3
+ import api from '@cloudcommerce/api';
4
+ import updateAppData from '@cloudcommerce/firebase/lib/helpers/update-app-data';
5
+ import postTiny from './post-tiny-erp';
6
+ import parseProduct from './parsers/product-from-tiny';
7
+
8
+ export default async (apiDoc, queueEntry, appData, canCreateNew, isHiddenQueue) => {
9
+ const [sku, productId] = String(queueEntry.nextId).split(';:');
10
+ let product: Products | null = null;
11
+ try {
12
+ product = (await api.get(`products/${(productId || `sku:${sku}`)}`)).data;
13
+ } catch (err: any) {
14
+ if (err.statusCode !== 404) {
15
+ throw err;
16
+ }
17
+ }
18
+ let hasVariations: boolean = false;
19
+ let variationId: string | undefined;
20
+ if (product) {
21
+ const { variations } = product;
22
+ hasVariations = Boolean(variations && variations.length);
23
+ const variation = variations?.find((variation) => sku === variation.sku);
24
+ if (variation) {
25
+ variationId = variation._id;
26
+ } else {
27
+ logger.info(`SKU not found ${sku}`);
28
+ if (!isHiddenQueue && !appData.update_product) {
29
+ const msg = sku
30
+ + ' corresponde a um produto com variações,'
31
+ + ' especifique o SKU da variação para importar.';
32
+ const err: any = new Error(msg);
33
+ err.isConfigError = true;
34
+ return err;
35
+ }
36
+ return null;
37
+ }
38
+ }
39
+
40
+ const handleTinyStock = ({ produto, tipo }, tinyProduct?) => {
41
+ let quantity = Number(produto.saldo) || Number(produto.estoqueAtual);
42
+ if (produto.saldoReservado) {
43
+ quantity -= Number(produto.saldoReservado);
44
+ }
45
+ if (product && (!appData.update_product || variationId)) {
46
+ if (!Number.isNaN(quantity)) {
47
+ if (quantity < 0) {
48
+ quantity = 0;
49
+ }
50
+ let endpoint = `products/${product._id}`;
51
+ if (variationId) {
52
+ endpoint += `variations/${variationId}`;
53
+ }
54
+ endpoint += '/quantity';
55
+ logger.info(endpoint, { quantity });
56
+ // @ts-ignore
57
+ return api.put(endpoint, quantity);
58
+ }
59
+ return null;
60
+ }
61
+ if (!tinyProduct) {
62
+ return null;
63
+ }
64
+
65
+ return postTiny('/produto.obter.php', { id: tinyProduct.id })
66
+ .then(({ produto }) => {
67
+ let method;
68
+ let endpoint;
69
+ let productId = product && product._id;
70
+ if (productId) {
71
+ method = 'PATCH';
72
+ endpoint = `products/${productId}`;
73
+ } else if (tipo === 'produto' || !tipo) {
74
+ method = 'POST';
75
+ endpoint = 'products';
76
+ } else {
77
+ return null;
78
+ }
79
+ // @ts-ignore
80
+ return parseProduct(produto, method === 'POST').then((product: Products) => {
81
+ if (!Number.isNaN(quantity)) {
82
+ product.quantity = quantity >= 0 ? quantity : 0;
83
+ }
84
+ logger.info(`${method} ${endpoint}`);
85
+ const promise = api({
86
+ method,
87
+ endpoint,
88
+ data: product,
89
+ });
90
+
91
+ if (Array.isArray(produto.variacoes) && produto.variacoes.length) {
92
+ if (!queueEntry.app) {
93
+ logger.warn('Variations cannot be queued without `queueEntry.app`');
94
+ return promise;
95
+ }
96
+ promise.then((response) => {
97
+ let skus = appData.__importation && appData.__importation.skus;
98
+ if (!Array.isArray(skus)) {
99
+ skus = [];
100
+ }
101
+ let isQueuedVariations = false;
102
+ produto.variacoes.forEach(({ variacao }) => {
103
+ const { codigo } = variacao;
104
+ let skuAndId = codigo;
105
+ if (!productId) {
106
+ productId = response.data && response.data._id;
107
+ }
108
+ if (productId) {
109
+ skuAndId += `;:${productId}`;
110
+ }
111
+ if (!skus.includes(codigo) && !skus.includes(skuAndId)) {
112
+ isQueuedVariations = true;
113
+ skus.push(skuAndId);
114
+ }
115
+ });
116
+ return isQueuedVariations
117
+ ? updateAppData(queueEntry.app, {
118
+ __importation: {
119
+ ...appData.__importation,
120
+ skus,
121
+ },
122
+ })
123
+ : response;
124
+ });
125
+ }
126
+ return promise;
127
+ });
128
+ });
129
+ };
130
+
131
+ logger.info(JSON.stringify({
132
+ sku,
133
+ productId,
134
+ hasVariations,
135
+ variationId,
136
+ }));
137
+ const { tinyStockUpdate } = queueEntry;
138
+ if (tinyStockUpdate && isHiddenQueue && productId) {
139
+ return handleTinyStock(tinyStockUpdate as any);
140
+ }
141
+ return postTiny('/produtos.pesquisa.php', { pesquisa: sku })
142
+ .then(({ produtos }) => {
143
+ if (Array.isArray(produtos)) {
144
+ let tinyProduct = produtos.find(({ produto }) => sku === String(produto.codigo));
145
+ if (tinyProduct) {
146
+ tinyProduct = tinyProduct.produto;
147
+ if (!hasVariations || variationId) {
148
+ if (tinyStockUpdate) {
149
+ return handleTinyStock(tinyStockUpdate as any, tinyProduct);
150
+ }
151
+ return postTiny('/produto.obter.estoque.php', { id: tinyProduct.id })
152
+ .then((tinyStock) => handleTinyStock(tinyStock, tinyProduct));
153
+ }
154
+ return handleTinyStock({ produto: {} } as any, tinyProduct);
155
+ }
156
+ }
157
+ const msg = `SKU ${sku} não encontrado no Tiny`;
158
+ const err: any = new Error(msg);
159
+ err.isConfigError = true;
160
+ throw new Error(err);
161
+ });
162
+ };
@@ -0,0 +1,49 @@
1
+ import postTiny from '../post-tiny-erp';
2
+
3
+ export default (tinyOrder, shippingLines) => new Promise((resolve, reject) => {
4
+ const partialOrder: Record<string, any> = {};
5
+ if (tinyOrder.obs_interna) {
6
+ partialOrder.staff_notes = tinyOrder.obs_interna;
7
+ }
8
+
9
+ if (shippingLines && shippingLines.length) {
10
+ const shippingLine = shippingLines[0];
11
+ if (
12
+ (tinyOrder.codigo_rastreamento || tinyOrder.url_rastreamento)
13
+ && (!shippingLine.tracking_codes || !shippingLine.tracking_codes.length)
14
+ ) {
15
+ let link;
16
+ if (tinyOrder.url_rastreamento) {
17
+ link = tinyOrder.url_rastreamento;
18
+ }
19
+ const tracking = {
20
+ code: String(tinyOrder.codigo_rastreamento)
21
+ || link.replace(/^https?:\/\/[^/]+/, '').replace(/^[^?]+\?/, '').substring(0, 70),
22
+ link,
23
+ };
24
+ shippingLine.tracking_codes = [tracking];
25
+ partialOrder.shipping_lines = shippingLines;
26
+ }
27
+
28
+ if (tinyOrder.id_nota_fiscal > 0) {
29
+ if (!shippingLine.invoices) {
30
+ shippingLine.invoices = [];
31
+ }
32
+ postTiny('/nota.fiscal.obter.php', { id: tinyOrder.id_nota_fiscal })
33
+ .then((tinyInvoice) => {
34
+ const number = String(tinyInvoice.nota_fiscal.numero);
35
+ if (number && !shippingLine.invoices.find((invoice) => invoice.number === number)) {
36
+ shippingLine.invoices.push({
37
+ number,
38
+ serial_number: String(tinyInvoice.nota_fiscal.serie),
39
+ });
40
+ }
41
+ partialOrder.shipping_lines = shippingLines;
42
+ resolve(partialOrder);
43
+ })
44
+ .catch(reject);
45
+ return;
46
+ }
47
+ }
48
+ resolve(partialOrder);
49
+ });
@@ -0,0 +1,205 @@
1
+ import type { Orders } from '@cloudcommerce/types';
2
+ import ecomUtils from '@ecomplus/utils';
3
+ import formatDate from '../helpers/format-tiny-date';
4
+ import parseStatus from './status-to-tiny';
5
+
6
+ export default (order: Orders, appData) => {
7
+ const orderRef = String(order.number) || order._id;
8
+ const tinyOrder: Record<string, any> = {
9
+ numero_pedido_ecommerce: orderRef,
10
+ data_pedido: formatDate(new Date(order.opened_at || order.created_at)),
11
+ ecommerce: 'E-Com Plus',
12
+ situacao: parseStatus(order),
13
+ itens: [],
14
+ };
15
+
16
+ const buyer = order.buyers && order.buyers[0];
17
+ const shippingLine = order.shipping_lines && order.shipping_lines[0];
18
+ const transaction = order.transactions && order.transactions[0];
19
+ const shippingAddress = shippingLine && shippingLine.to;
20
+ const billingAddress = transaction && transaction.billing_address;
21
+
22
+ const parseAddress = (address, tinyObject) => {
23
+ [
24
+ ['street', 'endereco', 50],
25
+ ['number', 'numero', 10],
26
+ ['complement', 'complemento', 50],
27
+ ['borough', 'bairro', 30],
28
+ ['zip', 'cep', 10],
29
+ ['city', 'cidade', 30],
30
+ ['province_code', 'uf', 30],
31
+ ].forEach(([addressField, tinyField, maxLength]) => {
32
+ if (address[addressField]) {
33
+ tinyObject[tinyField] = String(address[addressField])
34
+ .substring(0, maxLength as number);
35
+ }
36
+ });
37
+ };
38
+
39
+ if (buyer) {
40
+ const tinyCustomer: Record<string, any> = {
41
+ codigo: buyer._id,
42
+ nome: (buyer.corporate_name || ecomUtils.fullName(buyer)).substring(0, 30)
43
+ || `Comprador de #${orderRef}`,
44
+ tipo_pessoa: buyer.registry_type === 'j' ? 'J' : 'F',
45
+ };
46
+ if (buyer.display_name) {
47
+ tinyCustomer.nome_fantasia = buyer.display_name.substring(0, 30);
48
+ }
49
+ if (buyer.doc_number && buyer.doc_number.length <= 18) {
50
+ tinyCustomer.cpf_cnpj = buyer.doc_number;
51
+ }
52
+ if (buyer.inscription_number && buyer.inscription_number.length <= 18) {
53
+ tinyCustomer.ie = buyer.inscription_number;
54
+ }
55
+ if (buyer.main_email && buyer.main_email.length <= 50) {
56
+ tinyCustomer.email = buyer.main_email;
57
+ }
58
+ if (shippingAddress) {
59
+ parseAddress(billingAddress || shippingAddress, tinyCustomer);
60
+ }
61
+ const phone = buyer.phones && buyer.phones[0];
62
+ if (phone) {
63
+ tinyCustomer.fone = phone.country_code ? `+${phone.country_code} ` : '';
64
+ tinyCustomer.fone += phone.number;
65
+ }
66
+ tinyOrder.cliente = tinyCustomer;
67
+ } else {
68
+ tinyOrder.cliente = {
69
+ nome: `Comprador de #${orderRef}`,
70
+ };
71
+ }
72
+
73
+ if (shippingAddress && billingAddress) {
74
+ tinyOrder.endereco_entrega = {};
75
+ parseAddress(shippingAddress, tinyOrder.endereco_entrega);
76
+ if (shippingAddress.name) {
77
+ tinyOrder.endereco_entrega.nome_destinatario = shippingAddress.name.substring(0, 60);
78
+ }
79
+ }
80
+
81
+ if (order.items) {
82
+ order.items.forEach((item) => {
83
+ if (item.quantity) {
84
+ const itemRef = (item.sku || item._id || Math.random().toString()).substring(0, 30);
85
+ tinyOrder.itens.push({
86
+ item: {
87
+ codigo: itemRef,
88
+ descricao: item.name ? item.name.substring(0, 120) : itemRef,
89
+ unidade: 'UN',
90
+ quantidade: item.quantity,
91
+ valor_unitario: ecomUtils.price(item),
92
+ },
93
+ });
94
+ }
95
+ });
96
+ }
97
+
98
+ if (order.payment_method_label) {
99
+ tinyOrder.meio_pagamento = order.payment_method_label;
100
+ }
101
+ if (transaction) {
102
+ switch (transaction.payment_method.code) {
103
+ case 'credit_card':
104
+ tinyOrder.forma_pagamento = 'credito';
105
+ break;
106
+ case 'banking_billet':
107
+ tinyOrder.forma_pagamento = 'boleto';
108
+ break;
109
+ case 'account_deposit':
110
+ tinyOrder.forma_pagamento = 'deposito';
111
+ break;
112
+ case 'online_debit':
113
+ case 'debit_card':
114
+ case 'balance_on_intermediary':
115
+ tinyOrder.forma_pagamento = 'debito';
116
+ break;
117
+ default:
118
+ tinyOrder.forma_pagamento = 'multiplas';
119
+ }
120
+ if (!tinyOrder.meio_pagamento && transaction.payment_method.name) {
121
+ tinyOrder.meio_pagamento = transaction.payment_method.name.substring(0, 100);
122
+ }
123
+ }
124
+
125
+ if (order.shipping_method_label) {
126
+ tinyOrder.forma_frete = order.shipping_method_label;
127
+ }
128
+ if (shippingLine) {
129
+ tinyOrder.forma_envio = 'X';
130
+ if (shippingLine.app) {
131
+ const { carrier } = shippingLine.app;
132
+ if (carrier) {
133
+ if (/correios/i.test(carrier)) {
134
+ tinyOrder.forma_envio = 'C';
135
+ } else if (/b2w/i.test(carrier)) {
136
+ tinyOrder.forma_envio = 'B';
137
+ } else if (/mercado envios/i.test(carrier)) {
138
+ tinyOrder.forma_envio = 'M';
139
+ } else {
140
+ tinyOrder.forma_envio = 'T';
141
+ }
142
+ }
143
+ if (
144
+ (!tinyOrder.forma_envio || tinyOrder.forma_envio === 'X' || tinyOrder.forma_envio === 'T')
145
+ && shippingLine.app.service_name && /(pac|sedex)/i.test(shippingLine.app.service_name)
146
+ ) {
147
+ tinyOrder.forma_envio = 'C';
148
+ }
149
+ if (!tinyOrder.forma_frete && shippingLine.app.label) {
150
+ tinyOrder.forma_frete = shippingLine.app.label;
151
+ }
152
+ }
153
+ } else {
154
+ tinyOrder.forma_envio = 'S';
155
+ }
156
+
157
+ const { amount } = order;
158
+ if (amount) {
159
+ if (typeof amount.freight === 'number') {
160
+ tinyOrder.valor_frete = amount.freight;
161
+ if (amount.tax) {
162
+ tinyOrder.valor_frete += amount.tax;
163
+ }
164
+ if (amount.extra) {
165
+ tinyOrder.valor_frete += amount.extra;
166
+ }
167
+ }
168
+ if (amount.discount) {
169
+ tinyOrder.valor_desconto = amount.discount;
170
+ }
171
+ }
172
+
173
+ if (order.notes) {
174
+ tinyOrder.obs = order.notes.substring(0, 100);
175
+ }
176
+ if (order.extra_discount && order.extra_discount.discount_coupon) {
177
+ tinyOrder.obs = `${(tinyOrder.obs || '')} - ${order.extra_discount.discount_coupon}`
178
+ .substring(0, 100);
179
+ }
180
+ if (order.staff_notes) {
181
+ tinyOrder.obs_internas = order.staff_notes.substring(0, 100);
182
+ }
183
+
184
+ if (appData.tiny_order_data && typeof appData.tiny_order_data === 'object') {
185
+ Object.keys(appData.tiny_order_data).forEach((field) => {
186
+ let value = appData.tiny_order_data[field];
187
+ switch (value) {
188
+ case undefined:
189
+ case '':
190
+ case null:
191
+ break;
192
+ default:
193
+ if (typeof value === 'string') {
194
+ value = value.trim();
195
+ if (value) {
196
+ tinyOrder[field] = value;
197
+ }
198
+ } else {
199
+ tinyOrder[field] = value;
200
+ }
201
+ }
202
+ });
203
+ }
204
+ return tinyOrder;
205
+ };