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,148 @@
import { Service, Inject } from 'typedi';
import * as R from 'ramda';
import { Knex } from 'knex';
import { AccountNormal, IInventoryLotCost, ILedgerEntry } from '@/interfaces';
import { increment } from 'utils';
import HasTenancyService from '@/services/Tenancy/TenancyService';
import Ledger from '@/services/Accounting/Ledger';
import LedgerStorageService from '@/services/Accounting/LedgerStorageService';
import { groupInventoryTransactionsByTypeId } from '../../Inventory/utils';
@Service()
export class SaleReceiptCostGLEntries {
@Inject()
private tenancy: HasTenancyService;
@Inject()
private ledgerStorage: LedgerStorageService;
/**
* Writes journal entries from sales invoices.
* @param {number} tenantId - The tenant id.
* @param {Date} startingDate - Starting date.
* @param {boolean} override
*/
public writeInventoryCostJournalEntries = async (
tenantId: number,
startingDate: Date,
trx?: Knex.Transaction
): Promise<void> => {
const { InventoryCostLotTracker } = this.tenancy.models(tenantId);
const inventoryCostLotTrans = await InventoryCostLotTracker.query()
.where('direction', 'OUT')
.where('transaction_type', 'SaleReceipt')
.where('cost', '>', 0)
.modify('filterDateRange', startingDate)
.orderBy('date', 'ASC')
.withGraphFetched('receipt')
.withGraphFetched('item');
const ledger = this.getInventoryCostLotsLedger(inventoryCostLotTrans);
// Commit the ledger to the storage.
await this.ledgerStorage.commit(tenantId, ledger, trx);
};
/**
* Retrieves the inventory cost lots ledger.
* @param {} inventoryCostLots
* @returns {Ledger}
*/
private getInventoryCostLotsLedger = (
inventoryCostLots: IInventoryLotCost[]
) => {
// Groups the inventory cost lots transactions.
const inventoryTransactions =
groupInventoryTransactionsByTypeId(inventoryCostLots);
//
const entries = inventoryTransactions
.map(this.getSaleInvoiceCostGLEntries)
.flat();
return new Ledger(entries);
};
/**
*
* @param {IInventoryLotCost} inventoryCostLot
* @returns {}
*/
private getInvoiceCostGLCommonEntry = (
inventoryCostLot: IInventoryLotCost
) => {
return {
currencyCode: inventoryCostLot.receipt.currencyCode,
exchangeRate: inventoryCostLot.receipt.exchangeRate,
transactionType: inventoryCostLot.transactionType,
transactionId: inventoryCostLot.transactionId,
date: inventoryCostLot.date,
indexGroup: 20,
costable: true,
createdAt: inventoryCostLot.createdAt,
debit: 0,
credit: 0,
branchId: inventoryCostLot.receipt.branchId,
};
};
/**
* Retrieves the inventory cost GL entry.
* @param {IInventoryLotCost} inventoryLotCost
* @returns {ILedgerEntry[]}
*/
private getInventoryCostGLEntry = R.curry(
(
getIndexIncrement,
inventoryCostLot: IInventoryLotCost
): ILedgerEntry[] => {
const commonEntry = this.getInvoiceCostGLCommonEntry(inventoryCostLot);
const costAccountId =
inventoryCostLot.costAccountId || inventoryCostLot.item.costAccountId;
// XXX Debit - Cost account.
const costEntry = {
...commonEntry,
debit: inventoryCostLot.cost,
accountId: costAccountId,
accountNormal: AccountNormal.DEBIT,
itemId: inventoryCostLot.itemId,
index: getIndexIncrement(),
};
// XXX Credit - Inventory account.
const inventoryEntry = {
...commonEntry,
credit: inventoryCostLot.cost,
accountId: inventoryCostLot.item.inventoryAccountId,
accountNormal: AccountNormal.DEBIT,
itemId: inventoryCostLot.itemId,
index: getIndexIncrement(),
};
return [costEntry, inventoryEntry];
}
);
/**
* Writes journal entries for given sale invoice.
* -------
* - Cost of goods sold -> Debit -> YYYY
* - Inventory assets -> Credit -> YYYY
* --------
* @param {ISaleInvoice} saleInvoice
* @param {JournalPoster} journal
*/
public getSaleInvoiceCostGLEntries = (
inventoryCostLots: IInventoryLotCost[]
): ILedgerEntry[] => {
const getIndexIncrement = increment(0);
const getInventoryLotEntry =
this.getInventoryCostGLEntry(getIndexIncrement);
return inventoryCostLots.map(getInventoryLotEntry).flat();
};
}

View File

@@ -0,0 +1,44 @@
import { Service } from 'typedi';
import { ISaleReceipt } from '@/interfaces';
import { Transformer } from '@/lib/Transformer/Transformer';
import { formatNumber } from 'utils';
@Service()
export class SaleReceiptTransformer extends Transformer {
/**
* Include these attributes to sale invoice object.
* @returns {Array}
*/
public includeAttributes = (): string[] => {
return ['formattedAmount', 'formattedReceiptDate', 'formattedClosedAtDate'];
};
/**
* Retrieve formatted receipt date.
* @param {ISaleReceipt} invoice
* @returns {String}
*/
protected formattedReceiptDate = (receipt: ISaleReceipt): string => {
return this.formatDate(receipt.receiptDate);
};
/**
* Retrieve formatted estimate closed at date.
* @param {ISaleReceipt} invoice
* @returns {String}
*/
protected formattedClosedAtDate = (receipt: ISaleReceipt): string => {
return this.formatDate(receipt.closedAt);
};
/**
* Retrieve formatted invoice amount.
* @param {ISaleReceipt} estimate
* @returns {string}
*/
protected formattedAmount = (receipt: ISaleReceipt): string => {
return formatNumber(receipt.amount, {
currencyCode: receipt.currencyCode,
});
};
}

View File

@@ -0,0 +1,36 @@
import { Inject, Service } from 'typedi';
import PdfService from '@/services/PDF/PdfService';
import { templateRender } from 'utils';
import HasTenancyService from '@/services/Tenancy/TenancyService';
import { Tenant } from '@/system/models';
@Service()
export default class SaleReceiptsPdf {
@Inject()
pdfService: PdfService;
@Inject()
tenancy: HasTenancyService;
/**
* Retrieve sale invoice pdf content.
* @param {} saleInvoice -
*/
async saleReceiptPdf(tenantId: number, saleReceipt) {
const i18n = this.tenancy.i18n(tenantId);
const organization = await Tenant.query()
.findById(tenantId)
.withGraphFetched('metadata');
const htmlContent = templateRender('modules/receipt-regular', {
saleReceipt,
organizationName: organization.metadata.name,
organizationEmail: organization.metadata.email,
...i18n,
});
const pdfContent = await this.pdfService.pdfDocument(htmlContent);
return pdfContent;
}
}

View File

@@ -0,0 +1,31 @@
export const ERRORS = {
SALE_RECEIPT_NOT_FOUND: 'SALE_RECEIPT_NOT_FOUND',
DEPOSIT_ACCOUNT_NOT_FOUND: 'DEPOSIT_ACCOUNT_NOT_FOUND',
DEPOSIT_ACCOUNT_NOT_CURRENT_ASSET: 'DEPOSIT_ACCOUNT_NOT_CURRENT_ASSET',
SALE_RECEIPT_NUMBER_NOT_UNIQUE: 'SALE_RECEIPT_NUMBER_NOT_UNIQUE',
SALE_RECEIPT_IS_ALREADY_CLOSED: 'SALE_RECEIPT_IS_ALREADY_CLOSED',
SALE_RECEIPT_NO_IS_REQUIRED: 'SALE_RECEIPT_NO_IS_REQUIRED',
CUSTOMER_HAS_SALES_INVOICES: 'CUSTOMER_HAS_SALES_INVOICES',
};
export const DEFAULT_VIEW_COLUMNS = [];
export const DEFAULT_VIEWS = [
{
name: 'Draft',
slug: 'draft',
rolesLogicExpression: '1',
roles: [
{ index: 1, fieldKey: 'status', comparator: 'equals', value: 'draft' },
],
columns: DEFAULT_VIEW_COLUMNS,
},
{
name: 'Closed',
slug: 'closed',
rolesLogicExpression: '1',
roles: [
{ index: 1, fieldKey: 'status', comparator: 'equals', value: 'closed' },
],
columns: DEFAULT_VIEW_COLUMNS,
},
];

View File

@@ -0,0 +1,36 @@
import { Inject, Service } from 'typedi';
import events from '@/subscribers/events';
import { IInventoryCostLotsGLEntriesWriteEvent } from '@/interfaces';
import { SaleReceiptCostGLEntries } from '../SaleReceiptCostGLEntries';
@Service()
export class SaleReceiptCostGLEntriesSubscriber {
@Inject()
saleReceiptCostEntries: SaleReceiptCostGLEntries;
/**
* Attaches events.
*/
public attach(bus) {
bus.subscribe(
events.inventory.onCostLotsGLEntriesWrite,
this.writeJournalEntriesOnceWriteoffCreate
);
}
/**
* Writes the receipts cost GL entries once the inventory cost lots be written.
* @param {IInventoryCostLotsGLEntriesWriteEvent}
*/
writeJournalEntriesOnceWriteoffCreate = async ({
trx,
startingDate,
tenantId,
}: IInventoryCostLotsGLEntriesWriteEvent) => {
await this.saleReceiptCostEntries.writeInventoryCostJournalEntries(
tenantId,
startingDate,
trx
);
};
}