Skip to content

Commit

Permalink
feat: supporting warehouses (multi cd) ou calculate shipping and tag …
Browse files Browse the repository at this point in the history
…creation
  • Loading branch information
leomp12 committed Sep 14, 2024
1 parent 558298a commit 161dfaa
Show file tree
Hide file tree
Showing 4 changed files with 157 additions and 47 deletions.
108 changes: 94 additions & 14 deletions functions/ecom.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -141,16 +141,16 @@ const app = {
/**
* JSON schema based fields to be configured by merchant and saved to app `data` / `hidden_data`, such as:
*/
zip: {
schema: {
type: 'string',
maxLength: 9,
pattern: '^[0-9]{5}-?[0-9]{3}$',
title: 'CEP de origem'
},
hide: true
zip: {
schema: {
type: 'string',
maxLength: 9,
pattern: '^[0-9]{5}-?[0-9]{3}$',
title: 'CEP de origem'
},
api_key: {
hide: true
},
api_key: {
schema: {
type: 'string',
maxLength: 600,
Expand Down Expand Up @@ -464,6 +464,89 @@ const app = {
},
hide: true
},
warehouses: {
schema: {
title: 'Armazéns (multi CD)',
description: 'Origens e destinos para cada centro de distribuição',
type: 'array',
maxItems: 30,
items: {
title: 'Centro de distribuição',
type: 'object',
required: ['code', 'zip'],
additionalProperties: false,
properties: {
code: {
type: 'string',
maxLength: 30,
pattern: '^[A-Za-z0-9-_]{2,30}$',
title: 'Código do CD'
},
api_key: {
type: 'string',
maxLength: 600,
title: 'Api Key',
description: 'Api Key da Frete Click específica para o CD, se houver'
},
zip: {
type: 'string',
maxLength: 9,
pattern: '^[0-9]{5}-?[0-9]{3}$',
title: 'CEP de origem',
description: 'Código postal do remetente para cálculo do frete'
},
posting_deadline: {
title: 'Prazo de envio do CD',
type: 'object',
required: ['days'],
additionalProperties: false,
properties: {
days: {
type: 'integer',
minimum: 0,
maximum: 999999,
title: 'Número de dias',
description: 'Dias de prazo para postar os produtos após a compra'
},
working_days: {
type: 'boolean',
default: true,
title: 'Dias úteis'
},
after_approval: {
type: 'boolean',
default: true,
title: 'Após aprovação do pagamento'
}
}
},
zip_range: {
title: 'Faixa de CEP atendida',
type: 'object',
required: [
'min',
'max'
],
properties: {
min: {
type: 'integer',
minimum: 10000,
maximum: 999999999,
title: 'CEP inicial'
},
max: {
type: 'integer',
minimum: 10000,
maximum: 999999999,
title: 'CEP final'
}
}
}
}
}
},
hide: true
},
}
}

Expand All @@ -474,9 +557,7 @@ const app = {

const procedures = []


/** Uncomment and edit code above to configure `triggers` and receive respective `webhooks`:
**/
/** Uncomment and edit code above to configure `triggers` and receive respective `webhooks`: **/
const { baseUri } = require('./__env')

procedures.push({
Expand Down Expand Up @@ -508,8 +589,7 @@ procedures.push({
]
})

/* You may also edit `routes/ecom/webhook.js` to treat notifications properly.
*/
/* You may also edit `routes/ecom/webhook.js` to treat notifications properly. */

exports.app = app

Expand Down
17 changes: 12 additions & 5 deletions functions/lib/freteclick/create-tag.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,16 @@ const getOrCreateCustomer = require('./customer')
const getCompanyId = require('./me')
const client = require('./client')

module.exports = async (order, token, storeId, appData, appSdk) => {
// create new shipping tag with Kangu
// https://portal.kangu.com.br/docs/api/transporte/#/
module.exports = async (order, storeId, appData, appSdk) => {
let token = appData.api_key
const shippingLine = order.shipping_lines[0]
const warehouseCode = shippingLine.warehouse_code
if (warehouseCode) {
const warehouse = appData.warehouses?.find(({ code }) => code === warehouseCode)
if (warehouse.api_key) {
token = warehouse.api_key
}
}
const {
peopleId,
companyId
Expand All @@ -15,9 +22,9 @@ module.exports = async (order, token, storeId, appData, appSdk) => {
const customer = order.buyers?.[0]
const address = order.shipping_lines?.[0]?.to
const retrieve = {
...(order.shipping_lines?.[0]?.from),
...appData.from,
zip: appData.zip
zip: appData.zip,
...(order.shipping_lines?.[0]?.from)
}
const freteClickCustom = (order, field) => {
const shippingCustom = order.shipping_lines[0] && order.shipping_lines[0].custom_fields
Expand Down
77 changes: 50 additions & 27 deletions functions/routes/ecom/modules/calculate-shipping.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ exports.post = async ({ appSdk }, req, res) => {

const selectedStoreId = [51316, 51317]

const token = appData.api_key
let token = appData.api_key
if (!token) {
// must have configured kangu doc number and token
return res.status(409).send({
Expand All @@ -55,9 +55,47 @@ exports.post = async ({ appSdk }, req, res) => {
}

const destinationZip = params.to ? params.to.zip.replace(/\D/g, '') : ''
const originZip = params.from
? params.from.zip.replace(/\D/g, '')
: appData.zip ? appData.zip.replace(/\D/g, '') : ''
const checkZipCode = (rule) => {
// validate rule zip range
if (destinationZip && rule.zip_range) {
const { min, max } = rule.zip_range
return Boolean((!min || destinationZip >= min) && (!max || destinationZip <= max))
}
return true
}

let originZip, warehouseCode
let postingDeadline = appData.posting_deadline
if (params.from) {
originZip = params.from.zip
} else if (Array.isArray(appData.warehouses) && appData.warehouses.length) {
for (let i = 0; i < appData.warehouses.length; i++) {
const warehouse = appData.warehouses[i]
if (warehouse?.zip && checkZipCode(warehouse)) {
const { code } = warehouse
if (!code) continue
if (params.items) {
const itemNotOnWarehouse = params.items.find(({ quantity, inventory }) => {
return inventory && Object.keys(inventory).length && !(inventory[code] >= quantity)
})
if (itemNotOnWarehouse) continue
}
originZip = warehouse.zip
if (warehouse.posting_deadline?.days) {
postingDeadline = warehouse.posting_deadline
}
if (warehouse.api_key) {
token = warehouse.api_key
}
warehouseCode = code
}
}
}

if (!originZip) {
originZip = appData.zip
}
originZip = typeof originZip === 'string' ? originZip.replace(/\D/g, '') : ''

const matchService = (service, name) => {
const fields = ['service_name', 'service_code']
Expand All @@ -69,18 +107,6 @@ exports.post = async ({ appSdk }, req, res) => {
return true
}

const checkZipCode = rule => {
// validate rule zip range
if (destinationZip && rule.zip_range) {
const { min, max } = rule.zip_range
return Boolean((!min || destinationZip >= min) && (!max || destinationZip <= max))
}
return true
}

const destination = destinationZip
const origin = originZip

// search for configured free shipping rule
if (Array.isArray(appData.free_shipping_rules)) {
for (let i = 0; i < appData.free_shipping_rules.length; i++) {
Expand All @@ -102,9 +128,6 @@ exports.post = async ({ appSdk }, req, res) => {
res.send(response)
return
}

/* DO THE STUFF HERE TO FILL RESPONSE OBJECT WITH SHIPPING SERVICES */

if (!originZip) {
// must have configured origin zip code to continue
return res.status(409).send({
Expand Down Expand Up @@ -177,8 +200,8 @@ exports.post = async ({ appSdk }, req, res) => {
const quoteType = 'full'

const body = {
destination,
origin,
destination: destinationZip,
origin: originZip,
productType,
productTotalPrice,
quoteType,
Expand All @@ -195,7 +218,8 @@ exports.post = async ({ appSdk }, req, res) => {
url: '/quotes',
method: 'post',
token,
data: body
data: body,
timeout: (params.is_checkout_confirmation ? 8000 : 4000)
}).then(({ data, status }) => {
let result
if (typeof data === 'string') {
Expand All @@ -209,12 +233,11 @@ exports.post = async ({ appSdk }, req, res) => {
})
}
} else {
result = data && data.response && data.response.data && data.response.data.order && data.response.data.order.quotes
result = data?.response?.data?.order?.quotes
}

if (result && Number(status) === 200 && Array.isArray(result)) {
// success response
console.log('Quote with success', storeId)
const orderId = data.response.data.order.id
let lowestPriceShipping
result.forEach((freteClickService, index) => {
Expand All @@ -241,7 +264,7 @@ exports.post = async ({ appSdk }, req, res) => {
delivery_instructions: 'Gestão Logística via Frete Click',
posting_deadline: {
days: 3,
...appData.posting_deadline
...postingDeadline
},
package: {
weight: {
Expand All @@ -259,13 +282,13 @@ exports.post = async ({ appSdk }, req, res) => {
value: orderId
}
],
warehouse_code: warehouseCode,
flags: ['freteclick-ws', `freteclick-${serviceCode}`.substr(0, 20)]
}
if (!lowestPriceShipping || lowestPriceShipping.price > price) {
lowestPriceShipping = shippingLine
}

if (shippingLine.posting_deadline && shippingLine.posting_deadline.days >= 0) {
if (shippingLine.posting_deadline?.days >= 0) {
shippingLine.posting_deadline.days += parseInt(freteClickService.retrieveDeadline, 10)
}

Expand Down
2 changes: 1 addition & 1 deletion functions/routes/ecom/webhook.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ exports.post = ({ appSdk }, req, res) => {
return res.send(ECHO_SKIP)
}
console.log(`Shipping tag for #${storeId} ${order._id}`)
return createTag(order, api_key, storeId, appData, appSdk)
return createTag(order, storeId, appData, appSdk)
.then(data => {
console.log(`>> Etiqueta Criada Com Sucesso #${storeId} ${resourceId}`, data)
// updates metafields with the generated tag id
Expand Down

0 comments on commit 161dfaa

Please sign in to comment.