services.js 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. const _ = require('lodash')
  2. const moment = require('moment-immutable')
  3. const { getWeeks, formatDate, parseDate } = require('../dates')
  4. const { Retailer, Workday, Terminal, Service, sequelize } = require('../database')
  5. const { Op } = require('sequelize')
  6. const list = async (req, res) => {
  7. const terminalKey = req.params.terminal
  8. const terminal = await Terminal.findOne({where: {key: terminalKey}})
  9. if (!terminal) return res.status(404).end()
  10. const workdays = await Workday.findAll({where: { terminalId: terminal.id }})
  11. let workweeks = _.groupBy(workdays, d => formatDate(moment(d.date).startOf('week')))
  12. // fill workweeks
  13. getWeeks(10).forEach(week => {
  14. const w = formatDate(week)
  15. if (!workweeks[w]) workweeks[w] = []
  16. })
  17. // fill workdays
  18. workweeks = _.chain(workweeks)
  19. .toPairs()
  20. .map(([w, days]) => {
  21. days = _.chain(days)
  22. .map(d => [moment(d.date).weekday(), d])
  23. .fromPairs()
  24. .value()
  25. days = _.range(0, 7).map(d => days[d] || null)
  26. .map(day => day && {
  27. cartons: day.cartons
  28. })
  29. return {
  30. workweek: w,
  31. workdays: days
  32. }
  33. })
  34. .sortBy(x => x.workweek)
  35. .reverse()
  36. .value()
  37. res.status(200).send(workweeks)
  38. }
  39. const get = async (req, res) => {
  40. const terminalKey = req.params.terminal
  41. const terminal = await Terminal.findOne({where: {key: terminalKey}})
  42. const week = parseDate(req.params.week)
  43. const workdays = await Workday.findAll({
  44. where: {
  45. terminalId: terminal.id,
  46. date: {
  47. [Op.gte]: week,
  48. [Op.lt]: moment(week).endOf('week')
  49. }
  50. },
  51. order: [ 'date' ]
  52. })
  53. const services = await Service.findAll({
  54. where: {
  55. workdayId: {
  56. [Op.in]: workdays.map(x => x.id)
  57. }
  58. }
  59. })
  60. const servicesByWorkday = _.groupBy(services, x => x.workdayId)
  61. const extraRetailers = _.chain(services)
  62. .map(x => x.retailerId)
  63. .filter(x => x)
  64. .uniq()
  65. .value()
  66. const retailers = await Retailer.findAll({
  67. where: {
  68. [Op.or]: [
  69. { terminalId: terminal.id },
  70. {
  71. id: {
  72. [Op.in]: extraRetailers
  73. }
  74. }
  75. ]
  76. },
  77. order: [ 'name' ]
  78. })
  79. const retailersById = _.chain(retailers).map(x => [x.id, x]).fromPairs().value()
  80. // Fill in empty days
  81. const workdaysByKey = _.chain(workdays).map(wd => [formatDate(wd.date), wd]).fromPairs().value()
  82. const allWorkdays = []
  83. for (let day = week, i = 0; i < 7; i++, day = day.add(1, 'day')) {
  84. const wd = workdaysByKey[formatDate(day)]
  85. allWorkdays[i] = wd ? wd.toJSON() : {}
  86. }
  87. const workdaysWithServices = allWorkdays.map(wd => {
  88. const services = servicesByWorkday[wd.id] || []
  89. const serviceByRetailer = _.chain(services).map(l => [l.retailerId, l]).fromPairs().value()
  90. // Map from staffMembers to preserve sorting
  91. wd.services = retailers
  92. .map(sm => serviceByRetailer[sm.id] || {retailerId: sm.id})
  93. .map(sm => ({
  94. retailerId: sm.retailerId,
  95. cartons: sm.cartons || null
  96. }))
  97. // Restore any staffMembers that are no longer assigned this terminal
  98. services.forEach(l => {
  99. if (!serviceByRetailer[l.retailerId]) {
  100. wd.services.push(l)
  101. }
  102. })
  103. return wd
  104. })
  105. res.status(200).send({
  106. workdays: allWorkdays
  107. })
  108. }
  109. const patch = async (req, res) => {
  110. const transaction = await sequelize.transaction()
  111. try {
  112. const terminalKey = req.params.terminal
  113. const terminal = await Terminal.findOne({where: {key: terminalKey}})
  114. const week = parseDate(req.params.week)
  115. const workdays = await Workday.findAll({
  116. where: {
  117. terminalId: terminal.id,
  118. date: {
  119. [Op.gte]: week,
  120. [Op.lte]: moment(week).endOf('week')
  121. }
  122. },
  123. order: [ 'date' ]
  124. })
  125. const services = await Service.findAll({
  126. where: {
  127. workdayId: {
  128. [Op.in]: workdays.map(x => x.id)
  129. }
  130. }
  131. })
  132. const servicesByWorkday = _.groupBy(services, x => x.workdayId)
  133. const extraRetailers = _.chain(services)
  134. .map(x => x.retailerId)
  135. .filter(x => x)
  136. .uniq()
  137. .value()
  138. const retailers = await Retailer.findAll({
  139. where: {
  140. [Op.or]: [
  141. { terminalId: terminal.id },
  142. {
  143. id: {
  144. [Op.in]: extraRetailers
  145. }
  146. }
  147. ]
  148. },
  149. order: [ 'name' ]
  150. })
  151. const retailersById = _.chain(retailers).map(x => [x.id, x]).fromPairs().value()
  152. // Fill in empty days
  153. const workdaysByKey = _.chain(workdays).map(wd => [formatDate(wd.date), wd]).fromPairs().value()
  154. const allWorkdays = []
  155. for (let day = week, i = 0; i < 7; i++, day = day.add(1, 'day')) {
  156. const wd = workdaysByKey[formatDate(day)]
  157. allWorkdays[i] = wd || Workday.build({
  158. terminalId: terminal.id,
  159. date: week.add(i, 'day')
  160. })
  161. }
  162. const workdaysWithServices = allWorkdays.map(wd => {
  163. const services = servicesByWorkday[wd.id] || []
  164. const servicesByRetailer = _.chain(services).map(l => [l.retailerId, l]).fromPairs().value()
  165. // Map from staffMembers to preserve sorting
  166. wd.services = retailers.map(sm => servicesByRetailer[sm.id] || Service.build({retailerId: sm.id, workdayId: wd.id}))
  167. // Restore any staffMembers that are no longer assigned this terminal
  168. services.forEach(l => {
  169. if (!retailersById[l.retailerId]) {
  170. wd.services.push(l)
  171. }
  172. })
  173. return wd
  174. })
  175. // Update with model
  176. const model = req.body
  177. await Promise.all(model.workdays.map(async (modelWorkday, i) => {
  178. const modelServicesById = _.chain(modelWorkday.services).map(l => [l.retailerId, l]).fromPairs().value()
  179. const workday = allWorkdays[i]
  180. workday.services.forEach(service => {
  181. const modelService = modelServicesById[service.retailerId]
  182. service.cartons = modelService.cartons || 0
  183. })
  184. workday.cartons = workday.services.map(l => l.cartons).reduce((a, b) => a + b, 0)
  185. if (workday.cartons || !workday.isNewRecord) {
  186. await workday.save({ transaction })
  187. }
  188. await Promise.all(workday.services.map(async service => {
  189. if (service.cartons || !service.isNewRecord) {
  190. await service.save({ transaction })
  191. }
  192. }))
  193. }))
  194. await transaction.commit()
  195. res.status(200).end()
  196. } catch (err) {
  197. await transaction.rollback()
  198. console.log(err.message)
  199. console.log(err.sql)
  200. throw err
  201. }
  202. }
  203. module.exports = {
  204. list,
  205. get,
  206. patch
  207. }