portal/modules/projects/server/methods.js

import {Meteor} from 'meteor/meteor';
import {Roles} from 'meteor/alanning:roles';

Meteor.methods({
	'project.reassign'({projectIds, newAssignee}) {
		if (!Meteor.users.findOne({_id: this.userId, uses: 'portal'})) throw new Meteor.Error(403, 'Not authorized to do this operation - project.reassign');
		const {default: userIsInRole} = require('/common/utils/userIsInRole');
		if (!userIsInRole(Meteor.userId(), ['admin', 'manager'], 'portal-group')) throw new Meteor.Error(403, 'Not authorized to reassign project - project.reassign');
		const {check} = require('meteor/check');
		check(projectIds, [String]);
		check(newAssignee, String);
		const {default: AssigneeHistory} = require('/common/db/history/assignee/server');
		try {
			projectIds.forEach(p => {
				new AssigneeHistory({doc: {collection: 'projects', _id: p}, assignee: newAssignee}, {defaults: true}).save();
			});
		}
		catch (e) {
			Log.fatal('Unable to create history for project reassign', e, {projectIds, newAssignee});
		}
		const {default: Projects} = require('/common/db/project');
		return Projects.update({_id: {$in: projectIds}, 'assignedTo.userId': {$ne: newAssignee}}, {$set: {'assignedTo': {userId: newAssignee, on: new Date(), by: Meteor.userId()}}}, {multi: true});
	},
	'project.updateProcessStatus'({data, projectId}) {
		if (!Meteor.users.findOne({_id: this.userId, uses: 'portal'})) throw new Meteor.Error(403, 'Not authorized to do this operation - project.updateProcessStatus');
		const {check} = require('meteor/check');
		check(data, Object);
		check(projectId, String);
		const {default: Project} = require('/common/db/project/collection');
		const p = Project.findOne({_id: projectId});
		if (!p) throw new Meteor.Error(403, 'No such project found to assign - project.updateProcessStatus');
		p.updateProcessStatus(data);
	},
	'project.createProcessDetails'({projectId}) {
		if (!Meteor.users.findOne({_id: this.userId, uses: 'portal'})) throw new Meteor.Error(403, 'Not authorized to do this operation - project.createProcessDetails');
		const {check} = require('meteor/check');
		check(projectId, String);
		const {default: Project} = require('/common/db/project/collection');
		const p = Project.findOne({_id: projectId});
		if (!p) throw new Meteor.Error(403, 'No such project found to assign - project.createProcessDetails');
		p.populateNextProcesses();
	},
	'project.getTotalUnits&TotalConfig'({projectId}) {
		if (!Meteor.users.findOne({_id: this.userId, uses: 'portal'})) throw new Meteor.Error(403, 'Not authorized to do this operation - project.getTotalUnits&TotalConfig');
		const {check} = require('meteor/check');
		check(projectId, String);
		const {default: Units} = require('/common/db/unit');
		let r = {};
		r.totalUnits = Units.find({'project.id': projectId, removed: false}, {fields: {_id: 1}}).count();
		const {default: Configurations} = require('/common/db/configuration');
		r.totalConfigs = Configurations.find({projectId: projectId, removed: false}, {fields: {_id: 1}}).count();
		return r;
	},
	'project.mergeBlocks'({idToBeKept, idToBeDeleted, projectId}) {
		if (!Roles.userIsInRole(Meteor.userId(), 'admin', 'portal-group')) throw new Meteor.Error(403, 'Not authorized to do this operation - project.blocksMerge');
		const {check} = require('meteor/check');
		try {
			check([idToBeKept, idToBeDeleted, projectId], [String]);
		}
		catch (e) {
			e.error = 'notFatal';
			throw new Meteor.Error(e);
		}
		const {default: Project} = require('/common/db/project/collection');
		const project = Project.findOne({_id: projectId});
		if (!project) throw new Meteor.Error('notFatal', 'Project not found');
		return project.mergeBlocks(idToBeKept, idToBeDeleted);
	},
	'project.merge'(idToBeKept, idToBeDeleted) { // without login
		const {check} = require('meteor/check');
		try {
			check([idToBeKept, idToBeDeleted], [String]);
		}
		catch (e) {
			e.error = 'notFatal';
			throw new Meteor.Error(e);
		}
		const {default: Project} = require('/common/db/project/collection');
		const projectToBeDeleted = Project.findOne({_id: idToBeDeleted});
		if (!projectToBeDeleted) throw new Meteor.Error('notFatal', 'Project to be deleted not found');

		const projectToBeKept = Project.findOne({_id: idToBeKept});
		if (!projectToBeKept) throw new Meteor.Error('notFatal', 'Project to be kept not found');
		return projectToBeDeleted.mergeInto(idToBeKept);
	},
	'project.updateBasicDetails'(projectId, data) {
		const {default: Project} = require('/common/db/project/collection');
		let project = Project.findOne({_id: projectId});
		if ((project.status || {}).locked) throw new Meteor.Error('notFatal', 'The project is locked. No edits allowed.');
		project.set(data, {cast: true});
		project.save();
	},
	'project.updateLocation'({location, projectId, checkDuplicate} = {}) {
		if (!Meteor.users.findOne({_id: this.userId, uses: 'portal'})) throw new Meteor.Error(403, 'Not authorized to do this operation - project.updateLocation');
		const {check} = require('meteor/check');
		check(projectId, String);
		const {default: Project} = require('/common/db/project/collection');
		const project = Project.findOne({_id: projectId});
		if (!project) throw new Meteor.Error('notFatal', `No project exist with id:${projectId}`);
		if ((project.status || {}).locked) throw new Meteor.Error('notFatal', 'The project is locked. No edits allowed.');
		const {default: sanitize} = require('/common/utils/sanitize');
		location = sanitize(location, 'location');
		const {default: Locations} = require('/common/db/location');
		let locationData = Locations.findOne({_id: location.locality}, {fields: {_id: 1, name: 1, subLocations: 1}});
		const locationName = locationData?.name;
		const subLocalityName = locationData?.subLocations?.find(v => v._id === location.subLocality)?.name;
		project.name = `${(project.name?.includes('(') ? project.name.split('(')[0] : project.name).trim().toProperCase()}${locationName ? ` (${locationName + (subLocalityName ? ' - ' + subLocalityName : '')})` : ''}`;
		try {
			if (checkDuplicate) project.checkDuplicate(location.gps?.coordinates);
		}
		catch (err) {
			if (err.error === 'duplicate') throw err;
		}

		project.set('location', location, {cast: true, merge: true});
		return project.save();
	},
	'project.unit.rawUnit.fetch'(projectId) {
		if (!Meteor.users.findOne({_id: this.userId, uses: 'portal'})) throw new Meteor.Error(403, 'Not authorized to do this operation - project.unit.rawUnit.fetch');
		const {default: Projects} = require('/common/db/project');
		var project = Projects.findOne({_id: projectId});
		if (!project) return {};
		const {default: regexEscape} = require('/common/utils/regexEscape');
		const {default: RawUnits} = require('/common/db/rawUnit');
		const {default: Units} = require('/common/db/unit');
		var units = Units.find({'project.id': projectId, removed: false}).fetch();
		var rUnits = RawUnits.find({$or: [
			{'detailsByTC.project.id': projectId},
			{$text: {$search: `"${project.name}"`}, projectName: new RegExp(regexEscape(project.name), 'i'), removed: false},
		]}).fetch();
		var res = {units: {sold: [], cancelled: [], registered: [], pending: [], count: 0}, rawUnits: {cancelled: [], processed: [], pending: [], suspended: []}, configs: {count: 0}};
		units.map(function(u) {
			if (u.removed) return null;
			if (u.sale.status?.includes('sold')) return res.units.sold.push(u._id);
			if (u.cancellation.flag) return res.units.cancelled.push(u._id);
			if (u.processDetails && u.processDetails[5]) {
				if (u.processDetails[5].status === 'approved') return res.units.registered.push(u._id);
			}
			return res.units.pending.push(u._id);
		});
		rUnits.map(function(r) {
			if (r.removed) return null;
			if (r.cancellation?.flag) {
				if (r.cancellation?.temporary) return res.rawUnits.suspended.push(r._id);
				return res.rawUnits.cancelled.push(r._id);
			}
			if (r.processDetails && r.processDetails[0]) {
				if (r.processDetails[0].status === 'processed') return res.rawUnits.processed.push(r._id);
				if (r.processDetails[0].stage === 'pending' || r.processDetails[0].stage === 'groupAssociated') return res.rawUnits.pending.push(r._id);
			}
			return null;
		});

		res.units.count = Units.find({'project.id': projectId, removed: false}, {fields: {_id: 1}}).count();
		const {default: Configurations} = require('/common/db/configuration');
		res.configs.count = Configurations.find({projectId, removed: false}, {fields: {_id: 1}}).count();

		return res;
	},
	/**
	 *Meteor method to cancel or revive the RawUnits associated to particular project due to 'under construction or not dealing yet'
	 * @param {object} options -contains {projectId,cancel,reason}
	 * @returns {undefined}
	 */
	'project.rawUnit.cancel.revive'(options) {
		//If user is not authorized
		if (!Meteor.users.findOne({_id: this.userId, uses: 'portal'})) throw new Meteor.Error(403, 'Not authorized to do this operation - project.rawUnit.cancel.revive');
		//check integrity of options
		const {check} = require('meteor/check');
		check(options, Object);
		check(options.projectId, String);
		check(options.cancel, Boolean);
		check(options.reason, String);
		const {default: RawUnit} = require('/common/db/rawUnit/collection');
		const {projectId, cancel, reason} = options;
		//find the project with projectId
		const {default: Projects} = require('/common/db/project');
		let project = Projects.findOne({_id: projectId});
		if (!project) throw new Meteor.Error(403, 'No Project found with this Project Id:' + projectId);
		//Find the RawUnits associated with this project.
		const {default: regexEscape} = require('/common/utils/regexEscape');
		const {default: RawUnits} = require('/common/db/rawUnit');
		let rUnits = RawUnits.find({$text: {$search: `"${project.name}"`}, projectName: new RegExp(regexEscape(project.name), 'i'), removed: false}).fetch();
		//Error if no RawUnit found.
		if (!rUnits.length) throw new Meteor.Error(403, 'No RawUnit in this Project found');
		//Error if number of RawUnit exceeds 100
		if (rUnits.length > 100 && !Roles.userIsInRole(Meteor.userId(), 'admin', 'portal-group')) throw Meteor.Error('too-many', 'Too many rawUnits to trash. Contact admin.');
		/**
		 * toRevive : Array of RawUnit Ids to revive from cancellation status with matching reason.
		 * toCancel : Array of RawUnit Ids to cancel from pending status with reason.
		 * cantCancel : Array of RawUnit Identifier which donot have project in detailsByTC.
		 */
		let rawUnits = {toRevive: [], toCancel: [], cantCancel: []};
		rUnits.map(function(r) {
			if (r.removed) return null;
			if ((r.cancellation || {}).flag) {
				const {cannotReviveRawUnitReason} = require('/common/info/rawUnit/revivalUtils');
				let cannotReviveReason = cannotReviveRawUnitReason({rawUnit: r});
				if ((r.cancellation?.status === reason || (reason === 'suspended' && r.cancellation?.temporary)) && !cannotReviveReason) return rawUnits.toRevive.push(r._id);
				return null;
			}
			if (r.processDetails && r.processDetails[0]) {
				if (r.processDetails[0].status === 'processed') return null;
				if (r.processDetails[0].stage === 'pending' || r.processDetails[0].stage === 'groupAssociated') {
					if (!['noValidContact', 'notInterested'].includes(reason) && (r.propertyType?.type === 'apartment' || r.propertyType?.project) && !r.detailsByTC?.project?.id) {
						return rawUnits.cantCancel.push(r.identifier);
					}
					return rawUnits.toCancel.push(r._id);
				}
			}
			return null;
		});
		if (cancel) {
			const {toCancel, cantCancel} = rawUnits;
			//Throw Error if no RawUnit is there to cancel and some RU in cantCancel.
			if (cantCancel.length && !toCancel.length) {
				if (cantCancel.length) {
					if (cantCancel.length > 1) throw new Meteor.Error(403, 'RawUnit: ' + cantCancel[0] + ' and many others donot have Project');
					else {
						throw new Meteor.Error(403, 'This RawUnit: ' + cantCancel[0] + ' didnot have Project');
					}
				}
			}
			if (!toCancel.length) {
				throw new Meteor.Error(403, 'No RawUnit to cancel');
			}
			else {
				try {
					RawUnit.find({_id: {$in: toCancel}}).forEach((r) => {
						r.createIndividualGroup();
						r = RawUnit.findOne({_id: r._id});
						r.trash(reason);
					});
				}
				catch (e) {
					throw new Meteor.Error(e.error, e.reason);
				}
			}
		}
		else {
			//Reviving RawUnits here with matching reason
			const {toRevive} = rawUnits;
			if (toRevive.length) {
				try {
					RawUnit.find({_id: {$in: toRevive}}).forEach((r) => {
						r.revive();
					});
				}
				catch (e) {
					throw new Meteor.Error(e.error, e.reason);
				}
			}
			else {
				throw new Meteor.Error(403, 'No RawUnit to revive');
			}
		}
		return rawUnits.cantCancel;
	},
	searchProjectName(name) {
		if (!this.userId) throw new Meteor.Error(403, 'Not authorized to do this operation - searchProjectName');
		const {default: Projects} = require('/common/db/project');
		return Projects.find({removed: false, $text: {$search: `"${name}"`}}, {fields: {name: 1, score: {$meta: 'textScore'}}, limit: 5, sort: {score: {$meta: 'textScore'}}}).fetch();
	},
	'project.updateName'({projectId, data} = {}) {
		if (!Meteor.users.findOne({_id: this.userId, uses: 'portal'})) throw new Meteor.Error(403, 'Not authorized to do this operation - project.updateName');
		let project, create = false;
		let projectLabel = data.name?.label, url = data.url, locLabel = data.location?.label;
		const {default: Project} = require('/common/db/project/collection');
		const {Random} = require('meteor/random');
		const {default: Projects} = require('/common/db/project');
		// Now doing concate of project name and location in project.name
		projectLabel = `${(projectLabel.includes('(') ? projectLabel.split('(')[0] : projectLabel).trim().toProperCase()}${locLabel ? ` (${locLabel})` : ''}`;
		// find existing project with project name
		const existingProject = Projects.findOne({name: projectLabel});
		const currentProject = Projects.findOne({_id: projectId});

		// throw error if diff project with same project name and locality
		if (existingProject && existingProject._id !== currentProject?._id && existingProject.location.locality === data.location?.value) throw new Meteor.Error('notFatal', `Project already exist with same projectName: ${existingProject.name} and location:${data.location?.value}`);
		if (projectId) project = Project.findOne({_id: projectId});
		else {
			project = new Project({_id: Random.id()}, {defaults: true});
			create = true;
		}
		let location;
		if (data.location?.value) {
			let loc = data.location.value.trim().split(' - ');
			location = {locality: loc[0], subLocality: loc[1], url};
		}
		project.updateNameComp({projectLabel, notDealingTill: data.notDealingTill, cpStatus: data.cpStatus, location, names: data.names.map(n => n.name)});
		const projectName = Project.findOne({_id: project._id}, {fields: {name: 1}})?.name;

		return {create, projectId: project?._id, projectName: projectName};
	},
	'project.trash'(id, {reason: cancelledStatus = '', suspension}) {
		if (!Meteor.users.findOne({_id: this.userId, uses: 'portal'})) throw new Meteor.Error(403, 'Not authorized to do this operation - project.trash');
		const {check} = require('meteor/check');
		check([id, cancelledStatus], [String]);
		const {default: Project} = require('/common/db/project/collection');
		const {default: History} = require('/common/db/history/cancellation/server');
		const doc = Project.findOne({_id: id});
		if (!doc) throw new Meteor.Error(404, 'No such Project found - unit.trash');
		if (cancelledStatus === 'notDealingYet') doc.notDealingTill = new Date(new Date().setFullYear(new Date().getFullYear() + 10));
		doc.cancellation = {flag: true, temporary: Boolean(suspension), status: cancelledStatus};
		doc.save();
		new History({doc: {id: doc._id, collection: 'projects'}, status: cancelledStatus, assignedTo: doc.assignedTo?.userId, temporary: true}).save();
	},
	'project.revive'(id) {
		if (!Meteor.users.findOne({_id: this.userId, uses: 'portal'})) throw new Meteor.Error(403, 'Not authorized to do this operation - project.trash');
		const {check} = require('meteor/check');
		check(id, String);
		const {default: Project} = require('/common/db/project/collection');
		const {default: History} = require('/common/db/history/cancellation/server');
		const doc = Project.findOne({_id: id});
		if (!doc) throw new Meteor.Error(404, 'No such Project found - project.revive');
		if (doc.notDealingTill >  new Date(new Date().setFullYear(new Date().getFullYear() + 1))) doc.notDealingTill = null;
		doc.cancellation = {flag: false, temporary: false, status: 'revived'};
		doc.save();
		new History({doc: {id: doc._id, collection: 'projects'}, assignedTo: doc.assignedTo?.userId, status: 'revived', temporary: false}).save();
	},
	'project.updateLogo'({projectId, data, name}) {
		if (!this.userId) throw new Meteor.Error(403, 'Not authorized to do this operation - project.updateLogo');
		const {check} = require('meteor/check');
		check(name, String);
		check(data, [Object]);
		check(projectId, String);
		const {default: Project} = require('/common/db/project/collection');
		const project = Project.findOne({_id: projectId});
		if (!project) throw new Meteor.Error('notFatal', `No project exist with id:${projectId}`);
		if (data[0]?.name) project[name] = data[0].name;
		else delete project[name];
		if (!project.isModified() || !data) return;
		project.save();
	},
	'project.updateBlocks'({projectId, data}) {
		if (!this.userId) throw new Meteor.Error(403, 'Not authorized to do this operation - project.updateBlocks');
		const {check} = require('meteor/check');
		check(data, Object);
		check(projectId, String);
		const {default: Project} = require('/common/db/project/collection');
		const project = Project.findOne({_id: projectId});
		if (!project) throw new Meteor.Error('notFatal', `No project exist with id:${projectId}`);
		project.callMethod('updateBlocks', data);
	},
	'project.statusLocked'({projectId, data}) {
		const {check} = require('meteor/check');
		check(data, Boolean);
		check(projectId, String);
		const {default: Project} = require('/common/db/project/collection');
		const project = Project.findOne({_id: projectId});
		if (!project) throw new Meteor.Error('notFatal', `No project exist with id:${projectId}`);
		project.callMethod('statusLocked', data);
	},
	'projects.map.all'({filters = {}, getDataFromSingleCollection}) {
		if (!this.userId) throw new Meteor.Error(403, 'Not authorized to do this operation - projects.map.all');
		const {check} = require('meteor/check');
		check(filters, Object);
		const {default: getQuery} = require('/common/utils/filters/getQueryUsingFilterList');
		let	query = {};
		if (getDataFromSingleCollection) {
			const {getPipelineMemoized, getQueriesMemoized} = require('/common/db/projectList/server/utils');
			const q = getQueriesMemoized({filters});
			const {default: ProjectLists} = require('/common/db/projectList');
			const pipeline = getPipelineMemoized({query: q, getIdsOnly: true});
			let projectIds = ProjectLists.aggregate(pipeline)[0]?.projectIds || [];
			if (projectIds.length) query = {_id: {$in: projectIds}};
			else return [];
		}
		else {
			const {default: filterFactory} = require('/common/info/project/filterFactory');
			query = getQuery(filters, filterFactory) || {};
		}
		query = {...query, 'location.gps.coordinates': {$nin: [null, 0]}, 'location.gps.coordinates.0': {$gt: 70, $lt: 80}, 'location.gps.coordinates.1': {$gt: 10, $lt: 18}, removed: false};
		const {default: Projects} = require('/common/db/project');
		return Projects.find(query, {fields: {name: 1, 'location.gps': 1}}).fetch();
	},
	'project.updateMissing'({projectId, data}) {
		if (!Meteor.userId()) throw new Meteor.Error(403, 'Not authorized to do this operation - project.updateMissing');
		const {check} = require('meteor/check');
		check(projectId, String);
		check(data, Object);
		const {default: Project} = require('/common/db/project/collection');
		const project = Project.findOne({_id: projectId});
		if (!project) throw new Meteor.Error(403, 'No such project found to assign - project.updateProcessStatus');
		project.missing = (data.missingInProject || []).filter(k => k.name.trim().toLowerCase() !== project.name.trim().toLowerCase());
		project.save();
	},
	'project.image.updateCover'({projectId, image}) {
		if (!Meteor.userId()) throw new Meteor.Error(403, 'Not authorized to do this operation - project.image.updateCover');
		const {check} = require('meteor/check');
		check([projectId, image], [String]);
		const {default: Project} = require('/common/db/project/collection');
		const project = Project.findOne({_id: projectId});
		if (!project) throw new Meteor.Error('notFatal', `No project exist with id:${projectId}`);
		project.cover = image;
		project.save();
	},
	'project.image.showHideFromWebsite'({projectId, path, space, imageName}) {
		if (!Meteor.userId()) throw new Meteor.Error(403, 'Not authorized to do this operation - uproject.image.showHideFromWebsite');
		const {check} = require('meteor/check');
		check([projectId, imageName], [String]);
		const {default: Project} = require('/common/db/project/collection');
		let project = Project.findOne({_id: projectId});
		if (!project) throw new Meteor.Error('notFatal', `No project exist with id:${projectId}`);
		let msg;
		if (path) {
			if (~path?.indexOf('spaces')) {
				const images = project.get(path);
				let imageIndex = images.indexOfKey(imageName, 'name');
				if (imageIndex === -1) return;
				if (!images[imageIndex].tags) images[imageIndex].tags = [];
				let tagIndex = images[imageIndex].tags.indexOf('hidden');
				if (tagIndex === -1) {
					images[imageIndex].tags.addToSet('hidden');
					msg = 'Image hidden from website.';
				}
				else {
					images[imageIndex].tags.splice(tagIndex, 1);
					msg = 'Image visible to website.';
				}
			}
		}
		else if (!space) {
			let imageIndex, tagIndex;
			if (~(project.modelFlatImages || []).indexOfKey(imageName, 'name')) {
				imageIndex = project.modelFlatImages.indexOfKey(imageName, 'name');
				if (!project.modelFlatImages[imageIndex].tags) project.modelFlatImages[imageIndex].tags = [];
				tagIndex = project.modelFlatImages[imageIndex].tags.indexOf('hidden');
				if (tagIndex === -1) {
					project.modelFlatImages[imageIndex].tags.addToSet('hidden');
					msg = 'ModelImage hidden from website.';
				}
				else {
					project.modelFlatImages[imageIndex].tags.splice(tagIndex, 1);
					msg = 'ModelImage visible to website.';
				}
			}
			else if (~project.images.indexOfKey(imageName, 'name')) {
				imageIndex = project.images.indexOfKey(imageName, 'name');
				if (!project.images[imageIndex].tags) project.images[imageIndex].tags = [];
				tagIndex = project.images[imageIndex].tags.indexOf('hidden');
				if (tagIndex === -1) {
					project.images[imageIndex].tags.addToSet('hidden');
					msg = 'Image hidden from website.';
				}
				else {
					project.images[imageIndex].tags.splice(tagIndex, 1);
					msg = 'Image visible to website.';
				}
			}
		}
		project.save();
		// eslint-disable-next-line consistent-return
		return msg;
	},
	'project.files.delete'({projectId, name}) {
		if (!Meteor.userId()) throw new Meteor.Error(403, 'Not authorized to do this operation - project.files.delete');
		const {check} = require('meteor/check');
		check([projectId, name], [String]);
		const {default: Project} = require('/common/db/project/collection');
		const project = Project.findOne({_id: projectId});
		if (!project) throw new Meteor.Error('notFatal', `No project exist with id:${projectId}`);
		project.files = project.files.filter(f => f.name !== name);
		project.save();
	},
	'project.files.update'({projectId, data, name}) {
		if (!Meteor.userId()) throw new Meteor.Error(403, 'Not authorized to do this operation - project.files.update');
		const {check} = require('meteor/check');
		check([projectId, name], [String]);
		const {default: Project} = require('/common/db/project/collection');
		const project = Project.findOne({_id: projectId});
		if (!project) throw new Meteor.Error('notFatal', `No project exist with id:${projectId}`);
		if (data) project[name] = data.map(f => ({name: f.name, tags: f.tags, dated: f.dated ? new Date(f.dated) : f.dated, notes: f.notes}));
		project.save();
	},
	'project.delete'({projectId}) {
		if (!Meteor.userId()) throw new Meteor.Error(403, 'Not authorized to do this operation - project.delete');
		const {check} = require('meteor/check');
		check(projectId, String);
		const {default: Project} = require('/common/db/project/collection');
		const project = Project.findOne({_id: projectId});
		if (!project) throw new Meteor.Error('notFatal', `No project exist with id:${projectId}`);
		project.callMethod('delete');
	},
	'project.updateUnits'({projectId}) {
		if (!Meteor.userId()) throw new Meteor.Error(403, 'Not authorized to do this operation - project.updateUnits');
		const {check} = require('meteor/check');
		check(projectId, String);
		const {default: Project} = require('/common/db/project/collection');
		const project = Project.findOne({_id: projectId});
		if (!project) throw new Meteor.Error('notFatal', `No project exist with id:${projectId}`);
		project.callMethod('updateUnits', true);
	},
	'project.updateSlug'({projectId}) {
		if (!Meteor.userId()) throw new Meteor.Error(403, 'Not authorized to do this operation - project.updateSlug');
		const {check} = require('meteor/check');
		check(projectId, String);
		const {default: Project} = require('/common/db/project/collection');
		const project = Project.findOne({_id: projectId});
		if (!project) throw new Meteor.Error('notFatal', `No project exist with id:${projectId}`);
		project.callMethod('updateSlug');
	},
	'projects.fetchSpsConfigsAndUnitsCount'(projectId) {
		const {default: SellerProjects} = require('/common/db/sellerProject');
		const {default: Units} = require('/common/db/unit');
		const {default: Configurations} = require('/common/db/configuration');
		const {check} = require('meteor/check');
		check(projectId, String);
		let sellerProjects = SellerProjects.find({'project.id': projectId, removed: false}, {type: 1}).fetch();
		return {
			builder: ~sellerProjects.findIndex(sp => sp.type === 'builder') ? true : false,
			sps: sellerProjects.length,
			units: Units.find({sample: {$ne: true}, 'project.id': projectId, removed: false}).count(),
			configurations: Configurations.find({projectId, removed: false}).count(),
		};
	},
	'user.getProjectLocation'(val) {
		if (!this.userId) throw new Meteor.Error(403, 'Not authorized to do this operation', {method: 'user.getProjectLocation'});
		const {default: Locations} = require('/common/db/location');
		const {default: Projects} = require('/common/db/project');
		if (!val) return null;
		let locality = {};
		let project = Projects.findOne({_id: val}, {fields: {'location': 1}});
		if (project?.location?.locality) {
			let location = Locations.findOne({code: project.location.locality}, {fields: {code: 1, name: 1, subLocations: 1}});
			if (location)locality = {code: location.code, name: location.name};
		}
		return {locality};
	},

	'project.updateVisitType'({projectId, visitType}) {
		if (!this.userId) throw new Meteor.Error(403, 'Not authorized to do this operation', {method: 'project.updateVisitType'});
		const {check} = require('meteor/check');
		check(projectId, String);
		check(visitType, String);
		const {default: Project} = require('/common/db/project/collection');
		let project = Project.findOne({_id: projectId});
		if (!project) throw new Meteor.Error('notFatal', `No such Project found for this projectId : ${projectId}`);
		project.visitType = visitType;
		project.save();
	},
	'project.togglePrioritize'({projectId}) {
		if (!this.userId) throw new Meteor.Error(403, 'Not authorized to do this operation', {method: 'project.updateVisitType'});
		const {check} = require('meteor/check');
		check(projectId, String);
		const {default: Project} = require('/common/db/project/collection');
		let project = Project.findOne({_id: projectId});
		if (!project) throw new Meteor.Error('notFatal', `No such Project found for this projectId : ${projectId}`);
		project.callMethod('togglePrioritize', e => e && Log.error(e));
	},
	'project.assignRawUnits'({projectId}) {
		const {check} = require('meteor/check');
		check(projectId, String);
		const {default: Project} = require('/common/db/project/collection');
		let project = Project.findOne({_id: projectId});
		if (!project) throw new Meteor.Error('notFatal', `No such Project found for this projectId : ${projectId}`);
		const {default: Assignees} = require('/common/db/assignees');
		let c2cAssignee = Assignees.findOne({for: 'c2c', 'doc.collection': 'projects', 'doc.id': projectId, userIds: {$ne: ''}});
		if (!c2cAssignee) throw new Meteor.Error('notFatal', `C2C Assignee not found for project: ${projectId}`);
		if (!(c2cAssignee.userIds || []).includes(Meteor.userId())) {
			if (!Roles.userIsInRole(Meteor.userId(), [ 'manager'], 'settlin-analysis-ops')) {
				throw new Meteor.Error('notFatal', 'Not authorized to do this operation : project.assigneRawUnits');
			}
		}
		const {default: RawUnit} = require('/common/db/rawUnit/collection');
		let count = 0;
		RawUnit.find({
			projectId,
			'cancellation.flag': false,
			'processDetails.stage': 'pending',
			//where assignee is not there or assignee with past followUp
			$or: [
				{'assignedTo.userId': ''},
				{'assignedTo.userId': {$ne: ''}, 'followUp.at': {$lt: new Date(new Date().setHours(0, 0, 0, 0))}},
			],
		},
		).map(r => {
			r.setAssignedTo(c2cAssignee.userIds[0], {forceReAssign: true});
			r.followUp = {at: new Date(), remarks: 'Triggered by assignment from project page'};
			r.save();
			count++;
		});
		return count;
	},
});