186 lines
5.5 KiB
JavaScript
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,
|
|
};
|