front/modules/tax/avalara.js

/* ============================================================================ *\
|| ########################################################################## ||
|| # Auction Software Marketplace          Release: 0.6   Build 0.7         # ||
|| # ---------------------------------------------------------------------- # ||
|| # License # 35YAHCNR9344X6O666C123AB                                     # ||
|| # ---------------------------------------------------------------------- # ||
|| # Copyright ©2014–2021 Develop Scripts LLC. All Rights Reserved          # ||
|| # This file may not be redistributed in whole or significant part.       # ||
|| # ------------- AUCTION SOFTWARE IS NOT FREE SOFTWARE ------------------ # ||
|| # http://www.auctionsoftwaremarketplace.com|support@auctionsoftware.com  # ||
|| # ---------------------------------------------------------------------- # ||
|| ########################################################################## ||
\* ============================================================================ */

const { default: axios } = require('axios')
const userModule = require('../user').default
const productModule = require('../product').default
const userController = require('../../controllers/user')
const avalaraTaxModule = require('./avalaramodule').default

let avatax = {}
if (require('config').has('Avatax')) {
    avatax = require('config').get('Avatax')
}
/**
 * @class class to handle deposit functions
 */
class Avatax {
    constructor(config = avatax) {
        /* eslint new-cap: ["error", { "properties": false }] */
        this.secret = new Buffer.from(`${config.username}:${config.password}`).toString('base64')
        this.header = {
            headers: { Authorization: `Basic ${this.secret}`, 'Content-Type': 'application/json' },
        }
        this.baseUrl = avatax.base_url
        this.taxCode = 'P0000000'
    }

    /**
     * shipping and other product detail handling
     * @param {object} item item
     * @returns {promise} object
     */
    async findUserAndProductDetails(item) {
        return new Promise(async (reslove) => {
            // find user address
            const [user] = await Promise.all([userController.findUserAddress(item)])
            ;[this.address] = user

            if (global.configColumns.custom_projects.enabled) {
                const [[productInfo]] = await Promise.all([
                    productModule.commonselectparenttable(
                        'tax_code',
                        'project_id',
                        item.id.toString(),
                        global.configColumns.custom_projects,
                    ),
                ])
                this.taxCode = productInfo.tax_code ? productInfo.tax_code : this.taxCode
            }

            reslove({ address: this.address, taxCode: this.taxCode })
        })
    }
    /**
     * calculate tax
     * @param {object} item item
     * @param {object} config configurations
     * @returns {any} tax
     */
    async calculateTax({ item, config = {} }) {
        // check record in database
        const [taxRecord] = await Promise.all([productModule.getAvatax(item)])
        if (taxRecord && taxRecord.length) return taxRecord[0].tax_amount
        const { address, taxCode } = await this.findUserAndProductDetails(item)
        const payload = {
            lines: [
                {
                    quantity: item.qty,
                    amount: item.wprice || item.per_total,
                    taxCode,
                    description: item.description || 'Kirpa tax calculation',
                },
            ],
            type: 'SalesInvoice',
            date: new Date(),
            customerCode: 'KIRPA',
            addresses: {
                singleLocation: {
                    postalCode: address.zip,
                },
            },
            commit: true,
            currencyCode: 'USD',
            description: 'Calculate tax for kirpa',
        }

        const response = await this.send('/api/v2/transactions/create', payload, config)
        const tax = response && response.totalTax ? response.totalTax : 0
        if (tax) await productModule.insertAvatax(item, tax, address)
        return tax
    }
    /**
     * adddress verification
     * @param {object} payload request data
     * @param {object} config configurations
     */
    async addressVerification(
        payload = { line1: '', line2: '', city: '', region: '', country: 'US', postalCode: '' },
        config,
    ) {
        return this.send('/api/v2/addresses/resolve', payload, config)
    }

    async send(url, payload, config = {}) {
        const configs = { ...this.header, ...config }
        const uri = this.baseUrl + url

        const options = {
            ...configs,
            method: 'post',
            data: payload,
            url: uri,
        }

        const [log] = await Promise.all([avalaraTaxModule.insertLog(payload, options, uri)])
        const responseUpdate = {
            id: log.insertId,
        }

        return new Promise((reslove) => {
            axios(options)
                .then(({ status, data }) => {
                    responseUpdate.response = data
                    if (status === 201 || status === 200) {
                        responseUpdate.status = 'success'
                        avalaraTaxModule.updateLog(responseUpdate)
                        reslove(data)
                    } else {
                        responseUpdate.status = 'error'
                        avalaraTaxModule.updateLog(responseUpdate)
                        reslove(null)
                    }
                })
                .catch((error) => {
                    responseUpdate.response = error
                    responseUpdate.status = 'error'
                    avalaraTaxModule.updateLog(responseUpdate)
                    console.log(error)
                    reslove(null)
                })
        })
    }
}

module.exports.default = Avatax