const _ = require('lodash') const moment = require('moment-immutable') const { getWeeks, formatDate, parseDate } = require('../dates') const { Client, 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 && { inbound: day.inbound }) 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 extraClients = _.chain(services) .map(x => x.clientId) .filter(x => x) .uniq() .value() const clients = await Client.findAll({ where: { [Op.or]: [ { terminalId: terminal.id }, { id: { [Op.in]: extraClients } } ] }, order: [ 'name' ] }) const clientsById = _.chain(clients).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 serviceByClient = _.chain(services).map(l => [l.clientId, l]).fromPairs().value() // Map from staffMembers to preserve sorting wd.services = clients .map(sm => serviceByClient[sm.id] || {clientId: sm.id}) .map(sm => ({ clientId: sm.clientId, inbound: sm.inbound || null })) // Restore any staffMembers that are no longer assigned this terminal services.forEach(l => { if (!serviceByClient[l.clientId]) { 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 extraClients = _.chain(services) .map(x => x.clientId) .filter(x => x) .uniq() .value() const clients = await Client.findAll({ where: { [Op.or]: [ { terminalId: terminal.id }, { id: { [Op.in]: extraClients } } ] }, order: [ 'name' ] }) const clientsById = _.chain(clients).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 servicesByClient = _.chain(services).map(l => [l.clientId, l]).fromPairs().value() // Map from staffMembers to preserve sorting wd.services = clients.map(sm => servicesByClient[sm.id] || Service.build({clientId: sm.id, workdayId: wd.id})) // Restore any staffMembers that are no longer assigned this terminal services.forEach(l => { if (!clientsById[l.clientId]) { 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.clientId, l]).fromPairs().value() const workday = allWorkdays[i] workday.services.forEach(service => { const modelService = modelServicesById[service.clientId] service.inbound = modelService.inbound || 0 }) workday.inbound = workday.services.map(l => l.inbound).reduce((a, b) => a + b, 0) if (workday.inbound || !workday.isNewRecord) { await workday.save({ transaction }) } await Promise.all(workday.services.map(async service => { if (service.inbound || !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 }