Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Preço e prazo de fretes pelos correios #260

Draft
wants to merge 10 commits into
base: main
Choose a base branch
from
68 changes: 68 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@
"react": "16.12.0",
"react-dom": "16.12.0",
"redoc": "^2.0.0-rc.35",
"styled-components": "^5.1.1"
"styled-components": "^5.1.1",
"xml2js": "^0.4.23",
"yup": "^0.29.1"
},
"devDependencies": {
"eslint": "6.8.0",
Expand Down
37 changes: 37 additions & 0 deletions pages/api/shipping/v1/calculate-price.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import microCors from 'micro-cors';
import {
calculateCorreiosShipping,
validateCorreiosShippingData,
ValidationError,
} from '../../../../services/shipping';

const cors = microCors();

async function shippingPrice(request, response) {
if (request.method !== 'POST') {
return response.status(405).json({
message:
'This method is not allowed for this route, try POST with a valid request body',
more_info: 'https://brasilapi.com.br/docs',
});
}

try {
pedrosancao marked this conversation as resolved.
Show resolved Hide resolved
await validateCorreiosShippingData(request.body);
const result = await calculateCorreiosShipping(request.body);
return response.status(200).json(result);
} catch (err) {
if (err instanceof ValidationError) {
return response.status(422).json({
message: 'validation error',
errors: err.errors,
});
}

return response.status(500).json({
message: 'Internal Server Error',
});
}
}

export default cors(shippingPrice);
62 changes: 62 additions & 0 deletions services/shipping/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import axios from 'axios';
import { Parser } from 'xml2js';
import * as Yup from 'yup';

function buildQuery(data) {
return Object.entries(data)
.map(([key, value]) => `${key}=${value}`)
.join('&');
}

function xmlToJson(xml) {
return new Promise((resolve, reject) => {
const xmlParser = new Parser();
xmlParser.parseString(xml, (err, result) => {
if (err) {
return reject(err);
}
return resolve(result);
});
});
}

export function validateCorreiosShippingData(data) {
return Yup.object()
.shape({
nCdEmpresa: Yup.string(),
sDsSenha: Yup.string(),
nCdServico: Yup.string().required(),
sCepOrigem: Yup.string().required(),
sCepDestino: Yup.string().required(),
nVlPeso: Yup.string().required(),
nCdFormato: Yup.string().required(),
nVlComprimento: Yup.string().required(),
nVlAltura: Yup.string().required(),
nVlLargura: Yup.string().required(),
nVlDiametro: Yup.string().required(),
sCdMaoPropria: Yup.string(),
nVlValorDeclarado: Yup.string(),
sCdAvisoRecebimento: Yup.string(),
})
.validate(data, {
abortEarly: false,
stripUnknown: true,
});
}

export async function calculateCorreiosShipping(data) {
const response = await axios({
url: 'http://ws.correios.com.br/calculador/CalcPrecoPrazo.asmx/CalcPreco',
method: 'POST',
// quando `data` é uma string o conteúdo é enviado no corpo da requisição
data: buildQuery(data),
});
const result = await xmlToJson(response.data);
const shippingData = result.cResultado.Servicos[0].cServico[0];
Object.getOwnPropertyNames(shippingData).forEach((property) => {
[shippingData[property]] = shippingData[property];
});
return shippingData;
}

export const { ValidationError } = Yup;
114 changes: 114 additions & 0 deletions tests/shipping-v1.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
const axios = require('axios');

/**
* nCdServico - String
*
* Código do serviço:
*
* 04014 = SEDEX à vista
* 04065 = SEDEX à vista pagamento na entrega
* 04510 = PAC à vista
* 04707 = PAC à vista pagamento na entrega
* 40169 = SEDEX12 ( à vista e a faturar)
* 40215 = SEDEX 10 (à vista e a faturar)
* 40290 = SEDEX Hoje Varejo
*/
describe('/shipping/v1/calculate-price (E2E)', () => {
test('Utilizando payload válido, SEDEX à vista', async () => {
const requestUrl = `${global.SERVER_URL}/api/shipping/v1/calculate-price`;
const response = await axios.post(requestUrl, {
nCdEmpresa: '',
sDsSenha: '',
nCdServico: '04014',
sCepOrigem: '37410220',
sCepDestino: '05311900',
nVlPeso: '1',
nCdFormato: '1',
nVlComprimento: '20',
nVlAltura: '5',
nVlLargura: '15',
nVlDiametro: '0',
sCdMaoPropria: 'n',
nVlValorDeclarado: '100',
sCdAvisoRecebimento: 'n',
});

expect(response.data).toEqual({
Codigo: '4014',
Valor: '59,99',
ValorMaoPropria: '0,00',
ValorAvisoRecebimento: '0,00',
ValorValorDeclarado: '1,59',
Erro: '',
MsgErro: '',
ValorSemAdicionais: '58,40',
});
});

test('Utilizando payload válido, PAC à vista', async () => {
const requestUrl = `${global.SERVER_URL}/api/shipping/v1/calculate-price`;
const response = await axios.post(requestUrl, {
nCdEmpresa: '',
sDsSenha: '',
nCdServico: '04510',
sCepOrigem: '37410220',
sCepDestino: '05311900',
nVlPeso: '1',
nCdFormato: '1',
nVlComprimento: '20',
nVlAltura: '5',
nVlLargura: '15',
nVlDiametro: '0',
sCdMaoPropria: 'n',
nVlValorDeclarado: '100',
sCdAvisoRecebimento: 'n',
});

expect(response.data).toEqual({
Codigo: '4510',
Valor: '30,99',
ValorMaoPropria: '0,00',
ValorAvisoRecebimento: '0,00',
ValorValorDeclarado: '1,59',
Erro: '',
MsgErro: '',
ValorSemAdicionais: '29,40',
});
});

test('Utilizando payload invalido, dois campos faltantes', async () => {
const requestUrl = `${global.SERVER_URL}/api/shipping/v1/calculate-price`;

const response = await axios.post(
requestUrl,
{
nCdEmpresa: '',
sDsSenha: '',
nCdServico: '04510',
sCepOrigem: '',
sCepDestino: '',
nVlPeso: '1',
nCdFormato: '1',
nVlComprimento: '20',
nVlAltura: '5',
nVlLargura: '15',
nVlDiametro: '0',
sCdMaoPropria: 'n',
nVlValorDeclarado: '100',
sCdAvisoRecebimento: 'n',
},
{
validateStatus: (status) => status === 422,
}
);

expect(response.status).toEqual(422);
expect(response.data).toEqual({
message: 'validation error',
errors: [
'sCepOrigem is a required field',
'sCepDestino is a required field',
],
});
});
});