Advertisement
Guest User

Untitled

a guest
Feb 17th, 2020
159
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 14.90 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. 'product_price_sub_period.price_sub_period', 'price.price as price')
  88. .innerJoin('product_price_sub_period', 'product_price_sub_period.product_price_period_id', 'product_price_period.id')
  89. .joinRaw(`INNER JOIN lateral (
  90. select
  91. (case
  92. when product_price_period.price_mode_id = 1 then (
  93. select
  94. price
  95. from
  96. price_per_occupation
  97. where
  98. product_price_period_id = product_price_period.id
  99. and price notnull
  100. limit 1)
  101. when product_price_period.price_mode_id = 2 then (
  102. select
  103. fit_price
  104. from
  105. fixed_price
  106. where
  107. product_price_period_id = product_price_period.id
  108. and fit_price notnull
  109. limit 1)
  110. when product_price_period.price_mode_id = 3 then (
  111. select
  112. fit_price
  113. from
  114. price_per_pax
  115. where
  116. product_price_period_id = product_price_period.id
  117. and fit_price notnull
  118. limit 1)
  119. when product_price_period.price_mode_id = 4 then (
  120. select
  121. fit_price
  122. from
  123. price_per_age
  124. where
  125. product_price_period_id = product_price_period.id
  126. and fit_price notnull
  127. limit 1)
  128. end) as price
  129. ) as price on true`)
  130. .where(raw('product_price_period.price_period && ? = true', [requestedDateRange]));
  131.  
  132. const priceInfo = requestedDateRange => Product
  133. .query()
  134. .select(
  135. 'product_id', raw(`json_agg(json_build_object(
  136. 'sub_periods',price_sub_period
  137. )) FILTER (WHERE price IS NOT NULL) as price_info`),
  138. )
  139. .from(subPriceInfo(requestedDateRange).as('price_info'))
  140. .groupBy('product_id', 'price_sub_period');
  141. let products = await Product
  142. .query()
  143. .skipUndefined()
  144. .where('establishment_id', req.query.establishment_id)
  145. .andWhere('product_type_id', req.query.product_type_id)
  146. .modify((qb) => {
  147. if (req.query.is_balance === true) {
  148. qb.select('product.*', 'allotment_info',
  149. 'price_info',
  150. 'allotment_usage_info',
  151. 'unavailability_info')
  152. .from('product')
  153. .innerJoin(allotmentInfo(dateRange).as('product_allotment_info'),
  154. 'product_allotment_info.product_id', 'product.id')
  155. .leftJoin(allotmentUsageInfo(dateRange).as('product_allotment_usage_info'),
  156. 'product_allotment_usage_info.product_id', 'product.id')
  157. .leftJoin(isNotInBlackout(dateRange).as('product_unavailability_info'),
  158. 'product_unavailability_info.product_id', 'product.id')
  159. .innerJoin('establishment', 'establishment.id', 'product.establishment_id')
  160. .innerJoin(priceInfo(dateRange).as('product_price_info'),
  161. 'product_price_info.product_id', 'product.id')
  162. .innerJoin('provider', 'provider.id', 'establishment.provider_id')
  163. .where('product.status', true)
  164. .andWhere('establishment.status', true)
  165. .andWhere('provider.status', true)
  166. .whereNotNull('product_allotment_info')
  167. .whereNotNull('product_price_info');
  168. }
  169. })
  170. .limit(req.query.limit);
  171. if (products.length === 0) {
  172. return sendNoContentFound(req, res, productsWord);
  173. }
  174. if (req.query.is_balance === true) {
  175. products = products.map((product) => {
  176. const balance = _.flatten(product.allotment_info.map((allotement) => {
  177. const days = generateDaysFromRange(allotement.allotment_period);
  178.  
  179. const balanceArray = days && days.map((day) => {
  180. const quantity = product.allotment_usage_info && product.allotment_usage_info
  181. .filter(usage => usage.consumption_date === day).length > 0
  182. ? product.allotment_usage_info.filter(usage => usage.consumption_date
  183. === day)[0].quantity : 0;
  184. const nBalance = allotement.initial_stock + allotement.reassort - quantity;
  185. if (nBalance <= 0) {
  186. const blackOutDays = product.unavailability_info
  187. && _.flatten(product.unavailability_info.map(unavailability =>
  188. isDayOfYearInRange(unavailability.unavailability_period, moment(day))));
  189. if (blackOutDays && blackOutDays.some(black => black === true)) return null;
  190. // const subPeriods = product.price_info.map(sub =>
  191. // isDayOfYearInRange(sub.sub_period, moment(day)));
  192. // if (subPeriods.some(period => period === true)) {
  193. // return { day, balance: nBalance };
  194. // }
  195. // return null;
  196. return { day, balance: nBalance };
  197. }
  198. return null;
  199. });
  200.  
  201. return balanceArray;
  202. })).filter(Boolean);
  203. const nProduct = product;
  204. delete nProduct.allotment_usage_info;
  205. delete nProduct.unavailability_info;
  206. // delete nProduct.price_info;
  207. nProduct.balance = balance;
  208. if (balance.length > 0) return nProduct;
  209. return null;
  210. });
  211. }
  212. return sendJsonResponse(req, res, OK, products, foundSuccessfully(productsWord));
  213. };
  214.  
  215. module.exports.readProductSchedules = async (req, res) => {
  216. const requestedDateRange = `[${req.query.start_date},${req.query.end_date})`;
  217. const products = await ProductSchedule
  218. .query()
  219. .select()
  220. .distinct('activity_date', 'start_hour', 'duration_in_minute')
  221. .joinRaw(`INNER JOIN lateral (
  222. select activity_date::date
  223. from generate_series(lower(period * ?::daterange),
  224. upper(period * ?::daterange) - interval '1day', '1 day') as activity_date
  225. where EXTRACT(DOW FROM activity_date) = ANY(checked_days::INT[])
  226. ) as days on true`, [requestedDateRange, requestedDateRange])
  227. .skipUndefined()
  228. .where('product_id', req.params.products_id)
  229. .orderBy('activity_date', 'asc');
  230. if (products.length === 0) {
  231. return sendNoContentFound(req, res, productsWord);
  232. }
  233. return sendJsonResponse(req, res, OK, products, foundSuccessfully(productsWord));
  234. };
  235.  
  236.  
  237. module.exports.readProduct = async (req, res) => {
  238. const product = await Product
  239. .query()
  240. .with(
  241. 'schedules', (qb) => {
  242. qb
  243. .select(
  244. 'product.*',
  245. raw(`COALESCE (
  246. json_agg(
  247. json_build_object(
  248. 'id',product_schedule.id,
  249. 'start_date',lower(product_schedule.period)::text,
  250. 'end_date',(upper(product_schedule.period) - integer '1')::text,
  251. 'checked_days',product_schedule.checked_days,
  252. 'start_hour',to_char(product_schedule.start_hour, 'HH24:MI'),
  253. 'hours', (product_schedule.duration_in_minute / 60),
  254. 'minutes', (product_schedule.duration_in_minute % 60))
  255. ) FILTER (WHERE product_schedule.id IS NOT NULL), '[]')
  256. as product_schedule`),
  257. )
  258. .from('product')
  259. .leftJoin('product_schedule', 'product.id', 'product_schedule.product_id')
  260. .where('product.id', req.params.products_id)
  261. .groupBy('product.id');
  262. },
  263. )
  264. .with(
  265. 'options', (qb) => {
  266. qb
  267. .select(
  268. 'product.id',
  269. raw(`COALESCE (
  270. json_agg(
  271. json_build_object(
  272. 'establishment_option_id', product_option.establishment_option_id,
  273. 'is_required', product_option.is_required)
  274. ) FILTER (WHERE product_option.id IS NOT NULL), '[]')
  275. as product_option`),
  276. )
  277. .from('product')
  278. .leftJoin('product_option', 'product.id', 'product_option.product_id')
  279. .where('product.id', req.params.products_id)
  280. .groupBy('product.id');
  281. },
  282. )
  283. .select()
  284. .from(raw('schedules JOIN options USING (id)'));
  285.  
  286.  
  287. if (product.length === 0) {
  288. return sendNoContentFound(req, res, productWord);
  289. }
  290. return sendJsonResponse(req, res, OK, product[0], foundSuccessfully(productWord));
  291. };
  292.  
  293. module.exports.createProduct = async (req, res) => {
  294. const product = await Product
  295. .query()
  296. .insert({
  297. name: req.body.name,
  298. product_type_id: req.body.product_type_id,
  299. establishment_id: req.body.establishment_id,
  300. tax_profile_id: req.body.tax_profile_id,
  301. });
  302. return sendJsonResponse(req, res, CREATED, { id: product.id }, addedSuccessfully(productWord));
  303. };
  304.  
  305. module.exports.updateProduct = async (req, res) => {
  306. const updatedValues = Object.assign({}, req.body, { id: parseInt(req.params.products_id, 10) });
  307. const productOptionsTodelete = [];
  308. if (updatedValues.product_option && updatedValues.product_option.length > 0) {
  309. const productOptionsToUpsert = [];
  310. updatedValues.product_option.forEach((opt) => {
  311. if (Object.keys(opt).length === 1 && Object.keys(opt)[0] === 'establishment_option_id') {
  312. productOptionsTodelete.push(opt.establishment_option_id);
  313. } else {
  314. productOptionsToUpsert.push({
  315. id: opt.establishment_option_id,
  316. is_required: opt.is_required,
  317. });
  318. }
  319. });
  320. updatedValues.product_option = productOptionsToUpsert;
  321. }
  322. const productScheduleTodelete = [];
  323. if (updatedValues.product_schedule && updatedValues.product_schedule.length > 0) {
  324. const productScheduleToUpsert = [];
  325. updatedValues.product_schedule.forEach((ps) => {
  326. if (Object.keys(ps).length === 1 && Object.keys(ps)[0] === 'id') {
  327. productScheduleTodelete.push(ps.id);
  328. } else {
  329. const productSchedule = Object.assign({}, ps);
  330. if (ps.checked_days) {
  331. productSchedule.checked_days = lit(ps.checked_days).asArray().castTo('int[]');
  332. }
  333. if (ps.start_date && ps.end_date) {
  334. productSchedule.period = `[${ps.start_date}, ${ps.end_date}]`;
  335. delete productSchedule.start_date;
  336. delete productSchedule.end_date;
  337. }
  338.  
  339. if (ps.hours !== undefined && ps.minutes !== undefined) {
  340. const hourPerMinutes = 60;
  341. productSchedule.duration_in_minute = ps.hours * hourPerMinutes + ps.minutes;
  342. delete productSchedule.hours;
  343. delete productSchedule.minutes;
  344. }
  345. productScheduleToUpsert.push(productSchedule);
  346. }
  347. });
  348. updatedValues.product_schedule = productScheduleToUpsert;
  349. }
  350.  
  351. return transaction(Product.knex(), async (trx) => {
  352. const productUpdate = await Product
  353. .query(trx)
  354. .upsertGraph(
  355. updatedValues,
  356. {
  357. relate: true,
  358. unrelate: false,
  359. noDelete: true,
  360. },
  361. );
  362. if (productOptionsTodelete.length > 0) {
  363. const product = await Product
  364. .query()
  365. .findById(req.params.products_id);
  366.  
  367. const productOptionDelete = await product
  368. .$relatedQuery('product_option', trx)
  369. .unrelate()
  370. .whereIn('establishment_option.id', productOptionsTodelete);
  371.  
  372. if (productOptionDelete === 0) {
  373. throw new Error(errorInDeleting(productOptionsWord));
  374. }
  375. return productOptionDelete;
  376. }
  377. if (productScheduleTodelete.length > 0) {
  378. const productScheduleDelete = await ProductSchedule
  379. .query()
  380. .delete()
  381. .whereIn('id', productScheduleTodelete);
  382. if (productScheduleDelete === 0) {
  383. throw new Error(errorInDeleting(productScheduleWord));
  384. }
  385. return productScheduleDelete;
  386. }
  387. return productUpdate;
  388. })
  389. .then(() => {
  390. sendJsonResponse(
  391. req, res, CREATED,
  392. updatedSuccessfully(productWord), updatedSuccessfully(productWord),
  393. );
  394. });
  395. };
  396. module.exports.deleteProduct = async (req, res) => {
  397. const product = await Product
  398. .query()
  399. .delete()
  400. .where('id', req.params.products_id);
  401.  
  402. if (product === 0) {
  403. return sendNotFoundError(req, res, productWord);
  404. }
  405. return sendJsonResponse(
  406. req, res, NO_CONTENT, deletedSuccessfully(productWord),
  407. deletedSuccessfully(productWord),
  408. );
  409. };
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement