first commit
This commit is contained in:
@@ -0,0 +1,176 @@
|
||||
import { Document, Model, Schema, model, FilterQuery } from "mongoose";
|
||||
import {
|
||||
CreateCashFlowParams,
|
||||
FindCashFlowParams,
|
||||
ICashFlow,
|
||||
ICashFlowAdapter,
|
||||
PaginateCashFlowParams,
|
||||
PaginateCashFlowResults,
|
||||
} from "./CashFlow.Interface";
|
||||
import { PAYMENT_PROCCESS_DATE } from "../Payments/Payments.Interface";
|
||||
import AppointmentList from "../Appointments/Appointments";
|
||||
|
||||
export interface ICashFlowDocument extends Omit<ICashFlow, "id">, Document {}
|
||||
|
||||
export class CashFlowAdapterMongoose implements ICashFlowAdapter {
|
||||
schema: Schema;
|
||||
movementList: Model<ICashFlowDocument>;
|
||||
|
||||
constructor() {
|
||||
this.schema = new Schema({
|
||||
companyId: {
|
||||
type: Schema.Types.ObjectId,
|
||||
required: true,
|
||||
ref: "Company",
|
||||
},
|
||||
clientId: {
|
||||
type: Schema.Types.ObjectId,
|
||||
required: false,
|
||||
ref: "Client",
|
||||
},
|
||||
clientAccountMovementId: {
|
||||
type: Schema.Types.ObjectId,
|
||||
required: false,
|
||||
ref: "ClientAccountMovement",
|
||||
},
|
||||
paymentId: {
|
||||
type: Schema.Types.ObjectId,
|
||||
required: false,
|
||||
ref: "Payment",
|
||||
},
|
||||
appointmentId: {
|
||||
type: Schema.Types.ObjectId,
|
||||
required: false,
|
||||
ref: "Appointment",
|
||||
},
|
||||
employeeId: {
|
||||
type: Schema.Types.ObjectId,
|
||||
required: false,
|
||||
ref: "Employee",
|
||||
},
|
||||
amount: { type: Number, required: true, default: 0 },
|
||||
description: { type: String, required: false, default: "" },
|
||||
year: { type: Number, required: true, default: 0 },
|
||||
month: { type: Number, required: true, default: 0 },
|
||||
type: { type: String, required: true, default: 0 },
|
||||
reference: { type: String, required: false, default: "" },
|
||||
paymentMethod: { type: String, required: false },
|
||||
createdAt: { type: Date, required: true, default: Date.now },
|
||||
});
|
||||
|
||||
this.movementList = model<ICashFlowDocument>("CashFlow", this.schema);
|
||||
}
|
||||
|
||||
public async create(data: CreateCashFlowParams): Promise<ICashFlow> {
|
||||
let creationDate = new Date();
|
||||
|
||||
if (data.proccessDate == PAYMENT_PROCCESS_DATE.NOW) {
|
||||
creationDate = new Date();
|
||||
} else if (data.proccessDate == PAYMENT_PROCCESS_DATE.APPOINTMENT) {
|
||||
const appointment = await AppointmentList.Appointments.AppointmentList.findOne({
|
||||
_id: data.appointmentId,
|
||||
});
|
||||
if (!appointment) {
|
||||
throw new Error("No se encontró la reserva");
|
||||
}
|
||||
creationDate = new Date(appointment.start);
|
||||
}
|
||||
|
||||
return await this.movementList.create({ ...data, createdAt: creationDate });
|
||||
}
|
||||
|
||||
public async delete(id: string): Promise<void> {
|
||||
await this.movementList.deleteOne({ _id: id });
|
||||
}
|
||||
|
||||
private buildSearchCriteria(
|
||||
filters: Omit<FindCashFlowParams, "sessionUser">
|
||||
): FilterQuery<ICashFlow> {
|
||||
const searchCriteria: FilterQuery<ICashFlow> = {};
|
||||
|
||||
if (filters.startDate) {
|
||||
searchCriteria.createdAt = {
|
||||
$gte: filters.startDate,
|
||||
$lte: filters.endDate,
|
||||
};
|
||||
}
|
||||
|
||||
if (filters.year) {
|
||||
searchCriteria.year = filters.year;
|
||||
}
|
||||
|
||||
if (filters.month) {
|
||||
searchCriteria.month = filters.month;
|
||||
}
|
||||
|
||||
if (filters.type) {
|
||||
searchCriteria.type = filters.type;
|
||||
}
|
||||
|
||||
if (filters.reference) {
|
||||
searchCriteria.reference = filters.reference;
|
||||
}
|
||||
|
||||
if (filters.clientId) {
|
||||
searchCriteria.clientId = filters.clientId;
|
||||
}
|
||||
|
||||
if (filters.clientAccountMovementId) {
|
||||
searchCriteria.clientAccountMovementId = filters.clientAccountMovementId;
|
||||
}
|
||||
|
||||
if (filters.companyId) {
|
||||
searchCriteria.companyId = filters.companyId;
|
||||
}
|
||||
|
||||
if (filters.paymentId) {
|
||||
searchCriteria.paymentId = filters.paymentId;
|
||||
}
|
||||
|
||||
if (filters.appointmentId) {
|
||||
searchCriteria.appointmentId = filters.appointmentId;
|
||||
}
|
||||
|
||||
if (filters.employeeId) {
|
||||
searchCriteria.employeeId = filters.employeeId;
|
||||
}
|
||||
|
||||
if (filters.paymentMethod) {
|
||||
searchCriteria.paymentMethod = filters.paymentMethod;
|
||||
}
|
||||
|
||||
return searchCriteria;
|
||||
}
|
||||
|
||||
public async paginate(filters: PaginateCashFlowParams): Promise<PaginateCashFlowResults> {
|
||||
const searchCriteria = this.buildSearchCriteria(filters);
|
||||
|
||||
const count = await this.movementList.countDocuments(searchCriteria).exec();
|
||||
const skip = (filters.page - 1) * filters.limit;
|
||||
|
||||
const results = await this.movementList
|
||||
.find(searchCriteria)
|
||||
.skip(skip)
|
||||
.limit(filters.limit)
|
||||
.sort({ createdAt: -1 })
|
||||
.exec();
|
||||
|
||||
return {
|
||||
data: results,
|
||||
balance: 0,
|
||||
page: filters.page,
|
||||
pages: Math.ceil(count / filters.limit),
|
||||
};
|
||||
}
|
||||
|
||||
public async find(filters: Omit<FindCashFlowParams, "sessionUser">): Promise<ICashFlow[]> {
|
||||
const searchCriteria = this.buildSearchCriteria(filters);
|
||||
return this.movementList.find(searchCriteria).exec();
|
||||
}
|
||||
|
||||
public async findOne(
|
||||
filters: Omit<FindCashFlowParams, "sessionUser">
|
||||
): Promise<ICashFlowDocument | null> {
|
||||
return this.movementList.findOne(filters).exec();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
import {
|
||||
CLIENT_ACCOUNT_MOVEMENT_TYPES,
|
||||
CLIENT_ACCOUNT_PAYMENT_METHODS,
|
||||
} from "../ClientAccountMovements/ClientAccountMovements.Interface";
|
||||
import {
|
||||
PAYMENT_METHODS_CLIENT_ACCOUNT,
|
||||
PAYMENT_PROCCESS_DATE,
|
||||
} from "../Payments/Payments.Interface";
|
||||
import { ICashFlowDocument } from "./CashFlow.Adapter.Mongoose";
|
||||
|
||||
export type FindCashFlowParams = {
|
||||
id?: string;
|
||||
companyId: string;
|
||||
paymentId?: string;
|
||||
clientId?: string;
|
||||
clientAccountMovementId?: string;
|
||||
appointmentId?: string;
|
||||
employeeId?: string;
|
||||
type?: CLIENT_ACCOUNT_MOVEMENT_TYPES;
|
||||
paymentMethod?: CLIENT_ACCOUNT_PAYMENT_METHODS | PAYMENT_METHODS_CLIENT_ACCOUNT;
|
||||
startDate?: Date;
|
||||
endDate?: Date;
|
||||
year?: number;
|
||||
month?: number;
|
||||
reference?: string;
|
||||
sessionUser: string;
|
||||
};
|
||||
|
||||
export type PaginateCashFlowParams = FindCashFlowParams & {
|
||||
page: number;
|
||||
limit: number;
|
||||
};
|
||||
|
||||
export type PaginateCashFlowResults = {
|
||||
data: ICashFlow[];
|
||||
balance: number;
|
||||
page: number;
|
||||
pages: number;
|
||||
};
|
||||
|
||||
export type CreateCashFlowParams = {
|
||||
companyId: string;
|
||||
paymentId?: string;
|
||||
clientId?: string;
|
||||
clientAccountMovenemtId?: string;
|
||||
appointmentId?: string;
|
||||
employeeId?: string;
|
||||
amount: number;
|
||||
description: string;
|
||||
reference: string;
|
||||
year: number;
|
||||
month: number;
|
||||
type: CLIENT_ACCOUNT_MOVEMENT_TYPES;
|
||||
paymentMethod: CLIENT_ACCOUNT_PAYMENT_METHODS | PAYMENT_METHODS_CLIENT_ACCOUNT;
|
||||
proccessDate: PAYMENT_PROCCESS_DATE;
|
||||
sessionUser: string;
|
||||
};
|
||||
|
||||
export type DeleteMovementByPaymentParams = {
|
||||
companyId: string;
|
||||
paymentId: string;
|
||||
sessionUser: string;
|
||||
};
|
||||
|
||||
export type DeleteMovementParams = {
|
||||
id: string;
|
||||
companyId: string;
|
||||
sessionUser: string;
|
||||
};
|
||||
|
||||
export type DeleteByClientAccountMovementParams = {
|
||||
companyId: string;
|
||||
clientAccountMovementId: string;
|
||||
sessionUser: string;
|
||||
};
|
||||
|
||||
export interface ICashFlow {
|
||||
id?: string;
|
||||
companyId: string;
|
||||
paymentId?: string;
|
||||
clientId?: string;
|
||||
clientAccountMovementId?: string;
|
||||
appointmentId?: string;
|
||||
employeeId?: string;
|
||||
amount: number;
|
||||
description: string;
|
||||
reference: string;
|
||||
year: number;
|
||||
month: number;
|
||||
type: CLIENT_ACCOUNT_MOVEMENT_TYPES;
|
||||
paymentMethod: CLIENT_ACCOUNT_PAYMENT_METHODS | PAYMENT_METHODS_CLIENT_ACCOUNT;
|
||||
createdAt: Date;
|
||||
}
|
||||
|
||||
export interface ICashFlowAdapter {
|
||||
create(data: CreateCashFlowParams): Promise<ICashFlow>;
|
||||
delete(id: string): Promise<void>;
|
||||
find(filters: FindCashFlowParams): Promise<ICashFlow[]>;
|
||||
findOne(filters: FindCashFlowParams): Promise<ICashFlowDocument | null>;
|
||||
paginate(filters: PaginateCashFlowParams): Promise<PaginateCashFlowResults>;
|
||||
}
|
||||
|
||||
export interface ICashFlowManager {
|
||||
movements: ICashFlowAdapter;
|
||||
add(data: CreateCashFlowParams): Promise<ICashFlow>;
|
||||
paginate(data: PaginateCashFlowParams): Promise<PaginateCashFlowResults>;
|
||||
getCashFlowBalance(data: FindCashFlowParams): Promise<number>;
|
||||
deleteByPayment(data: DeleteMovementByPaymentParams): Promise<void>;
|
||||
deleteByClientAccountMovement(data: DeleteByClientAccountMovementParams): Promise<void>;
|
||||
delete(data: DeleteMovementParams): Promise<void>;
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
import UsersManager from "../Users/Users";
|
||||
import { IUserDocument } from "../Users/Users.Adapter.Mongoose";
|
||||
import CompaniesList from "../Companies/Companies";
|
||||
import { EmployeeRoles } from "../Employees/Employees.Interface";
|
||||
import EmployeeManager from "../Employees/Employee";
|
||||
import { NoPermissionMessage } from "../../helpers/NoPermissionMessage";
|
||||
|
||||
import {
|
||||
CreateCashFlowParams,
|
||||
DeleteByClientAccountMovementParams,
|
||||
DeleteMovementByPaymentParams,
|
||||
DeleteMovementParams,
|
||||
FindCashFlowParams,
|
||||
ICashFlow,
|
||||
ICashFlowManager,
|
||||
PaginateCashFlowParams,
|
||||
PaginateCashFlowResults,
|
||||
} from "./CashFlow.Interface";
|
||||
import { CashFlowAdapterMongoose } from "./CashFlow.Adapter.Mongoose";
|
||||
import { CLIENT_ACCOUNT_MOVEMENT_TYPES } from "../ClientAccountMovements/ClientAccountMovements.Interface";
|
||||
import PlanSubscriptionsList from "../PlanSubscriptions/PlanSubscriptons";
|
||||
import { PlanFeatures } from "../Plans/Plans.interface";
|
||||
|
||||
class CashFlowManager implements ICashFlowManager {
|
||||
movements: CashFlowAdapterMongoose;
|
||||
|
||||
constructor() {
|
||||
this.movements = new CashFlowAdapterMongoose();
|
||||
}
|
||||
|
||||
public async getCashFlowBalance(data: FindCashFlowParams): Promise<number> {
|
||||
const userSession = await this.validateSessionUser(data.sessionUser);
|
||||
await this.validatePermissions(String(userSession.id), data.companyId);
|
||||
const movements = await this.movements.find(data);
|
||||
return movements.reduce((acc, movement) => acc + movement.amount, 0);
|
||||
}
|
||||
|
||||
public async delete(data: DeleteMovementParams): Promise<void> {
|
||||
const userSession = await this.validateSessionUser(data.sessionUser);
|
||||
await this.validatePermissions(String(userSession.id), data.companyId);
|
||||
await this.movements.delete(data.id);
|
||||
}
|
||||
|
||||
public async deleteByPayment(data: DeleteMovementByPaymentParams): Promise<void> {
|
||||
const userSession = await this.validateSessionUser(data.sessionUser);
|
||||
await this.validatePermissions(String(userSession.id), data.companyId);
|
||||
await this.movements.movementList.deleteOne({ paymentId: data.paymentId });
|
||||
}
|
||||
|
||||
public async deleteByClientAccountMovement(
|
||||
data: DeleteByClientAccountMovementParams
|
||||
): Promise<void> {
|
||||
const userSession = await this.validateSessionUser(data.sessionUser);
|
||||
await this.validatePermissions(String(userSession.id), data.companyId);
|
||||
await this.movements.movementList.deleteOne({
|
||||
clientAccountMovementId: data.clientAccountMovementId,
|
||||
});
|
||||
}
|
||||
|
||||
private async validateSessionUser(sessionUserId: string): Promise<IUserDocument> {
|
||||
const sessionUser = await UsersManager.users.findOne({
|
||||
_id: sessionUserId,
|
||||
});
|
||||
|
||||
if (!sessionUser) {
|
||||
throw new Error(
|
||||
"No se ha encontrado el usuario o no tiene permisos para realizar esta acción"
|
||||
);
|
||||
}
|
||||
|
||||
return sessionUser;
|
||||
}
|
||||
|
||||
private async validatePermissions(sessionUserId: string, companyId: string): Promise<void> {
|
||||
const company = await CompaniesList.companies.findOne({
|
||||
_id: companyId,
|
||||
});
|
||||
|
||||
if (!company) {
|
||||
throw new Error("No se ha encontrado la organización");
|
||||
}
|
||||
|
||||
// Verificar si el usuario de sesión es un empleado con permisos de administrador
|
||||
const hasAdminPermission = await EmployeeManager.checkRoleById(
|
||||
companyId,
|
||||
sessionUserId,
|
||||
EmployeeRoles.ADMIN
|
||||
);
|
||||
|
||||
if (!hasAdminPermission) {
|
||||
throw new Error(NoPermissionMessage());
|
||||
}
|
||||
|
||||
const canAccess = await PlanSubscriptionsList.checkFeature({
|
||||
userId: String(company.ownerId),
|
||||
feature: PlanFeatures.PAYMENTS,
|
||||
});
|
||||
|
||||
if (!canAccess) {
|
||||
throw new Error("La organizacion no tiene un plan que soporte el módulo de pagos");
|
||||
}
|
||||
}
|
||||
|
||||
public async add(data: CreateCashFlowParams): Promise<ICashFlow> {
|
||||
const userSession = await this.validateSessionUser(data.sessionUser);
|
||||
await this.validatePermissions(String(userSession.id), data.companyId);
|
||||
|
||||
if (data.type === CLIENT_ACCOUNT_MOVEMENT_TYPES.DEPOSIT) {
|
||||
data.amount = Math.abs(data.amount);
|
||||
} else {
|
||||
data.amount = -Math.abs(data.amount);
|
||||
}
|
||||
|
||||
const movement = await this.movements.create({
|
||||
...data,
|
||||
...{ createdAt: new Date() },
|
||||
});
|
||||
|
||||
return movement;
|
||||
}
|
||||
|
||||
public async paginate(data: PaginateCashFlowParams): Promise<PaginateCashFlowResults> {
|
||||
const balance = await this.getCashFlowBalance(data);
|
||||
|
||||
const result = await this.movements.paginate(data);
|
||||
|
||||
return {
|
||||
...result,
|
||||
balance,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export default new CashFlowManager();
|
||||
Reference in New Issue
Block a user