agmission/Development/server/controllers/client.js

170 lines
5.2 KiB
JavaScript

'use strict';
const Client = require('../model/client'),
Country = require('../model/country'),
ObjectId = require('mongodb').ObjectId,
userCtl = require('../controllers/user'),
cache = require('../helpers/mem_cache'),
utils = require('../helpers/utils'),
{ Errors } = require('../helpers/constants'),
{ AppError, AppParamError } = require('../helpers/app_error');
async function createClient_post(req, res) {
const _client = req.body;
delete _client._id;
await userCtl.ensureParentExists(_client);
delete _client.kind;
const newClient = new Client(_client);
const client = await newClient.save();
res.json(client);
}
async function getClient_get(req, res) {
const cId = req.params.client_id;
if (!ObjectId.isValid(cId)) AppError.throw(Errors.INVALID_PARAM);
const client = await Client.findOne({ _id: ObjectId(cId) }, null, { lean: true })
.populate({ path: 'Country', select: 'code name -_id' });
res.json(client);
}
async function updateClient_put(req, res) {
if (!utils.isObjectId(req.body['_id'])) AppError.throw(Errors.INVALID_PARAM);
const _client = req.body;
if (utils.isBlank(_client.username) && !utils.isBlank(_client.password))
_client.password = undefined;
if (!_client.hasOwnProperty('active')) _client.active = true;
const client = await Client.findOneAndUpdate({ _id: ObjectId(_client._id) }, _client, { runValidators: true, new: true, lean: true });
res.json(client);
}
async function deleteClient(req, res) {
const _id = req.params.client_id;
if (!utils.isObjectId(_id)) AppError.throw(Errors.INVALID_PARAM);
const client = await Client.findById(ObjectId(_id));
if (client) {
await client.removeFull();
}
cache.delete(_id);
res.json(client);
}
async function search_post(req, res) {
if (!utils.isObjectId(req.body.byPuid)) AppParamError.throw(Errors.INVALID_PUID);
const clients = await Client.find({ parent: ObjectId(req.body.byPuid), markedDelete: { $ne: true } }, '-password', { lean: true })
.populate({ path: 'Country', select: 'code name -_id' });
res.json(clients);
}
async function searchWithSetting_post(req, res) {
/*
params {
byPuid: <Parent (Applicator) User Id>,
excludeIds: [] (Optional - excluded Client Ids),
populateCountry: boolean (Optional - whether to populate country references, default false)
}
*/
const input = req.body;
if (!utils.isObjectId(input.byPuid)) AppParamError.throw(Errors.INVALID_PUID);
if (!utils.isEmptyArray(input.excludeIds) && input.excludeIds.some(id => !utils.isObjectId(id))) AppParamError.throw();
// Default to populating country if not specified
const populateCountry = input.populateCountry || false;
// Build the aggregation pipeline
const pipeline = [
{
$match: {
markedDelete: { $ne: true }, parent: ObjectId(input.byPuid),
...(!utils.isEmptyArray(input.excludeIds) && { _id: { $nin: input.excludeIds.map(id => ObjectId(id)) } })
}
},
{ $unset: ['password'] }
];
// Conditionally add country lookup
if (populateCountry) {
pipeline.push(
{
$lookup: {
from: 'countries',
let: { countryCode: '$country' },
pipeline: [
{ $match: { $expr: { $eq: ['$code', '$$countryCode'] } } },
{ $project: { _id: 0, code: 1, name: 1 } }
],
as: 'Country'
}
},
{ $unwind: { path: '$Country', preserveNullAndEmptyArrays: true } }
);
}
// Always include invoice settings lookup
pipeline.push(
{
$lookup: {
from: 'invoice_settings',
localField: '_id',
foreignField: 'userId',
as: 'invoiceSettings'
}
},
{ $unwind: { path: '$invoiceSettings', preserveNullAndEmptyArrays: true } }
);
const clients = await Client.aggregate(pipeline);
// For addresses, conditionally process country population
if (populateCountry && clients && clients.length > 0) {
// Get all unique country codes from addresses
const countryCodes = new Set();
for (const client of clients) {
if (client.addresses && client.addresses.length > 0) {
for (const addr of client.addresses) {
if (addr.country && typeof addr.country === 'string') {
countryCodes.add(addr.country);
}
}
}
}
// If we have country codes, fetch countries in a single query
if (countryCodes.size > 0) {
const countries = await Country.find({ code: { $in: Array.from(countryCodes) } }, 'code name -_id').lean();
// Create a map for quick lookup
const countryMap = {};
for (const country of countries) {
countryMap[country.code] = country;
}
// Replace country codes with country objects in each address
for (const client of clients) {
if (client.addresses && client.addresses.length > 0) {
for (const addr of client.addresses) {
if (addr.country && typeof addr.country === 'string' && countryMap[addr.country]) {
addr.country = countryMap[addr.country];
}
}
}
}
}
}
res.json(clients);
}
module.exports = {
createClient_post, getClient_get, updateClient_put, deleteClient, search_post, searchWithSetting_post,
};