@cloudcommerce/app-correios 0.30.0 → 0.31.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.
@@ -0,0 +1,84 @@
1
+ import logger from 'firebase-functions/logger';
2
+ import { newCorreios } from './utils/correios-axios.mjs';
3
+
4
+ const calculate = async ({
5
+ correiosParams,
6
+ serviceCodes = ['03220', '03298'],
7
+ correios,
8
+ timeout = 20000,
9
+ }) => {
10
+ if (!correios) {
11
+ correios = await newCorreios();
12
+ }
13
+ const { nuContrato, nuDR } = correios.$contract;
14
+ if (!(Number(correiosParams.psObjeto) >= 200)) {
15
+ correiosParams.psObjeto = '200';
16
+ }
17
+ if (!(Number(correiosParams.comprimento) >= 15)) {
18
+ correiosParams.comprimento = '15';
19
+ }
20
+ if (!(Number(correiosParams.altura) >= 2)) {
21
+ correiosParams.altura = '2';
22
+ }
23
+ if (!(Number(correiosParams.largura) >= 11)) {
24
+ correiosParams.largura = '11';
25
+ }
26
+ [
27
+ 'psObjeto',
28
+ 'comprimento',
29
+ 'altura',
30
+ 'largura',
31
+ ].forEach((param) => {
32
+ if (typeof correiosParams[param] === 'number') {
33
+ correiosParams[param] = String(Math.round(correiosParams[param]));
34
+ }
35
+ });
36
+ const debugError = (err) => {
37
+ if (err.response) {
38
+ logger.warn('[calculate] failed for', {
39
+ body: err.config.data,
40
+ response: err.response.data,
41
+ status: err.response.status,
42
+ });
43
+ } else {
44
+ logger.error(err);
45
+ }
46
+ throw err;
47
+ };
48
+ const params = serviceCodes
49
+ .filter((coProduto) => typeof coProduto === 'string' && coProduto)
50
+ .map((coProduto, nuRequisicao) => {
51
+ const _params = {
52
+ ...correiosParams,
53
+ coProduto,
54
+ nuContrato,
55
+ nuDR,
56
+ nuRequisicao,
57
+ tpObjeto: '2',
58
+ };
59
+
60
+ return _params;
61
+ });
62
+ return Promise.all([
63
+ correios.post('/preco/v1/nacional', {
64
+ idLote: '1',
65
+ parametrosProduto: params,
66
+ }, { timeout })
67
+ .catch(debugError),
68
+ correios.post('/prazo/v1/nacional', {
69
+ idLote: '1',
70
+ parametrosPrazo: params,
71
+ }, { timeout })
72
+ .catch(debugError),
73
+ ]).then((responses) => {
74
+ responses[1].data.forEach(({ coProduto, ...value }) => {
75
+ const result = responses[0].data.find((resultFind) => resultFind.coProduto === coProduto);
76
+ if (result) {
77
+ Object.assign(result, value);
78
+ }
79
+ });
80
+ return responses[0];
81
+ });
82
+ };
83
+
84
+ export default calculate;
@@ -0,0 +1,135 @@
1
+ import logger from 'firebase-functions/logger';
2
+
3
+ const zipRangeStep = 5000;
4
+
5
+ const weightsKg = [0.5];
6
+ let weight = 0;
7
+
8
+ do {
9
+ // representation in kg
10
+ const lastWeight = weightsKg[weightsKg.length - 1];
11
+ weight = lastWeight + Math.ceil(lastWeight / 10);
12
+
13
+ if (lastWeight < 1) {
14
+ weight = 1;
15
+ } else if (lastWeight >= 40) {
16
+ weight = 50;
17
+ }
18
+ weightsKg.push(weight);
19
+ } while (weight < 50);
20
+
21
+ const weights = weightsKg.map((weightKg) => weightKg * 1000);
22
+
23
+ const parseZipCode = (zipCode) => {
24
+ return (Number(zipCode) - (Number(zipCode) % zipRangeStep) + 1)
25
+ .toString().padStart(8, '0');
26
+ };
27
+
28
+ const findBaseWeight = (findWeight) => {
29
+ for (let i = 0; i < weights.length; i++) {
30
+ if (findWeight <= weights[i]) return weights[i];
31
+ }
32
+ return weights[weights.length - 1];
33
+ };
34
+
35
+ const getDocId = ({
36
+ cepOrigem,
37
+ cepDestino,
38
+ psObjeto,
39
+ nuContrato,
40
+ serviceCodes,
41
+ }) => {
42
+ let id = `${nuContrato}_${cepOrigem}_${cepDestino}_${psObjeto}`;
43
+
44
+ if (serviceCodes && serviceCodes.length) {
45
+ id += serviceCodes.reduce((accumulator, code) => {
46
+ return `${accumulator}_${code}`;
47
+ }, '');
48
+ }
49
+
50
+ return `correiosResults/1_${id}`;
51
+ };
52
+
53
+ const setCredentials = (appData) => {
54
+ if (!process.env.CORREIOS_POSTCARD) {
55
+ const correiosPostCard = appData.correios_contract?.post_card_number;
56
+ if (correiosPostCard && typeof correiosPostCard === 'string') {
57
+ process.env.CORREIOS_POSTCARD = correiosPostCard;
58
+ } else {
59
+ logger.warn('Missing Correios Postcard number');
60
+ }
61
+ }
62
+
63
+ if (!process.env.CORREIOS_USER) {
64
+ const correiosUser = appData.correios_contract?.username;
65
+ if (correiosUser && typeof correiosUser === 'string') {
66
+ process.env.CORREIOS_USER = correiosUser;
67
+ } else {
68
+ logger.warn('Missing Correios Username');
69
+ }
70
+ }
71
+
72
+ if (!process.env.CORREIOS_ACCESS_CODE) {
73
+ const correiosAccessCode = appData.correios_contract?.access_code;
74
+ if (correiosAccessCode && typeof correiosAccessCode === 'string') {
75
+ process.env.CORREIOS_ACCESS_CODE = correiosAccessCode;
76
+ } else {
77
+ logger.warn('Missing Correios Access code');
78
+ }
79
+ }
80
+ };
81
+
82
+ const dataToDoc = (data) => {
83
+ const d = data.map(({
84
+ coProduto,
85
+ pcProduto,
86
+ prazoEntrega,
87
+ txErro,
88
+ }) => {
89
+ const obj = {
90
+ c: coProduto,
91
+ p: pcProduto,
92
+ e: prazoEntrega,
93
+ m: txErro,
94
+ };
95
+ // TODO:
96
+ // set ignoreUndefinedProperties in Firestore
97
+ // no need to delete undefined fields
98
+
99
+ Object.keys(obj).forEach((key) => {
100
+ if (obj[key] === undefined) delete obj[key];
101
+ });
102
+
103
+ return obj;
104
+ });
105
+
106
+ return { d };
107
+ };
108
+
109
+ const docToData = ({ d }) => {
110
+ const data = d.map(({
111
+ c,
112
+ p,
113
+ e,
114
+ m,
115
+ }) => {
116
+ return {
117
+ coProduto: c,
118
+ pcProduto: p,
119
+ prazoEntrega: e,
120
+ txErro: m,
121
+ };
122
+ });
123
+ return data;
124
+ };
125
+
126
+ export {
127
+ zipRangeStep,
128
+ weights,
129
+ parseZipCode,
130
+ findBaseWeight,
131
+ getDocId,
132
+ setCredentials,
133
+ dataToDoc,
134
+ docToData,
135
+ };
@@ -0,0 +1,93 @@
1
+ import { getFirestore, Timestamp } from 'firebase-admin/firestore';
2
+ import axios from 'axios';
3
+
4
+ const baseURL = 'https://api.correios.com.br/';
5
+
6
+ const newCorreiosAuth = async () => {
7
+ const username = process.env.CORREIOS_USER;
8
+ const accessCode = process.env.CORREIOS_ACCESS_CODE;
9
+ if (!username || !accessCode) {
10
+ throw new Error('No Correios contract credentials');
11
+ }
12
+
13
+ return axios.create({
14
+ baseURL,
15
+ timeout: 6000,
16
+ headers: {
17
+ 'Content-Type': 'application/json',
18
+ Authorization: 'Basic '
19
+ + Buffer.from(`${username}:${accessCode}`, 'utf8').toString('base64'),
20
+ },
21
+ });
22
+ };
23
+
24
+ const newCorreios = async () => {
25
+ let token;
26
+ let correiosContract;
27
+ const docRef = getFirestore().doc('correios/contract');
28
+ let correiosAuth;
29
+
30
+ const postCardNumber = process.env.CORREIOS_POSTCARD;
31
+
32
+ if (postCardNumber) {
33
+ correiosAuth = await newCorreiosAuth();
34
+ } else {
35
+ throw Error('Correios postCard number not found');
36
+ }
37
+
38
+ const docSnapshot = await docRef.get();
39
+ if (docSnapshot.exists) {
40
+ const { expiredAt, ...docData } = docSnapshot.data();
41
+ const now = Timestamp.now().toMillis();
42
+ if (now + 9000 < expiredAt.toMillis()) {
43
+ token = docData.token;
44
+ } else {
45
+ correiosAuth = await newCorreiosAuth();
46
+ }
47
+ correiosContract = docData;
48
+ }
49
+
50
+ if (correiosAuth && !token) {
51
+ const { data } = await correiosAuth.post('/token/v1/autentica/cartaopostagem', {
52
+ numero: postCardNumber,
53
+ });
54
+ token = data.token;
55
+ const { cartaoPostagem, cnpj } = data;
56
+ const nuContrato = cartaoPostagem.contrato;
57
+ const nuDR = cartaoPostagem.dr;
58
+ if (!correiosContract) {
59
+ correiosContract = {
60
+ postCardNumber,
61
+ nuContrato,
62
+ nuDR,
63
+ cnpj,
64
+ token,
65
+ cartaoPostagem,
66
+ };
67
+ } else {
68
+ Object.assign(correiosContract, {
69
+ nuContrato,
70
+ nuDR,
71
+ cnpj,
72
+ token,
73
+ cartaoPostagem,
74
+ });
75
+ }
76
+ docRef.set({
77
+ ...correiosContract,
78
+ expiredAt: Timestamp.fromDate(new Date(data.expiraEm)),
79
+ }, { merge: true });
80
+ }
81
+ const correios = axios.create({
82
+ baseURL,
83
+ timeout: 20000,
84
+ headers: {
85
+ 'Content-Type': 'application/json',
86
+ Authorization: `Bearer ${token}`,
87
+ },
88
+ });
89
+ correios.$contract = correiosContract;
90
+ return correios;
91
+ };
92
+
93
+ export { newCorreiosAuth, newCorreios };
package/package.json CHANGED
@@ -1,9 +1,13 @@
1
1
  {
2
2
  "name": "@cloudcommerce/app-correios",
3
3
  "type": "module",
4
- "version": "0.30.0",
4
+ "version": "0.31.0",
5
5
  "description": "E-Com Plus Cloud Commerce app for Correios shipping calculation",
6
- "main": "lib/correios.js",
6
+ "main": "lib/index.js",
7
+ "exports": {
8
+ ".": "./lib/index.js",
9
+ "./fill-database": "./lib-mjs/correios-db.mjs"
10
+ },
7
11
  "repository": {
8
12
  "type": "git",
9
13
  "url": "git+https://github.com/ecomplus/cloud-commerce.git",
@@ -16,15 +20,19 @@
16
20
  },
17
21
  "homepage": "https://github.com/ecomplus/cloud-commerce/tree/main/packages/apps/correios#readme",
18
22
  "dependencies": {
19
- "axios": "^1.6.0",
20
- "xml2js": "0.6.2",
21
- "@cloudcommerce/api": "0.30.0"
23
+ "@google-cloud/pubsub": "^4.0.6",
24
+ "axios": "^1.5.1",
25
+ "firebase-admin": "^11.11.0",
26
+ "firebase-functions": "^4.4.1",
27
+ "@cloudcommerce/api": "0.31.0",
28
+ "@cloudcommerce/firebase": "0.31.0"
22
29
  },
23
30
  "devDependencies": {
24
- "@cloudcommerce/test-base": "0.30.0",
25
- "@cloudcommerce/types": "0.30.0"
31
+ "@cloudcommerce/test-base": "0.31.0",
32
+ "@cloudcommerce/types": "0.31.0"
26
33
  },
27
34
  "scripts": {
28
- "build": "bash ../../../scripts/build-lib.sh"
35
+ "build": "bash ../../../scripts/build-lib.sh",
36
+ "test": "bash scripts/tests.sh"
29
37
  }
30
38
  }
@@ -0,0 +1,11 @@
1
+ #!/bin/bash
2
+
3
+ if [ -z "$CORREIOS_POSTCARD" ]; then
4
+ echo -e "CORREIOS_POSTCARD not set\n"
5
+ elif [ -z "$CORREIOS_USER" ]; then
6
+ echo -e "CORREIOS_USER not set\n"
7
+ elif [ -z "$CORREIOS_ACCESS_CODE" ]; then
8
+ echo -e "CORREIOS_ACCESS_CODE not set\n"
9
+ else
10
+ node --test tests/
11
+ fi
package/src/correios.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  /* eslint-disable import/prefer-default-export */
2
2
  import type { AppModuleBody } from '@cloudcommerce/types';
3
- import handleCalculateShipping from '../lib-mjs/calculate-correios.mjs';
3
+ import '@cloudcommerce/firebase/lib/init';
4
+ import handleCalculateShipping from '../lib-mjs/calculate-shipping.mjs';
4
5
 
5
6
  export const calculateShipping = async (modBody: AppModuleBody) => {
6
7
  return handleCalculateShipping(modBody);
@@ -9,7 +9,7 @@ import {
9
9
  describe('Test Shipping Calculation in the Correios App', async () => {
10
10
  let req;
11
11
  let data;
12
- const appId = 1248;
12
+ const appId = 126334;
13
13
 
14
14
  before(async () => {
15
15
  req = await fetch(`${modulesUrl}/calculate_shipping?app_id=${appId}`, {