const _ = require('lodash') const moment = require('moment-immutable') const { getWeeks, formatDate, parseDate } = require('../dates') const { Retailer, Workday, Terminal, Service, sequelize } = require('../database') const { Op } = require('sequelize') const list = async (req, res) => { const terminalKey = req.params.terminal const terminal = await Terminal.findOne({where: {key: terminalKey}}) if (!terminal) return res.status(404).end() const workdays = await Workday.findAll({where: { terminalId: terminal.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 terminalKey = req.params.terminal const terminal = await Terminal.findOne({where: {key: terminalKey}}) const week = parseDate(req.params.week) const workdays = await Workday.findAll({ where: { terminalId: terminal.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]: [ { terminalId: terminal.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 terminal 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 terminalKey = req.params.terminal const terminal = await Terminal.findOne({where: {key: terminalKey}}) const week = parseDate(req.params.week) const workdays = await Workday.findAll({ where: { terminalId: terminal.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]: [ { terminalId: terminal.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({ terminalId: terminal.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 terminal 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 }