'use strict'; const { AppParamError } = require('../helpers/app_error'); const Customer = require('../model/customer'), utils = require('../helpers/utils'), excelUtil = require('../helpers/file_excel'), moment = require('moment-timezone'); async function getCustUsage_post(req, res) { const input = req.body; if (!input || !utils.isValidDate(input.from) || !utils.isValidDate(input.to)) AppParamError.throw(); let matchOps = { active: true }; let from = new Date(input.from), to = new Date(input.to); if (Boolean(input.billable)) matchOps.billable = true; const pineline = [ { $match: matchOps }, { $lookup: { from: "jobs", localField: "_id", foreignField: "byPuid", as: "cust_jobs" } }, { $unwind: { path: '$cust_jobs' } }, { // Filter jobs at least from the creation dates $match: { "cust_jobs.createdAt": { $gte: from } } }, { $project: { name: 1, "cust_jobs._id": 1, "monthYear": { $dateToString: { "format": "%Y-%m", date: "$cust_jobs.createdAt", timezone: input.tz } } } }, { $lookup: { from: "applications", localField: "cust_jobs._id", foreignField: "jobId", as: "job_apps" } }, { $unwind: { path: '$job_apps' } }, { // Filter applications by processed dates $match: { "job_apps.updateDate": { $gte: from, $lte: to } } }, { $group: { "_id": { customer: "$name", month: "$monthYear" }, "totalSpray": { $sum: "$job_apps.totalSprayed" } } }, { $replaceRoot: { newRoot: { $mergeObjects: ["$_id", "$$ROOT"] } } }, { $sort: { customer: 1, month: 1 } }, { $group: { "_id": { customer: "$customer" }, "data": { $push: { month: "$month", sprayHa: { $round: ["$totalSpray", 2] } } } } }, { $project: { "tmp": { $arrayToObject: { $zip: { inputs: ["$data.month", "$data.sprayHa"] } } } } } ]; const data = await Customer.aggregate(pineline); let usage = []; if (data && data.length) { // Make full default month ranges value 0 spray let ranges = []; const dateFrom = moment(input.from).tz(input.tz); const dateTo = moment(input.to).tz(input.tz); let interim = dateFrom.clone(); while (dateTo > interim || interim.format('M') === dateTo.format('M')) { ranges[interim.format('YYYY-MM')] = 0; interim.add(1, 'month'); } // Merge full month ranges (with 0 spray) and found data to have full month-ranges data usage = data.map(it => ({ ...it._id, ...{ ...ranges, ...it.tmp } })); } res.json(usage); } async function exportUsageDetail_post(req, res) { const input = req.body; if (!input || !utils.isValidDate(input.from) || !utils.isValidDate(input.to)) AppParamError.throw(); let matchOps = { active: true }; let from = new Date(input.from), to = new Date(input.to); if (Boolean(input.billable)) matchOps.billable = true; // Optional applicators filter with case insensitive regex let applicatorFilter = {}; if (!utils.isEmptyArray(input.applicators)) { const regexPatterns = input.applicators.map(email => ({ $regex: `^${email.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}$`, $options: "i" })); applicatorFilter = { "cust_jobs.applicator": { $in: regexPatterns } }; } const pineline = [ { $match: matchOps }, { $lookup: { from: "jobs", localField: "_id", foreignField: "byPuid", as: "cust_jobs" } }, { $unwind: { path: '$cust_jobs' } }, { // Filter jobs at least from the creation dates and applicator $match: Object.assign({ "cust_jobs.createdAt": { $gte: from } }, applicatorFilter) }, { $project: { name: 1, contact: 1, address: 1, email: 1, phone: 1, "cust_jobs._id": 1, "cust_jobs.createdAt": input.tz ? { $dateToString: { date: "$cust_jobs.createdAt", format: '%Y-%m-%d', timezone: input.tz } } : 1, "cust_jobs.applicator": 1 } }, { $lookup: { from: "applications", localField: "cust_jobs._id", foreignField: "jobId", as: "job_apps" } }, { $unwind: { path: '$job_apps' } }, { $match: { "job_apps.updateDate": { $gte: from, $lte: to } } }, { $group: { "_id": { name: "$name", contact: "$contact", address: "$address", email: "$email", phone: "$phone", jobId: "$cust_jobs._id", "createdAt": "$cust_jobs.createdAt", applicator: "$cust_jobs.applicator" }, "totalSpray": { $sum: "$job_apps.totalSprayed" } } }, { $sort: { "_id.name": 1, "_id.createdAt": 1 } }, { $group: { "_id": { name: "$_id.name", contact: "$_id.contact", address: "$_id.address", email: "$_id.email", phone: "$_id.phone" }, "jobs": { $push: { jobId: "$_id.jobId", createdAt: "$_id.createdAt", applicator: "$_id.applicator", totalSpray: "$totalSpray" } } } }, { $addFields: { "_id.jobs": "$jobs" } }, { $project: { jobs: 0 } }, { $replaceRoot: { newRoot: "$_id" } } ]; const data = await Customer.aggregate(pineline); // Pipe the excel stream for client to download const dateFmt = 'YYYY-MM'; const dateFrom = input.tz ? moment(input.from).tz(input.tz) : moment.utc(input.from); const dateTo = input.tz ? moment(input.to).tz(input.tz) : moment.utc(input.from); let fileName = `CustomerSpray_${dateFrom.format(dateFmt)}`; if (Math.abs(dateFrom.diff(dateTo, 'months', true)) > 1.0) fileName += `_${dateTo.format(dateFmt)}`; res.status(200); res.setHeader('Content-disposition', `attachment; filename=${fileName}.xlsx`); res.setHeader('Content-type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'); await excelUtil.exportUsageDetail(data, res); res.end(); } function getCustBillingStatus_get(req, res) { // Dummy next billing cycle date const next_cycle = new Date(); next_cycle.setDate(next_cycle.getFullYear() + 1); res.json({ premium: 1, status: 'active', start: new Date(), next_cycle: next_cycle }); // next(); } module.exports = { getCustUsage_post, exportUsageDetail_post, getCustBillingStatus_get }