From c584a85e417a0f207f5c6782d96a343c9533614e Mon Sep 17 00:00:00 2001 From: tkostuch Date: Thu, 31 Oct 2019 13:22:39 +0100 Subject: [PATCH 1/4] refactor taxcalc --- src/lib/taxcalc.js | 245 +++++++++++++++++---------------------------- 1 file changed, 92 insertions(+), 153 deletions(-) diff --git a/src/lib/taxcalc.js b/src/lib/taxcalc.js index 3f8c3916..7d08f27c 100644 --- a/src/lib/taxcalc.js +++ b/src/lib/taxcalc.js @@ -1,3 +1,5 @@ +import camelCase from 'lodash-es/camelCase' + function isSpecialPriceActive (fromDate, toDate) { if (!fromDate && !toDate) { return true @@ -20,84 +22,96 @@ function isSpecialPriceActive (fromDate, toDate) { } } +/** + * change object keys to camelCase + */ +function toCamelCase (obj = {}) { + return Object.keys(obj).reduce((accObj, currKey) => { + accObj[camelCase(currKey)] = obj[currKey] + return accObj + }, {}) +} + +/** + * Create price object with base price and tax + * @param price - product price which is used to extract tax value + * @param rateFactor - tax % in decimal + * @param isPriceInclTax - determines if price already include tax + */ +function createSinglePrice (price = 0, rateFactor = 0, isPriceInclTax) { + const _price = isPriceInclTax ? price / (1 + rateFactor) : price + const tax = _price * rateFactor + + return { price: _price, tax } +} + +/** + * assign price and tax to product with proper keys + * @param AssignPriceParams + */ +function assignPrice ({ product, target, price = 0, tax = 0, deprecatedPriceFieldsSupport = true }) { + let priceUpdate = { + [target]: price, + [`${target}_tax`]: tax, + [`${target}_incl_tax`]: price + tax + } + + if (deprecatedPriceFieldsSupport) { + /** BEGIN @deprecated - inconsitent naming kept just for the backward compatibility */ + priceUpdate = Object.assign(priceUpdate, toCamelCase(priceUpdate)) + /** END */ + } + + Object.assign(product, priceUpdate) +} + export function updateProductPrices ({ product, rate, sourcePriceInclTax = false, deprecatedPriceFieldsSupport = false, finalPriceInclTax = true }) { const rate_factor = parseFloat(rate.rate) / 100 - if (finalPriceInclTax) { - product.final_price_incl_tax = parseFloat(product.final_price) // final price does include tax - product.final_price = product.final_price_incl_tax / (1 + rate_factor) - product.final_price_tax = product.final_price_incl_tax - product.final_price - } else { - product.final_price = parseFloat(product.final_price) // final price does include tax - product.final_price_tax = product.final_price * rate_factor - product.final_price_incl_tax = product.final_price + product.final_price_tax + const hasOriginalPrices = ( + product.hasOwnProperty('original_price') && + product.hasOwnProperty('original_final_price') && + product.hasOwnProperty('original_special_price') + ) + // build objects with original price and tax + // for first calculation use `price`, for next one use `original_price` + const priceWithTax = createSinglePrice(parseFloat(product.original_price || product.price), rate_factor, sourcePriceInclTax && !hasOriginalPrices) + const finalPriceWithTax = createSinglePrice(parseFloat(product.original_final_price || product.final_price), rate_factor, finalPriceInclTax && !hasOriginalPrices) + const specialPriceWithTax = createSinglePrice(parseFloat(product.original_special_price || product.special_price), rate_factor, sourcePriceInclTax && !hasOriginalPrices) + + // save original prices + if (!hasOriginalPrices) { + assignPrice({product, target: 'original_price', ...priceWithTax, deprecatedPriceFieldsSupport}) + + product.original_final_price = finalPriceWithTax.price + product.original_special_price = specialPriceWithTax.price } - product.price = parseFloat(product.price) - product.special_price = parseFloat(product.special_price) + + // reset previous calculation + assignPrice({product, target: 'price', ...priceWithTax, deprecatedPriceFieldsSupport}) + assignPrice({product, target: 'final_price', ...finalPriceWithTax, deprecatedPriceFieldsSupport}) + assignPrice({product, target: 'special_price', ...specialPriceWithTax, deprecatedPriceFieldsSupport}) if (product.final_price) { if (product.final_price < product.price) { // compare the prices with the product final price if provided; final prices is used in case of active catalog promo rules for example if (product.final_price < product.special_price) { // for VS - special_price is any price lowered than regular price (`price`); in Magento there is a separate mechanism for setting the `special_prices` - product.price = product.special_price // if the `final_price` is lower than the original `special_price` - it means some catalog rules were applied over it + assignPrice({product, target: 'price', ...specialPriceWithTax, deprecatedPriceFieldsSupport}) // if the `final_price` is lower than the original `special_price` - it means some catalog rules were applied over it } - product.special_to_date = null - product.special_from_date = null - product.special_price = product.final_price + assignPrice({product, target: 'special_price', ...finalPriceWithTax, deprecatedPriceFieldsSupport}) } else { - product.price = product.final_price + assignPrice({product, target: 'price', ...finalPriceWithTax, deprecatedPriceFieldsSupport}) } } - let price_excl_tax = product.price - if (sourcePriceInclTax) { - price_excl_tax = product.price / (1 + rate_factor) - product.price = price_excl_tax - } - - product.price_tax = price_excl_tax * rate_factor - product.price_incl_tax = price_excl_tax + product.price_tax - - let special_price_excl_tax = product.special_price - if (sourcePriceInclTax) { - special_price_excl_tax = product.special_price / (1 + rate_factor) - product.special_price = special_price_excl_tax - } - - product.special_price_tax = special_price_excl_tax * rate_factor - product.special_price_incl_tax = special_price_excl_tax + product.special_price_tax - - if (deprecatedPriceFieldsSupport) { - /** BEGIN @deprecated - inconsitent naming kept just for the backward compatibility */ - product.priceTax = product.price_tax - product.priceInclTax = product.price_incl_tax - product.specialPriceTax = product.special_price_tax - product.specialPriceInclTax = product.special_price_incl_tax - /** END */ - } - - if (product.special_price && (product.special_price < product.price)) { + if (product.special_price && (product.special_price < product.original_price)) { if (!isSpecialPriceActive(product.special_from_date, product.special_to_date)) { - product.special_price = 0 // out of the dates period + // out of the dates period + assignPrice({product, target: 'special_price', price: 0, tax: 0, deprecatedPriceFieldsSupport}) } else { - product.original_price = price_excl_tax - product.original_price_incl_tax = product.price_incl_tax - product.original_price_tax = product.price_tax - - product.price = special_price_excl_tax - product.price_incl_tax = product.special_price_incl_tax - product.price_tax = product.special_price_tax - - if (deprecatedPriceFieldsSupport) { - /** BEGIN @deprecated - inconsitent naming kept just for the backward compatibility */ - product.priceInclTax = product.price_incl_tax - product.priceTax = product.price_tax - product.originalPrice = product.original_price - product.originalPriceInclTax = product.original_price_incl_tax - product.originalPriceTax = product.original_price_tax - /** END */ - } + assignPrice({product, target: 'price', ...specialPriceWithTax, deprecatedPriceFieldsSupport}) } } else { - product.special_price = 0 // the same price as original; it's not a promotion + // the same price as original; it's not a promotion + assignPrice({product, target: 'special_price', price: 0, tax: 0, deprecatedPriceFieldsSupport}) } if (product.configurable_children) { @@ -107,100 +121,25 @@ export function updateProductPrices ({ product, rate, sourcePriceInclTax = false configurableChild[opt.attribute_code] = opt.value } } - configurableChild.price = parseFloat(configurableChild.price) - configurableChild.special_price = parseFloat(configurableChild.special_price) - configurableChild.final_price_incl_tax = parseFloat(configurableChild.final_price) // final price does include tax - configurableChild.final_price = configurableChild.final_price_incl_tax / (1 + rate_factor) - - if (configurableChild.final_price) { - if (configurableChild.final_price < configurableChild.price) { // compare the prices with the product final price if provided; final prices is used in case of active catalog promo rules for example - if (configurableChild.final_price < configurableChild.special_price) { // for VS - special_price is any price lowered than regular price (`price`); in Magento there is a separate mechanism for setting the `special_prices` - configurableChild.price = configurableChild.special_price // if the `final_price` is lower than the original `special_price` - it means some catalog rules were applied over it - } - configurableChild.special_to_date = null - configurableChild.special_from_date = null - configurableChild.special_price = product.final_price - } else { - configurableChild.price = configurableChild.final_price - } - } - - let price_excl_tax = configurableChild.price - if (sourcePriceInclTax) { - price_excl_tax = configurableChild.price / (1 + rate_factor) - configurableChild.price = price_excl_tax - } - - configurableChild.price_tax = price_excl_tax * rate_factor - configurableChild.price_incl_tax = price_excl_tax + configurableChild.price_tax - - let special_price_excl_tax = parseFloat(configurableChild.special_price) - - if (sourcePriceInclTax) { - special_price_excl_tax = configurableChild.special_price / (1 + rate_factor) - configurableChild.special_price = special_price_excl_tax - } - configurableChild.special_price_tax = special_price_excl_tax * rate_factor - configurableChild.special_price_incl_tax = special_price_excl_tax + configurableChild.special_price_tax - - if (deprecatedPriceFieldsSupport) { - /** BEGIN @deprecated - inconsitent naming kept just for the backward compatibility */ - configurableChild.priceTax = configurableChild.price_tax - configurableChild.priceInclTax = configurableChild.price_incl_tax - configurableChild.specialPriceTax = configurableChild.special_price_tax - configurableChild.specialPriceInclTax = configurableChild.special_price_incl_tax - /** END */ - } - - if (configurableChild.special_price && (configurableChild.special_price < configurableChild.price)) { - if (!isSpecialPriceActive(configurableChild.special_from_date, configurableChild.special_to_date)) { - configurableChild.special_price = 0 // out of the dates period - } else { - configurableChild.original_price = price_excl_tax - configurableChild.original_price_incl_tax = configurableChild.price_incl_tax - configurableChild.original_price_tax = configurableChild.price_tax - - configurableChild.price = special_price_excl_tax - configurableChild.price_incl_tax = configurableChild.special_price_incl_tax - configurableChild.price_tax = configurableChild.special_price_tax - - if (deprecatedPriceFieldsSupport) { - /** BEGIN @deprecated - inconsitent naming kept just for the backward compatibility */ - configurableChild.originalPrice = configurableChild.original_price - configurableChild.originalPriceInclTax = configurableChild.original_price_incl_tax - configurableChild.originalPriceTax = configurableChild.original_price_tax - configurableChild.priceInclTax = configurableChild.price_incl_tax - configurableChild.priceTax = configurableChild.price_tax - /** END */ - } - } - } else { - configurableChild.special_price = 0 - } + // update children prices + updateProductPrices({ product: configurableChild, rate, sourcePriceInclTax, deprecatedPriceFieldsSupport, finalPriceInclTax }) if ((configurableChild.price_incl_tax <= product.price_incl_tax) || product.price === 0) { // always show the lowest price - product.price_incl_tax = configurableChild.price_incl_tax - product.price_tax = configurableChild.price_tax - product.price = configurableChild.price - product.special_price = configurableChild.special_price - product.special_price_incl_tax = configurableChild.special_price_incl_tax - product.special_price_tax = configurableChild.special_price_tax - product.original_price = configurableChild.original_price - product.original_price_incl_tax = configurableChild.original_price_incl_tax - product.original_price_tax = configurableChild.original_price_tax - - if (deprecatedPriceFieldsSupport) { - /** BEGIN @deprecated - inconsitent naming kept just for the backward compatibility */ - product.priceInclTax = product.price_incl_tax - product.priceTax = product.price_tax - product.specialPriceInclTax = product.special_price_incl_tax - product.specialPriceTax = product.special_price_tax - product.originalPrice = product.original_price - product.originalPriceInclTax = product.original_price_incl_tax - product.originalPriceTax = product.original_price_tax - /** END */ - } + assignPrice({ + product, + target: 'price', + price: configurableChild.price, + tax: configurableChild.price_tax, + deprecatedPriceFieldsSupport + }) + assignPrice({ + product, + target: 'special_price', + price: configurableChild.special_price, + tax: configurableChild.special_price_tax, + deprecatedPriceFieldsSupport + }) } } } From be99ce413cc7690f32141ef8a5be5224bc3b354b Mon Sep 17 00:00:00 2001 From: tkostuch Date: Thu, 31 Oct 2019 13:24:34 +0100 Subject: [PATCH 2/4] lint fix --- src/api/user.js | 8 ++++---- src/platform/magento2/user.js | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/api/user.js b/src/api/user.js index 71292917..1e978b50 100755 --- a/src/api/user.js +++ b/src/api/user.js @@ -150,10 +150,10 @@ export default ({config, db}) => { userApi.get('/order-history', (req, res) => { const userProxy = _getProxy(req) userProxy.orderHistory( - req.query.token, - req.query.pageSize || 20, - req.query.currentPage || 1 - ).then((result) => { + req.query.token, + req.query.pageSize || 20, + req.query.currentPage || 1 + ).then((result) => { apiStatus(res, result, 200); }).catch(err => { apiError(res, err); diff --git a/src/platform/magento2/user.js b/src/platform/magento2/user.js index b8eab151..c5b0fe7f 100644 --- a/src/platform/magento2/user.js +++ b/src/platform/magento2/user.js @@ -21,7 +21,7 @@ class UserProxy extends AbstractUserProxy { return this.api.customers.me(requestToken) } - orderHistory (requestToken, pageSize = 20, currentPage = 1) { + orderHistory (requestToken, pageSize = 20, currentPage = 1) { return this.api.customers.orderHistory(requestToken, pageSize, currentPage) } resetPassword (emailData) { From 9ad142f4756e4d2458df958e4a29ec28448fffe6 Mon Sep 17 00:00:00 2001 From: tkostuch Date: Thu, 31 Oct 2019 13:40:39 +0100 Subject: [PATCH 3/4] add lodash fn --- src/lib/taxcalc.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/taxcalc.js b/src/lib/taxcalc.js index 7d08f27c..d760667b 100644 --- a/src/lib/taxcalc.js +++ b/src/lib/taxcalc.js @@ -1,4 +1,4 @@ -import camelCase from 'lodash-es/camelCase' +import camelCase from 'lodash/camelCase' function isSpecialPriceActive (fromDate, toDate) { if (!fromDate && !toDate) { From f10e525ceb3aa3958a85238cd0a5ace1144a89a8 Mon Sep 17 00:00:00 2001 From: tkostuch Date: Thu, 31 Oct 2019 13:43:47 +0100 Subject: [PATCH 4/4] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 65b9f337..3ecbfa94 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - Error responses for mailchimp - @andrzejewsky (#3337) - Replaced function arguments to object destructuring in `calculateProductTax` - @andrzejewsky (#3337) +- Refactor `taxcalc.js` similar to frontend - @gibkigonzo (#356) ## [1.10.0] - 2019.08.12