Created
March 7, 2018 09:49
-
-
Save pbalan/33d96fef24a6988dd4af762161862ea4 to your computer and use it in GitHub Desktop.
Context data gets lost when changing database
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Model.observe('before save', (ctx, next) => { | |
const promises = []; | |
let userId = null; | |
if (undefined !== ctx.options.accessToken) { | |
userId = ctx.options.accessToken && ctx.options.accessToken.userId; | |
} | |
ctx.hookState.relations = {}; | |
/* istanbul ignore if */ | |
/* istanbul ignore else */ | |
if (ctx.isNewInstance && ctx.instance) { | |
Object.keys(Model.relations).forEach((related) => { | |
ctx.hookState.relations[related] = ctx.instance [related](); | |
}); | |
} else if (ctx.instance) { | |
Object.keys(Model.relations).forEach((related) => { | |
ctx.hookState.relations[related] = ctx.instance [related](); | |
}); | |
} | |
if (ctx.isNewInstance) { | |
ctx.instance.createdBy = userId || ctx.instance.createdBy; | |
ctx.instance.createdAt = new Date(); | |
ctx.instance.totalPrice = 0; | |
ctx.instance.grandTotal = 0; | |
// this collection would hold the unit price for each product | |
ctx.instance.__data['price'] = []; | |
// this collection would hold the quantity for each product | |
ctx.instance.__data['qty'] = []; | |
// this collection would hold the discount for each product | |
ctx.instance.__data['discount'] = []; | |
// this collection would hold the active Group Buy product IDs | |
ctx.instance.__data['activeGroupBuyProduct'] = []; | |
// this collection would hold the bonusProduct discount for same product | |
ctx.instance.__data['bonusProduct'] = []; | |
// this collection would hold the isMembershipDiscount for each product | |
// as it is required to update the product discount based on if the | |
// member who bought the item has membership or not | |
ctx.instance.__data['isMembershipDiscount'] = []; | |
ctx.instance.__data['hasMembership'] = false; | |
let transactionDetail = ctx.hookState.relations['transactionDetail']; | |
transactionDetail.forEach((detail) => { | |
let promise = getProductPriceFromTransactionDetail( | |
ctx, | |
detail, | |
detail.productId, | |
next | |
); | |
promises.push(promise); | |
}); | |
// by default, new transactions are pending | |
if (ctx.instance.transactionStatusId === undefined) { | |
ctx.instance.transactionStatusId = '1'; | |
} | |
} | |
let promise = isMember(ctx, ctx.instance.boughtBy, ctx.instance.venueId); | |
promises.push(promise); | |
// add transaction discount to the promise chain | |
promise = | |
app | |
.models | |
.TransactionDiscount | |
.hasTransactionDiscount(ctx, ctx.instance.__data['venueId']); | |
promises.push(promise); | |
/* istanbul ignore next */ | |
Promise.all(promises) | |
.then((result) => { | |
let totalDiscount = 0; | |
// check if any transaction discounts are applied | |
// Transaction discounts take precedence over product discounts, | |
// thus it should make all product discounts 0 | |
let totalQty = 0; | |
let totalPrice = 0; | |
let cntr = 0; | |
let txnDiscount = ctx.instance.__data['transactionDiscount']; | |
let txnDetail = ctx.hookState.relations['transactionDetail']; | |
if (undefined !== txnDiscount) { | |
// remove bonus product if exists | |
txnDetail = txnDetail.filter((item) => { | |
return item.discount === undefined; | |
}); | |
ctx.instance.__data['qty'] = ctx.instance.__data['qty'].map( | |
(qty, item) => { | |
if (ctx.instance.__data['bonusProduct'][item] !== undefined) { | |
qty -= ctx.instance.__data['bonusProduct'][item]; | |
} | |
totalQty += qty; | |
return qty; | |
}); | |
ctx.instance.__data['price'].map( | |
(price, item) => { | |
totalPrice += (ctx.instance.__data['qty'][item] * price); | |
}); | |
ctx.instance.transactionDiscountId = txnDiscount.id; | |
ctx.instance.totalDiscount = | |
app | |
.models | |
.TransactionDiscount | |
.getTotalTransactionDiscount( | |
txnDiscount.discount, | |
totalPrice, | |
totalQty | |
); | |
cntr = 0; | |
ctx.instance.__data['price'].map((price, item) => { | |
let subTotal = price * ctx.instance.__data['qty'][item]; | |
txnDetail[cntr]['subTotal'] = subTotal; | |
txnDetail[cntr]['netTotal'] = subTotal; | |
txnDetail[cntr]['discount'] = 0; | |
ctx.instance.totalPrice += subTotal; | |
ctx.instance.grandTotal = | |
ctx.instance.totalPrice - ctx.instance.totalDiscount; | |
cntr++; | |
}); | |
} else { | |
// iterate over each product price | |
// and calculate subTotal, qty, product discount, and netTotal | |
cntr = 0; | |
ctx.instance.__data['price'].map((price, item) => { | |
let appliedDiscount = 0; | |
// special case, when bonus products are of same type, we must | |
// update the quantity here | |
txnDetail[cntr]['quantity'] = ctx.instance.__data['qty'][item]; | |
let subTotal = price * ctx.instance.__data['qty'][item]; | |
// when its membership discount and user has no membership, | |
// reset discount to 0 | |
if (ctx.instance.__data['isMembershipDiscount'][item] && | |
ctx.instance.__data['hasMembership'] === false | |
) { | |
ctx.instance.__data['discount'][item] = 0; | |
} | |
appliedDiscount += ctx.instance.__data['discount'][item]; | |
txnDetail[cntr]['subTotal'] = subTotal; | |
txnDetail[cntr]['discount'] = appliedDiscount; | |
txnDetail[cntr]['netTotal'] = subTotal - appliedDiscount; | |
ctx.instance.totalPrice += subTotal; | |
ctx.instance.totalDiscount += appliedDiscount; | |
// Calculate grandTotal by subtracting discount from totalPrice | |
ctx.instance.grandTotal = | |
ctx.instance.totalPrice - ctx.instance.totalDiscount; | |
cntr++; | |
}); | |
} | |
ctx.hookState.relations['transactionDetail'] = txnDetail; | |
delete ctx.instance.__data['price']; | |
delete ctx.instance.__data['qty']; | |
delete ctx.instance.__data['discount']; | |
delete ctx.instance.__data['hasMembership']; | |
delete ctx.instance.__data['isMembershipDiscount']; | |
delete ctx.instance.__data['transactionDiscount']; | |
delete ctx.instance.__data['bonusProduct']; | |
next(); | |
}) | |
.catch(err => { | |
/* istanbul ignore next */ | |
next(err); | |
}); | |
}); | |
/** | |
* @param {Object} ctx LoopbackContext | |
* @param {Object} detail TransactionDetail Model instance | |
* @param {Integer} productId Product Id | |
* @param {Function} next callback | |
* @return {Object} ctx LoopbackContext | |
*/ | |
function getProductPriceFromTransactionDetail( | |
ctx, detail, productId, next) { | |
let promise = Promise.resolve('ready'); | |
promise = app.models.Product.findById(productId, { | |
include: [ | |
{ | |
relation: 'productPricing', | |
scope: { | |
order: 'id DESC', | |
limit: 1, | |
}, | |
}, | |
{ | |
relation: 'productDiscount', | |
scope: { | |
order: 'id DESC', | |
limit: 1, | |
where: { | |
and: [{ | |
or: [{ | |
endDate: null, | |
}, { | |
endDate: { | |
gte: Date.now(), | |
}, | |
}], | |
}, | |
{ | |
startDate: { | |
lte: Date.now(), | |
}, | |
}], | |
}, | |
include: { | |
relation: 'discount', | |
scope: { | |
order: 'id DESC', | |
limit: 1, | |
}, | |
}, | |
}, | |
}, | |
], | |
}, (err, instance) => { | |
let discount = 0; | |
if (null !== instance) { | |
const data = instance.toJSON(); | |
const productPricing = data.productPricing[0]; | |
ctx.instance.__data['price'][productId] = productPricing.unitPrice; | |
ctx.instance.__data['qty'][productId] = detail.quantity; | |
ctx.instance.__data['discount'][productId] = discount; | |
if (data.productDiscount.length > 0) { | |
const discountObj = data.productDiscount[0].discount; | |
let discountTypeId = undefined; | |
if (discountObj !== undefined && discountObj !== null) { | |
discountTypeId = discountObj.discountTypeId; | |
} | |
discount = app.models.Discount.getProductDiscounts( | |
productPricing, | |
discountObj, | |
detail.quantity | |
); | |
if (discountTypeId === | |
discountTypes.DISCOUNT_TYPE_MEMBERSHIP_PRICE_OFF) { | |
ctx.instance.__data['isMembershipDiscount'][productId] = true; | |
} else { | |
ctx.instance.__data['isMembershipDiscount'][productId] = false; | |
} | |
ctx.instance.__data['discount'][productId] = discount; | |
// run once per transaction | |
// NOTE: group buy product must be checked before bonus product | |
// to prevent group buy product being offered as a bonus product | |
if (ctx.instance.__data['activeGroupBuyProduct'].length === 0) { | |
getActiveGroupBuyProducts(ctx); | |
} | |
if (discountTypeId === discountTypes.DISCOUNT_TYPE_GROUP_BUY) { | |
// check if this user is allowed for group buy discount | |
isGroupBuyAllowed( | |
ctx, | |
discountObj, | |
productPricing, | |
detail.quantity, | |
productId, | |
ctx.instance.boughtBy, | |
next | |
); | |
} | |
if (discountTypeId === | |
discountTypes.DISCOUNT_TYPE_BONUS_PRODUCT) { | |
// TODO: @prashant | |
// add configured bonus products to the cart | |
// by either updating the quantity if same product | |
// or getProduct with unitPrice 0.0 | |
addBonusProduct( | |
ctx, | |
discountObj, | |
productPricing, | |
productId | |
); | |
} | |
} | |
} | |
return ctx; | |
}); | |
return promise; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment