|
|
@@ -0,0 +1,229 @@
|
|
|
+const _ = require('lodash')
|
|
|
+const moment = require('moment-immutable')
|
|
|
+const { getWeeks, formatDate, parseDate } = require('../dates')
|
|
|
+const { Retailer, Workday, Location, Service, sequelize } = require('../database')
|
|
|
+const { Op } = require('sequelize')
|
|
|
+
|
|
|
+const list = async (req, res) => {
|
|
|
+ const locationKey = req.params.location
|
|
|
+ const location = await Location.findOne({where: {key: locationKey}})
|
|
|
+ if (!location) return res.status(404).end()
|
|
|
+ const workdays = await Workday.findAll({where: { locationId: location.id }})
|
|
|
+
|
|
|
+ let workweeks = _.groupBy(workdays, d => formatDate(moment(d.date).startOf('week')))
|
|
|
+
|
|
|
+ // fill workweeks
|
|
|
+ getWeeks(10).forEach(week => {
|
|
|
+ const w = formatDate(week)
|
|
|
+ if (!workweeks[w]) workweeks[w] = []
|
|
|
+ })
|
|
|
+
|
|
|
+ // fill workdays
|
|
|
+ workweeks = _.chain(workweeks)
|
|
|
+ .toPairs()
|
|
|
+ .map(([w, days]) => {
|
|
|
+ days = _.chain(days)
|
|
|
+ .map(d => [moment(d.date).weekday(), d])
|
|
|
+ .fromPairs()
|
|
|
+ .value()
|
|
|
+
|
|
|
+ days = _.range(0, 7).map(d => days[d] || null)
|
|
|
+ .map(day => day && {
|
|
|
+ cartons: day.cartons
|
|
|
+ })
|
|
|
+
|
|
|
+ return {
|
|
|
+ workweek: w,
|
|
|
+ workdays: days
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .sortBy(x => x.workweek)
|
|
|
+ .reverse()
|
|
|
+ .value()
|
|
|
+
|
|
|
+ res.status(200).send(workweeks)
|
|
|
+}
|
|
|
+
|
|
|
+const get = async (req, res) => {
|
|
|
+ const locationKey = req.params.location
|
|
|
+ const location = await Location.findOne({where: {key: locationKey}})
|
|
|
+ const week = parseDate(req.params.week)
|
|
|
+ const workdays = await Workday.findAll({
|
|
|
+ where: {
|
|
|
+ locationId: location.id,
|
|
|
+ date: {
|
|
|
+ [Op.gte]: week,
|
|
|
+ [Op.lt]: moment(week).endOf('week')
|
|
|
+ }
|
|
|
+ },
|
|
|
+ order: [ 'date' ]
|
|
|
+ })
|
|
|
+ const services = await Service.findAll({
|
|
|
+ where: {
|
|
|
+ workdayId: {
|
|
|
+ [Op.in]: workdays.map(x => x.id)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+ const servicesByWorkday = _.groupBy(services, x => x.workdayId)
|
|
|
+ const extraRetailers = _.chain(services)
|
|
|
+ .map(x => x.retailerId)
|
|
|
+ .filter(x => x)
|
|
|
+ .uniq()
|
|
|
+ .value()
|
|
|
+ const retailers = await Retailer.findAll({
|
|
|
+ where: {
|
|
|
+ [Op.or]: [
|
|
|
+ { locationId: location.id },
|
|
|
+ {
|
|
|
+ id: {
|
|
|
+ [Op.in]: extraRetailers
|
|
|
+ }
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ },
|
|
|
+ order: [ 'name' ]
|
|
|
+ })
|
|
|
+ const retailersById = _.chain(retailers).map(x => [x.id, x]).fromPairs().value()
|
|
|
+
|
|
|
+ // Fill in empty days
|
|
|
+ const workdaysByKey = _.chain(workdays).map(wd => [formatDate(wd.date), wd]).fromPairs().value()
|
|
|
+ const allWorkdays = []
|
|
|
+ for (let day = week, i = 0; i < 7; i++, day = day.add(1, 'day')) {
|
|
|
+ const wd = workdaysByKey[formatDate(day)]
|
|
|
+ allWorkdays[i] = wd ? wd.toJSON() : {}
|
|
|
+ }
|
|
|
+
|
|
|
+ const workdaysWithServices = allWorkdays.map(wd => {
|
|
|
+ const services = servicesByWorkday[wd.id] || []
|
|
|
+ const serviceByRetailer = _.chain(services).map(l => [l.retailerId, l]).fromPairs().value()
|
|
|
+ // Map from staffMembers to preserve sorting
|
|
|
+ wd.services = retailers
|
|
|
+ .map(sm => serviceByRetailer[sm.id] || {retailerId: sm.id})
|
|
|
+ .map(sm => ({
|
|
|
+ retailerId: sm.retailerId,
|
|
|
+ cartons: sm.cartons || null
|
|
|
+ }))
|
|
|
+ // Restore any staffMembers that are no longer assigned this location
|
|
|
+ services.forEach(l => {
|
|
|
+ if (!serviceByRetailer[l.retailerId]) {
|
|
|
+ wd.services.push(l)
|
|
|
+ }
|
|
|
+ })
|
|
|
+ return wd
|
|
|
+ })
|
|
|
+
|
|
|
+ res.status(200).send({
|
|
|
+ workdays: allWorkdays
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+const patch = async (req, res) => {
|
|
|
+ const transaction = await sequelize.transaction()
|
|
|
+ try {
|
|
|
+ const locationKey = req.params.location
|
|
|
+ const location = await Location.findOne({where: {key: locationKey}})
|
|
|
+ const week = parseDate(req.params.week)
|
|
|
+ const workdays = await Workday.findAll({
|
|
|
+ where: {
|
|
|
+ locationId: location.id,
|
|
|
+ date: {
|
|
|
+ [Op.gte]: week,
|
|
|
+ [Op.lte]: moment(week).endOf('week')
|
|
|
+ }
|
|
|
+ },
|
|
|
+ order: [ 'date' ]
|
|
|
+ })
|
|
|
+ const services = await Service.findAll({
|
|
|
+ where: {
|
|
|
+ workdayId: {
|
|
|
+ [Op.in]: workdays.map(x => x.id)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+ const servicesByWorkday = _.groupBy(services, x => x.workdayId)
|
|
|
+ const extraRetailers = _.chain(services)
|
|
|
+ .map(x => x.retailerId)
|
|
|
+ .filter(x => x)
|
|
|
+ .uniq()
|
|
|
+ .value()
|
|
|
+ const retailers = await Retailer.findAll({
|
|
|
+ where: {
|
|
|
+ [Op.or]: [
|
|
|
+ { locationId: location.id },
|
|
|
+ {
|
|
|
+ id: {
|
|
|
+ [Op.in]: extraRetailers
|
|
|
+ }
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ },
|
|
|
+ order: [ 'name' ]
|
|
|
+ })
|
|
|
+ const retailersById = _.chain(retailers).map(x => [x.id, x]).fromPairs().value()
|
|
|
+
|
|
|
+ // Fill in empty days
|
|
|
+ const workdaysByKey = _.chain(workdays).map(wd => [formatDate(wd.date), wd]).fromPairs().value()
|
|
|
+ const allWorkdays = []
|
|
|
+ for (let day = week, i = 0; i < 7; i++, day = day.add(1, 'day')) {
|
|
|
+ const wd = workdaysByKey[formatDate(day)]
|
|
|
+ allWorkdays[i] = wd || Workday.build({
|
|
|
+ locationId: location.id,
|
|
|
+ date: week.add(i, 'day')
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ const workdaysWithServices = allWorkdays.map(wd => {
|
|
|
+ const services = servicesByWorkday[wd.id] || []
|
|
|
+ const servicesByRetailer = _.chain(services).map(l => [l.retailerId, l]).fromPairs().value()
|
|
|
+ // Map from staffMembers to preserve sorting
|
|
|
+ wd.services = retailers.map(sm => servicesByRetailer[sm.id] || Service.build({retailerId: sm.id, workdayId: wd.id}))
|
|
|
+ // Restore any staffMembers that are no longer assigned this location
|
|
|
+ services.forEach(l => {
|
|
|
+ if (!retailersById[l.retailerId]) {
|
|
|
+ wd.services.push(l)
|
|
|
+ }
|
|
|
+ })
|
|
|
+ return wd
|
|
|
+ })
|
|
|
+
|
|
|
+ // Update with model
|
|
|
+ const model = req.body
|
|
|
+ await Promise.all(model.workdays.map(async (modelWorkday, i) => {
|
|
|
+ const modelServicesById = _.chain(modelWorkday.services).map(l => [l.retailerId, l]).fromPairs().value()
|
|
|
+ const workday = allWorkdays[i]
|
|
|
+
|
|
|
+ workday.services.forEach(service => {
|
|
|
+ const modelService = modelServicesById[service.retailerId]
|
|
|
+
|
|
|
+ service.cartons = modelService.cartons || 0
|
|
|
+ })
|
|
|
+
|
|
|
+ workday.cartons = workday.services.map(l => l.cartons).reduce((a, b) => a + b, 0)
|
|
|
+
|
|
|
+ if (workday.cartons || !workday.isNewRecord) {
|
|
|
+ await workday.save({ transaction })
|
|
|
+ }
|
|
|
+
|
|
|
+ await Promise.all(workday.services.map(async service => {
|
|
|
+ if (service.cartons || !service.isNewRecord) {
|
|
|
+ await service.save({ transaction })
|
|
|
+ }
|
|
|
+ }))
|
|
|
+ }))
|
|
|
+ await transaction.commit()
|
|
|
+
|
|
|
+ res.status(200).end()
|
|
|
+
|
|
|
+ } catch (err) {
|
|
|
+ await transaction.rollback()
|
|
|
+ console.log(err.message)
|
|
|
+ console.log(err.sql)
|
|
|
+ throw err
|
|
|
+ }
|
|
|
+}
|
|
|
+module.exports = {
|
|
|
+ list,
|
|
|
+ get,
|
|
|
+ patch
|
|
|
+}
|