first commit

This commit is contained in:
2026-07-16 20:48:43 -03:00
commit 5696cee264
1111 changed files with 322270 additions and 0 deletions
@@ -0,0 +1,220 @@
import { ClientAccountsAdapterMongoose } from "./ClientAccounts.Adapter.Mongoose";
import {
CreateClientAccountParams,
IClientAccount,
IClientAccountsManager,
DeleteClientAccountParams,
FindClientAccountsParams,
ClientAccountView,
DeleteClientsAccountsByCompanyParams,
ClientAccountReport,
GetClientAccountReportParams,
GetPrevoiusBalanceParams,
ClientAccountReportItem,
} from "./ClientAccounts.Interface";
import ClientsList from "../Clients/Clients";
import ClientAccountMovements from "../ClientAccountMovements/ClientAccountMovements";
import { PlanFeatures } from "../Plans/Plans.interface";
import { validatePermissionsByClient, validateSessionUser } from "../../helpers/check";
class ClientAccountManager implements IClientAccountsManager {
clientAccounts: ClientAccountsAdapterMongoose;
constructor() {
this.clientAccounts = new ClientAccountsAdapterMongoose();
}
public async deleteClientsAccountsByCompany(
data: DeleteClientsAccountsByCompanyParams
): Promise<void> {
const clients = await ClientsList.clients.find({
companyId: data.companyId,
});
for (const client of clients) {
await ClientAccountMovements.movements.movementList.deleteMany({
clientId: String(client.id),
});
await this.clientAccounts.clientAccountList.deleteMany({
clientId: String(client.id),
});
}
}
public async createClientAccount(data: CreateClientAccountParams): Promise<IClientAccount> {
await validateSessionUser({ sessionUser: data.sessionUser });
await validatePermissionsByClient({
sessionUser: data.sessionUser,
feature: PlanFeatures.PAYMENTS,
clientId: data.clientId,
});
const existingAccount = await this.clientAccounts.findOne({
clientId: data.clientId,
});
if (existingAccount) {
throw new Error("El cliente ya tiene una cuenta registrada");
}
return await this.clientAccounts.create(data);
}
public async findById(data: FindClientAccountsParams): Promise<IClientAccount> {
await validateSessionUser({ sessionUser: data.sessionUser });
await validatePermissionsByClient({
sessionUser: String(data.sessionUser),
feature: PlanFeatures.PAYMENTS,
clientId: data.clientId,
});
let account = (await this.clientAccounts.findOne({
clientId: data.clientId,
})) as IClientAccount;
if (!account) {
account = await this.createClientAccount({
clientId: data.clientId,
amount: 0,
sessionUser: data.sessionUser,
});
}
return account;
}
public async deleteClientAccount(data: DeleteClientAccountParams): Promise<void> {
const { checkCashOnAccount = true } = data;
await validateSessionUser({ sessionUser: data.sessionUser });
const account = await this.clientAccounts.findOne({
clientId: data.clientId,
});
if (!account) {
return;
}
await validatePermissionsByClient({
sessionUser: String(data.sessionUser),
feature: PlanFeatures.PAYMENTS,
clientId: data.clientId,
});
if (account.amount && account.amount > 0 && checkCashOnAccount) {
throw new Error(
"No se puede eliminar la cuenta del cliente ya que tiene saldo positivo."
);
}
//eliminar todos los movimientos de la cuenta
await ClientAccountMovements.movements.movementList.deleteMany({
clientId: account.clientId,
});
await this.clientAccounts.delete(account.id);
}
public async clientAccountView(data: FindClientAccountsParams): Promise<ClientAccountView> {
await validateSessionUser({ sessionUser: data.sessionUser });
await validatePermissionsByClient({
sessionUser: String(data.sessionUser),
feature: PlanFeatures.PAYMENTS,
clientId: data.clientId,
});
const account = await this.findById({
clientId: data.clientId,
sessionUser: data.sessionUser,
});
if (!account || !account.id) {
throw new Error("No se encontró la cuenta del cliente");
}
const movements = await ClientAccountMovements.paginate({
clientId: data.clientId,
page: 1,
limit: 10,
sessionUser: data.sessionUser,
});
return {
id: account.id,
clientId: account.clientId,
amount: account.amount,
lastMovements: movements.data,
};
}
public async getAvailableAmount(data: FindClientAccountsParams): Promise<number> {
const account = await this.findById(data);
return account.amount;
}
public async getPrevoiusBalance(data: GetPrevoiusBalanceParams): Promise<number> {
const balance = await ClientAccountMovements.getBalance({
clientId: data.clientId,
endDate: data.date,
sessionUser: data.sessionUser,
});
return balance;
}
public async getAccountReport(
data: GetClientAccountReportParams
): Promise<ClientAccountReport> {
await validateSessionUser({ sessionUser: data.sessionUser });
const { company, client } = await validatePermissionsByClient({
sessionUser: String(data.sessionUser),
feature: PlanFeatures.PAYMENTS,
clientId: data.clientId,
});
const previousBalance = await this.getPrevoiusBalance({
clientId: data.clientId,
date: data.dateFrom,
sessionUser: data.sessionUser,
});
const movements = await ClientAccountMovements.movements.find({
clientId: data.clientId,
startDate: data.dateFrom,
endDate: data.dateTo,
}); //falta implementar filtros de fecha
const dataReport: ClientAccountReportItem[] = movements.map((movement) => {
return {
date: movement.createdAt,
description: movement.description,
credit: movement.amount > 0 ? movement.amount : 0,
debit: movement.amount < 0 ? Math.abs(movement.amount) : 0,
balance: 0, //se calcula luego
};
});
//calcular saldos parciales
let runningBalance = previousBalance;
for (let i = 0; i < dataReport.length; i++) {
runningBalance += dataReport[i].credit;
runningBalance -= dataReport[i].debit;
dataReport[i].balance = runningBalance;
}
//retornamos el reporte
return {
organizationId: String(company.id),
organizacionName: String(company.name),
clientId: String(data.clientId),
clientName: ClientsList.getClientFullName(client),
balance: previousBalance,
data: dataReport,
dateFrom: data.dateFrom,
dateTo: data.dateTo,
} as ClientAccountReport;
}
}
export default new ClientAccountManager();
@@ -0,0 +1,55 @@
import {
FindClientAccountsParams,
IClientAccountsAdapter,
IClientAccount,
CreateClientAccountParams,
} from "./ClientAccounts.Interface";
import { Document, Model, Schema, model } from "mongoose";
export interface IClientAccountDocument
extends Omit<IClientAccount, "id">,
Document {}
export class ClientAccountsAdapterMongoose implements IClientAccountsAdapter {
schema: Schema;
clientAccountList: Model<IClientAccountDocument>;
constructor() {
this.schema = new Schema({
clientId: {
type: Schema.Types.ObjectId,
required: true,
ref: "Client",
},
amount: { type: Number, required: true, default: 0 },
creationDate: { type: Date, required: true, default: Date.now },
});
this.clientAccountList = model<IClientAccountDocument>(
"ClientAccount",
this.schema
);
}
public async create(
data: CreateClientAccountParams
): Promise<IClientAccount> {
return await this.clientAccountList.create(data);
}
public async delete(id: string): Promise<void> {
await this.clientAccountList.deleteOne({ _id: id });
}
public async find(
filters: FindClientAccountsParams
): Promise<IClientAccount[]> {
return this.clientAccountList.find(filters).exec();
}
public async findOne(
filters: Omit<FindClientAccountsParams, "sessionUser">
): Promise<IClientAccountDocument | null> {
return this.clientAccountList.findOne(filters).exec();
}
}
@@ -0,0 +1,87 @@
import { IClientAccountMovement } from "../ClientAccountMovements/ClientAccountMovements.Interface";
import { IClientAccountDocument } from "./ClientAccounts.Adapter.Mongoose";
export type FindClientAccountsParams = {
clientId: string;
sessionUser: string;
};
export type CreateClientAccountParams = {
clientId: string;
amount: number;
sessionUser: string;
};
export type DeleteClientAccountParams = {
clientId: string;
checkCashOnAccount?: boolean;
sessionUser: string;
};
export type DeleteClientsAccountsByCompanyParams = {
companyId: string;
};
export type ClientAccountReportItem = {
date: Date;
description: string;
credit: number;
debit: number;
balance: number;
};
export type ClientAccountReport = {
organizacionName: string;
organizationId: string;
clientId: string;
clientName: string;
balance: number;
dateFrom: Date;
dateTo: Date;
data: ClientAccountReportItem[];
};
export type GetPrevoiusBalanceParams = {
clientId: string;
date: Date;
sessionUser: string;
};
export type GetClientAccountReportParams = {
clientId: string;
dateFrom: Date;
dateTo: Date;
sessionUser: string;
};
export interface ClientAccountView {
id: string;
clientId: string;
amount: number;
lastMovements: IClientAccountMovement[];
}
export interface IClientAccount {
id?: string;
clientId: string;
amount: number;
}
export interface IClientAccountsAdapter {
create(data: CreateClientAccountParams): Promise<IClientAccount>;
delete(id: string): Promise<void>;
find(filters: FindClientAccountsParams): Promise<IClientAccount[]>;
findOne(filters: FindClientAccountsParams): Promise<IClientAccountDocument | null>;
}
export interface IClientAccountsManager {
clientAccounts: IClientAccountsAdapter;
createClientAccount(data: CreateClientAccountParams): Promise<IClientAccount>;
findById(data: FindClientAccountsParams): Promise<IClientAccount>;
deleteClientAccount(data: DeleteClientAccountParams): Promise<void>;
deleteClientsAccountsByCompany(data: DeleteClientsAccountsByCompanyParams): Promise<void>;
clientAccountView(data: FindClientAccountsParams): Promise<ClientAccountView>;
getAvailableAmount(data: FindClientAccountsParams): Promise<number>;
getPrevoiusBalance(data: GetPrevoiusBalanceParams): Promise<number>;
getAccountReport(data: GetClientAccountReportParams): Promise<ClientAccountReport>;
}