Skip to content
This repository has been archived by the owner on May 28, 2023. It is now read-only.

#327 and #328 #330

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added jest support - @resubaka (#321)
- Added caching factory and action factory for the image endpoint. This gives the possibility to use other services for caching or image processing - @resubaka (#317, #315)
- Added support for tax calculation where the values from customer_tax_class_ids is used - @resubaka (#307)
- The `db` context object - passed to every api endpoint now has two usefull methods: `getElasticClient` and `getRedisClient` for accesing the data stores - @pkarw (#328)
- The `lib/utils` got two new methods `getStoreCode(req: Express.Request)` and `getStoreView(code: string)` for getting the current multistore context from `vue-storefront` frontend requests - @pkarw

### Fixed
- The way Elastic and Redis clients have been fixed and code duplication removed across the app - @pkarw (#327)
- The `product.price_*` fields have been normalized with the backward compatibility support (see `config.tax.deprecatedPriceFieldsSupport` which is by default true) - @pkarw (#289)
- The `product.final_price` field is now being taken into product price calcualtion. Moreover, we've added the `config.tax.finalPriceIncludesTax` - which is set to `true` by default. All the `price`, `original_price` and `special_price` fields are calculated accordingly. It was required as Magento2 uses `final_price` to set the catalog pricing rules after-prices - @pkarw (#289)
- Force ES connections to use protocol config option - @cewald (#303, #304)
Expand Down
25 changes: 5 additions & 20 deletions migrations/.common.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,9 @@

let config = require('config')
let kue = require('kue')
let queue = kue.createQueue(Object.assign(config.kue, { redis: config.redis }))

let es = require('elasticsearch')
const esConfig = {
host: {
host: config.elasticsearch.host,
port: config.elasticsearch.port,
protocol: config.elasticsearch.protocol
},
log: 'debug',
apiVersion: config.elasticsearch.apiVersion,
requestTimeout: 1000 * 60 * 60,
keepAlive: false
}
if (config.elasticsearch.user) {
esConfig.httpAuth = config.elasticsearch.user + ':' + config.elasticsearch.password
}
let client = new es.Client(esConfig)
const config = require('config')
const kue = require('kue')
const queue = kue.createQueue(Object.assign(config.kue, { redis: config.redis }))
const es = require('../src/lib/elastic')
const client = es.getClient(config)

exports.db = client
exports.queue = queue
32 changes: 6 additions & 26 deletions src/api/extensions/elastic-stock/index.js
Original file line number Diff line number Diff line change
@@ -1,34 +1,14 @@
import { apiStatus } from '../../../lib/util';
import { apiStatus, getCurrentStoreView, getCurrentStoreCode } from '../../../lib/util';
import { getClient as getElasticClient } from '../../../lib/elastic'
import { Router } from 'express';
const es = require('elasticsearch')
const bodybuilder = require('bodybuilder')

module.exports = ({ config, db }) => {

let api = Router();

const getElasticClient = (config) => {
const esConfig = { // as we're runing tax calculation and other data, we need a ES indexer
host: {
host: config.elasticsearch.host,
port: config.elasticsearch.port,
protocol: config.elasticsearch.protocol
},
apiVersion: config.elasticsearch.apiVersion,
requestTimeout: 5000
}
if (config.elasticsearch.user) {
esConfig.httpAuth = config.elasticsearch.user + ':' + config.elasticsearch.password
}
return new es.Client(esConfig)
}

const getStockList = (storeCode, skus) => {
let storeView = config
if (storeCode && config.storeViews[storeCode]) {
storeView = config.storeViews[storeCode]
}

let storeView = getCurrentStoreView(storeCode)
const esQuery = {
index: storeView.elasticsearch.indexName, // current index name
type: 'product',
Expand All @@ -52,7 +32,7 @@ module.exports = ({ config, db }) => {
return apiStatus(res, 'sku parameter is required', 500);
}

getStockList(req.params.storeCode, [req.params.sku]).then((result) => {
getStockList(getCurrentStoreCode(req), [req.params.sku]).then((result) => {
if (result && result.length > 0) {
apiStatus(res, result[0], 200);
} else {
Expand All @@ -70,7 +50,7 @@ module.exports = ({ config, db }) => {
if (!req.query.sku) {
return apiStatus(res, 'sku parameter is required', 500);
}
getStockList(req.params.storeCode, [req.query.sku]).then((result) => {
getStockList(getCurrentStoreCode(req), [req.query.sku]).then((result) => {
if (result && result.length > 0) {
apiStatus(res, result[0], 200);
} else {
Expand All @@ -89,7 +69,7 @@ module.exports = ({ config, db }) => {
return apiStatus(res, 'skus parameter is required', 500);
}
const skuArray = req.query.skus.split(',')
getStockList(req.params.storeCode, skuArray).then((result) => {
getStockList(getCurrentStoreCode(req), skuArray).then((result) => {
if (result && result.length > 0) {
apiStatus(res, result, 200);
} else {
Expand Down
12 changes: 3 additions & 9 deletions src/api/sync.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { apiStatus, apiError } from '../lib/util'; import { Router } from 'express';
import { apiStatus } from '../lib/util'; import { Router } from 'express';
import * as redis from '../lib/redis'

export default ({ config, db }) => {
let syncApi = Router();
Expand All @@ -7,14 +8,7 @@ export default ({ config, db }) => {
* GET get stock item
*/
syncApi.get('/order/:order_id', (req, res) => {
const Redis = require('redis');
let redisClient = Redis.createClient(config.redis); // redis client
redisClient.on('error', (err) => { // workaround for https://github.com/NodeRedis/node_redis/issues/713
redisClient = Redis.createClient(config.redis); // redis client
});
if (config.redis.auth) {
redisClient.auth(config.redis.auth);
}
const redisClient = db.getRedisClient(config)

redisClient.get('order$$id$$' + req.param('order_id'), (err, reply) => {
const orderMetaData = JSON.parse(reply)
Expand Down
10 changes: 9 additions & 1 deletion src/db.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
import config from 'config'
import * as redis from '../src/lib/redis'
import * as elastic from '../src/lib/elastic'

export default callback => {
// connect to a database if needed, then pass it to `callback`:
callback();
const dbContext = {
getRedisClient: () => redis.getClient(config),
getElasticClient: () => elastic.getClient(config)
}
callback(dbContext);
}
18 changes: 18 additions & 0 deletions src/lib/elastic.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,23 @@ const path = require('path')
const _ = require('lodash')
const fs = require('fs');
const jsonFile = require('jsonfile')
const es = require('elasticsearch')

function getClient(config) {
pkarw marked this conversation as resolved.
Show resolved Hide resolved
const esConfig = { // as we're runing tax calculation and other data, we need a ES indexer
host: {
host: config.elasticsearch.host,
port: config.elasticsearch.port,
protocol: config.elasticsearch.protocol
},
apiVersion: config.elasticsearch.apiVersion,
requestTimeout: 5000
}
if (config.elasticsearch.user) {
esConfig.httpAuth = config.elasticsearch.user + ':' + config.elasticsearch.password
}
return new es.Client(esConfig)
}

function putAlias (db, originalName, aliasName, next) {
let step2 = () => {
Expand Down Expand Up @@ -182,6 +199,7 @@ function putMappings (db, indexName, next) {
}

module.exports = {
getClient,
putMappings,
putAlias,
createIndex,
Expand Down
16 changes: 16 additions & 0 deletions src/lib/redis.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import Redis from 'redis'

/**
* Return Redis Client
* @param {config} config
*/
export function getClient(config) {
pkarw marked this conversation as resolved.
Show resolved Hide resolved
let redisClient = Redis.createClient(config.redis); // redis client
redisClient.on('error', (err) => { // workaround for https://github.com/NodeRedis/node_redis/issues/713
redisClient = Redis.createClient(config.redis); // redis client
});
if (config.redis.auth) {
redisClient.auth(config.redis.auth);
}
return redisClient
}
26 changes: 26 additions & 0 deletions src/lib/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,32 @@ import config from 'config';
import crypto from 'crypto';
const algorithm = 'aes-256-ctr';

/**
* Get current store code from parameter passed from the vue storefront frotnend app
* @param {Express.Request} req
*/
export function getCurrentStoreCode (req) {
if (req.headers['x-vs-store-code']) {
return req.headers['x-vs-store']
pkarw marked this conversation as resolved.
Show resolved Hide resolved
}
if (req.query.storeCode) {
return req.query.storeCode
}
return null
}

/**
* Get the config.storeViews[storeCode]
* @param {string} storeCode
*/
export function getCurrentStoreView (storeCode = null) {
if (storeCode && config.storeViews[storeCode]) {
storeView = config.storeViews[storeCode]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why aren't we returning the storeView here?

For me it looks like a bug here and the default that we return looks bad to in my eyes. Here we should do it like we do in prepareStoreView in the frontend.

  let storeView = { // current, default store
    tax: config.tax,
    i18n: config.i18n,
    elasticsearch: config.elasticsearch,
    storeCode: null,
    storeId: config.defaultStoreCode && config.defaultStoreCode !== '' ? config.storeViews[config.defaultStoreCode].storeId : 1
  }

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks fixed

}
return config // main config is used as default storeview
}


/** Creates a callback that proxies node callback style arguments to an Express Response object.
* @param {express.Response} res Express HTTP Response
* @param {number} [status=200] Status code to send on success
Expand Down
20 changes: 3 additions & 17 deletions src/platform/magento1/tax.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import AbstractTaxProxy from '../abstract/tax'
import { calculateProductTax, checkIfTaxWithUserGroupIsActive, getUserGroupIdToUse } from '../../lib/taxcalc'
import TierHelper from '../../helpers/priceTiers'
const es = require('elasticsearch')
const bodybuilder = require('bodybuilder')
import bodybuilder from bodybuilder
import es from '../../lib/elastic'

class TaxProxy extends AbstractTaxProxy {
constructor (config, entityType, indexName, taxCountry, taxRegion = '', sourcePriceInclTax = null, finalPriceInclTax = null) {
Expand Down Expand Up @@ -72,21 +72,7 @@ class TaxProxy extends AbstractTaxProxy {
inst.applyTierPrices(productList, groupId)

if (this._config.tax.calculateServerSide) {
const esConfig = { // as we're runing tax calculation and other data, we need a ES indexer
host: {
host: this._config.elasticsearch.host,
port: this._config.elasticsearch.port,
protocol: this._config.elasticsearch.protocol
},
log: 'debug',
apiVersion: this._config.elasticsearch.apiVersion,
requestTimeout: 5000
}
if (this._config.elasticsearch.user) {
esConfig.httpAuth = this._config.elasticsearch.user + ':' + this._config.elasticsearch.password
}

const client = new es.Client(esConfig)
const client = es.getClient(this._config)
const esQuery = {
index: this._indexName,
type: 'taxrule',
Expand Down
11 changes: 2 additions & 9 deletions src/platform/magento1/util.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,13 @@
import config from 'config'
import { getCurrentStoreCode } from '../../lib/util'
/**
* Adjust the config provided to the current store selected via request params
* @param Object config configuration
* @param Express request req
*/
export function multiStoreConfig (apiConfig, req) {
let confCopy = Object.assign({}, apiConfig)
let storeCode = ''

if (req.headers['x-vs-store-code']) {
storeCode = req.headers['x-vs-store']
}
if (req.query.storeCode) {
storeCode = req.query.storeCode
}

let storeCode = getCurrentStoreCode(req)
if (storeCode && config.availableStores.indexOf(storeCode) >= 0) {
if (config.magento1['api_' + storeCode]) {
confCopy = Object.assign({}, config.magento1['api_' + storeCode]) // we're to use the specific api configuration - maybe even separate magento instance
Expand Down
28 changes: 12 additions & 16 deletions src/platform/magento2/o2m.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,8 @@
const Magento2Client = require('magento2-rest-client').Magento2Client;

const config = require('config')
const Redis = require('redis');
let redisClient = Redis.createClient(config.redis); // redis client
redisClient.on('error', (err) => { // workaround for https://github.com/NodeRedis/node_redis/issues/713
redisClient = Redis.createClient(config.redis); // redis client
});
if (config.redis.auth) {
redisClient.auth(config.redis.auth);
}
const redis = require('../../lib/redis');
const redisClient = redis.getClient(config)
const countryMapper = require('../../lib/countrymapper')
const Ajv = require('ajv'); // json validator
const fs = require('fs');
Expand Down Expand Up @@ -228,14 +222,16 @@ function processSingleOrder (orderData, config, job, done, logger = console) {

logger.info(THREAD_ID + '[OK] Order placed with ORDER ID', result);
logger.debug(THREAD_ID + result)
redisClient.set('order$$id$$' + orderData.order_id, JSON.stringify({
platform_order_id: result,
transmited: true,
transmited_at: new Date(),
platform: 'magento2',
order: orderData
}));
redisClient.set('order$$totals$$' + orderData.order_id, JSON.stringify(result[1]));
if (orderData.order_id) {
redisClient.set('order$$id$$' + orderData.order_id, JSON.stringify({
platform_order_id: result,
transmited: true,
transmited_at: new Date(),
platform: 'magento2',
order: orderData
}));
redisClient.set('order$$totals$$' + orderData.order_id, JSON.stringify(result[1]));
}
let orderIncrementId = null;
api.orders.incrementIdById(result).then(result => {
orderIncrementId = result.increment_id
Expand Down
20 changes: 3 additions & 17 deletions src/platform/magento2/tax.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import AbstractTaxProxy from '../abstract/tax'
import { calculateProductTax, checkIfTaxWithUserGroupIsActive, getUserGroupIdToUse } from '../../lib/taxcalc';
import TierHelper from '../../helpers/priceTiers'
const es = require('elasticsearch')
const bodybuilder = require('bodybuilder')
import es from '../../lib/elastic'
import bodybuilder from 'bodybuilder'

class TaxProxy extends AbstractTaxProxy {
constructor (config, entityType, indexName, taxCountry, taxRegion = '', sourcePriceInclTax = null, finalPriceInclTax = null) {
Expand Down Expand Up @@ -71,21 +71,7 @@ class TaxProxy extends AbstractTaxProxy {
inst.applyTierPrices(productList, groupId)

if (this._config.tax.calculateServerSide) {
const esConfig = { // as we're runing tax calculation and other data, we need a ES indexer
host: {
host: this._config.elasticsearch.host,
port: this._config.elasticsearch.port,
protocol: this._config.elasticsearch.protocol
},
log: 'debug',
apiVersion: this._config.elasticsearch.apiVersion,
requestTimeout: 5000
}
if (this._config.elasticsearch.user) {
esConfig.httpAuth = this._config.elasticsearch.user + ':' + this._config.elasticsearch.password
}

let client = new es.Client(esConfig)
const client = es.getClient(this._config)
const esQuery = {
index: this._indexName,
type: 'taxrule',
Expand Down
10 changes: 2 additions & 8 deletions src/platform/magento2/util.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,13 @@
import config from 'config'
import { getCurrentStoreCode } from '../../lib/util'
/**
* Adjust the config provided to the current store selected via request params
* @param Object config configuration
* @param Express request req
*/
export function multiStoreConfig (apiConfig, req) {
let confCopy = Object.assign({}, apiConfig)
let storeCode = ''

if (req.headers['x-vs-store-code']) {
storeCode = req.headers['x-vs-store']
}
if (req.query.storeCode) {
storeCode = req.query.storeCode
}
let storeCode = getCurrentStoreCode(req)

if (storeCode && config.availableStores.indexOf(storeCode) >= 0) {
if (config.magento2['api_' + storeCode]) {
Expand Down