@cloudcommerce/app-melhor-envio 0.3.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/events.js +1 -0
- package/lib/functions-lib/database.d.ts +18 -0
- package/lib/functions-lib/database.js +115 -0
- package/lib/functions-lib/database.js.map +1 -0
- package/lib/functions-lib/events-to-melhor-envio.d.ts +7 -0
- package/lib/functions-lib/events-to-melhor-envio.js +112 -0
- package/lib/functions-lib/events-to-melhor-envio.js.map +1 -0
- package/lib/functions-lib/new-label.d.ts +42 -0
- package/lib/functions-lib/new-label.js +185 -0
- package/lib/functions-lib/new-label.js.map +1 -0
- package/lib/functions-lib/order-is-valid.d.ts +5 -0
- package/lib/functions-lib/order-is-valid.js +40 -0
- package/lib/functions-lib/order-is-valid.js.map +1 -0
- package/lib/functions-lib/tracking-codes.d.ts +2 -0
- package/lib/functions-lib/tracking-codes.js +164 -0
- package/lib/functions-lib/tracking-codes.js.map +1 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.js +2 -0
- package/lib/index.js.map +1 -0
- package/lib/melhor-envio-events.d.ts +6 -0
- package/lib/melhor-envio-events.js +17 -0
- package/lib/melhor-envio-events.js.map +1 -0
- package/lib/melhor-envio.d.ts +2 -0
- package/lib/melhor-envio.js +6 -0
- package/lib/melhor-envio.js.map +1 -0
- package/lib-mjs/calculate-melhor-envio.mjs +341 -0
- package/lib-mjs/functions/client-melhor-envio.mjs +14 -0
- package/lib-mjs/functions/error-handling.mjs +62 -0
- package/lib-mjs/functions/new-shipment.mjs +119 -0
- package/package.json +36 -0
- package/src/functions-lib/database.ts +140 -0
- package/src/functions-lib/events-to-melhor-envio.ts +137 -0
- package/src/functions-lib/new-label.ts +214 -0
- package/src/functions-lib/order-is-valid.ts +51 -0
- package/src/functions-lib/tracking-codes.ts +191 -0
- package/src/index.ts +1 -0
- package/src/melhor-envio-events.ts +24 -0
- package/src/melhor-envio.ts +7 -0
- package/tsconfig.json +6 -0
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { getFirestore, Timestamp } from 'firebase-admin/firestore';
|
|
2
|
+
import logger from 'firebase-functions/logger';
|
|
3
|
+
|
|
4
|
+
const firestoreColl = 'melhorEnvioTracking';
|
|
5
|
+
|
|
6
|
+
export type Lable = {
|
|
7
|
+
id: string,
|
|
8
|
+
labelId: string,
|
|
9
|
+
status: string,
|
|
10
|
+
resourceId: string,
|
|
11
|
+
createdAt: Timestamp,
|
|
12
|
+
updateAt?: string,
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const searchLabel = async (resourceId: string): Promise<Lable | null> => new Promise(
|
|
16
|
+
(resolve, reject) => {
|
|
17
|
+
getFirestore().doc(`${firestoreColl}/${resourceId}`)
|
|
18
|
+
.get()
|
|
19
|
+
.then((documentSnapshot) => {
|
|
20
|
+
if (documentSnapshot && documentSnapshot.exists) {
|
|
21
|
+
const data = documentSnapshot.data() as Lable;
|
|
22
|
+
if (data) {
|
|
23
|
+
resolve(data);
|
|
24
|
+
} else {
|
|
25
|
+
resolve(null);
|
|
26
|
+
}
|
|
27
|
+
} else {
|
|
28
|
+
resolve(null);
|
|
29
|
+
}
|
|
30
|
+
})
|
|
31
|
+
.catch((err: any) => {
|
|
32
|
+
reject(err);
|
|
33
|
+
});
|
|
34
|
+
},
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
const saveLabel = (
|
|
38
|
+
labelId: string,
|
|
39
|
+
status: string,
|
|
40
|
+
resourceId: string,
|
|
41
|
+
) => new Promise((resolve) => {
|
|
42
|
+
const documentRef = getFirestore().doc(`${firestoreColl}/${resourceId}`);
|
|
43
|
+
if (documentRef) {
|
|
44
|
+
documentRef.set({
|
|
45
|
+
id: resourceId,
|
|
46
|
+
labelId,
|
|
47
|
+
status,
|
|
48
|
+
resourceId,
|
|
49
|
+
createdAt: Timestamp.now(),
|
|
50
|
+
}).then(() => resolve(true))
|
|
51
|
+
.catch(logger.error);
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
const getAllLabels = (): Promise<Lable[]> => new Promise((resolve, reject) => {
|
|
56
|
+
getFirestore().collection(firestoreColl).get()
|
|
57
|
+
.then((docsRef) => {
|
|
58
|
+
if (docsRef.size > 0) {
|
|
59
|
+
const list: Lable[] = [];
|
|
60
|
+
docsRef.forEach((documentSnapshot) => {
|
|
61
|
+
if (documentSnapshot && documentSnapshot.exists) {
|
|
62
|
+
const data = documentSnapshot.data() as Lable;
|
|
63
|
+
list.push(data);
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
resolve(list);
|
|
67
|
+
} else {
|
|
68
|
+
const err = new Error('No label');
|
|
69
|
+
reject(err);
|
|
70
|
+
}
|
|
71
|
+
})
|
|
72
|
+
.catch(reject);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
const updateLabel = async (
|
|
76
|
+
status: string,
|
|
77
|
+
labelId: string,
|
|
78
|
+
): Promise<boolean> => new Promise((resolve, reject) => {
|
|
79
|
+
getFirestore().collection(firestoreColl)
|
|
80
|
+
.where('labelId', '==', labelId)
|
|
81
|
+
.get()
|
|
82
|
+
.then((docsRef) => {
|
|
83
|
+
if (docsRef.size > 0) {
|
|
84
|
+
docsRef.forEach(async (documentSnapshot) => {
|
|
85
|
+
if (documentSnapshot && documentSnapshot.exists) {
|
|
86
|
+
const documentRef = documentSnapshot.ref;
|
|
87
|
+
await documentRef.set({
|
|
88
|
+
status,
|
|
89
|
+
updateAt: new Date().toISOString(),
|
|
90
|
+
}, { merge: true });
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
resolve(true);
|
|
95
|
+
})
|
|
96
|
+
.catch(reject);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
const deleteLabel = async (id: string): Promise<boolean> => new Promise((resolve, reject) => {
|
|
100
|
+
getFirestore().doc(`${firestoreColl}/${id}`)
|
|
101
|
+
.get()
|
|
102
|
+
.then(async (documentSnapshot) => {
|
|
103
|
+
if (documentSnapshot && documentSnapshot.exists) {
|
|
104
|
+
const data = documentSnapshot.data();
|
|
105
|
+
if (data) {
|
|
106
|
+
await documentSnapshot.ref.delete();
|
|
107
|
+
resolve(true);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
resolve(false);
|
|
111
|
+
})
|
|
112
|
+
.catch(reject);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
const clearLabels = async (): Promise<boolean> => new Promise((resolve, reject) => {
|
|
116
|
+
const deadline = new Date();
|
|
117
|
+
deadline.setMonth(deadline.getMonth() - 2);
|
|
118
|
+
|
|
119
|
+
getFirestore().collection(firestoreColl)
|
|
120
|
+
.where('createdAt', '<=', deadline)
|
|
121
|
+
.get()
|
|
122
|
+
.then((docsRef) => {
|
|
123
|
+
docsRef.docs.forEach((doc) => {
|
|
124
|
+
doc.ref.delete();
|
|
125
|
+
});
|
|
126
|
+
resolve(true);
|
|
127
|
+
})
|
|
128
|
+
.catch(reject);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
const db = {
|
|
132
|
+
searchLabel,
|
|
133
|
+
saveLabel,
|
|
134
|
+
getAllLabels,
|
|
135
|
+
updateLabel,
|
|
136
|
+
deleteLabel,
|
|
137
|
+
clearLabels,
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
export default db;
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import type { Orders } from '@cloudcommerce/types';
|
|
2
|
+
import logger from 'firebase-functions/logger';
|
|
3
|
+
import api from '@cloudcommerce/api';
|
|
4
|
+
import meClient from '../../lib-mjs/functions/client-melhor-envio.mjs';
|
|
5
|
+
import errorHandling from '../../lib-mjs/functions/error-handling.mjs';
|
|
6
|
+
import db from './database';
|
|
7
|
+
import orderIsValid from './order-is-valid';
|
|
8
|
+
import newLabel from './new-label';
|
|
9
|
+
|
|
10
|
+
const ECHO_SKIP = (msg?: string) => logger.warn(msg || 'SKIP');
|
|
11
|
+
|
|
12
|
+
const metafieldName = 'melhor_envio_label_id';
|
|
13
|
+
|
|
14
|
+
const handleApiEvent = async ({
|
|
15
|
+
evName,
|
|
16
|
+
apiEvent,
|
|
17
|
+
apiDoc,
|
|
18
|
+
app,
|
|
19
|
+
}) => {
|
|
20
|
+
const resourceId = apiEvent.resource_id;
|
|
21
|
+
logger.info('>> ', resourceId, ' - Action: ', apiEvent.action);
|
|
22
|
+
const key = `${evName}_${resourceId}`;
|
|
23
|
+
const appData = { ...app.data, ...app.hidden_data };
|
|
24
|
+
if (
|
|
25
|
+
Array.isArray(appData.ignore_events)
|
|
26
|
+
&& appData.ignore_events.includes(evName)
|
|
27
|
+
) {
|
|
28
|
+
logger.info('>> ', key, ' - Ignored event');
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
logger.info(`> Webhook ${resourceId} [${evName}] => ${apiDoc}`);
|
|
32
|
+
|
|
33
|
+
try {
|
|
34
|
+
const trackingCode = await db.searchLabel(resourceId);
|
|
35
|
+
if (!trackingCode) {
|
|
36
|
+
const accessToken = appData.access_token;
|
|
37
|
+
const { sandbox } = appData;
|
|
38
|
+
if (!accessToken) {
|
|
39
|
+
ECHO_SKIP('>> Melhor Envio token not found');
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const order = apiDoc as Orders;
|
|
44
|
+
if (!appData.enabled_label_purchase || !orderIsValid(order, appData)) {
|
|
45
|
+
ECHO_SKIP();
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
const merchantData = await meClient(accessToken, sandbox).get('/')
|
|
49
|
+
.then(({ data }) => data);
|
|
50
|
+
|
|
51
|
+
const label = newLabel(order, appData, merchantData);
|
|
52
|
+
// logger.log(`>> Comprando etiquetas #${storeId} ${order._id}`);
|
|
53
|
+
const { data } = await meClient(accessToken, sandbox).post('/cart', label);
|
|
54
|
+
if (data) {
|
|
55
|
+
logger.log(`>> Etiqueta inserida no carrinho com sucesso #${data.id}`);
|
|
56
|
+
if (appData.enabled_label_checkout) {
|
|
57
|
+
await meClient(accessToken, sandbox).post('/shipment/checkout', { orders: [data.id] });
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// logger.log(`>> Carrinho finalizado com sucesso #${data.id}`);
|
|
61
|
+
await db.saveLabel(data.id, data.status, resourceId);
|
|
62
|
+
|
|
63
|
+
// logger.log(`>> Etiquetas salvas no db para futuros rastreio #${storeId} ${resourceId}`);
|
|
64
|
+
// updates hidden_metafields with the generated tag id
|
|
65
|
+
const bodyHiddenMetaField = {
|
|
66
|
+
namespace: 'app-melhor-envio',
|
|
67
|
+
field: metafieldName,
|
|
68
|
+
value: data.id,
|
|
69
|
+
} as any; // TODO: type amount
|
|
70
|
+
await api.post(`orders/${resourceId}/hidden_metafields`, bodyHiddenMetaField);
|
|
71
|
+
|
|
72
|
+
if (typeof data.tracking === 'string' && data.tracking.length) {
|
|
73
|
+
let shippingLine = order.shipping_lines?.find(({ app: application }) => application
|
|
74
|
+
&& application.service_code && application.service_code.startsWith('ME'));
|
|
75
|
+
|
|
76
|
+
if (!shippingLine && order.shipping_lines) {
|
|
77
|
+
[shippingLine] = order.shipping_lines;
|
|
78
|
+
}
|
|
79
|
+
if (shippingLine) {
|
|
80
|
+
const trackingCodes = shippingLine.tracking_codes || [];
|
|
81
|
+
trackingCodes.push({
|
|
82
|
+
code: data.tracking,
|
|
83
|
+
link: `https://www.melhorrastreio.com.br/rastreio/${data.tracking}`,
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
await api.patch(
|
|
87
|
+
`orders/${resourceId}/shipping_lines/${shippingLine._id}`,
|
|
88
|
+
{ tracking_codes: trackingCodes },
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
logger.log(`>> 'hidden_metafields' do pedido ${order._id} atualizado com sucesso!`);
|
|
92
|
+
// done
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
ECHO_SKIP();
|
|
99
|
+
return null;
|
|
100
|
+
} catch (err: any) {
|
|
101
|
+
if (err.response && err.isAxiosError) {
|
|
102
|
+
const { data } = err.response;
|
|
103
|
+
|
|
104
|
+
if (data) {
|
|
105
|
+
// update order hidden_metafields
|
|
106
|
+
const bodyHiddenMetaField = {
|
|
107
|
+
namespace: 'app-melhor-envio',
|
|
108
|
+
field: 'melhor_envio_label_error',
|
|
109
|
+
value: JSON.stringify(data).substring(0, 255),
|
|
110
|
+
} as any;
|
|
111
|
+
|
|
112
|
+
await api.post(`orders/${resourceId}/hidden_metafields`, bodyHiddenMetaField);
|
|
113
|
+
|
|
114
|
+
if (
|
|
115
|
+
data.error
|
|
116
|
+
=== 'Os documentos (CPFs) dos participantes do frete não podem ser iguais'
|
|
117
|
+
|| data.error.startsWith('Seu saldo de R$ ')
|
|
118
|
+
) {
|
|
119
|
+
// ignoring known ME/merchant errors
|
|
120
|
+
logger.warn(`ME: ${data.error}`);
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
logger.error('BuyLabelErr:', JSON.stringify({
|
|
126
|
+
data,
|
|
127
|
+
status: err.response.status,
|
|
128
|
+
config: err.response.config,
|
|
129
|
+
}, null, 4));
|
|
130
|
+
} else {
|
|
131
|
+
errorHandling(err);
|
|
132
|
+
}
|
|
133
|
+
return err;
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
export default handleApiEvent;
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import type { Orders } from '@cloudcommerce/types';
|
|
2
|
+
|
|
3
|
+
export default (
|
|
4
|
+
order: Orders,
|
|
5
|
+
appConfig: { [x: string]: any },
|
|
6
|
+
merchantData: { [x: string]: any },
|
|
7
|
+
) => {
|
|
8
|
+
const {
|
|
9
|
+
firstname, lastname, phone, email, address,
|
|
10
|
+
} = merchantData;
|
|
11
|
+
const from: { [x: string]: any } = {
|
|
12
|
+
name: `${firstname} ${lastname}`,
|
|
13
|
+
phone: (phone && phone.phone) || '',
|
|
14
|
+
email,
|
|
15
|
+
};
|
|
16
|
+
if (merchantData.company_document) {
|
|
17
|
+
from.company_document = merchantData.company_document;
|
|
18
|
+
}
|
|
19
|
+
if (merchantData.document) {
|
|
20
|
+
const field = merchantData.document.length > 11 ? 'company_document' : 'document';
|
|
21
|
+
from[field] = merchantData.document;
|
|
22
|
+
}
|
|
23
|
+
if (address) {
|
|
24
|
+
if (typeof address === 'string') {
|
|
25
|
+
from.address = address;
|
|
26
|
+
} else {
|
|
27
|
+
[
|
|
28
|
+
'address',
|
|
29
|
+
'complement',
|
|
30
|
+
'number',
|
|
31
|
+
'district',
|
|
32
|
+
'postal_code',
|
|
33
|
+
'city',
|
|
34
|
+
'state_abbr',
|
|
35
|
+
'country_id',
|
|
36
|
+
].forEach((field) => {
|
|
37
|
+
from[field] = address[field] || '';
|
|
38
|
+
});
|
|
39
|
+
if (typeof address.city === 'object') {
|
|
40
|
+
from.city = address.city.city || '';
|
|
41
|
+
if (address.city.state) {
|
|
42
|
+
from.state_abbr = address.city.state.state_abbr || '';
|
|
43
|
+
from.country_id = (address.city.state.country && address.city.state.country.id) || '';
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const shippingLine = (order.shipping_lines && order.shipping_lines[0]);
|
|
50
|
+
// || {};
|
|
51
|
+
const buyer = order.buyers && order.buyers[0];
|
|
52
|
+
const to = {
|
|
53
|
+
email: '',
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
if (buyer && buyer.main_email) {
|
|
57
|
+
to.email = buyer.main_email;
|
|
58
|
+
if (buyer.registry_type === 'j') {
|
|
59
|
+
Object.assign(to, { company_document: buyer.doc_number || '' });
|
|
60
|
+
} else {
|
|
61
|
+
Object.assign(to, { document: buyer.doc_number || '' });
|
|
62
|
+
}
|
|
63
|
+
if (buyer.phones && buyer.phones[0]) {
|
|
64
|
+
Object.assign(to, { phone: buyer.phones[0].number });
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (shippingLine?.to) {
|
|
69
|
+
const {
|
|
70
|
+
name,
|
|
71
|
+
street,
|
|
72
|
+
complement,
|
|
73
|
+
number,
|
|
74
|
+
borough,
|
|
75
|
+
city,
|
|
76
|
+
zip,
|
|
77
|
+
} = shippingLine.to;
|
|
78
|
+
|
|
79
|
+
Object.assign(to, {
|
|
80
|
+
name,
|
|
81
|
+
address: street || '',
|
|
82
|
+
complement,
|
|
83
|
+
number,
|
|
84
|
+
district: borough || '',
|
|
85
|
+
city,
|
|
86
|
+
state_abbr: shippingLine.to.province_code || '',
|
|
87
|
+
country_id: shippingLine.to.country_code || 'BR',
|
|
88
|
+
postal_code: zip || '',
|
|
89
|
+
note: shippingLine.to.near_to || '',
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
let physicalWeight = 0;
|
|
94
|
+
if (shippingLine?.package) {
|
|
95
|
+
const { weight } = shippingLine.package;
|
|
96
|
+
if (weight && weight.value) {
|
|
97
|
+
switch (weight.unit) {
|
|
98
|
+
case 'kg':
|
|
99
|
+
physicalWeight = weight.value;
|
|
100
|
+
break;
|
|
101
|
+
case 'g':
|
|
102
|
+
physicalWeight = weight.value / 1000;
|
|
103
|
+
break;
|
|
104
|
+
case 'mg':
|
|
105
|
+
physicalWeight = weight.value / 1000000;
|
|
106
|
+
break;
|
|
107
|
+
default:
|
|
108
|
+
break;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const getDimensions = (side: string) => {
|
|
114
|
+
const dimensions = shippingLine?.package && shippingLine.package.dimensions;
|
|
115
|
+
if (dimensions && dimensions[side]) {
|
|
116
|
+
const dimension = dimensions[side];
|
|
117
|
+
if (dimension && dimension.unit) {
|
|
118
|
+
let dimensionValue = 0;
|
|
119
|
+
switch (dimension.unit) {
|
|
120
|
+
case 'cm':
|
|
121
|
+
dimensionValue = dimension.value;
|
|
122
|
+
break;
|
|
123
|
+
case 'm':
|
|
124
|
+
dimensionValue = dimension.value * 100;
|
|
125
|
+
break;
|
|
126
|
+
case 'mm':
|
|
127
|
+
dimensionValue = dimension.value / 10;
|
|
128
|
+
break;
|
|
129
|
+
default:
|
|
130
|
+
break;
|
|
131
|
+
}
|
|
132
|
+
return dimensionValue;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return 0;
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
const products: {
|
|
139
|
+
name: string
|
|
140
|
+
quantity: number
|
|
141
|
+
unitary_value: number
|
|
142
|
+
}[] = [];
|
|
143
|
+
|
|
144
|
+
let insuranceValue = 0;
|
|
145
|
+
if (order.items) {
|
|
146
|
+
order.items.forEach((item) => {
|
|
147
|
+
products.push({
|
|
148
|
+
name: item.name || item.product_id,
|
|
149
|
+
quantity: item.quantity,
|
|
150
|
+
unitary_value: item.price,
|
|
151
|
+
});
|
|
152
|
+
insuranceValue += item.final_price || item.price;
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const options = {
|
|
157
|
+
insurance_value: insuranceValue,
|
|
158
|
+
receipt: (appConfig.receipt),
|
|
159
|
+
own_hand: (appConfig.own_hand),
|
|
160
|
+
collect: false,
|
|
161
|
+
reverse: false,
|
|
162
|
+
platform: 'E-Com Plus',
|
|
163
|
+
tags: [
|
|
164
|
+
{
|
|
165
|
+
tag: `Etiqueta referente ao pedido: #${order.number}`,
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
tag: 'order_id',
|
|
169
|
+
url: order._id,
|
|
170
|
+
},
|
|
171
|
+
],
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
// https://docs.menv.io/?version=latest#9a8f308b-4872-4268-b402-e1b0d64d1f1c
|
|
175
|
+
if (appConfig.enabled_non_commercial) {
|
|
176
|
+
Object.assign(options, { non_commercial: true });
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const invoices = shippingLine?.invoices;
|
|
180
|
+
if (invoices && Array.isArray(invoices) && invoices[0].number) {
|
|
181
|
+
Object.assign(options, {
|
|
182
|
+
invoice: {
|
|
183
|
+
number: invoices[0].number,
|
|
184
|
+
key: invoices[0].access_key,
|
|
185
|
+
},
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const label = {
|
|
190
|
+
from,
|
|
191
|
+
to,
|
|
192
|
+
package: {
|
|
193
|
+
weight: physicalWeight,
|
|
194
|
+
width: getDimensions('width'),
|
|
195
|
+
height: getDimensions('height'),
|
|
196
|
+
length: getDimensions('length'),
|
|
197
|
+
},
|
|
198
|
+
products,
|
|
199
|
+
options,
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
if (shippingLine?.app && shippingLine.app.service_code) {
|
|
203
|
+
Object.assign(label, {
|
|
204
|
+
service: parseInt(shippingLine.app.service_code.replace('ME ', ''), 10),
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
if (appConfig.jadlog_agency) {
|
|
208
|
+
Object.assign(label, {
|
|
209
|
+
agency: appConfig.jadlog_agency,
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
return label;
|
|
214
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { Orders } from '@cloudcommerce/types';
|
|
2
|
+
|
|
3
|
+
export default (order: Orders, appConfig: { [x: string]: any; }) => {
|
|
4
|
+
if (!order.fulfillment_status || !order.shipping_lines) {
|
|
5
|
+
return false;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
// check if the shipping calculation was done with the app-melhor-envio
|
|
9
|
+
const isByMelhorEnvio = Boolean(order.shipping_lines.find((shippingLine) => {
|
|
10
|
+
return shippingLine.custom_fields && shippingLine.custom_fields.find(({ field }) => {
|
|
11
|
+
return field === 'by_melhor_envio';
|
|
12
|
+
});
|
|
13
|
+
}));
|
|
14
|
+
|
|
15
|
+
// checks if the non-commercial shipping option is enabled
|
|
16
|
+
const isNonCommercial = () => (appConfig.enabled_non_commercial);
|
|
17
|
+
|
|
18
|
+
// checks if order is ready to ship by last
|
|
19
|
+
// entry in fulfillments instead of checking fulfillment_status
|
|
20
|
+
|
|
21
|
+
const isReadyForShipping = () => {
|
|
22
|
+
const current = order.fulfillment_status?.current;
|
|
23
|
+
return (current && current === 'ready_for_shipping');
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
// check if nf was issued for the order
|
|
27
|
+
const hasInvoice = () => {
|
|
28
|
+
return Boolean(order.shipping_lines?.find(({ invoices }) => {
|
|
29
|
+
return invoices && invoices[0] && invoices[0].number;
|
|
30
|
+
}));
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const hasLabelBuyIt = () => {
|
|
34
|
+
if (order.hidden_metafields) {
|
|
35
|
+
return order.hidden_metafields
|
|
36
|
+
.find(({ field }) => field === 'melhor_envio_label_id');
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return false;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
if (!isByMelhorEnvio || !isReadyForShipping() || hasLabelBuyIt()) {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (isNonCommercial() || hasInvoice()) {
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return false;
|
|
51
|
+
};
|