Advertisement
Guest User

Untitled

a guest
Feb 17th, 2020
102
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 14.66 KB | None | 0 0
  1. const { lit, raw, transaction } = require('objection');
  2. const _ = require('lodash');
  3. const moment = require('moment');
  4. const Product = require('../../models/product');
  5. const ProductSchedule = require('../../models/productSchedule');
  6. const ProductAllotmentUsage = require('../../models/productAllotmentUsage');
  7. const Allotment = require('../../models/allotment');
  8. const ProductPricePeriod = require('../../models/productPricePeriod');
  9. const ProductUnavailability = require('../../models/productUnavailability');
  10. const {
  11. OK,
  12. CREATED,
  13. NO_CONTENT,
  14. } = require('../../common/constants');
  15. const {
  16. addedSuccessfully,
  17. deletedSuccessfully,
  18. errorInDeleting,
  19. foundSuccessfully,
  20. updatedSuccessfully,
  21. } = require('../../common/messages');
  22. const {
  23. sendJsonResponse,
  24. sendNoContentFound,
  25. sendNotFoundError,
  26. generateDaysFromRange,
  27. isDayOfYearInRange,
  28. } = require('../../common/helpers');
  29.  
  30. const productWord = 'product';
  31. const productOptionsWord = 'productOptions';
  32. const productScheduleWord = 'productSchedule';
  33. const productsWord = 'products';
  34. module.exports.readProducts = async (req, res) => {
  35. const currentDate = moment().format('YYYY-MM-DD');
  36. const dateRange = `[${currentDate},)`;
  37. const allotmentUsageInfo = requestedDateRange => ProductAllotmentUsage
  38. .query()
  39. .select(
  40. 'allotment_usage_per_day.product_id',
  41. raw(`json_agg(
  42. json_build_object(
  43. 'consumption_date',consumption_date,
  44. 'quantity',quantity
  45. )
  46. ) as allotment_usage_info`),
  47. )
  48. .from(raw(`(select
  49. product_id,consumption_date,sum(coalesce(quantity, 0)) as quantity
  50. from product_allotment_usage
  51. where ?::daterange @> consumption_date
  52. group by product_id , consumption_date
  53. ) as allotment_usage_per_day`, [requestedDateRange]))
  54. .groupBy('allotment_usage_per_day.product_id');
  55. const isNotInBlackout = requestedDateRange => ProductUnavailability
  56. .query()
  57. .select(
  58. 'product_unavailability.product_id',
  59. raw(`json_agg(
  60. json_build_object(
  61. 'unavailability_period',product_unavailability.unavailability_period * ?
  62. )
  63. ) as unavailability_info`, [requestedDateRange]),
  64. )
  65. .where(raw('unavailability_period && ? = true', [requestedDateRange]))
  66. .groupBy('product_unavailability.product_id');
  67.  
  68. const allotmentInfo = requestedDateRange => Allotment
  69. .query()
  70. .select(
  71. 'allotment.product_id',
  72. raw(`json_agg(
  73. json_build_object(
  74. 'allotment_period',allotment.allotment_period * ?,
  75. 'initial_stock',allotment.initial_stock,
  76. 'reassort',allotment.reassort
  77. )
  78. ) as allotment_info`, [requestedDateRange]),
  79. )
  80. .where(raw('allotment_period && ? = true', [requestedDateRange]))
  81. .whereNotNull('allotment.initial_stock')
  82. .groupBy('allotment.product_id');
  83.  
  84. const subPriceInfo = requestedDateRange => ProductPricePeriod
  85. .query()
  86. .select('product_price_period.id', 'product_price_period.price_period', 'product_price_period.product_id',
  87. raw(`json_build_object(
  88. 'sub_period', product_price_sub_period.price_sub_period) as sub_periods`),
  89. raw(`(SELECT
  90. CASE
  91. WHEN product_price_period.price_mode_id = 1 THEN
  92. (select price from price_per_occupation where product_price_period_id = product_price_period.id and price notnull limit 1)
  93. WHEN product_price_period.price_mode_id = 2 THEN
  94. (select fit_price from fixed_price where product_price_period_id = product_price_period.id and fit_price notnull limit 1)
  95. WHEN product_price_period.price_mode_id = 3 THEN
  96. (select fit_price from price_per_pax where product_price_period_id = product_price_period.id and fit_price notnull limit 1)
  97. WHEN product_price_period.price_mode_id = 4 THEN
  98. (select fit_price from price_per_age where product_price_period_id = product_price_period.id and fit_price notnull limit 1)
  99. END) as price`))
  100. .innerJoin('product_price_sub_period', 'product_price_sub_period.product_price_period_id', 'product_price_period.id')
  101. .where(raw('product_price_period.price_period && ? = true', [requestedDateRange]))
  102.  
  103. .groupBy('product_price_period.id', 'product_price_sub_period.price_sub_period');
  104.  
  105. const priceInfo = requestedDateRange => Product
  106. .query()
  107. .select(
  108. 'product_id', raw(`json_agg(
  109. sub_periods
  110. ) FILTER (WHERE price IS NOT NULL)as price_info`),
  111. )
  112. .from(subPriceInfo(requestedDateRange).as('price_info'))
  113. .groupBy('product_id');
  114. let products = await Product
  115. .query()
  116. .skipUndefined()
  117. .where('establishment_id', req.query.establishment_id)
  118. .andWhere('product_type_id', req.query.product_type_id)
  119. .modify((qb) => {
  120. if (req.query.is_balance === true) {
  121. qb.select('product.*', 'allotment_info',
  122. 'price_info',
  123. 'allotment_usage_info',
  124. 'unavailability_info')
  125. .from('product')
  126. .innerJoin(allotmentInfo(dateRange).as('product_allotment_info'),
  127. 'product_allotment_info.product_id', 'product.id')
  128. .leftJoin(allotmentUsageInfo(dateRange).as('product_allotment_usage_info'),
  129. 'product_allotment_usage_info.product_id', 'product.id')
  130. .leftJoin(isNotInBlackout(dateRange).as('product_unavailability_info'),
  131. 'product_unavailability_info.product_id', 'product.id')
  132. .innerJoin('establishment', 'establishment.id', 'product.establishment_id')
  133. .innerJoin(priceInfo(dateRange).as('product_price_info'),
  134. 'product_price_info.product_id', 'product.id')
  135. .innerJoin('provider', 'provider.id', 'establishment.provider_id')
  136. .where('product.status', true)
  137. .andWhere('establishment.status', true)
  138. .andWhere('provider.status', true)
  139. .whereNotNull('product_allotment_info')
  140. .whereNotNull('product_price_info');
  141. }
  142. })
  143. .limit(req.query.limit);
  144. if (products.length === 0) {
  145. return sendNoContentFound(req, res, productsWord);
  146. }
  147. if (req.query.is_balance === true) {
  148. products = products.map((product) => {
  149. const balance = _.flatten(product.allotment_info.map((allotement) => {
  150. const days = generateDaysFromRange(allotement.allotment_period);
  151.  
  152. const balanceArray = days && days.map((day) => {
  153. const quantity = product.allotment_usage_info && product.allotment_usage_info
  154. .filter(usage => usage.consumption_date === day).length > 0
  155. ? product.allotment_usage_info.filter(usage => usage.consumption_date
  156. === day)[0].quantity : 0;
  157. const nBalance = allotement.initial_stock + allotement.reassort - quantity;
  158. if (nBalance <= 0) {
  159. const blackOutDays = product.unavailability_info
  160. && _.flatten(product.unavailability_info.map(unavailability =>
  161. isDayOfYearInRange(unavailability.unavailability_period, moment(day))));
  162. if (blackOutDays && blackOutDays.some(black => black === true)) return null;
  163. const subPeriods = product.price_info.map(sub =>
  164. isDayOfYearInRange(sub.sub_period, moment(day)));
  165. if (subPeriods.some(period => period === true)) {
  166. return { day, balance: nBalance };
  167. }
  168. return null;
  169. // return { day, balance: nBalance };
  170. }
  171. return null;
  172. });
  173.  
  174. return balanceArray;
  175. })).filter(Boolean);
  176. const nProduct = product;
  177. delete nProduct.allotment_usage_info;
  178. delete nProduct.unavailability_info;
  179. delete nProduct.price_info;
  180. nProduct.balance = balance;
  181. if (balance.length > 0) return nProduct;
  182. return null;
  183. });
  184. }
  185. return sendJsonResponse(req, res, OK, products, foundSuccessfully(productsWord));
  186. };
  187.  
  188. module.exports.readProductSchedules = async (req, res) => {
  189. const requestedDateRange = `[${req.query.start_date},${req.query.end_date})`;
  190. const products = await ProductSchedule
  191. .query()
  192. .select()
  193. .distinct('activity_date', 'start_hour', 'duration_in_minute')
  194. .joinRaw(`INNER JOIN lateral (
  195. select activity_date::date
  196. from generate_series(lower(period * ?::daterange),
  197. upper(period * ?::daterange) - interval '1day', '1 day') as activity_date
  198. where EXTRACT(DOW FROM activity_date) = ANY(checked_days::INT[])
  199. ) as days on true`, [requestedDateRange, requestedDateRange])
  200. .skipUndefined()
  201. .where('product_id', req.params.products_id)
  202. .orderBy('activity_date', 'asc');
  203. if (products.length === 0) {
  204. return sendNoContentFound(req, res, productsWord);
  205. }
  206. return sendJsonResponse(req, res, OK, products, foundSuccessfully(productsWord));
  207. };
  208.  
  209.  
  210. module.exports.readProduct = async (req, res) => {
  211. const product = await Product
  212. .query()
  213. .with(
  214. 'schedules', (qb) => {
  215. qb
  216. .select(
  217. 'product.*',
  218. raw(`COALESCE (
  219. json_agg(
  220. json_build_object(
  221. 'id',product_schedule.id,
  222. 'start_date',lower(product_schedule.period)::text,
  223. 'end_date',(upper(product_schedule.period) - integer '1')::text,
  224. 'checked_days',product_schedule.checked_days,
  225. 'start_hour',to_char(product_schedule.start_hour, 'HH24:MI'),
  226. 'hours', (product_schedule.duration_in_minute / 60),
  227. 'minutes', (product_schedule.duration_in_minute % 60))
  228. ) FILTER (WHERE product_schedule.id IS NOT NULL), '[]')
  229. as product_schedule`),
  230. )
  231. .from('product')
  232. .leftJoin('product_schedule', 'product.id', 'product_schedule.product_id')
  233. .where('product.id', req.params.products_id)
  234. .groupBy('product.id');
  235. },
  236. )
  237. .with(
  238. 'options', (qb) => {
  239. qb
  240. .select(
  241. 'product.id',
  242. raw(`COALESCE (
  243. json_agg(
  244. json_build_object(
  245. 'establishment_option_id', product_option.establishment_option_id,
  246. 'is_required', product_option.is_required)
  247. ) FILTER (WHERE product_option.id IS NOT NULL), '[]')
  248. as product_option`),
  249. )
  250. .from('product')
  251. .leftJoin('product_option', 'product.id', 'product_option.product_id')
  252. .where('product.id', req.params.products_id)
  253. .groupBy('product.id');
  254. },
  255. )
  256. .select()
  257. .from(raw('schedules JOIN options USING (id)'));
  258.  
  259.  
  260. if (product.length === 0) {
  261. return sendNoContentFound(req, res, productWord);
  262. }
  263. return sendJsonResponse(req, res, OK, product[0], foundSuccessfully(productWord));
  264. };
  265.  
  266. module.exports.createProduct = async (req, res) => {
  267. const product = await Product
  268. .query()
  269. .insert({
  270. name: req.body.name,
  271. product_type_id: req.body.product_type_id,
  272. establishment_id: req.body.establishment_id,
  273. tax_profile_id: req.body.tax_profile_id,
  274. });
  275. return sendJsonResponse(req, res, CREATED, { id: product.id }, addedSuccessfully(productWord));
  276. };
  277.  
  278. module.exports.updateProduct = async (req, res) => {
  279. const updatedValues = Object.assign({}, req.body, { id: parseInt(req.params.products_id, 10) });
  280. const productOptionsTodelete = [];
  281. if (updatedValues.product_option && updatedValues.product_option.length > 0) {
  282. const productOptionsToUpsert = [];
  283. updatedValues.product_option.forEach((opt) => {
  284. if (Object.keys(opt).length === 1 && Object.keys(opt)[0] === 'establishment_option_id') {
  285. productOptionsTodelete.push(opt.establishment_option_id);
  286. } else {
  287. productOptionsToUpsert.push({
  288. id: opt.establishment_option_id,
  289. is_required: opt.is_required,
  290. });
  291. }
  292. });
  293. updatedValues.product_option = productOptionsToUpsert;
  294. }
  295. const productScheduleTodelete = [];
  296. if (updatedValues.product_schedule && updatedValues.product_schedule.length > 0) {
  297. const productScheduleToUpsert = [];
  298. updatedValues.product_schedule.forEach((ps) => {
  299. if (Object.keys(ps).length === 1 && Object.keys(ps)[0] === 'id') {
  300. productScheduleTodelete.push(ps.id);
  301. } else {
  302. const productSchedule = Object.assign({}, ps);
  303. if (ps.checked_days) {
  304. productSchedule.checked_days = lit(ps.checked_days).asArray().castTo('int[]');
  305. }
  306. if (ps.start_date && ps.end_date) {
  307. productSchedule.period = `[${ps.start_date}, ${ps.end_date}]`;
  308. delete productSchedule.start_date;
  309. delete productSchedule.end_date;
  310. }
  311.  
  312. if (ps.hours !== undefined && ps.minutes !== undefined) {
  313. const hourPerMinutes = 60;
  314. productSchedule.duration_in_minute = ps.hours * hourPerMinutes + ps.minutes;
  315. delete productSchedule.hours;
  316. delete productSchedule.minutes;
  317. }
  318. productScheduleToUpsert.push(productSchedule);
  319. }
  320. });
  321. updatedValues.product_schedule = productScheduleToUpsert;
  322. }
  323.  
  324. return transaction(Product.knex(), async (trx) => {
  325. const productUpdate = await Product
  326. .query(trx)
  327. .upsertGraph(
  328. updatedValues,
  329. {
  330. relate: true,
  331. unrelate: false,
  332. noDelete: true,
  333. },
  334. );
  335. if (productOptionsTodelete.length > 0) {
  336. const product = await Product
  337. .query()
  338. .findById(req.params.products_id);
  339.  
  340. const productOptionDelete = await product
  341. .$relatedQuery('product_option', trx)
  342. .unrelate()
  343. .whereIn('establishment_option.id', productOptionsTodelete);
  344.  
  345. if (productOptionDelete === 0) {
  346. throw new Error(errorInDeleting(productOptionsWord));
  347. }
  348. return productOptionDelete;
  349. }
  350. if (productScheduleTodelete.length > 0) {
  351. const productScheduleDelete = await ProductSchedule
  352. .query()
  353. .delete()
  354. .whereIn('id', productScheduleTodelete);
  355. if (productScheduleDelete === 0) {
  356. throw new Error(errorInDeleting(productScheduleWord));
  357. }
  358. return productScheduleDelete;
  359. }
  360. return productUpdate;
  361. })
  362. .then(() => {
  363. sendJsonResponse(
  364. req, res, CREATED,
  365. updatedSuccessfully(productWord), updatedSuccessfully(productWord),
  366. );
  367. });
  368. };
  369. module.exports.deleteProduct = async (req, res) => {
  370. const product = await Product
  371. .query()
  372. .delete()
  373. .where('id', req.params.products_id);
  374.  
  375. if (product === 0) {
  376. return sendNotFoundError(req, res, productWord);
  377. }
  378. return sendJsonResponse(
  379. req, res, NO_CONTENT, deletedSuccessfully(productWord),
  380. deletedSuccessfully(productWord),
  381. );
  382. };
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement