@cloudcommerce/app-tiny-erp 0.0.59 → 0.0.60

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 +32 -6
  2. package/lib/event-to-tiny.js +111 -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 +94 -0
  15. package/lib/integration/import-order-from-tiny.js.map +1 -0
  16. package/lib/integration/import-product-from-tiny.js +169 -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 +135 -0
  35. package/lib/tiny-webhook.js.map +1 -0
  36. package/package.json +13 -6
  37. package/src/event-to-tiny.ts +129 -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 +104 -0
  44. package/src/integration/import-product-from-tiny.ts +174 -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 +143 -0
  54. package/src/firebase.ts +0 -0
@@ -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
+ };
@@ -0,0 +1,215 @@
1
+ import type { Products } from '@cloudcommerce/types';
2
+ import logger from 'firebase-functions/lib/logger';
3
+ import axios from 'axios';
4
+ import FormData from 'form-data';
5
+ import ecomUtils from '@ecomplus/utils';
6
+ import getEnv from '@cloudcommerce/firebase/lib/env';
7
+
8
+ const removeAccents = (str: string) => str.replace(/áàãâÁÀÃÂ/g, 'a')
9
+ .replace(/éêÉÊ/g, 'e')
10
+ .replace(/óõôÓÕÔ/g, 'o')
11
+ .replace(/íÍ/g, 'e')
12
+ .replace(/úÚ/g, 'u')
13
+ .replace(/çÇ/g, 'c');
14
+
15
+ const tryImageUpload = (originImgUrl: string, product: Products) => new Promise((resolve) => {
16
+ const {
17
+ storeId,
18
+ apiAuth: {
19
+ authenticationId,
20
+ apiKey,
21
+ },
22
+ } = getEnv();
23
+ axios.get(originImgUrl, {
24
+ responseType: 'arraybuffer',
25
+ }).then(({ data }) => {
26
+ const form = new FormData();
27
+ form.append('file', Buffer.from(data), originImgUrl.replace(/.*\/([^/]+)$/, '$1'));
28
+
29
+ return axios.post(`https://apx-storage.e-com.plus/${storeId}/api/v1/upload.json`, form, {
30
+ headers: {
31
+ ...form.getHeaders(),
32
+ 'X-Store-ID': storeId,
33
+ 'X-My-ID': authenticationId,
34
+ 'X-API-Key': apiKey,
35
+ },
36
+ }).then(({ data, status }) => {
37
+ if (data.picture) {
38
+ Object.keys(data.picture).forEach((imgSize) => {
39
+ if (data.picture[imgSize]) {
40
+ if (!data.picture[imgSize].url) {
41
+ delete data.picture[imgSize];
42
+ return;
43
+ }
44
+ if (data.picture[imgSize].size !== undefined) {
45
+ delete data.picture[imgSize].size;
46
+ }
47
+ data.picture[imgSize].alt = `${product.name} (${imgSize})`;
48
+ }
49
+ });
50
+ if (Object.keys(data.picture).length) {
51
+ return resolve({
52
+ _id: ecomUtils.randomObjectId(),
53
+ ...data.picture,
54
+ });
55
+ }
56
+ }
57
+ const err: any = new Error('Unexpected Storage API response');
58
+ err.response = { data, status };
59
+ throw err;
60
+ });
61
+ })
62
+
63
+ .catch((err) => {
64
+ logger.error(err);
65
+ resolve({
66
+ _id: ecomUtils.randomObjectId(),
67
+ normal: {
68
+ url: originImgUrl,
69
+ alt: product.name,
70
+ },
71
+ });
72
+ });
73
+ }).then((picture) => {
74
+ if (product && product.pictures) {
75
+ // @ts-ignore
76
+ product.pictures.push(picture);
77
+ }
78
+ return picture;
79
+ });
80
+
81
+ export default (tinyProduct, isNew = true) => new Promise((resolve) => {
82
+ const sku = tinyProduct.codigo || String(tinyProduct.id);
83
+ const name = (tinyProduct.nome || sku).trim();
84
+ const product: Omit<Products, '_id'| 'store_id' | 'created_at' | 'updated_at'> = {
85
+ available: tinyProduct.situacao === 'A',
86
+ sku,
87
+ name,
88
+ cost_price: tinyProduct.preco_custo,
89
+ price: tinyProduct.preco_promocional || tinyProduct.preco,
90
+ base_price: tinyProduct.preco,
91
+ body_html: tinyProduct.descricao_complementar,
92
+ };
93
+
94
+ if (isNew) {
95
+ product.slug = removeAccents(name.toLowerCase())
96
+ .replace(/\s+/g, '-')
97
+ .replace(/[^a-z0-9-_./]/g, '');
98
+ if (!/[a-z0-9]/.test(product.slug.charAt(0))) {
99
+ product.slug = `p-${product.slug}`;
100
+ }
101
+ }
102
+ if (tinyProduct.garantia) {
103
+ product.warranty = tinyProduct.garantia;
104
+ }
105
+ if (tinyProduct.unidade_por_caixa) {
106
+ product.min_quantity = Number(tinyProduct.unidade_por_caixa);
107
+ }
108
+ if (tinyProduct.ncm) {
109
+ product.mpn = [tinyProduct.ncm];
110
+ }
111
+ const validateGtin = (gtin) => {
112
+ return typeof gtin === 'string' && /^([0-9]{8}|[0-9]{12,14})$/.test(gtin);
113
+ };
114
+ if (validateGtin(tinyProduct.gtin)) {
115
+ product.gtin = [tinyProduct.gtin];
116
+ if (validateGtin(tinyProduct.gtin_embalagem)) {
117
+ product.gtin.push(tinyProduct.gtin_embalagem);
118
+ }
119
+ }
120
+
121
+ const weight = tinyProduct.peso_bruto || tinyProduct.peso_liquido;
122
+ if (weight > 0) {
123
+ product.weight = {
124
+ unit: 'kg',
125
+ value: parseFloat(weight),
126
+ };
127
+ }
128
+ [
129
+ ['largura', 'width'],
130
+ ['altura', 'height'],
131
+ ['comprimento', 'length'],
132
+ ].forEach(([lado, side]) => {
133
+ const dimension = tinyProduct[`${lado}_embalagem`] || tinyProduct[`${lado}Embalagem`];
134
+ if (dimension > 0) {
135
+ if (!product.dimensions) {
136
+ product.dimensions = {};
137
+ }
138
+ product.dimensions[side] = {
139
+ unit: 'cm',
140
+ value: parseFloat(dimension),
141
+ };
142
+ }
143
+ });
144
+
145
+ if (isNew) {
146
+ if (Array.isArray(tinyProduct.variacoes) && tinyProduct.variacoes.length) {
147
+ product.variations = [];
148
+ tinyProduct.variacoes.forEach(({ variacao }) => {
149
+ const { codigo, preco, grade } = variacao;
150
+ if (grade && typeof grade === 'object') {
151
+ const specifications = {};
152
+ const specTexts: string[] = [];
153
+ Object.keys(grade).forEach((tipo) => {
154
+ if (grade[tipo]) {
155
+ const gridId = removeAccents(tipo.toLowerCase())
156
+ .replace(/\s+/g, '_')
157
+ .replace(/[^a-z0-9_]/g, '')
158
+ .substring(0, 30)
159
+ .padStart(2, 'i');
160
+ const spec: Record<string, string> = {
161
+ text: grade[tipo],
162
+ };
163
+ specTexts.push(spec.text);
164
+ if (gridId !== 'colors') {
165
+ spec.value = removeAccents(spec.text.toLowerCase()).substring(0, 100);
166
+ }
167
+ specifications[gridId] = [spec];
168
+ }
169
+ });
170
+
171
+ if (specTexts.length) {
172
+ product.variations?.push({
173
+ _id: ecomUtils.randomObjectId(),
174
+ name: `${name} / ${specTexts.join(' / ')}`.substring(0, 100),
175
+ sku: codigo,
176
+ specifications,
177
+ price: parseFloat(preco || 0),
178
+ });
179
+ }
180
+ }
181
+ });
182
+ }
183
+
184
+ if (Array.isArray(tinyProduct.imagens_externas)) {
185
+ product.pictures = [];
186
+ tinyProduct.imagens_externas.forEach((imagemExterna) => {
187
+ if (imagemExterna.imagem_externa) {
188
+ const { url } = imagemExterna.imagem_externa;
189
+ if (url) {
190
+ product.pictures?.push({
191
+ normal: { url },
192
+ _id: ecomUtils.randomObjectId(),
193
+ });
194
+ }
195
+ }
196
+ });
197
+ }
198
+
199
+ if (tinyProduct.anexos) {
200
+ if (!product.pictures) {
201
+ product.pictures = [];
202
+ }
203
+ const promises: Promise<any>[] = [];
204
+ tinyProduct.anexos.forEach(({ anexo }) => {
205
+ if (typeof anexo === 'string' && anexo.startsWith('http')) {
206
+ promises.push(tryImageUpload(anexo, product as Products));
207
+ }
208
+ });
209
+ Promise.all(promises).then(() => resolve(product));
210
+ return;
211
+ }
212
+ }
213
+
214
+ resolve(product);
215
+ });
@@ -0,0 +1,138 @@
1
+ /* eslint-disable no-nested-ternary */
2
+ import type { Products } from '@cloudcommerce/types';
3
+ import ecomUtils from '@ecomplus/utils';
4
+
5
+ export default async (product: Products, originalTinyProduct, appData) => {
6
+ const hasVariations = product.variations && product.variations.length;
7
+ const tinyProduct: Record<string, any> = {
8
+ sequencia: 1,
9
+ origem: 0,
10
+ situacao: product.available && product.visible ? 'A' : 'I',
11
+ tipo: 'P',
12
+ classe_produto: hasVariations ? 'V' : 'S',
13
+ codigo: product.sku,
14
+ nome: ecomUtils.name(product, 'pt_br').substring(0, 120),
15
+ unidade: originalTinyProduct && originalTinyProduct.unidade
16
+ ? originalTinyProduct.unidade
17
+ : product.measurement && product.measurement.unit !== 'oz' && product.measurement.unit !== 'ct'
18
+ ? product.measurement.unit.substring(0, 3).toUpperCase()
19
+ : 'UN',
20
+ };
21
+
22
+ if (ecomUtils.onPromotion(product)) {
23
+ tinyProduct.preco = product.base_price;
24
+ tinyProduct.preco_promocional = ecomUtils.price(product);
25
+ } else {
26
+ tinyProduct.preco = product.price;
27
+ }
28
+ if (product.cost_price) {
29
+ tinyProduct.preco_custo = product.cost_price;
30
+ }
31
+ if (product.min_quantity) {
32
+ tinyProduct.unidade_por_caixa = product.min_quantity < 1000
33
+ ? String(product.min_quantity) : '999';
34
+ }
35
+
36
+ if (product.short_description) {
37
+ tinyProduct.descricao_complementar = product.short_description;
38
+ }
39
+ if (product.warranty) {
40
+ tinyProduct.garantia = product.warranty.substring(0, 20);
41
+ }
42
+
43
+ if (product.mpn && product.mpn.length) {
44
+ [tinyProduct.ncm] = product.mpn;
45
+ }
46
+ if (product.gtin && product.gtin.length) {
47
+ [tinyProduct.gtin] = product.gtin;
48
+ if (product.gtin[1]) {
49
+ // eslint-disable-next-line prefer-destructuring
50
+ tinyProduct.gtin_embalagem = product.gtin[1];
51
+ }
52
+ }
53
+
54
+ if (product.weight && product.weight.value) {
55
+ tinyProduct.peso_bruto = product.weight.value;
56
+ if (product.weight.unit === 'mg') {
57
+ tinyProduct.peso_bruto /= 1000000;
58
+ } else if (product.weight.unit === 'g') {
59
+ tinyProduct.peso_bruto /= 1000;
60
+ }
61
+ }
62
+ const { dimensions } = product;
63
+ if (dimensions) {
64
+ Object.keys(dimensions).forEach((side) => {
65
+ if (dimensions[side] && dimensions[side].value) {
66
+ let field = side === 'width' ? 'largura'
67
+ : side === 'height' ? 'altura'
68
+ : 'comprimento';
69
+ field += '_embalagem';
70
+ tinyProduct[field] = dimensions[side].value;
71
+ if (dimensions[side].unit === 'mm') {
72
+ tinyProduct[field] *= 0.1;
73
+ } else if (dimensions[side].unit === 'm') {
74
+ tinyProduct[field] *= 100;
75
+ }
76
+ }
77
+ });
78
+ }
79
+
80
+ if (product.brands && product.brands.length) {
81
+ tinyProduct.marca = product.brands[0].name;
82
+ }
83
+ if (product.category_tree) {
84
+ tinyProduct.categoria = product.category_tree.replace(/\s?>\s?/g, ' >> ');
85
+ } else if (product.categories && product.categories.length) {
86
+ tinyProduct.categoria = product.categories.map(({ name }) => name).join(' >> ');
87
+ }
88
+
89
+ if (product.pictures && product.pictures.length) {
90
+ tinyProduct.anexos = [];
91
+ product.pictures.forEach(({ zoom, big, normal }) => {
92
+ const img = (zoom || big || normal) as { url: string };
93
+ if (img) {
94
+ tinyProduct.anexos.push({
95
+ anexo: img.url,
96
+ });
97
+ }
98
+ });
99
+ }
100
+
101
+ if (originalTinyProduct) {
102
+ tinyProduct.id = originalTinyProduct.id;
103
+ if (!appData.update_price) {
104
+ ['preco', 'preco_promocional', 'preco_custo'].forEach((field) => {
105
+ if (typeof originalTinyProduct[field] === 'number') {
106
+ tinyProduct[field] = originalTinyProduct[field];
107
+ }
108
+ });
109
+ }
110
+ } else {
111
+ tinyProduct.estoque_atual = product.quantity || 0;
112
+ }
113
+
114
+ if (hasVariations) {
115
+ tinyProduct.variacoes = [];
116
+ product.variations?.forEach((variation, i) => {
117
+ const tinyVariation: Record<string, any> = {
118
+ codigo: variation.sku || `${product.sku}-${(i + 1)}`,
119
+ grade: {},
120
+ };
121
+ if (!originalTinyProduct) {
122
+ tinyVariation.estoque_atual = variation.quantity || 0;
123
+ }
124
+ Object.keys(variation.specifications).forEach((gridId) => {
125
+ const gridOptions = variation.specifications[gridId];
126
+ if (gridOptions && gridOptions.length) {
127
+ gridOptions.forEach(({ text }, i) => {
128
+ tinyVariation.grade[i === 0 ? gridId : `${gridId}_${(i + 1)}`] = text;
129
+ });
130
+ }
131
+ });
132
+ tinyProduct.variacoes.push({
133
+ variacao: tinyVariation,
134
+ });
135
+ });
136
+ }
137
+ return tinyProduct;
138
+ };
@@ -0,0 +1,35 @@
1
+ import type { Orders } from '@cloudcommerce/types';
2
+
3
+ export default (situacao: string) => {
4
+ let financialStatus: Exclude<Orders['financial_status'], undefined>['current'] | undefined;
5
+ let fulfillmentStatus: Exclude<Orders['fulfillment_status'], undefined>['current'] | undefined;
6
+ switch (situacao) {
7
+ case 'aprovado':
8
+ financialStatus = 'paid';
9
+ break;
10
+ case 'preparando_envio':
11
+ case 'preparando envio':
12
+ fulfillmentStatus = 'in_separation';
13
+ break;
14
+ case 'faturado':
15
+ case 'faturado (atendido)':
16
+ case 'atendido':
17
+ fulfillmentStatus = 'invoice_issued';
18
+ break;
19
+ case 'pronto_envio':
20
+ case 'pronto para envio':
21
+ fulfillmentStatus = 'ready_for_shipping';
22
+ break;
23
+ case 'enviado':
24
+ fulfillmentStatus = 'shipped';
25
+ break;
26
+ case 'entregue':
27
+ fulfillmentStatus = 'delivered';
28
+ break;
29
+ case 'cancelado':
30
+ financialStatus = 'voided';
31
+ break;
32
+ default:
33
+ }
34
+ return { financialStatus, fulfillmentStatus };
35
+ };
@@ -0,0 +1,42 @@
1
+ import type { Orders } from '@cloudcommerce/types';
2
+
3
+ export default (order: Orders) => {
4
+ const financialStatus = order.financial_status && order.financial_status.current;
5
+ switch (financialStatus) {
6
+ case 'pending':
7
+ case 'under_analysis':
8
+ case 'unknown':
9
+ case 'authorized':
10
+ case 'partially_paid':
11
+ return 'aberto';
12
+ case 'voided':
13
+ case 'refunded':
14
+ case 'in_dispute':
15
+ case 'unauthorized':
16
+ return 'cancelado';
17
+ default:
18
+ }
19
+
20
+ switch (order.fulfillment_status && order.fulfillment_status.current) {
21
+ case 'in_production':
22
+ case 'in_separation':
23
+ return 'preparando_envio';
24
+ case 'invoice_issued':
25
+ return 'faturado';
26
+ case 'ready_for_shipping':
27
+ return 'pronto_envio';
28
+ case 'shipped':
29
+ case 'partially_shipped':
30
+ return 'enviado';
31
+ case 'delivered':
32
+ return 'entregue';
33
+ case 'returned':
34
+ return 'cancelado';
35
+ default:
36
+ }
37
+
38
+ if (financialStatus === 'paid') {
39
+ return 'aprovado';
40
+ }
41
+ return 'aberto';
42
+ };
@@ -0,0 +1,52 @@
1
+ import axios, { AxiosRequestConfig } from 'axios';
2
+
3
+ export default (
4
+ url: string,
5
+ body: Record<string, any>,
6
+ token = process.env.TINY_ERP_TOKEN,
7
+ options: AxiosRequestConfig = {},
8
+ ) => {
9
+ // https://www.tiny.com.br/ajuda/api/api2
10
+ let data = `token=${token}&formato=JSON`;
11
+ if (body) {
12
+ Object.keys(body).forEach((field) => {
13
+ if (body[field]) {
14
+ switch (typeof body[field]) {
15
+ case 'object':
16
+ data += `&${field}=${JSON.stringify(body[field])}`;
17
+ break;
18
+ case 'string':
19
+ case 'number':
20
+ data += `&${field}=${body[field]}`;
21
+ break;
22
+ default:
23
+ }
24
+ }
25
+ });
26
+ }
27
+
28
+ return axios.post(url, data, {
29
+ baseURL: 'https://api.tiny.com.br/api2/',
30
+ timeout: 30000,
31
+ ...options,
32
+ })
33
+ .then((response) => {
34
+ const { retorno } = response.data;
35
+ if (retorno.status === 'Erro') {
36
+ const err: any = new Error('Tiny error response');
37
+ const tinyErrorCode = parseInt(retorno.codigo_erro, 10);
38
+ if (tinyErrorCode <= 2) {
39
+ response.status = 401;
40
+ } else if (tinyErrorCode === 6) {
41
+ response.status = 503;
42
+ } else if (tinyErrorCode === 20) {
43
+ response.status = 404;
44
+ }
45
+ err.response = response;
46
+ err.config = response.config;
47
+ err.request = response.request;
48
+ throw err;
49
+ }
50
+ return retorno;
51
+ });
52
+ };