agmission/Development/server/controllers/client.js

186 lines
5.5 KiB
JavaScript

'use strict';
const Client = require('../model/client'),
Country = require('../model/country'),
ObjectId = require('mongodb').ObjectId,
userCtl = require('../controllers/user'),
{ updateUser_put } = require('./user'), // Import user controller functions
cache = require('../helpers/mem_cache'),
utils = require('../helpers/utils'),
{ buildDynamicFilter } = require('../helpers/dynamic_filter'),
{ Errors, UserTypes } = require('../helpers/constants'),
{ AppError, AppParamError } = require('../helpers/app_error');
const CLIENT_FILTER_SCHEMA = {
name: 'text',
username: 'text',
email: 'text',
phone: 'text',
contact: 'text',
address: 'text',
};
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.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);
}
// Update client (reuses user controller logic)
async function updateClient_put(req, res) {
if (!req.body.kind) {
req.body.kind = UserTypes.CLIENT;
}
// Reuse the user controller's updateUser_put function directly
return updateUser_put(req, res);
}
// Delete client (reuses user controller logic)
async function deleteClient(req, res) {
const id = req.params.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 baseFilter = { parent: ObjectId(req.body.byPuid), markedDelete: { $ne: true } };
let dynFilter = {};
if (req.body.filters) {
try {
dynFilter = buildDynamicFilter(req.body.filters, CLIENT_FILTER_SCHEMA);
} catch (_e) { /* ignore invalid filter */ }
}
const clients = await Client.find({ ...baseFilter, ...dynFilter }, '-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,
};