add server to monorepo.

This commit is contained in:
a.bouhuolia
2023-02-03 11:57:50 +02:00
parent 28e309981b
commit 80b97b5fdc
1303 changed files with 137049 additions and 0 deletions

View File

@@ -0,0 +1,108 @@
import * as R from 'ramda';
import { isEmpty } from 'lodash';
import {
ILedger,
IVendor,
IVendorBalanceSummaryVendor,
IVendorBalanceSummaryQuery,
IVendorBalanceSummaryData,
INumberFormatQuery,
} from '@/interfaces';
import { ContactBalanceSummaryReport } from '../ContactBalanceSummary/ContactBalanceSummary';
export class VendorBalanceSummaryReport extends ContactBalanceSummaryReport {
readonly ledger: ILedger;
readonly baseCurrency: string;
readonly vendors: IVendor[];
readonly filter: IVendorBalanceSummaryQuery;
readonly numberFormat: INumberFormatQuery;
/**
* Constructor method.
* @param {IJournalPoster} receivableLedger
* @param {IVendor[]} vendors
* @param {IVendorBalanceSummaryQuery} filter
* @param {string} baseCurrency
*/
constructor(
ledger: ILedger,
vendors: IVendor[],
filter: IVendorBalanceSummaryQuery,
baseCurrency: string
) {
super();
this.ledger = ledger;
this.baseCurrency = baseCurrency;
this.vendors = vendors;
this.filter = filter;
this.numberFormat = this.filter.numberFormat;
}
/**
* Customer section mapper.
* @param {IVendor} vendor
* @returns {IVendorBalanceSummaryVendor}
*/
private vendorMapper = (vendor: IVendor): IVendorBalanceSummaryVendor => {
const closingBalance = this.ledger
.whereContactId(vendor.id)
.getClosingBalance();
return {
id: vendor.id,
vendorName: vendor.displayName,
total: this.getContactTotalFormat(closingBalance),
};
};
/**
* Mappes the vendor model object to vendor balance summary section.
* @param {IVendor[]} vendors - Customers.
* @returns {IVendorBalanceSummaryVendor[]}
*/
private vendorsMapper = (
vendors: IVendor[]
): IVendorBalanceSummaryVendor[] => {
return vendors.map(this.vendorMapper);
};
/**
* Detarmines whether the vendors post filter is active.
* @returns {boolean}
*/
private isVendorsPostFilter = (): boolean => {
return isEmpty(this.filter.vendorsIds);
};
/**
* Retrieve the vendors sections of the report.
* @param {IVendor} vendors
* @returns {IVendorBalanceSummaryVendor[]}
*/
private getVendorsSection(vendors: IVendor[]): IVendorBalanceSummaryVendor[] {
return R.compose(
R.when(this.isVendorsPostFilter, this.contactsFilter),
R.when(
R.always(this.filter.percentageColumn),
this.contactCamparsionPercentageOfColumn
),
this.vendorsMapper
)(vendors);
}
/**
* Retrieve the report statement data.
* @returns {IVendorBalanceSummaryData}
*/
public reportData(): IVendorBalanceSummaryData {
const vendors = this.getVendorsSection(this.vendors);
const total = this.getContactsTotalSection(vendors);
return { vendors, total };
}
reportColumns() {
return [];
}
}

View File

@@ -0,0 +1,69 @@
import { Inject, Service } from 'typedi';
import { isEmpty, map } from 'lodash';
import { IVendor, IAccount } from '@/interfaces';
import HasTenancyService from '@/services/Tenancy/TenancyService';
import { ACCOUNT_TYPE } from '@/data/AccountTypes';
@Service()
export default class VendorBalanceSummaryRepository {
@Inject()
tenancy: HasTenancyService;
/**
* Retrieve the report vendors.
* @param {number} tenantId
* @param {number[]} vendorsIds - Vendors ids.
* @returns {IVendor[]}
*/
public getVendors(
tenantId: number,
vendorsIds?: number[]
): Promise<IVendor[]> {
const { Vendor } = this.tenancy.models(tenantId);
const vendorQuery = Vendor.query().orderBy('displayName');
if (!isEmpty(vendorsIds)) {
vendorQuery.whereIn('id', vendorsIds);
}
return vendorQuery;
}
/**
* Retrieve the payable accounts.
* @param {number} tenantId
* @returns {Promise<IAccount[]>}
*/
public getPayableAccounts(tenantId: number): Promise<IAccount[]> {
const { Account } = this.tenancy.models(tenantId);
return Account.query().where('accountType', ACCOUNT_TYPE.ACCOUNTS_PAYABLE);
}
/**
* Retrieve the vendors transactions.
* @param {number} tenantId
* @param {Date} asDate
* @returns
*/
public async getVendorsTransactions(tenantId: number, asDate: Date | string) {
const { AccountTransaction } = this.tenancy.models(tenantId);
// Retrieve payable accounts .
const payableAccounts = await this.getPayableAccounts(tenantId);
const payableAccountsIds = map(payableAccounts, 'id');
// Retrieve the customers transactions of A/R accounts.
const customersTranasctions = await AccountTransaction.query().onBuild(
(query) => {
query.whereIn('accountId', payableAccountsIds);
query.modify('filterDateRange', null, asDate);
query.groupBy('contactId');
query.sum('credit as credit');
query.sum('debit as debit');
query.select('contactId');
}
);
return customersTranasctions;
}
}

View File

@@ -0,0 +1,118 @@
import { Inject } from 'typedi';
import moment from 'moment';
import { map } from 'lodash';
import * as R from 'ramda';
import TenancyService from '@/services/Tenancy/TenancyService';
import {
IVendor,
IVendorBalanceSummaryService,
IVendorBalanceSummaryQuery,
IVendorBalanceSummaryStatement,
ILedgerEntry,
} from '@/interfaces';
import { VendorBalanceSummaryReport } from './VendorBalanceSummary';
import Ledger from '@/services/Accounting/Ledger';
import VendorBalanceSummaryRepository from './VendorBalanceSummaryRepository';
import { Tenant } from '@/system/models';
export default class VendorBalanceSummaryService
implements IVendorBalanceSummaryService
{
@Inject()
tenancy: TenancyService;
@Inject('logger')
logger: any;
@Inject()
reportRepo: VendorBalanceSummaryRepository;
/**
* Defaults balance sheet filter query.
* @return {IVendorBalanceSummaryQuery}
*/
get defaultQuery(): IVendorBalanceSummaryQuery {
return {
asDate: moment().format('YYYY-MM-DD'),
numberFormat: {
precision: 2,
divideOn1000: false,
showZero: false,
formatMoney: 'total',
negativeFormat: 'mines',
},
percentageColumn: false,
noneZero: false,
noneTransactions: true,
};
}
/**
* Retrieve the vendors ledger entrjes.
* @param {number} tenantId -
* @param {Date|string} date -
* @returns {Promise<ILedgerEntry>}
*/
private async getReportVendorsEntries(
tenantId: number,
date: Date | string
): Promise<ILedgerEntry[]> {
const transactions = await this.reportRepo.getVendorsTransactions(
tenantId,
date
);
const commonProps = { accountNormal: 'credit' };
return R.map(R.merge(commonProps))(transactions);
}
/**
* Retrieve the statment of customer balance summary report.
* @param {number} tenantId - Tenant id.
* @param {IVendorBalanceSummaryQuery} query -
* @return {Promise<IVendorBalanceSummaryStatement>}
*/
async vendorBalanceSummary(
tenantId: number,
query: IVendorBalanceSummaryQuery
): Promise<IVendorBalanceSummaryStatement> {
const tenant = await Tenant.query()
.findById(tenantId)
.withGraphFetched('metadata');
const filter = { ...this.defaultQuery, ...query };
this.logger.info(
'[customer_balance_summary] trying to calculate the report.',
{
filter,
tenantId,
}
);
// Retrieve the vendors transactions.
const vendorsEntries = await this.getReportVendorsEntries(
tenantId,
query.asDate
);
// Retrieve the customers list ordered by the display name.
const vendors = await this.reportRepo.getVendors(
tenantId,
query.vendorsIds
);
// Ledger query.
const vendorsLedger = new Ledger(vendorsEntries);
// Report instance.
const reportInstance = new VendorBalanceSummaryReport(
vendorsLedger,
vendors,
filter,
tenant.metadata.baseCurrency
);
return {
data: reportInstance.reportData(),
columns: reportInstance.reportColumns(),
query: filter,
};
}
}

View File

@@ -0,0 +1,150 @@
import * as R from 'ramda';
import { tableMapper, tableRowMapper } from 'utils';
import {
IVendorBalanceSummaryData,
IVendorBalanceSummaryVendor,
IVendorBalanceSummaryTotal,
ITableRow,
IColumnMapperMeta,
IVendorBalanceSummaryQuery,
ITableColumn,
} from '@/interfaces';
enum TABLE_ROWS_TYPES {
VENDOR = 'VENDOR',
TOTAL = 'TOTAL',
}
export default class VendorBalanceSummaryTable {
i18n: any;
report: IVendorBalanceSummaryData;
query: IVendorBalanceSummaryQuery;
/**
* Constructor method.
* @param {IVendorBalanceSummaryData} report
* @param i18n
*/
constructor(
report: IVendorBalanceSummaryData,
query: IVendorBalanceSummaryQuery,
i18n
) {
this.report = report;
this.query = query;
this.i18n = i18n;
}
/**
* Retrieve percentage columns accessor.
* @returns {IColumnMapperMeta[]}
*/
private getPercentageColumnsAccessor = (): IColumnMapperMeta[] => {
return [
{
key: 'percentageOfColumn',
accessor: 'percentageOfColumn.formattedAmount',
},
];
};
/**
* Retrieve vendor node columns accessor.
* @returns {IColumnMapperMeta[]}
*/
private getVendorColumnsAccessor = (): IColumnMapperMeta[] => {
const columns = [
{ key: 'vendorName', accessor: 'vendorName' },
{ key: 'total', accessor: 'total.formattedAmount' },
];
return R.compose(
R.concat(columns),
R.when(
R.always(this.query.percentageColumn),
R.concat(this.getPercentageColumnsAccessor())
)
)([]);
};
/**
* Transformes the vendors to table rows.
* @param {IVendorBalanceSummaryVendor[]} vendors
* @returns {ITableRow[]}
*/
private vendorsTransformer = (
vendors: IVendorBalanceSummaryVendor[]
): ITableRow[] => {
const columns = this.getVendorColumnsAccessor();
return tableMapper(vendors, columns, {
rowTypes: [TABLE_ROWS_TYPES.VENDOR],
});
};
/**
* Retrieve total node columns accessor.
* @returns {IColumnMapperMeta[]}
*/
private getTotalColumnsAccessor = (): IColumnMapperMeta[] => {
const columns = [
{ key: 'total', value: this.i18n.__('Total') },
{ key: 'total', accessor: 'total.formattedAmount' },
];
return R.compose(
R.concat(columns),
R.when(
R.always(this.query.percentageColumn),
R.concat(this.getPercentageColumnsAccessor())
)
)([]);
};
/**
* Transformes the total to table row.
* @param {IVendorBalanceSummaryTotal} total
* @returns {ITableRow}
*/
private totalTransformer = (total: IVendorBalanceSummaryTotal): ITableRow => {
const columns = this.getTotalColumnsAccessor();
return tableRowMapper(total, columns, {
rowTypes: [TABLE_ROWS_TYPES.TOTAL],
});
};
/**
* Transformes the vendor balance summary to table rows.
* @param {IVendorBalanceSummaryData} vendorBalanceSummary
* @returns {ITableRow[]}
*/
public tableRows = (): ITableRow[] => {
const vendors = this.vendorsTransformer(this.report.vendors);
const total = this.totalTransformer(this.report.total);
return vendors.length > 0 ? [...vendors, total] : [];
};
/**
* Retrieve the report statement columns
* @returns {ITableColumn[]}
*/
public tableColumns = (): ITableColumn[] => {
const columns = [
{
key: 'name',
label: this.i18n.__('contact_summary_balance.account_name'),
},
{ key: 'total', label: this.i18n.__('contact_summary_balance.total') },
];
return R.compose(
R.when(
R.always(this.query.percentageColumn),
R.append({
key: 'percentage_of_column',
label: this.i18n.__('contact_summary_balance.percentage_column'),
})
),
R.concat(columns)
)([]);
};
}