Compare commits
17 Commits
patch-3
...
feature/20
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
04d065b969 | ||
|
|
ca910ee489 | ||
|
|
17651e0768 | ||
|
|
151b623771 | ||
|
|
2d4459c2f9 | ||
|
|
3cbdc3ec96 | ||
|
|
3cfb5cdde8 | ||
|
|
736f2c4109 | ||
|
|
2e21437056 | ||
|
|
340b78d968 | ||
|
|
d006362be2 | ||
|
|
bc21dcb37e | ||
|
|
578b0deb3e | ||
|
|
c3dc26a1e4 | ||
|
|
32d74b0413 | ||
|
|
71b1206f8a | ||
|
|
cb1bcaae77 |
@@ -168,6 +168,16 @@
|
||||
"contributions": [
|
||||
"bug"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "Daniel15",
|
||||
"name": "Daniel Lo Nigro",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/91933?v=4",
|
||||
"profile": "https://d.sb/",
|
||||
"contributions": [
|
||||
"bug",
|
||||
"code"
|
||||
]
|
||||
}
|
||||
],
|
||||
"contributorsPerLine": 7,
|
||||
|
||||
@@ -135,6 +135,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://myself.vercel.app/"><img src="https://avatars.githubusercontent.com/u/42431274?v=4?s=100" width="100px;" alt="Sachin Mittal"/><br /><sub><b>Sachin Mittal</b></sub></a><br /><a href="https://github.com/bigcapitalhq/bigcapital/issues?q=author%3Amittalsam98" title="Bug reports">🐛</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://www.camilooviedo.com/"><img src="https://avatars.githubusercontent.com/u/64604272?v=4?s=100" width="100px;" alt="Camilo Oviedo"/><br /><sub><b>Camilo Oviedo</b></sub></a><br /><a href="https://github.com/bigcapitalhq/bigcapital/commits?author=Champetaman" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://nklmantey.com/"><img src="https://avatars.githubusercontent.com/u/90279429?v=4?s=100" width="100px;" alt="Mantey"/><br /><sub><b>Mantey</b></sub></a><br /><a href="https://github.com/bigcapitalhq/bigcapital/issues?q=author%3Anklmantey" title="Bug reports">🐛</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://d.sb/"><img src="https://avatars.githubusercontent.com/u/91933?v=4?s=100" width="100px;" alt="Daniel Lo Nigro"/><br /><sub><b>Daniel Lo Nigro</b></sub></a><br /><a href="https://github.com/bigcapitalhq/bigcapital/issues?q=author%3ADaniel15" title="Bug reports">🐛</a> <a href="https://github.com/bigcapitalhq/bigcapital/commits?author=Daniel15" title="Code">💻</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
5
packages/server/src/common/config/app.ts
Normal file
5
packages/server/src/common/config/app.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import { registerAs } from '@nestjs/config';
|
||||
|
||||
export default registerAs('app', () => ({
|
||||
baseUrl: process.env.BASE_URL,
|
||||
}));
|
||||
@@ -1,3 +1,4 @@
|
||||
import app from './app';
|
||||
import systemDatabase from './system-database';
|
||||
import tenantDatabase from './tenant-database';
|
||||
import signup from './signup';
|
||||
@@ -18,6 +19,7 @@ import throttle from './throttle';
|
||||
import cloud from './cloud';
|
||||
|
||||
export const config = [
|
||||
app,
|
||||
systemDatabase,
|
||||
cloud,
|
||||
tenantDatabase,
|
||||
|
||||
@@ -7,53 +7,46 @@ import {
|
||||
} from '@nestjs/common';
|
||||
import { type Observable } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { mapKeysDeep } from '@/utils/deepdash';
|
||||
|
||||
export function camelToSnake<T = any>(value: T) {
|
||||
export function camelToSnake<T = any>(value: T): T {
|
||||
if (value === null || value === undefined) {
|
||||
return value;
|
||||
}
|
||||
if (Array.isArray(value)) {
|
||||
return value.map(camelToSnake);
|
||||
}
|
||||
if (typeof value === 'object' && !(value instanceof Date)) {
|
||||
return Object.fromEntries(
|
||||
Object.entries(value).map(([key, value]) => [
|
||||
key
|
||||
.split(/(?=[A-Z])/)
|
||||
.join('_')
|
||||
.toLowerCase(),
|
||||
camelToSnake(value),
|
||||
]),
|
||||
);
|
||||
}
|
||||
return value;
|
||||
return mapKeysDeep(
|
||||
value,
|
||||
(_value: string, key: any, parent: any, context: any) => {
|
||||
if (Array.isArray(parent)) {
|
||||
// tell mapKeysDeep to skip mapping inside this branch
|
||||
context.skipChildren = true;
|
||||
return key;
|
||||
}
|
||||
return key
|
||||
.split(/(?=[A-Z])/)
|
||||
.join('_')
|
||||
.toLowerCase();
|
||||
},
|
||||
) as T;
|
||||
}
|
||||
|
||||
export function snakeToCamel<T = any>(value: T) {
|
||||
export function snakeToCamel<T = any>(value: T): T {
|
||||
if (value === null || value === undefined) {
|
||||
return value;
|
||||
}
|
||||
|
||||
if (Array.isArray(value)) {
|
||||
return value.map(snakeToCamel);
|
||||
}
|
||||
|
||||
const impl = (str: string) => {
|
||||
const converted = str.replace(/([-_]\w)/g, (group) =>
|
||||
group[1].toUpperCase(),
|
||||
);
|
||||
return converted[0].toLowerCase() + converted.slice(1);
|
||||
};
|
||||
|
||||
if (typeof value === 'object' && !(value instanceof Date)) {
|
||||
return Object.fromEntries(
|
||||
Object.entries(value).map(([key, value]) => [
|
||||
impl(key),
|
||||
snakeToCamel(value),
|
||||
]),
|
||||
);
|
||||
}
|
||||
return value;
|
||||
return mapKeysDeep(
|
||||
value,
|
||||
(_value: string, key: any, parent: any, context: any) => {
|
||||
if (Array.isArray(parent)) {
|
||||
// tell mapKeysDeep to skip mapping inside this branch
|
||||
context.skipChildren = true;
|
||||
return key;
|
||||
}
|
||||
const converted = key.replace(/([-_]\w)/g, (group) =>
|
||||
group[1].toUpperCase(),
|
||||
);
|
||||
return converted[0].toLowerCase() + converted.slice(1);
|
||||
},
|
||||
) as T;
|
||||
}
|
||||
|
||||
export const DEFAULT_STRATEGY = {
|
||||
@@ -63,7 +56,7 @@ export const DEFAULT_STRATEGY = {
|
||||
|
||||
@Injectable()
|
||||
export class SerializeInterceptor implements NestInterceptor<any, any> {
|
||||
constructor(@Optional() readonly strategy = DEFAULT_STRATEGY) {}
|
||||
constructor(@Optional() readonly strategy = DEFAULT_STRATEGY) { }
|
||||
|
||||
intercept(
|
||||
context: ExecutionContext,
|
||||
|
||||
@@ -8,6 +8,7 @@ import { ServiceErrorFilter } from './common/filters/service-error.filter';
|
||||
import { ModelHasRelationsFilter } from './common/filters/model-has-relations.filter';
|
||||
import { ValidationPipe } from './common/pipes/ClassValidation.pipe';
|
||||
import { ToJsonInterceptor } from './common/interceptors/to-json.interceptor';
|
||||
import { NestExpressApplication } from '@nestjs/platform-express';
|
||||
|
||||
global.__public_dirname = path.join(__dirname, '..', 'public');
|
||||
global.__static_dirname = path.join(__dirname, '../static');
|
||||
@@ -15,7 +16,10 @@ global.__views_dirname = path.join(global.__static_dirname, '/views');
|
||||
global.__images_dirname = path.join(global.__static_dirname, '/images');
|
||||
|
||||
async function bootstrap() {
|
||||
const app = await NestFactory.create(AppModule, { rawBody: true });
|
||||
const app = await NestFactory.create<NestExpressApplication>(AppModule, {
|
||||
rawBody: true,
|
||||
});
|
||||
app.set('query parser', 'extended');
|
||||
app.setGlobalPrefix('/api');
|
||||
|
||||
// create and mount the middleware manually here
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Type } from 'class-transformer';
|
||||
import { Transform, Type } from 'class-transformer';
|
||||
import {
|
||||
IsBoolean,
|
||||
IsEnum,
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
IsPositive,
|
||||
} from 'class-validator';
|
||||
import { ApiPropertyOptional } from '@nestjs/swagger';
|
||||
import { parseBoolean } from '@/utils/parse-boolean';
|
||||
|
||||
export class NumberFormatQueryDto {
|
||||
@ApiPropertyOptional({
|
||||
@@ -24,6 +25,7 @@ export class NumberFormatQueryDto {
|
||||
example: false,
|
||||
})
|
||||
@IsBoolean()
|
||||
@Transform(({ value }) => parseBoolean(value, false))
|
||||
@IsOptional()
|
||||
readonly divideOn1000: boolean;
|
||||
|
||||
@@ -32,6 +34,7 @@ export class NumberFormatQueryDto {
|
||||
example: true,
|
||||
})
|
||||
@IsBoolean()
|
||||
@Transform(({ value }) => parseBoolean(value, false))
|
||||
@IsOptional()
|
||||
readonly showZero: boolean;
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ export class BillBranchValidateSubscriber {
|
||||
* Validate branch existance on bill creating.
|
||||
* @param {IBillCreatingPayload} payload
|
||||
*/
|
||||
@OnEvent(events.bill.onCreating)
|
||||
@OnEvent(events.bill.onCreating, { suppressErrors: false })
|
||||
async validateBranchExistanceOnBillCreating({
|
||||
billDTO,
|
||||
}: IBillCreatingPayload) {
|
||||
@@ -30,7 +30,7 @@ export class BillBranchValidateSubscriber {
|
||||
* Validate branch existance once bill editing.
|
||||
* @param {IBillEditingPayload} payload
|
||||
*/
|
||||
@OnEvent(events.bill.onEditing)
|
||||
@OnEvent(events.bill.onEditing, { suppressErrors: false })
|
||||
async validateBranchExistanceOnBillEditing({ billDTO }: IBillEditingPayload) {
|
||||
await this.validateBranchExistance.validateTransactionBranchWhenActive(
|
||||
billDTO.branchId,
|
||||
|
||||
@@ -14,7 +14,7 @@ export class CashflowBranchDTOValidatorSubscriber {
|
||||
* Validate branch existance once cashflow transaction creating.
|
||||
* @param {ICommandCashflowCreatingPayload} payload
|
||||
*/
|
||||
@OnEvent(events.cashflow.onTransactionCreating)
|
||||
@OnEvent(events.cashflow.onTransactionCreating, { suppressErrors: false })
|
||||
async validateBranchExistanceOnCashflowTransactionCreating({
|
||||
newTransactionDTO,
|
||||
}: ICommandCashflowCreatingPayload) {
|
||||
|
||||
@@ -15,13 +15,13 @@ import {
|
||||
export class ContactBranchValidateSubscriber {
|
||||
constructor(
|
||||
private readonly validateBranchExistance: ValidateBranchExistance,
|
||||
) { }
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Validate branch existance on customer creating.
|
||||
* @param {ICustomerEventCreatingPayload} payload
|
||||
*/
|
||||
@OnEvent(events.customers.onCreating)
|
||||
@OnEvent(events.customers.onCreating, { suppressErrors: false })
|
||||
async validateBranchExistanceOnCustomerCreating({
|
||||
customerDTO,
|
||||
}: ICustomerEventCreatingPayload) {
|
||||
@@ -37,7 +37,7 @@ export class ContactBranchValidateSubscriber {
|
||||
* Validate branch existance once customer opening balance editing.
|
||||
* @param {ICustomerOpeningBalanceEditingPayload} payload
|
||||
*/
|
||||
@OnEvent(events.customers.onOpeningBalanceChanging)
|
||||
@OnEvent(events.customers.onOpeningBalanceChanging, { suppressErrors: false })
|
||||
async validateBranchExistanceOnCustomerOpeningBalanceEditing({
|
||||
openingBalanceEditDTO,
|
||||
}: ICustomerOpeningBalanceEditingPayload) {
|
||||
@@ -52,7 +52,7 @@ export class ContactBranchValidateSubscriber {
|
||||
* Validates the branch existance on vendor creating.
|
||||
* @param {IVendorEventCreatingPayload} payload
|
||||
*/
|
||||
@OnEvent(events.vendors.onCreating)
|
||||
@OnEvent(events.vendors.onCreating, { suppressErrors: false })
|
||||
async validateBranchExistanceonVendorCreating({
|
||||
vendorDTO,
|
||||
}: IVendorEventCreatingPayload) {
|
||||
@@ -68,7 +68,7 @@ export class ContactBranchValidateSubscriber {
|
||||
* Validate branch existance once the vendor opening balance editing.
|
||||
* @param {IVendorOpeningBalanceEditingPayload} payload
|
||||
*/
|
||||
@OnEvent(events.vendors.onOpeningBalanceChanging)
|
||||
@OnEvent(events.vendors.onOpeningBalanceChanging, { suppressErrors: false })
|
||||
async validateBranchExistanceOnVendorOpeningBalanceEditing({
|
||||
openingBalanceEditDTO,
|
||||
}: IVendorOpeningBalanceEditingPayload) {
|
||||
|
||||
@@ -15,7 +15,7 @@ export class CreditNoteBranchValidateSubscriber {
|
||||
* Validate branch existance on credit note creating.
|
||||
* @param {ICreditNoteCreatingPayload} payload
|
||||
*/
|
||||
@OnEvent(events.creditNote.onCreating)
|
||||
@OnEvent(events.creditNote.onCreating, { suppressErrors: false })
|
||||
async validateBranchExistanceOnCreditCreating({
|
||||
creditNoteDTO,
|
||||
}: ICreditNoteCreatingPayload) {
|
||||
@@ -28,7 +28,7 @@ export class CreditNoteBranchValidateSubscriber {
|
||||
* Validate branch existance once credit note editing.
|
||||
* @param {ICreditNoteEditingPayload} payload
|
||||
*/
|
||||
@OnEvent(events.creditNote.onEditing)
|
||||
@OnEvent(events.creditNote.onEditing, { suppressErrors: false })
|
||||
async validateBranchExistanceOnCreditEditing({
|
||||
creditNoteEditDTO,
|
||||
}: ICreditNoteEditingPayload) {
|
||||
|
||||
@@ -14,7 +14,7 @@ export class CreditNoteRefundBranchValidateSubscriber {
|
||||
* Validate branch existance on refund credit note creating.
|
||||
* @param {IRefundCreditNoteCreatingPayload} payload
|
||||
*/
|
||||
@OnEvent(events.creditNote.onRefundCreating)
|
||||
@OnEvent(events.creditNote.onRefundCreating, { suppressErrors: false })
|
||||
async validateBranchExistanceOnCreditRefundCreating({
|
||||
newCreditNoteDTO,
|
||||
}: IRefundCreditNoteCreatingPayload) {
|
||||
|
||||
@@ -16,7 +16,7 @@ export class ExpenseBranchValidateSubscriber {
|
||||
* Validate branch existance once expense transaction creating.
|
||||
* @param {IExpenseCreatingPayload} payload
|
||||
*/
|
||||
@OnEvent(events.expenses.onCreating)
|
||||
@OnEvent(events.expenses.onCreating, { suppressErrors: false })
|
||||
async validateBranchExistanceOnExpenseCreating({
|
||||
expenseDTO,
|
||||
}: IExpenseCreatingPayload) {
|
||||
@@ -29,7 +29,7 @@ export class ExpenseBranchValidateSubscriber {
|
||||
* Validate branch existance once expense transaction editing.
|
||||
* @param {IExpenseEventEditingPayload} payload
|
||||
*/
|
||||
@OnEvent(events.expenses.onEditing)
|
||||
@OnEvent(events.expenses.onEditing, { suppressErrors: false })
|
||||
async validateBranchExistanceOnExpenseEditing({
|
||||
expenseDTO,
|
||||
}: IExpenseEventEditingPayload) {
|
||||
|
||||
@@ -14,7 +14,7 @@ export class InventoryAdjustmentBranchValidateSubscriber {
|
||||
* Validate branch existance on inventory adjustment creating.
|
||||
* @param {IInventoryAdjustmentCreatingPayload} payload
|
||||
*/
|
||||
@OnEvent(events.inventoryAdjustment.onQuickCreating)
|
||||
@OnEvent(events.inventoryAdjustment.onQuickCreating, { suppressErrors: false })
|
||||
async validateBranchExistanceOnInventoryCreating({
|
||||
quickAdjustmentDTO,
|
||||
}: IInventoryAdjustmentCreatingPayload) {
|
||||
|
||||
@@ -17,7 +17,7 @@ export class InvoiceBranchValidateSubscriber {
|
||||
* Validate branch existance on invoice creating.
|
||||
* @param {ISaleInvoiceCreatingPayload} payload
|
||||
*/
|
||||
@OnEvent(events.saleInvoice.onCreating)
|
||||
@OnEvent(events.saleInvoice.onCreating, { suppressErrors: false })
|
||||
async validateBranchExistanceOnInvoiceCreating({
|
||||
saleInvoiceDTO,
|
||||
}: ISaleInvoiceCreatingPaylaod) {
|
||||
@@ -30,7 +30,7 @@ export class InvoiceBranchValidateSubscriber {
|
||||
* Validate branch existance once invoice editing.
|
||||
* @param {ISaleInvoiceEditingPayload} payload
|
||||
*/
|
||||
@OnEvent(events.saleInvoice.onEditing)
|
||||
@OnEvent(events.saleInvoice.onEditing, { suppressErrors: false })
|
||||
async validateBranchExistanceOnInvoiceEditing({
|
||||
saleInvoiceDTO,
|
||||
}: ISaleInvoiceEditingPayload) {
|
||||
|
||||
@@ -17,7 +17,7 @@ export class PaymentMadeBranchValidateSubscriber {
|
||||
* Validate branch existance on estimate creating.
|
||||
* @param {ISaleEstimateCreatedPayload} payload
|
||||
*/
|
||||
@OnEvent(events.billPayment.onCreating)
|
||||
@OnEvent(events.billPayment.onCreating, { suppressErrors: false })
|
||||
async validateBranchExistanceOnPaymentCreating({
|
||||
billPaymentDTO,
|
||||
}: IBillPaymentCreatingPayload) {
|
||||
@@ -30,7 +30,7 @@ export class PaymentMadeBranchValidateSubscriber {
|
||||
* Validate branch existance once estimate editing.
|
||||
* @param {ISaleEstimateEditingPayload} payload
|
||||
*/
|
||||
@OnEvent(events.billPayment.onEditing)
|
||||
@OnEvent(events.billPayment.onEditing, { suppressErrors: false })
|
||||
async validateBranchExistanceOnPaymentEditing({
|
||||
billPaymentDTO,
|
||||
}: IBillPaymentEditingPayload) {
|
||||
|
||||
@@ -17,7 +17,7 @@ export class PaymentReceiveBranchValidateSubscriber {
|
||||
* Validate branch existance on estimate creating.
|
||||
* @param {IPaymentReceivedCreatingPayload} payload
|
||||
*/
|
||||
@OnEvent(events.paymentReceive.onCreating)
|
||||
@OnEvent(events.paymentReceive.onCreating, { suppressErrors: false })
|
||||
async validateBranchExistanceOnPaymentCreating({
|
||||
paymentReceiveDTO,
|
||||
}: IPaymentReceivedCreatingPayload) {
|
||||
@@ -30,7 +30,7 @@ export class PaymentReceiveBranchValidateSubscriber {
|
||||
* Validate branch existance once estimate editing.
|
||||
* @param {IPaymentReceivedEditingPayload} payload
|
||||
*/
|
||||
@OnEvent(events.paymentReceive.onEditing)
|
||||
@OnEvent(events.paymentReceive.onEditing, { suppressErrors: false })
|
||||
async validateBranchExistanceOnPaymentEditing({
|
||||
paymentReceiveDTO,
|
||||
}: IPaymentReceivedEditingPayload) {
|
||||
|
||||
@@ -17,7 +17,7 @@ export class SaleEstimateBranchValidateSubscriber {
|
||||
* Validate branch existance on estimate creating.
|
||||
* @param {ISaleEstimateCreatedPayload} payload
|
||||
*/
|
||||
@OnEvent(events.saleEstimate.onCreating)
|
||||
@OnEvent(events.saleEstimate.onCreating, { suppressErrors: false })
|
||||
async validateBranchExistanceOnEstimateCreating({
|
||||
estimateDTO,
|
||||
}: ISaleEstimateCreatingPayload) {
|
||||
@@ -30,7 +30,7 @@ export class SaleEstimateBranchValidateSubscriber {
|
||||
* Validate branch existance once estimate editing.
|
||||
* @param {ISaleEstimateEditingPayload} payload
|
||||
*/
|
||||
@OnEvent(events.saleEstimate.onEditing)
|
||||
@OnEvent(events.saleEstimate.onEditing, { suppressErrors: false })
|
||||
async validateBranchExistanceOnEstimateEditing({
|
||||
estimateDTO,
|
||||
}: ISaleEstimateEditingPayload) {
|
||||
|
||||
@@ -17,7 +17,7 @@ export class SaleReceiptBranchValidateSubscriber {
|
||||
* Validate branch existance on estimate creating.
|
||||
* @param {ISaleReceiptCreatingPayload} payload
|
||||
*/
|
||||
@OnEvent(events.saleReceipt.onCreating)
|
||||
@OnEvent(events.saleReceipt.onCreating, { suppressErrors: false })
|
||||
async validateBranchExistanceOnInvoiceCreating({
|
||||
saleReceiptDTO,
|
||||
}: ISaleReceiptCreatingPayload) {
|
||||
@@ -30,7 +30,7 @@ export class SaleReceiptBranchValidateSubscriber {
|
||||
* Validate branch existance once estimate editing.
|
||||
* @param {ISaleReceiptEditingPayload} payload
|
||||
*/
|
||||
@OnEvent(events.saleReceipt.onEditing)
|
||||
@OnEvent(events.saleReceipt.onEditing, { suppressErrors: false })
|
||||
async validateBranchExistanceOnInvoiceEditing({
|
||||
saleReceiptDTO,
|
||||
}: ISaleReceiptEditingPayload) {
|
||||
|
||||
@@ -17,7 +17,7 @@ export class VendorCreditBranchValidateSubscriber {
|
||||
* Validate branch existance on estimate creating.
|
||||
* @param {ISaleEstimateCreatedPayload} payload
|
||||
*/
|
||||
@OnEvent(events.vendorCredit.onCreating)
|
||||
@OnEvent(events.vendorCredit.onCreating, { suppressErrors: false })
|
||||
async validateBranchExistanceOnCreditCreating({
|
||||
vendorCreditCreateDTO,
|
||||
}: IVendorCreditCreatingPayload) {
|
||||
@@ -30,7 +30,7 @@ export class VendorCreditBranchValidateSubscriber {
|
||||
* Validate branch existance once estimate editing.
|
||||
* @param {ISaleEstimateEditingPayload} payload
|
||||
*/
|
||||
@OnEvent(events.vendorCredit.onEditing)
|
||||
@OnEvent(events.vendorCredit.onEditing, { suppressErrors: false })
|
||||
async validateBranchExistanceOnCreditEditing({
|
||||
vendorCreditDTO,
|
||||
}: IVendorCreditEditingPayload) {
|
||||
|
||||
@@ -14,7 +14,7 @@ export class VendorCreditRefundBranchValidateSubscriber {
|
||||
* Validate branch existance on refund credit note creating.
|
||||
* @param {IRefundVendorCreditCreatingPayload} payload
|
||||
*/
|
||||
@OnEvent(events.vendorCredit.onRefundCreating)
|
||||
@OnEvent(events.vendorCredit.onRefundCreating, { suppressErrors: false })
|
||||
async validateBranchExistanceOnCreditRefundCreating({
|
||||
refundVendorCreditDTO,
|
||||
}: IRefundVendorCreditCreatingPayload) {
|
||||
|
||||
@@ -1,117 +1,103 @@
|
||||
// import { Service, Inject } from 'typedi';
|
||||
// import { AccountNormal, ICustomer, ILedgerEntry } from '@/interfaces';
|
||||
// import Ledger from '@/services/Accounting/Ledger';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { AccountNormal } from '@/interfaces/Account';
|
||||
import { ILedgerEntry } from '@/modules/Ledger/types/Ledger.types';
|
||||
import { Ledger } from '@/modules/Ledger/Ledger';
|
||||
import { Customer } from './models/Customer';
|
||||
|
||||
// @Service()
|
||||
// export class CustomerGLEntries {
|
||||
// /**
|
||||
// * Retrieves the customer opening balance common entry attributes.
|
||||
// * @param {ICustomer} customer
|
||||
// */
|
||||
// private getCustomerOpeningGLCommonEntry = (customer: ICustomer) => {
|
||||
// return {
|
||||
// exchangeRate: customer.openingBalanceExchangeRate,
|
||||
// currencyCode: customer.currencyCode,
|
||||
@Injectable()
|
||||
export class CustomerGLEntries {
|
||||
/**
|
||||
* Retrieves the customer opening balance common entry attributes.
|
||||
*/
|
||||
private getCustomerOpeningGLCommonEntry = (customer: Customer) => {
|
||||
return {
|
||||
exchangeRate: customer.openingBalanceExchangeRate,
|
||||
currencyCode: customer.currencyCode,
|
||||
|
||||
// transactionType: 'CustomerOpeningBalance',
|
||||
// transactionId: customer.id,
|
||||
transactionType: 'CustomerOpeningBalance',
|
||||
transactionId: customer.id,
|
||||
|
||||
// date: customer.openingBalanceAt,
|
||||
// userId: customer.userId,
|
||||
// contactId: customer.id,
|
||||
date: customer.openingBalanceAt,
|
||||
contactId: customer.id,
|
||||
|
||||
// credit: 0,
|
||||
// debit: 0,
|
||||
credit: 0,
|
||||
debit: 0,
|
||||
|
||||
// branchId: customer.openingBalanceBranchId,
|
||||
// };
|
||||
// };
|
||||
branchId: customer.openingBalanceBranchId,
|
||||
};
|
||||
};
|
||||
|
||||
// /**
|
||||
// * Retrieves the customer opening GL credit entry.
|
||||
// * @param {number} ARAccountId
|
||||
// * @param {ICustomer} customer
|
||||
// * @returns {ILedgerEntry}
|
||||
// */
|
||||
// private getCustomerOpeningGLCreditEntry = (
|
||||
// ARAccountId: number,
|
||||
// customer: ICustomer
|
||||
// ): ILedgerEntry => {
|
||||
// const commonEntry = this.getCustomerOpeningGLCommonEntry(customer);
|
||||
/**
|
||||
* Retrieves the customer opening GL credit entry.
|
||||
*/
|
||||
private getCustomerOpeningGLCreditEntry = (
|
||||
ARAccountId: number,
|
||||
customer: Customer
|
||||
): ILedgerEntry => {
|
||||
const commonEntry = this.getCustomerOpeningGLCommonEntry(customer);
|
||||
|
||||
// return {
|
||||
// ...commonEntry,
|
||||
// credit: 0,
|
||||
// debit: customer.localOpeningBalance,
|
||||
// accountId: ARAccountId,
|
||||
// accountNormal: AccountNormal.DEBIT,
|
||||
// index: 1,
|
||||
// };
|
||||
// };
|
||||
return {
|
||||
...commonEntry,
|
||||
credit: 0,
|
||||
debit: customer.localOpeningBalance,
|
||||
accountId: ARAccountId,
|
||||
accountNormal: AccountNormal.DEBIT,
|
||||
index: 1,
|
||||
};
|
||||
};
|
||||
|
||||
// /**
|
||||
// * Retrieves the customer opening GL debit entry.
|
||||
// * @param {number} incomeAccountId
|
||||
// * @param {ICustomer} customer
|
||||
// * @returns {ILedgerEntry}
|
||||
// */
|
||||
// private getCustomerOpeningGLDebitEntry = (
|
||||
// incomeAccountId: number,
|
||||
// customer: ICustomer
|
||||
// ): ILedgerEntry => {
|
||||
// const commonEntry = this.getCustomerOpeningGLCommonEntry(customer);
|
||||
/**
|
||||
* Retrieves the customer opening GL debit entry.
|
||||
*/
|
||||
private getCustomerOpeningGLDebitEntry = (
|
||||
incomeAccountId: number,
|
||||
customer: Customer
|
||||
): ILedgerEntry => {
|
||||
const commonEntry = this.getCustomerOpeningGLCommonEntry(customer);
|
||||
|
||||
// return {
|
||||
// ...commonEntry,
|
||||
// credit: customer.localOpeningBalance,
|
||||
// debit: 0,
|
||||
// accountId: incomeAccountId,
|
||||
// accountNormal: AccountNormal.CREDIT,
|
||||
return {
|
||||
...commonEntry,
|
||||
credit: customer.localOpeningBalance,
|
||||
debit: 0,
|
||||
accountId: incomeAccountId,
|
||||
accountNormal: AccountNormal.CREDIT,
|
||||
|
||||
// index: 2,
|
||||
// };
|
||||
// };
|
||||
index: 2,
|
||||
};
|
||||
};
|
||||
|
||||
// /**
|
||||
// * Retrieves the customer opening GL entries.
|
||||
// * @param {number} ARAccountId
|
||||
// * @param {number} incomeAccountId
|
||||
// * @param {ICustomer} customer
|
||||
// * @returns {ILedgerEntry[]}
|
||||
// */
|
||||
// public getCustomerOpeningGLEntries = (
|
||||
// ARAccountId: number,
|
||||
// incomeAccountId: number,
|
||||
// customer: ICustomer
|
||||
// ) => {
|
||||
// const debitEntry = this.getCustomerOpeningGLDebitEntry(
|
||||
// incomeAccountId,
|
||||
// customer
|
||||
// );
|
||||
// const creditEntry = this.getCustomerOpeningGLCreditEntry(
|
||||
// ARAccountId,
|
||||
// customer
|
||||
// );
|
||||
// return [debitEntry, creditEntry];
|
||||
// };
|
||||
/**
|
||||
* Retrieves the customer opening GL entries.
|
||||
*/
|
||||
public getCustomerOpeningGLEntries = (
|
||||
ARAccountId: number,
|
||||
incomeAccountId: number,
|
||||
customer: Customer
|
||||
) => {
|
||||
const debitEntry = this.getCustomerOpeningGLDebitEntry(
|
||||
incomeAccountId,
|
||||
customer
|
||||
);
|
||||
const creditEntry = this.getCustomerOpeningGLCreditEntry(
|
||||
ARAccountId,
|
||||
customer
|
||||
);
|
||||
return [debitEntry, creditEntry];
|
||||
};
|
||||
|
||||
// /**
|
||||
// * Retrieves the customer opening balance ledger.
|
||||
// * @param {number} ARAccountId
|
||||
// * @param {number} incomeAccountId
|
||||
// * @param {ICustomer} customer
|
||||
// * @returns {ILedger}
|
||||
// */
|
||||
// public getCustomerOpeningLedger = (
|
||||
// ARAccountId: number,
|
||||
// incomeAccountId: number,
|
||||
// customer: ICustomer
|
||||
// ) => {
|
||||
// const entries = this.getCustomerOpeningGLEntries(
|
||||
// ARAccountId,
|
||||
// incomeAccountId,
|
||||
// customer
|
||||
// );
|
||||
// return new Ledger(entries);
|
||||
// };
|
||||
// }
|
||||
/**
|
||||
* Retrieves the customer opening balance ledger.
|
||||
*/
|
||||
public getCustomerOpeningLedger = (
|
||||
ARAccountId: number,
|
||||
incomeAccountId: number,
|
||||
customer: Customer
|
||||
) => {
|
||||
const entries = this.getCustomerOpeningGLEntries(
|
||||
ARAccountId,
|
||||
incomeAccountId,
|
||||
customer
|
||||
);
|
||||
return new Ledger(entries);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,90 +1,84 @@
|
||||
// import { Knex } from 'knex';
|
||||
// import LedgerStorageService from '@/services/Accounting/LedgerStorageService';
|
||||
// import HasTenancyService from '@/services/Tenancy/TenancyService';
|
||||
// import { Service, Inject } from 'typedi';
|
||||
// import { CustomerGLEntries } from './CustomerGLEntries';
|
||||
import { Knex } from 'knex';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { LedgerStorageService } from '@/modules/Ledger/LedgerStorage.service';
|
||||
import { AccountRepository } from '@/modules/Accounts/repositories/Account.repository';
|
||||
import { CustomerGLEntries } from './CustomerGLEntries';
|
||||
import { Customer } from './models/Customer';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
import { Account } from '../Accounts/models/Account.model';
|
||||
|
||||
// @Service()
|
||||
// export class CustomerGLEntriesStorage {
|
||||
// @Inject()
|
||||
// private tenancy: HasTenancyService;
|
||||
@Injectable()
|
||||
export class CustomerGLEntriesStorage {
|
||||
constructor(
|
||||
private readonly ledgerStorage: LedgerStorageService,
|
||||
private readonly accountRepository: AccountRepository,
|
||||
private readonly customerGLEntries: CustomerGLEntries,
|
||||
|
||||
// @Inject()
|
||||
// private ledegrRepository: LedgerStorageService;
|
||||
@Inject(Account.name)
|
||||
private readonly accountModel: TenantModelProxy<typeof Account>,
|
||||
|
||||
// @Inject()
|
||||
// private customerGLEntries: CustomerGLEntries;
|
||||
@Inject(Customer.name)
|
||||
private readonly customerModel: TenantModelProxy<typeof Customer>,
|
||||
) { }
|
||||
|
||||
// /**
|
||||
// * Customer opening balance journals.
|
||||
// * @param {number} tenantId
|
||||
// * @param {number} customerId
|
||||
// * @param {Knex.Transaction} trx
|
||||
// */
|
||||
// public writeCustomerOpeningBalance = async (
|
||||
// tenantId: number,
|
||||
// customerId: number,
|
||||
// trx?: Knex.Transaction
|
||||
// ) => {
|
||||
// const { Customer } = this.tenancy.models(tenantId);
|
||||
// const { accountRepository } = this.tenancy.repositories(tenantId);
|
||||
/**
|
||||
* Customer opening balance journals.
|
||||
*/
|
||||
public writeCustomerOpeningBalance = async (
|
||||
customerId: number,
|
||||
trx?: Knex.Transaction,
|
||||
) => {
|
||||
const customer = await this.customerModel()
|
||||
.query(trx)
|
||||
.findById(customerId);
|
||||
|
||||
// const customer = await Customer.query(trx).findById(customerId);
|
||||
// Finds the income account.
|
||||
const incomeAccount = await this.accountModel()
|
||||
.query(trx)
|
||||
.findOne({ slug: 'other-income' });
|
||||
|
||||
// // Finds the income account.
|
||||
// const incomeAccount = await accountRepository.findOne({
|
||||
// slug: 'other-income',
|
||||
// });
|
||||
// // Find or create the A/R account.
|
||||
// const ARAccount = await accountRepository.findOrCreateAccountReceivable(
|
||||
// customer.currencyCode,
|
||||
// {},
|
||||
// trx
|
||||
// );
|
||||
// // Retrieves the customer opening balance ledger.
|
||||
// const ledger = this.customerGLEntries.getCustomerOpeningLedger(
|
||||
// ARAccount.id,
|
||||
// incomeAccount.id,
|
||||
// customer
|
||||
// );
|
||||
// // Commits the ledger entries to the storage.
|
||||
// await this.ledegrRepository.commit(tenantId, ledger, trx);
|
||||
// };
|
||||
// Find or create the A/R account.
|
||||
const ARAccount =
|
||||
await this.accountRepository.findOrCreateAccountReceivable(
|
||||
customer.currencyCode,
|
||||
{},
|
||||
trx,
|
||||
);
|
||||
// Retrieves the customer opening balance ledger.
|
||||
const ledger = this.customerGLEntries.getCustomerOpeningLedger(
|
||||
ARAccount.id,
|
||||
incomeAccount.id,
|
||||
customer,
|
||||
);
|
||||
// Commits the ledger entries to the storage.
|
||||
await this.ledgerStorage.commit(ledger, trx);
|
||||
};
|
||||
|
||||
// /**
|
||||
// * Reverts the customer opening balance GL entries.
|
||||
// * @param {number} tenantId
|
||||
// * @param {number} customerId
|
||||
// * @param {Knex.Transaction} trx
|
||||
// */
|
||||
// public revertCustomerOpeningBalance = async (
|
||||
// tenantId: number,
|
||||
// customerId: number,
|
||||
// trx?: Knex.Transaction
|
||||
// ) => {
|
||||
// await this.ledegrRepository.deleteByReference(
|
||||
// tenantId,
|
||||
// customerId,
|
||||
// 'CustomerOpeningBalance',
|
||||
// trx
|
||||
// );
|
||||
// };
|
||||
/**
|
||||
* Reverts the customer opening balance GL entries.
|
||||
*/
|
||||
public revertCustomerOpeningBalance = async (
|
||||
customerId: number,
|
||||
trx?: Knex.Transaction,
|
||||
) => {
|
||||
await this.ledgerStorage.deleteByReference(
|
||||
customerId,
|
||||
'CustomerOpeningBalance',
|
||||
trx,
|
||||
);
|
||||
};
|
||||
|
||||
// /**
|
||||
// * Writes the customer opening balance GL entries.
|
||||
// * @param {number} tenantId
|
||||
// * @param {number} customerId
|
||||
// * @param {Knex.Transaction} trx
|
||||
// */
|
||||
// public rewriteCustomerOpeningBalance = async (
|
||||
// tenantId: number,
|
||||
// customerId: number,
|
||||
// trx?: Knex.Transaction
|
||||
// ) => {
|
||||
// // Reverts the customer opening balance entries.
|
||||
// await this.revertCustomerOpeningBalance(tenantId, customerId, trx);
|
||||
/**
|
||||
* Writes the customer opening balance GL entries.
|
||||
*/
|
||||
public rewriteCustomerOpeningBalance = async (
|
||||
customerId: number,
|
||||
trx?: Knex.Transaction,
|
||||
) => {
|
||||
// Reverts the customer opening balance entries.
|
||||
await this.revertCustomerOpeningBalance(customerId, trx);
|
||||
|
||||
// // Write the customer opening balance entries.
|
||||
// await this.writeCustomerOpeningBalance(tenantId, customerId, trx);
|
||||
// };
|
||||
// }
|
||||
// Write the customer opening balance entries.
|
||||
await this.writeCustomerOpeningBalance(customerId, trx);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -9,10 +9,7 @@ import {
|
||||
Query,
|
||||
} from '@nestjs/common';
|
||||
import { CustomersApplication } from './CustomersApplication.service';
|
||||
import {
|
||||
ICustomerOpeningBalanceEditDTO,
|
||||
ICustomersFilter,
|
||||
} from './types/Customers.types';
|
||||
import { CustomerOpeningBalanceEditDto } from './dtos/CustomerOpeningBalanceEdit.dto';
|
||||
import {
|
||||
ApiOperation,
|
||||
ApiResponse,
|
||||
@@ -106,7 +103,7 @@ export class CustomersController {
|
||||
})
|
||||
editOpeningBalance(
|
||||
@Param('id') customerId: number,
|
||||
@Body() openingBalanceDTO: ICustomerOpeningBalanceEditDTO,
|
||||
@Body() openingBalanceDTO: CustomerOpeningBalanceEditDto,
|
||||
) {
|
||||
return this.customersApplication.editOpeningBalance(
|
||||
customerId,
|
||||
|
||||
@@ -18,9 +18,19 @@ import { GetCustomers } from './queries/GetCustomers.service';
|
||||
import { DynamicListModule } from '../DynamicListing/DynamicList.module';
|
||||
import { BulkDeleteCustomersService } from './BulkDeleteCustomers.service';
|
||||
import { ValidateBulkDeleteCustomersService } from './ValidateBulkDeleteCustomers.service';
|
||||
import { LedgerModule } from '../Ledger/Ledger.module';
|
||||
import { AccountsModule } from '../Accounts/Accounts.module';
|
||||
import { CustomerGLEntries } from './CustomerGLEntries';
|
||||
import { CustomerGLEntriesStorage } from './CustomerGLEntriesStorage';
|
||||
import { CustomerWriteGLOpeningBalanceSubscriber } from './subscribers/CustomerGLEntriesSubscriber';
|
||||
|
||||
@Module({
|
||||
imports: [TenancyDatabaseModule, DynamicListModule],
|
||||
imports: [
|
||||
TenancyDatabaseModule,
|
||||
DynamicListModule,
|
||||
LedgerModule,
|
||||
AccountsModule,
|
||||
],
|
||||
controllers: [CustomersController],
|
||||
providers: [
|
||||
ActivateCustomer,
|
||||
@@ -41,6 +51,9 @@ import { ValidateBulkDeleteCustomersService } from './ValidateBulkDeleteCustomer
|
||||
GetCustomers,
|
||||
BulkDeleteCustomersService,
|
||||
ValidateBulkDeleteCustomersService,
|
||||
CustomerGLEntries,
|
||||
CustomerGLEntriesStorage,
|
||||
CustomerWriteGLOpeningBalanceSubscriber,
|
||||
],
|
||||
})
|
||||
export class CustomersModule {}
|
||||
|
||||
@@ -4,10 +4,7 @@ import { CreateCustomer } from './commands/CreateCustomer.service';
|
||||
import { EditCustomer } from './commands/EditCustomer.service';
|
||||
import { DeleteCustomer } from './commands/DeleteCustomer.service';
|
||||
import { EditOpeningBalanceCustomer } from './commands/EditOpeningBalanceCustomer.service';
|
||||
import {
|
||||
ICustomerOpeningBalanceEditDTO,
|
||||
ICustomersFilter,
|
||||
} from './types/Customers.types';
|
||||
import { CustomerOpeningBalanceEditDto } from './dtos/CustomerOpeningBalanceEdit.dto';
|
||||
import { CreateCustomerDto } from './dtos/CreateCustomer.dto';
|
||||
import { EditCustomerDto } from './dtos/EditCustomer.dto';
|
||||
import { GetCustomers } from './queries/GetCustomers.service';
|
||||
@@ -18,12 +15,12 @@ import { ValidateBulkDeleteCustomersService } from './ValidateBulkDeleteCustomer
|
||||
@Injectable()
|
||||
export class CustomersApplication {
|
||||
constructor(
|
||||
private getCustomerService: GetCustomerService,
|
||||
private createCustomerService: CreateCustomer,
|
||||
private editCustomerService: EditCustomer,
|
||||
private deleteCustomerService: DeleteCustomer,
|
||||
private editOpeningBalanceService: EditOpeningBalanceCustomer,
|
||||
private getCustomersService: GetCustomers,
|
||||
private readonly getCustomerService: GetCustomerService,
|
||||
private readonly createCustomerService: CreateCustomer,
|
||||
private readonly editCustomerService: EditCustomer,
|
||||
private readonly deleteCustomerService: DeleteCustomer,
|
||||
private readonly editOpeningBalanceService: EditOpeningBalanceCustomer,
|
||||
private readonly getCustomersService: GetCustomers,
|
||||
private readonly bulkDeleteCustomersService: BulkDeleteCustomersService,
|
||||
private readonly validateBulkDeleteCustomersService: ValidateBulkDeleteCustomersService,
|
||||
) {}
|
||||
@@ -72,7 +69,7 @@ export class CustomersApplication {
|
||||
*/
|
||||
public editOpeningBalance = (
|
||||
customerId: number,
|
||||
openingBalanceEditDTO: ICustomerOpeningBalanceEditDTO,
|
||||
openingBalanceEditDTO: CustomerOpeningBalanceEditDto,
|
||||
) => {
|
||||
return this.editOpeningBalanceService.changeOpeningBalance(
|
||||
customerId,
|
||||
@@ -82,7 +79,7 @@ export class CustomersApplication {
|
||||
|
||||
/**
|
||||
* Retrieve customers paginated list.
|
||||
* @param {ICustomersFilter} filter - Cusotmers filter.
|
||||
* @param {GetCustomersQueryDto} filter - Cusotmers filter.
|
||||
*/
|
||||
public getCustomers = (filterDTO: GetCustomersQueryDto) => {
|
||||
return this.getCustomersService.getCustomersList(filterDTO);
|
||||
|
||||
@@ -31,7 +31,7 @@ export class CreateCustomer {
|
||||
|
||||
/**
|
||||
* Creates a new customer.
|
||||
* @param {ICustomerNewDTO} customerDTO
|
||||
* @param {CreateCustomerDto} customerDTO
|
||||
* @return {Promise<ICustomer>}
|
||||
*/
|
||||
public async createCustomer(
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { Knex } from 'knex';
|
||||
import {
|
||||
ICustomerOpeningBalanceEditDTO,
|
||||
ICustomerOpeningBalanceEditedPayload,
|
||||
ICustomerOpeningBalanceEditingPayload,
|
||||
} from '../types/Customers.types';
|
||||
import { CustomerOpeningBalanceEditDto } from '../dtos/CustomerOpeningBalanceEdit.dto';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service';
|
||||
import { Customer } from '../models/Customer';
|
||||
@@ -29,11 +29,11 @@ export class EditOpeningBalanceCustomer {
|
||||
/**
|
||||
* Changes the opening balance of the given customer.
|
||||
* @param {number} customerId - Customer ID.
|
||||
* @param {ICustomerOpeningBalanceEditDTO} openingBalanceEditDTO
|
||||
* @param {CustomerOpeningBalanceEditDto} openingBalanceEditDTO
|
||||
*/
|
||||
public async changeOpeningBalance(
|
||||
customerId: number,
|
||||
openingBalanceEditDTO: ICustomerOpeningBalanceEditDTO,
|
||||
openingBalanceEditDTO: CustomerOpeningBalanceEditDto,
|
||||
): Promise<Customer> {
|
||||
// Retrieves the old customer or throw not found error.
|
||||
const oldCustomer = await this.customerModel()
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
IsNotEmpty,
|
||||
IsNumber,
|
||||
IsString,
|
||||
ValidateIf,
|
||||
} from 'class-validator';
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsOptional, ToNumber } from '@/common/decorators/Validators';
|
||||
@@ -40,10 +41,11 @@ export class CreateCustomerDto extends ContactAddressDto {
|
||||
|
||||
@ApiProperty({
|
||||
required: false,
|
||||
description: 'Opening balance date',
|
||||
description: 'Opening balance date (required when openingBalance is provided)',
|
||||
example: '2024-01-01',
|
||||
})
|
||||
@IsOptional()
|
||||
@ValidateIf((o) => o.openingBalance != null)
|
||||
@IsNotEmpty({ message: 'openingBalanceAt is required when openingBalance is provided' })
|
||||
@IsString()
|
||||
openingBalanceAt?: string;
|
||||
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
import { IsNotEmpty, IsNumber, IsString } from 'class-validator';
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsOptional, ToNumber } from '@/common/decorators/Validators';
|
||||
|
||||
export class CustomerOpeningBalanceEditDto {
|
||||
@ApiProperty({
|
||||
required: true,
|
||||
description: 'Opening balance',
|
||||
example: 5000.0,
|
||||
})
|
||||
@IsNumber()
|
||||
@IsNotEmpty()
|
||||
@ToNumber()
|
||||
openingBalance: number;
|
||||
|
||||
@ApiProperty({
|
||||
required: false,
|
||||
description: 'Opening balance date',
|
||||
example: '2024-01-01',
|
||||
})
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
openingBalanceAt?: string;
|
||||
|
||||
@ApiProperty({
|
||||
required: false,
|
||||
description: 'Opening balance exchange rate',
|
||||
example: 1.0,
|
||||
})
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
@ToNumber()
|
||||
openingBalanceExchangeRate?: number;
|
||||
|
||||
@ApiProperty({
|
||||
required: false,
|
||||
description: 'Opening balance branch ID',
|
||||
example: 101,
|
||||
})
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
@ToNumber()
|
||||
openingBalanceBranchId?: number;
|
||||
}
|
||||
@@ -1,91 +1,63 @@
|
||||
// import { Service, Inject } from 'typedi';
|
||||
// import {
|
||||
// ICustomerEventCreatedPayload,
|
||||
// ICustomerEventDeletedPayload,
|
||||
// ICustomerOpeningBalanceEditedPayload,
|
||||
// } from '@/interfaces';
|
||||
// import events from '@/subscribers/events';
|
||||
// import { CustomerGLEntriesStorage } from '../CustomerGLEntriesStorage';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { OnEvent } from '@nestjs/event-emitter';
|
||||
import {
|
||||
ICustomerEventCreatedPayload,
|
||||
ICustomerEventDeletedPayload,
|
||||
ICustomerOpeningBalanceEditedPayload,
|
||||
} from '../types/Customers.types';
|
||||
import { events } from '@/common/events/events';
|
||||
import { CustomerGLEntriesStorage } from '../CustomerGLEntriesStorage';
|
||||
|
||||
// @Service()
|
||||
// export class CustomerWriteGLOpeningBalanceSubscriber {
|
||||
// @Inject()
|
||||
// private customerGLEntries: CustomerGLEntriesStorage;
|
||||
@Injectable()
|
||||
export class CustomerWriteGLOpeningBalanceSubscriber {
|
||||
constructor(private readonly customerGLEntries: CustomerGLEntriesStorage) { }
|
||||
|
||||
// /**
|
||||
// * Attaches events with handlers.
|
||||
// */
|
||||
// public attach(bus) {
|
||||
// bus.subscribe(
|
||||
// events.customers.onCreated,
|
||||
// this.handleWriteOpenBalanceEntries
|
||||
// );
|
||||
// bus.subscribe(
|
||||
// events.customers.onDeleted,
|
||||
// this.handleRevertOpeningBalanceEntries
|
||||
// );
|
||||
// bus.subscribe(
|
||||
// events.customers.onOpeningBalanceChanged,
|
||||
// this.handleRewriteOpeningEntriesOnChanged
|
||||
// );
|
||||
// }
|
||||
/**
|
||||
* Handles the writing opening balance journal entries once the customer created.
|
||||
*/
|
||||
@OnEvent(events.customers.onCreated)
|
||||
public async handleWriteOpenBalanceEntries({
|
||||
customer,
|
||||
trx,
|
||||
}: ICustomerEventCreatedPayload) {
|
||||
// Writes the customer opening balance journal entries.
|
||||
if (customer.openingBalance) {
|
||||
await this.customerGLEntries.writeCustomerOpeningBalance(
|
||||
customer.id,
|
||||
trx,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Handles the writing opening balance journal entries once the customer created.
|
||||
// * @param {ICustomerEventCreatedPayload} payload -
|
||||
// */
|
||||
// private handleWriteOpenBalanceEntries = async ({
|
||||
// tenantId,
|
||||
// customer,
|
||||
// trx,
|
||||
// }: ICustomerEventCreatedPayload) => {
|
||||
// // Writes the customer opening balance journal entries.
|
||||
// if (customer.openingBalance) {
|
||||
// await this.customerGLEntries.writeCustomerOpeningBalance(
|
||||
// tenantId,
|
||||
// customer.id,
|
||||
// trx
|
||||
// );
|
||||
// }
|
||||
// };
|
||||
/**
|
||||
* Handles the deleting opening balance journal entries once the customer deleted.
|
||||
*/
|
||||
@OnEvent(events.customers.onDeleted)
|
||||
public async handleRevertOpeningBalanceEntries({
|
||||
customerId,
|
||||
trx,
|
||||
}: ICustomerEventDeletedPayload) {
|
||||
await this.customerGLEntries.revertCustomerOpeningBalance(customerId, trx);
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Handles the deleting opeing balance journal entrise once the customer deleted.
|
||||
// * @param {ICustomerEventDeletedPayload} payload -
|
||||
// */
|
||||
// private handleRevertOpeningBalanceEntries = async ({
|
||||
// tenantId,
|
||||
// customerId,
|
||||
// trx,
|
||||
// }: ICustomerEventDeletedPayload) => {
|
||||
// await this.customerGLEntries.revertCustomerOpeningBalance(
|
||||
// tenantId,
|
||||
// customerId,
|
||||
// trx
|
||||
// );
|
||||
// };
|
||||
|
||||
// /**
|
||||
// * Handles the rewrite opening balance entries once opening balnace changed.
|
||||
// * @param {ICustomerOpeningBalanceEditedPayload} payload -
|
||||
// */
|
||||
// private handleRewriteOpeningEntriesOnChanged = async ({
|
||||
// tenantId,
|
||||
// customer,
|
||||
// trx,
|
||||
// }: ICustomerOpeningBalanceEditedPayload) => {
|
||||
// if (customer.openingBalance) {
|
||||
// await this.customerGLEntries.rewriteCustomerOpeningBalance(
|
||||
// tenantId,
|
||||
// customer.id,
|
||||
// trx
|
||||
// );
|
||||
// } else {
|
||||
// await this.customerGLEntries.revertCustomerOpeningBalance(
|
||||
// tenantId,
|
||||
// customer.id,
|
||||
// trx
|
||||
// );
|
||||
// }
|
||||
// };
|
||||
// }
|
||||
/**
|
||||
* Handles the rewrite opening balance entries once opening balance changed.
|
||||
*/
|
||||
@OnEvent(events.customers.onOpeningBalanceChanged)
|
||||
public async handleRewriteOpeningEntriesOnChanged({
|
||||
customer,
|
||||
trx,
|
||||
}: ICustomerOpeningBalanceEditedPayload) {
|
||||
if (customer.openingBalance) {
|
||||
await this.customerGLEntries.rewriteCustomerOpeningBalance(
|
||||
customer.id,
|
||||
trx,
|
||||
);
|
||||
} else {
|
||||
await this.customerGLEntries.revertCustomerOpeningBalance(
|
||||
customer.id,
|
||||
trx,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import { IContactAddressDTO } from '@/modules/Contacts/types/Contacts.types';
|
||||
import { IDynamicListFilter } from '@/modules/DynamicListing/DynamicFilter/DynamicFilter.types';
|
||||
import { IFilterMeta, IPaginationMeta } from '@/interfaces/Model';
|
||||
import { CreateCustomerDto } from '../dtos/CreateCustomer.dto';
|
||||
import { CustomerOpeningBalanceEditDto } from '../dtos/CustomerOpeningBalanceEdit.dto';
|
||||
import { EditCustomerDto } from '../dtos/EditCustomer.dto';
|
||||
|
||||
// Customer Interfaces.
|
||||
@@ -113,23 +114,16 @@ export enum VendorAction {
|
||||
View = 'View',
|
||||
}
|
||||
|
||||
export interface ICustomerOpeningBalanceEditDTO {
|
||||
openingBalance: number;
|
||||
openingBalanceAt: Date | string;
|
||||
openingBalanceExchangeRate: number;
|
||||
openingBalanceBranchId?: number;
|
||||
}
|
||||
|
||||
export interface ICustomerOpeningBalanceEditingPayload {
|
||||
oldCustomer: Customer;
|
||||
openingBalanceEditDTO: ICustomerOpeningBalanceEditDTO;
|
||||
openingBalanceEditDTO: CustomerOpeningBalanceEditDto;
|
||||
trx?: Knex.Transaction;
|
||||
}
|
||||
|
||||
export interface ICustomerOpeningBalanceEditedPayload {
|
||||
customer: Customer;
|
||||
oldCustomer: Customer;
|
||||
openingBalanceEditDTO: ICustomerOpeningBalanceEditDTO;
|
||||
openingBalanceEditDTO: CustomerOpeningBalanceEditDto;
|
||||
trx: Knex.Transaction;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,29 +3,30 @@ import { ITableColumn, ITableData, ITableRow } from '../types/Table.types';
|
||||
import { FinancialTableStructure } from './FinancialTableStructure';
|
||||
import { tableClassNames } from '../utils';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { TemplateInjectable } from '../../TemplateInjectable/TemplateInjectable.service';
|
||||
import { ChromiumlyTenancy } from '../../ChromiumlyTenancy/ChromiumlyTenancy.service';
|
||||
import { renderFinancialSheetTemplateHtml } from '@bigcapital/pdf-templates';
|
||||
|
||||
@Injectable()
|
||||
export class TableSheetPdf {
|
||||
/**
|
||||
* @param {TemplateInjectable} templateInjectable - The template injectable service.
|
||||
* @param {ChromiumlyTenancy} chromiumlyTenancy - The chromiumly tenancy service.
|
||||
*/
|
||||
constructor(
|
||||
private readonly templateInjectable: TemplateInjectable,
|
||||
private readonly chromiumlyTenancy: ChromiumlyTenancy,
|
||||
) {}
|
||||
) { }
|
||||
|
||||
/**
|
||||
* Converts the table data into a PDF format.
|
||||
* @param {ITableData} table - The table data to be converted.
|
||||
* @param {string} organizationName - The organization name.
|
||||
* @param {string} sheetName - The name of the sheet.
|
||||
* @param {string} sheetDate - The date of the sheet.
|
||||
* @param {string} customCSS - Optional custom CSS to inject.
|
||||
* @returns A promise that resolves with the PDF conversion result.
|
||||
*/
|
||||
public async convertToPdf(
|
||||
table: ITableData,
|
||||
organizationName: string,
|
||||
sheetName: string,
|
||||
sheetDate: string,
|
||||
customCSS?: string,
|
||||
@@ -33,19 +34,26 @@ export class TableSheetPdf {
|
||||
// Prepare columns and rows for PDF conversion
|
||||
const columns = this.tablePdfColumns(table.columns);
|
||||
const rows = this.tablePdfRows(table.rows);
|
||||
|
||||
const landscape = columns.length > 4;
|
||||
|
||||
// Generate HTML content from the template
|
||||
const htmlContent = await this.templateInjectable.render(
|
||||
'financial-sheet',
|
||||
{
|
||||
table: { rows, columns },
|
||||
sheetName,
|
||||
sheetDate,
|
||||
customCSS,
|
||||
// Generate HTML content from the React template
|
||||
const htmlContent = renderFinancialSheetTemplateHtml({
|
||||
organizationName,
|
||||
sheetName,
|
||||
sheetDate,
|
||||
table: {
|
||||
columns: columns.map((col) => ({
|
||||
key: col.key,
|
||||
label: col.label,
|
||||
style: (col as any).style, // style may be added during transformation
|
||||
})),
|
||||
rows: rows.map((row) => ({
|
||||
cells: row.cells,
|
||||
classNames: (row as any).classNames,
|
||||
})),
|
||||
},
|
||||
);
|
||||
customCSS,
|
||||
});
|
||||
// Convert the HTML content to PDF
|
||||
return this.chromiumlyTenancy.convertHtmlContent(htmlContent, {
|
||||
margins: { top: 0, bottom: 0, left: 0, right: 0 },
|
||||
@@ -74,7 +82,6 @@ export class TableSheetPdf {
|
||||
const flatNestedTree = curriedFlatNestedTree(R.__, {
|
||||
nestedPrefix: '<span style="padding-left: 15px;"></span>',
|
||||
});
|
||||
|
||||
// @ts-ignore
|
||||
return R.compose(tableClassNames, flatNestedTree)(rows);
|
||||
};
|
||||
|
||||
@@ -21,6 +21,7 @@ export class APAgingSummaryPdfInjectable {
|
||||
|
||||
return this.tableSheetPdf.convertToPdf(
|
||||
table.table,
|
||||
table.meta.organizationName,
|
||||
table.meta.sheetName,
|
||||
table.meta.formattedAsDate,
|
||||
HtmlTableCss,
|
||||
|
||||
@@ -21,6 +21,7 @@ export class ARAgingSummaryPdfInjectable {
|
||||
|
||||
return this.tableSheetPdf.convertToPdf(
|
||||
table.table,
|
||||
table.meta.organizationName,
|
||||
table.meta.sheetName,
|
||||
table.meta.formattedDateRange,
|
||||
HtmlTableCss,
|
||||
|
||||
@@ -9,7 +9,7 @@ export class BalanceSheetPdfInjectable {
|
||||
constructor(
|
||||
private readonly balanceSheetTable: BalanceSheetTableInjectable,
|
||||
private readonly tableSheetPdf: TableSheetPdf,
|
||||
) {}
|
||||
) { }
|
||||
|
||||
/**
|
||||
* Converts the given balance sheet table to pdf.
|
||||
@@ -21,6 +21,7 @@ export class BalanceSheetPdfInjectable {
|
||||
|
||||
return this.tableSheetPdf.convertToPdf(
|
||||
table.table,
|
||||
table.meta.organizationName,
|
||||
table.meta.sheetName,
|
||||
table.meta.formattedDateRange,
|
||||
HtmlTableCustomCss,
|
||||
|
||||
@@ -81,6 +81,7 @@ export class CashFlowStatementQueryDto extends FinancialSheetBranchesQueryDto {
|
||||
})
|
||||
@ValidateNested()
|
||||
@Type(() => NumberFormatQueryDto)
|
||||
@IsOptional()
|
||||
numberFormat: NumberFormatQueryDto;
|
||||
|
||||
@ApiProperty({
|
||||
|
||||
@@ -22,6 +22,7 @@ export class CashflowTablePdfInjectable {
|
||||
|
||||
return this.tableSheetPdf.convertToPdf(
|
||||
table.table,
|
||||
table.meta.organizationName,
|
||||
table.meta.sheetName,
|
||||
table.meta.formattedDateRange,
|
||||
HtmlTableCustomCss,
|
||||
|
||||
@@ -21,6 +21,7 @@ export class CustomerBalanceSummaryPdf {
|
||||
|
||||
return this.tableSheetPdf.convertToPdf(
|
||||
table.table,
|
||||
table.meta.organizationName,
|
||||
table.meta.sheetName,
|
||||
table.meta.formattedDateRange,
|
||||
HtmlTableCustomCss,
|
||||
|
||||
@@ -21,6 +21,7 @@ export class GeneralLedgerPdf {
|
||||
|
||||
return this.tableSheetPdf.convertToPdf(
|
||||
table.table,
|
||||
table.meta.organizationName,
|
||||
table.meta.sheetName,
|
||||
table.meta.formattedDateRange,
|
||||
HtmlTableCustomCss,
|
||||
|
||||
@@ -32,7 +32,7 @@ export class InventoryItemDetailsQueryDto {
|
||||
@ApiPropertyOptional({
|
||||
description: 'Number format for the inventory item details',
|
||||
})
|
||||
numberFormat: INumberFormatQuery;
|
||||
numberFormat: NumberFormatQueryDto;
|
||||
|
||||
@Transform(({ value }) => parseBoolean(value, false))
|
||||
@IsBoolean()
|
||||
|
||||
@@ -26,6 +26,7 @@ export class InventoryDetailsTablePdf {
|
||||
|
||||
return this.tableSheetPdf.convertToPdf(
|
||||
table.table,
|
||||
table.meta.organizationName,
|
||||
table.meta.sheetName,
|
||||
table.meta.formattedDateRange,
|
||||
HtmlTableCustomCss,
|
||||
|
||||
@@ -22,6 +22,7 @@ export class InventoryValuationSheetPdf {
|
||||
|
||||
return this.tableSheetPdf.convertToPdf(
|
||||
table.table,
|
||||
table.meta.organizationName,
|
||||
table.meta.sheetName,
|
||||
table.meta.formattedDateRange,
|
||||
HtmlTableCustomCss,
|
||||
|
||||
@@ -9,7 +9,7 @@ export class JournalSheetPdfInjectable {
|
||||
constructor(
|
||||
private readonly journalSheetTable: JournalSheetTableInjectable,
|
||||
private readonly tableSheetPdf: TableSheetPdf,
|
||||
) {}
|
||||
) { }
|
||||
|
||||
/**
|
||||
* Converts the given journal sheet table to pdf.
|
||||
@@ -22,6 +22,7 @@ export class JournalSheetPdfInjectable {
|
||||
|
||||
return this.tableSheetPdf.convertToPdf(
|
||||
table.table,
|
||||
table.meta.organizationName,
|
||||
table.meta.sheetName,
|
||||
table.meta.formattedDateRange,
|
||||
HtmlTableCustomCss,
|
||||
|
||||
@@ -7,11 +7,13 @@ import {
|
||||
IsEnum,
|
||||
IsOptional,
|
||||
IsString,
|
||||
ValidateNested,
|
||||
} from 'class-validator';
|
||||
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
||||
import { Transform, Type } from 'class-transformer';
|
||||
import { ToNumber } from '@/common/decorators/Validators';
|
||||
import { parseBoolean } from '@/utils/parse-boolean';
|
||||
import { NumberFormatQueryDto } from '@/modules/BankingTransactions/dtos/NumberFormatQuery.dto';
|
||||
|
||||
export class ProfitLossSheetQueryDto extends FinancialSheetBranchesQueryDto {
|
||||
@IsString()
|
||||
@@ -30,8 +32,10 @@ export class ProfitLossSheetQueryDto extends FinancialSheetBranchesQueryDto {
|
||||
toDate: moment.MomentInput;
|
||||
|
||||
@ApiProperty({ description: 'Number format configuration' })
|
||||
@Type(() => Object)
|
||||
numberFormat: INumberFormatQuery;
|
||||
@ValidateNested()
|
||||
@Type(() => NumberFormatQueryDto)
|
||||
@IsOptional()
|
||||
numberFormat: NumberFormatQueryDto;
|
||||
|
||||
@IsBoolean()
|
||||
@Transform(({ value }) => parseBoolean(value, false))
|
||||
|
||||
@@ -21,6 +21,7 @@ export class ProfitLossTablePdfInjectable {
|
||||
|
||||
return this.tableSheetPdf.convertToPdf(
|
||||
table.table,
|
||||
table.meta.organizationName,
|
||||
table.meta.sheetName,
|
||||
table.meta.formattedDateRange,
|
||||
HtmlTableCustomCss,
|
||||
|
||||
@@ -23,6 +23,7 @@ export class PurchasesByItemsPdf {
|
||||
|
||||
return this.tableSheetPdf.convertToPdf(
|
||||
table.table,
|
||||
table.meta.organizationName,
|
||||
table.meta.sheetName,
|
||||
table.meta.formattedDateRange,
|
||||
HtmlTableCustomCss,
|
||||
|
||||
@@ -9,7 +9,7 @@ export class SalesByItemsPdfInjectable {
|
||||
constructor(
|
||||
private readonly salesByItemsTable: SalesByItemsTableInjectable,
|
||||
private readonly tableSheetPdf: TableSheetPdf,
|
||||
) {}
|
||||
) { }
|
||||
|
||||
/**
|
||||
* Retrieves the sales by items sheet in pdf format.
|
||||
@@ -23,6 +23,7 @@ export class SalesByItemsPdfInjectable {
|
||||
|
||||
return this.tableSheetPdf.convertToPdf(
|
||||
table.table,
|
||||
table.meta.organizationName,
|
||||
table.meta.sheetName,
|
||||
table.meta.formattedDateRange,
|
||||
HtmlTableCustomCss,
|
||||
|
||||
@@ -8,7 +8,7 @@ export class SalesTaxLiabiltiySummaryPdf {
|
||||
constructor(
|
||||
private readonly salesTaxLiabiltiySummaryTable: SalesTaxLiabilitySummaryTableInjectable,
|
||||
private readonly tableSheetPdf: TableSheetPdf,
|
||||
) {}
|
||||
) { }
|
||||
|
||||
/**
|
||||
* Converts the given sales tax liability summary table to pdf.
|
||||
@@ -21,6 +21,7 @@ export class SalesTaxLiabiltiySummaryPdf {
|
||||
);
|
||||
return this.tableSheetPdf.convertToPdf(
|
||||
table.table,
|
||||
table.meta.organizationName,
|
||||
table.meta.sheetName,
|
||||
table.meta.formattedDateRange,
|
||||
);
|
||||
|
||||
@@ -6,7 +6,7 @@ export class TransactionsByCustomersPdf {
|
||||
constructor(
|
||||
private readonly transactionsByCustomersTable: TransactionsByCustomersTableInjectable,
|
||||
private readonly tableSheetPdf: TableSheetPdf,
|
||||
) {}
|
||||
) { }
|
||||
|
||||
/**
|
||||
* Retrieves the transactions by customers in PDF format.
|
||||
@@ -18,6 +18,7 @@ export class TransactionsByCustomersPdf {
|
||||
|
||||
return this.tableSheetPdf.convertToPdf(
|
||||
table.table,
|
||||
table.meta.organizationName,
|
||||
table.meta.sheetName,
|
||||
table.meta.formattedDateRange,
|
||||
);
|
||||
|
||||
@@ -9,7 +9,7 @@ export class TransactionsByVendorsPdf {
|
||||
constructor(
|
||||
private readonly transactionsByVendorTable: TransactionsByVendorTableInjectable,
|
||||
private readonly tableSheetPdf: TableSheetPdf,
|
||||
) {}
|
||||
) { }
|
||||
|
||||
/**
|
||||
* Converts the given balance sheet table to pdf.
|
||||
@@ -21,6 +21,7 @@ export class TransactionsByVendorsPdf {
|
||||
|
||||
return this.tableSheetPdf.convertToPdf(
|
||||
table.table,
|
||||
table.meta.organizationName,
|
||||
table.meta.sheetName,
|
||||
table.meta.formattedDateRange,
|
||||
HtmlTableCustomCss,
|
||||
|
||||
@@ -9,7 +9,7 @@ export class TrialBalanceSheetPdfInjectable {
|
||||
constructor(
|
||||
private readonly trialBalanceSheetTable: TrialBalanceSheetTableInjectable,
|
||||
private readonly tableSheetPdf: TableSheetPdf,
|
||||
) {}
|
||||
) { }
|
||||
|
||||
/**
|
||||
* Converts the given trial balance sheet table to pdf.
|
||||
@@ -21,6 +21,7 @@ export class TrialBalanceSheetPdfInjectable {
|
||||
|
||||
return this.tableSheetPdf.convertToPdf(
|
||||
table.table,
|
||||
table.meta.organizationName,
|
||||
table.meta.sheetName,
|
||||
table.meta.formattedDateRange,
|
||||
HtmlTableCustomCss,
|
||||
|
||||
@@ -9,7 +9,7 @@ export class VendorBalanceSummaryPdf {
|
||||
constructor(
|
||||
private readonly vendorBalanceSummaryTable: VendorBalanceSummaryTableInjectable,
|
||||
private readonly tableSheetPdf: TableSheetPdf,
|
||||
) {}
|
||||
) { }
|
||||
|
||||
/**
|
||||
* Retrieves the sales by items sheet in pdf format.
|
||||
@@ -23,6 +23,7 @@ export class VendorBalanceSummaryPdf {
|
||||
|
||||
return this.tableSheetPdf.convertToPdf(
|
||||
table.table,
|
||||
table.meta.organizationName,
|
||||
table.meta.sheetName,
|
||||
table.meta.formattedAsDate,
|
||||
HtmlTableCustomCss,
|
||||
|
||||
@@ -4,16 +4,18 @@ export class ServiceError extends Error {
|
||||
errorType: string;
|
||||
message: string;
|
||||
payload: any;
|
||||
httpStatus: HttpStatus;
|
||||
|
||||
constructor(errorType: string, message?: string, payload?: any) {
|
||||
constructor(errorType: string, message?: string, payload?: any, httpStatus?: HttpStatus) {
|
||||
super(message);
|
||||
|
||||
this.errorType = errorType;
|
||||
this.message = message || null;
|
||||
this.payload = payload;
|
||||
this.httpStatus = httpStatus || HttpStatus.BAD_REQUEST;
|
||||
}
|
||||
|
||||
getStatus(): HttpStatus {
|
||||
return HttpStatus.INTERNAL_SERVER_ERROR;
|
||||
return this.httpStatus;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import { JOB_REF, Process, Processor } from '@nestjs/bull';
|
||||
import { Job } from 'bull';
|
||||
import { Inject, Scope } from '@nestjs/common';
|
||||
import { ClsService, UseCls } from 'nestjs-cls';
|
||||
import {
|
||||
SEND_PAYMENT_RECEIVED_MAIL_JOB,
|
||||
SEND_PAYMENT_RECEIVED_MAIL_QUEUE,
|
||||
} from '../constants';
|
||||
import { Inject, Scope } from '@nestjs/common';
|
||||
import { REQUEST } from '@nestjs/core';
|
||||
import { ClsService } from 'nestjs-cls';
|
||||
import { SendPaymentReceiveMailNotification } from '../commands/PaymentReceivedMailNotification';
|
||||
import { SendPaymentReceivedMailPayload } from '../types/PaymentReceived.types';
|
||||
|
||||
@@ -21,9 +20,10 @@ export class SendPaymentReceivedMailProcessor {
|
||||
|
||||
@Inject(JOB_REF)
|
||||
private readonly jobRef: Job<SendPaymentReceivedMailPayload>,
|
||||
) {}
|
||||
) { }
|
||||
|
||||
@Process(SEND_PAYMENT_RECEIVED_MAIL_JOB)
|
||||
@UseCls()
|
||||
async handleSendMail() {
|
||||
const { messageOptions, paymentReceivedId, organizationId, userId } =
|
||||
this.jobRef.data;
|
||||
@@ -37,7 +37,8 @@ export class SendPaymentReceivedMailProcessor {
|
||||
messageOptions,
|
||||
);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
console.error('Failed to process payment received mail job:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ import { GetSaleEstimateMailTemplateService } from './queries/GetSaleEstimateMai
|
||||
import { SaleEstimateAutoIncrementSubscriber } from './subscribers/SaleEstimateAutoIncrementSubscriber';
|
||||
import { BulkDeleteSaleEstimatesService } from './BulkDeleteSaleEstimates.service';
|
||||
import { ValidateBulkDeleteSaleEstimatesService } from './ValidateBulkDeleteSaleEstimates.service';
|
||||
import { SendSaleEstimateMailProcess } from './processes/SendSaleEstimateMail.process';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
@@ -89,6 +90,7 @@ import { ValidateBulkDeleteSaleEstimatesService } from './ValidateBulkDeleteSale
|
||||
SaleEstimateAutoIncrementSubscriber,
|
||||
BulkDeleteSaleEstimatesService,
|
||||
ValidateBulkDeleteSaleEstimatesService,
|
||||
SendSaleEstimateMailProcess,
|
||||
],
|
||||
exports: [
|
||||
SaleEstimatesExportable,
|
||||
|
||||
@@ -24,6 +24,7 @@ import { Mail } from '@/modules/Mail/Mail';
|
||||
import { MailTransporter } from '@/modules/Mail/MailTransporter.service';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
import { GetSaleEstimateMailTemplateService } from '../queries/GetSaleEstimateMailTemplate.service';
|
||||
import { TenancyContext } from '@/modules/Tenancy/TenancyContext.service';
|
||||
|
||||
@Injectable()
|
||||
export class SendSaleEstimateMail {
|
||||
@@ -42,13 +43,14 @@ export class SendSaleEstimateMail {
|
||||
private readonly getEstimateMailTemplate: GetSaleEstimateMailTemplateService,
|
||||
private readonly eventPublisher: EventEmitter2,
|
||||
private readonly mailTransporter: MailTransporter,
|
||||
private readonly tenancyContext: TenancyContext,
|
||||
|
||||
@Inject(SaleEstimate.name)
|
||||
private readonly saleEstimateModel: TenantModelProxy<typeof SaleEstimate>,
|
||||
|
||||
@InjectQueue(SendSaleEstimateMailQueue)
|
||||
private readonly sendEstimateMailQueue: Queue,
|
||||
) {}
|
||||
) { }
|
||||
|
||||
/**
|
||||
* Triggers the reminder mail of the given sale estimate.
|
||||
@@ -60,10 +62,19 @@ export class SendSaleEstimateMail {
|
||||
saleEstimateId: number,
|
||||
messageOptions: SaleEstimateMailOptionsDTO,
|
||||
): Promise<void> {
|
||||
const tenant = await this.tenancyContext.getTenant();
|
||||
const user = await this.tenancyContext.getSystemUser();
|
||||
|
||||
const organizationId = tenant.organizationId;
|
||||
const userId = user.id;
|
||||
|
||||
const payload = {
|
||||
saleEstimateId,
|
||||
messageOptions,
|
||||
userId,
|
||||
organizationId,
|
||||
};
|
||||
|
||||
await this.sendEstimateMailQueue.add(SendSaleEstimateMailJob, payload);
|
||||
|
||||
// Triggers `onSaleEstimatePreMailSend` event.
|
||||
|
||||
@@ -1,19 +1,39 @@
|
||||
import { Process, Processor } from '@nestjs/bull';
|
||||
import { Job } from 'bull';
|
||||
import { Inject, Scope } from '@nestjs/common';
|
||||
import { JOB_REF } from '@nestjs/bull';
|
||||
import {
|
||||
SendSaleEstimateMailJob,
|
||||
SendSaleEstimateMailQueue,
|
||||
} from '../types/SaleEstimates.types';
|
||||
import { SendSaleEstimateMail } from '../commands/SendSaleEstimateMail';
|
||||
import { ClsService, UseCls } from 'nestjs-cls';
|
||||
|
||||
@Processor(SendSaleEstimateMailQueue)
|
||||
@Processor({
|
||||
name: SendSaleEstimateMailQueue,
|
||||
scope: Scope.REQUEST,
|
||||
})
|
||||
export class SendSaleEstimateMailProcess {
|
||||
constructor(private readonly sendEstimateMailService: SendSaleEstimateMail) {}
|
||||
constructor(
|
||||
private readonly sendEstimateMailService: SendSaleEstimateMail,
|
||||
private readonly clsService: ClsService,
|
||||
@Inject(JOB_REF)
|
||||
private readonly jobRef: Job,
|
||||
) { }
|
||||
|
||||
@Process(SendSaleEstimateMailJob)
|
||||
async handleSendMail(job: Job) {
|
||||
const { saleEstimateId, messageOptions } = job.data;
|
||||
@UseCls()
|
||||
async handleSendMail() {
|
||||
const { saleEstimateId, messageOptions, organizationId, userId } = this.jobRef.data;
|
||||
|
||||
await this.sendEstimateMailService.sendMail(saleEstimateId, messageOptions);
|
||||
this.clsService.set('organizationId', organizationId);
|
||||
this.clsService.set('userId', userId);
|
||||
|
||||
try {
|
||||
await this.sendEstimateMailService.sendMail(saleEstimateId, messageOptions);
|
||||
} catch (error) {
|
||||
console.error('Failed to process estimate mail job:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,7 +99,8 @@ export class SaleInvoicesController {
|
||||
return this.saleInvoiceApplication.createSaleInvoice(saleInvoiceDTO);
|
||||
}
|
||||
|
||||
@Put(':id/mail')
|
||||
@Post(':id/mail')
|
||||
@HttpCode(200)
|
||||
@ApiOperation({ summary: 'Send the sale invoice mail.' })
|
||||
@ApiResponse({
|
||||
status: 200,
|
||||
|
||||
@@ -10,6 +10,7 @@ import { PaymentLink } from '@/modules/PaymentLinks/models/PaymentLink';
|
||||
import { SaleInvoice } from '../models/SaleInvoice';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
import { TenancyContext } from '@/modules/Tenancy/TenancyContext.service';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
|
||||
@Injectable()
|
||||
export class GenerateShareLink {
|
||||
@@ -18,13 +19,14 @@ export class GenerateShareLink {
|
||||
private eventPublisher: EventEmitter2,
|
||||
private transformer: TransformerInjectable,
|
||||
private tenancyContext: TenancyContext,
|
||||
private configService: ConfigService,
|
||||
|
||||
@Inject(SaleInvoice.name)
|
||||
private saleInvoiceModel: TenantModelProxy<typeof SaleInvoice>,
|
||||
|
||||
@Inject(PaymentLink.name)
|
||||
private paymentLinkModel: typeof PaymentLink,
|
||||
) {}
|
||||
) { }
|
||||
|
||||
/**
|
||||
* Generates private or public payment link for the given sale invoice.
|
||||
@@ -75,6 +77,9 @@ export class GenerateShareLink {
|
||||
return this.transformer.transform(
|
||||
paymentLink,
|
||||
new GeneratePaymentLinkTransformer(),
|
||||
{
|
||||
baseUrl: this.configService.get('app.baseUrl'),
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import { Transformer } from '@/modules/Transformer/Transformer';
|
||||
import { PUBLIC_PAYMENT_LINK } from '../constants';
|
||||
|
||||
export class GeneratePaymentLinkTransformer extends Transformer {
|
||||
interface GeneratePaymentLinkTransformerOptions {
|
||||
baseUrl: string;
|
||||
}
|
||||
export class GeneratePaymentLinkTransformer extends Transformer<GeneratePaymentLinkTransformerOptions> {
|
||||
/**
|
||||
* Exclude these attributes from payment link object.
|
||||
* @returns {Array}
|
||||
@@ -23,6 +26,9 @@ export class GeneratePaymentLinkTransformer extends Transformer {
|
||||
* @returns {string}
|
||||
*/
|
||||
public link(link) {
|
||||
return PUBLIC_PAYMENT_LINK?.replace('{PAYMENT_LINK_ID}', link.linkId);
|
||||
return PUBLIC_PAYMENT_LINK?.replace(
|
||||
'{BASE_URL}',
|
||||
this.options.baseUrl,
|
||||
).replace('{PAYMENT_LINK_ID}', link.linkId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ export class SendSaleInvoiceMail {
|
||||
private readonly tenancyContect: TenancyContext,
|
||||
|
||||
@InjectQueue(SendSaleInvoiceQueue) private readonly sendInvoiceQueue: Queue,
|
||||
) {}
|
||||
) { }
|
||||
|
||||
/**
|
||||
* Sends the invoice mail of the given sale invoice.
|
||||
@@ -132,7 +132,13 @@ export class SendSaleInvoiceMail {
|
||||
events.saleInvoice.onMailSend,
|
||||
eventPayload,
|
||||
);
|
||||
await this.mailTransporter.send(mail);
|
||||
|
||||
try {
|
||||
await this.mailTransporter.send(mail);
|
||||
} catch (error) {
|
||||
console.error('Failed to send invoice mail:', error);
|
||||
throw error;
|
||||
}
|
||||
|
||||
// Triggers the event `onSaleInvoiceSend`.
|
||||
await this.eventEmitter.emitAsync(
|
||||
|
||||
@@ -3,10 +3,9 @@
|
||||
export const SendSaleInvoiceQueue = 'SendSaleInvoiceQueue';
|
||||
export const SendSaleInvoiceMailJob = 'SendSaleInvoiceMailJob';
|
||||
|
||||
const BASE_URL = 'http://localhost:3000';
|
||||
|
||||
export const DEFAULT_INVOICE_MAIL_SUBJECT =
|
||||
'Invoice {Invoice Number} from {Company Name} for {Customer Name}';
|
||||
'Invoice {Invoice Number} from {Company Name} for {Customer Name}';
|
||||
export const DEFAULT_INVOICE_MAIL_CONTENT = `Hi {Customer Name},
|
||||
|
||||
Here's invoice # {Invoice Number} for {Invoice Amount}
|
||||
@@ -23,8 +22,8 @@ Thanks,
|
||||
|
||||
export const DEFAULT_INVOICE_REMINDER_MAIL_SUBJECT =
|
||||
'Invoice {InvoiceNumber} reminder from {CompanyName}';
|
||||
export const DEFAULT_INVOICE_REMINDER_MAIL_CONTENT = `
|
||||
<p>Dear {CustomerName}</p>
|
||||
export const DEFAULT_INVOICE_REMINDER_MAIL_CONTENT = `
|
||||
<p>Dear {CustomerName}</p>
|
||||
<p>You might have missed the payment date and the invoice is now overdue by {OverdueDays} days.</p>
|
||||
<p>Invoice <strong>#{InvoiceNumber}</strong><br />
|
||||
Due Date : <strong>{InvoiceDueDate}</strong><br />
|
||||
@@ -36,7 +35,7 @@ Amount : <strong>{InvoiceAmount}</strong></p>
|
||||
</p>
|
||||
`;
|
||||
|
||||
export const PUBLIC_PAYMENT_LINK = `${BASE_URL}/payment/{PAYMENT_LINK_ID}`;
|
||||
export const PUBLIC_PAYMENT_LINK = "{BASE_URL}/payment/{PAYMENT_LINK_ID}";
|
||||
|
||||
export const ERRORS = {
|
||||
INVOICE_NUMBER_NOT_UNIQUE: 'INVOICE_NUMBER_NOT_UNIQUE',
|
||||
|
||||
@@ -18,9 +18,10 @@ export class SendSaleInvoiceMailProcessor {
|
||||
@Inject(JOB_REF)
|
||||
private readonly jobRef: Job<SendSaleInvoiceMailJobPayload>,
|
||||
private readonly clsService: ClsService,
|
||||
) {}
|
||||
) { }
|
||||
|
||||
@Process(SendSaleInvoiceMailJob)
|
||||
@UseCls()
|
||||
async handleSendInvoice() {
|
||||
const { messageOptions, saleInvoiceId, organizationId, userId } =
|
||||
this.jobRef.data;
|
||||
@@ -31,7 +32,8 @@ export class SendSaleInvoiceMailProcessor {
|
||||
try {
|
||||
await this.sendSaleInvoiceMail.sendMail(saleInvoiceId, messageOptions);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
console.error('Failed to process invoice mail job:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -209,7 +209,7 @@ class GetInvoicePaymentLinkTaxEntryTransformer extends SaleInvoiceTaxEntryTransf
|
||||
|
||||
class GetInvoicePaymentLinkBrandingTemplate extends GetPdfTemplateTransformer {
|
||||
public includeAttributes = (): string[] => {
|
||||
return ['companyLogoUri', 'primaryColor'];
|
||||
return ['companyLogoUri', 'primaryColor', 'secondaryColor'];
|
||||
};
|
||||
|
||||
public excludeAttributes = (): string[] => {
|
||||
@@ -219,4 +219,8 @@ class GetInvoicePaymentLinkBrandingTemplate extends GetPdfTemplateTransformer {
|
||||
primaryColor = (template) => {
|
||||
return template.attributes?.primaryColor;
|
||||
};
|
||||
|
||||
secondaryColor = (template) => {
|
||||
return template.attributes?.secondaryColor;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -25,7 +25,10 @@ import {
|
||||
CreateSaleReceiptDto,
|
||||
EditSaleReceiptDto,
|
||||
} from './dtos/SaleReceipt.dto';
|
||||
import { ISalesReceiptsFilter } from './types/SaleReceipts.types';
|
||||
import {
|
||||
ISalesReceiptsFilter,
|
||||
SaleReceiptMailOptsDTO,
|
||||
} from './types/SaleReceipts.types';
|
||||
import { AcceptType } from '@/constants/accept-type';
|
||||
import { Response } from 'express';
|
||||
import { SaleReceiptResponseDto } from './dtos/SaleReceiptResponse.dto';
|
||||
@@ -87,7 +90,7 @@ export class SaleReceiptsController {
|
||||
return this.saleReceiptApplication.createSaleReceipt(saleReceiptDTO);
|
||||
}
|
||||
|
||||
@Put(':id/mail')
|
||||
@Post(':id/mail')
|
||||
@HttpCode(200)
|
||||
@ApiOperation({ summary: 'Send the sale receipt mail.' })
|
||||
@ApiParam({
|
||||
@@ -96,8 +99,11 @@ export class SaleReceiptsController {
|
||||
type: Number,
|
||||
description: 'The sale receipt id',
|
||||
})
|
||||
sendSaleReceiptMail(@Param('id', ParseIntPipe) id: number) {
|
||||
return this.saleReceiptApplication.getSaleReceiptMail(id);
|
||||
sendSaleReceiptMail(
|
||||
@Param('id', ParseIntPipe) id: number,
|
||||
@Body() messageOpts: SaleReceiptMailOptsDTO,
|
||||
) {
|
||||
return this.saleReceiptApplication.sendSaleReceiptMail(id, messageOpts);
|
||||
}
|
||||
|
||||
@Get('state')
|
||||
|
||||
@@ -1,24 +1,42 @@
|
||||
import { Process, Processor } from '@nestjs/bull';
|
||||
import { Job } from 'bull';
|
||||
import { SendSaleReceiptMailQueue } from '../constants';
|
||||
import { Inject, Scope } from '@nestjs/common';
|
||||
import { JOB_REF } from '@nestjs/bull';
|
||||
import { SendSaleReceiptMailQueue, SendSaleReceiptMailJob } from '../constants';
|
||||
import { SaleReceiptMailNotification } from '../commands/SaleReceiptMailNotification';
|
||||
import { SaleReceiptSendMailPayload } from '../types/SaleReceipts.types';
|
||||
import { ClsService } from 'nestjs-cls';
|
||||
import { ClsService, UseCls } from 'nestjs-cls';
|
||||
|
||||
@Processor(SendSaleReceiptMailQueue)
|
||||
@Processor({
|
||||
name: SendSaleReceiptMailQueue,
|
||||
scope: Scope.REQUEST,
|
||||
})
|
||||
export class SendSaleReceiptMailProcess {
|
||||
constructor(
|
||||
private readonly saleReceiptMailNotification: SaleReceiptMailNotification,
|
||||
private readonly clsService: ClsService,
|
||||
) {}
|
||||
|
||||
@Process(SendSaleReceiptMailQueue)
|
||||
async handleSendMailJob(job: Job<SaleReceiptSendMailPayload>) {
|
||||
const { messageOpts, saleReceiptId, organizationId, userId } = job.data;
|
||||
@Inject(JOB_REF)
|
||||
private readonly jobRef: Job<SaleReceiptSendMailPayload>,
|
||||
) { }
|
||||
|
||||
@Process(SendSaleReceiptMailJob)
|
||||
@UseCls()
|
||||
async handleSendMailJob() {
|
||||
const { messageOpts, saleReceiptId, organizationId, userId } =
|
||||
this.jobRef.data;
|
||||
|
||||
this.clsService.set('organizationId', organizationId);
|
||||
this.clsService.set('userId', userId);
|
||||
|
||||
await this.saleReceiptMailNotification.sendMail(saleReceiptId, messageOpts);
|
||||
try {
|
||||
await this.saleReceiptMailNotification.sendMail(
|
||||
saleReceiptId,
|
||||
messageOpts,
|
||||
);
|
||||
} catch (error) {
|
||||
console.error('Failed to process receipt mail job:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import { ServiceError } from '@/modules/Items/ServiceError';
|
||||
export class TransactionsLockingGuard {
|
||||
constructor(
|
||||
private readonly transactionsLockingRepo: TransactionsLockingRepository,
|
||||
) {}
|
||||
) { }
|
||||
|
||||
/**
|
||||
* Detarmines whether the transaction date between the locking date period.
|
||||
@@ -31,7 +31,7 @@ export class TransactionsLockingGuard {
|
||||
const inUnlockDate =
|
||||
unlockFromDate && unlockToDate
|
||||
? moment(transactionDate).isSameOrAfter(unlockFromDate) &&
|
||||
moment(transactionDate).isSameOrBefore(unlockFromDate)
|
||||
moment(transactionDate).isSameOrBefore(unlockFromDate)
|
||||
: false;
|
||||
|
||||
// Retruns true in case the transaction date between locking date
|
||||
@@ -57,7 +57,7 @@ export class TransactionsLockingGuard {
|
||||
);
|
||||
|
||||
if (isLocked) {
|
||||
this.throwTransactionsLockError(lockingGroup);
|
||||
await this.throwTransactionsLockError(lockingGroup);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -90,11 +90,12 @@ export class TransactionsLockingGuard {
|
||||
await this.transactionsLockingRepo.getTransactionsLockingType();
|
||||
|
||||
if (lockingType === TransactionsLockingGroup.All) {
|
||||
return this.validateTransactionsLocking(
|
||||
await this.validateTransactionsLocking(
|
||||
transactionDate,
|
||||
TransactionsLockingGroup.All,
|
||||
);
|
||||
return;
|
||||
}
|
||||
return this.validateTransactionsLocking(transactionDate, moduleType);
|
||||
await this.validateTransactionsLocking(transactionDate, moduleType);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ import { events } from '@/common/events/events';
|
||||
export class FinancialTransactionLockingGuardSubscriber {
|
||||
constructor(
|
||||
public readonly financialTransactionsLocking: FinancialTransactionLocking,
|
||||
) {}
|
||||
) { }
|
||||
|
||||
/**
|
||||
* ---------------------------------------------
|
||||
@@ -33,7 +33,7 @@ export class FinancialTransactionLockingGuardSubscriber {
|
||||
* Transaction locking guard on manual journal creating.
|
||||
* @param {IManualJournalCreatingPayload} payload
|
||||
*/
|
||||
@OnEvent(events.manualJournals.onCreating)
|
||||
@OnEvent(events.manualJournals.onCreating, { suppressErrors: false })
|
||||
public async transactionsLockingGuardOnManualJournalCreating({
|
||||
manualJournalDTO,
|
||||
}: IManualJournalCreatingPayload) {
|
||||
@@ -49,7 +49,7 @@ export class FinancialTransactionLockingGuardSubscriber {
|
||||
* Transactions locking guard on manual journal deleting.
|
||||
* @param {IManualJournalEditingPayload} payload
|
||||
*/
|
||||
@OnEvent(events.manualJournals.onDeleting)
|
||||
@OnEvent(events.manualJournals.onDeleting, { suppressErrors: false })
|
||||
public async transactionsLockingGuardOnManualJournalDeleting({
|
||||
oldManualJournal,
|
||||
}: IManualJournalEditingPayload) {
|
||||
@@ -65,7 +65,7 @@ export class FinancialTransactionLockingGuardSubscriber {
|
||||
* Transactions locking guard on manual journal editing.
|
||||
* @param {IManualJournalDeletingPayload} payload
|
||||
*/
|
||||
@OnEvent(events.manualJournals.onEditing)
|
||||
@OnEvent(events.manualJournals.onEditing, { suppressErrors: false })
|
||||
public async transactionsLockingGuardOnManualJournalEditing({
|
||||
oldManualJournal,
|
||||
manualJournalDTO,
|
||||
@@ -87,7 +87,7 @@ export class FinancialTransactionLockingGuardSubscriber {
|
||||
* Transactions locking guard on manual journal publishing.
|
||||
* @param {IManualJournalPublishingPayload}
|
||||
*/
|
||||
@OnEvent(events.manualJournals.onPublishing)
|
||||
@OnEvent(events.manualJournals.onPublishing, { suppressErrors: false })
|
||||
public async transactionsLockingGuardOnManualJournalPublishing({
|
||||
oldManualJournal,
|
||||
}: IManualJournalPublishingPayload) {
|
||||
@@ -106,7 +106,7 @@ export class FinancialTransactionLockingGuardSubscriber {
|
||||
* Transactions locking guard on expense creating.
|
||||
* @param {IExpenseCreatingPayload} payload
|
||||
*/
|
||||
@OnEvent(events.expenses.onCreating)
|
||||
@OnEvent(events.expenses.onCreating, { suppressErrors: false })
|
||||
public async transactionsLockingGuardOnExpenseCreating({
|
||||
expenseDTO,
|
||||
}: IExpenseCreatingPayload) {
|
||||
@@ -122,7 +122,7 @@ export class FinancialTransactionLockingGuardSubscriber {
|
||||
* Transactions locking guard on expense deleting.
|
||||
* @param {IExpenseDeletingPayload} payload
|
||||
*/
|
||||
@OnEvent(events.expenses.onDeleting)
|
||||
@OnEvent(events.expenses.onDeleting, { suppressErrors: false })
|
||||
public async transactionsLockingGuardOnExpenseDeleting({
|
||||
oldExpense,
|
||||
}: IExpenseDeletingPayload) {
|
||||
@@ -138,7 +138,7 @@ export class FinancialTransactionLockingGuardSubscriber {
|
||||
* Transactions locking guard on expense editing.
|
||||
* @param {IExpenseEventEditingPayload}
|
||||
*/
|
||||
@OnEvent(events.expenses.onEditing)
|
||||
@OnEvent(events.expenses.onEditing, { suppressErrors: false })
|
||||
public async transactionsLockingGuardOnExpenseEditing({
|
||||
oldExpense,
|
||||
expenseDTO,
|
||||
@@ -160,7 +160,7 @@ export class FinancialTransactionLockingGuardSubscriber {
|
||||
* Transactions locking guard on expense publishing.
|
||||
* @param {IExpensePublishingPayload} payload -
|
||||
*/
|
||||
@OnEvent(events.expenses.onPublishing)
|
||||
@OnEvent(events.expenses.onPublishing, { suppressErrors: false })
|
||||
public async transactionsLockingGuardOnExpensePublishing({
|
||||
oldExpense,
|
||||
}: IExpensePublishingPayload) {
|
||||
@@ -179,7 +179,7 @@ export class FinancialTransactionLockingGuardSubscriber {
|
||||
* Transactions locking guard on cashflow transaction creating.
|
||||
* @param {ICommandCashflowCreatingPayload}
|
||||
*/
|
||||
@OnEvent(events.cashflow.onTransactionCreating)
|
||||
@OnEvent(events.cashflow.onTransactionCreating, { suppressErrors: false })
|
||||
public async transactionsLockingGuardOnCashflowTransactionCreating({
|
||||
newTransactionDTO,
|
||||
}: ICommandCashflowCreatingPayload) {
|
||||
@@ -194,7 +194,7 @@ export class FinancialTransactionLockingGuardSubscriber {
|
||||
* Transactions locking guard on cashflow transaction deleting.
|
||||
* @param {ICommandCashflowDeletingPayload}
|
||||
*/
|
||||
@OnEvent(events.cashflow.onTransactionDeleting)
|
||||
@OnEvent(events.cashflow.onTransactionDeleting, { suppressErrors: false })
|
||||
public async transactionsLockingGuardOnCashflowTransactionDeleting({
|
||||
oldCashflowTransaction,
|
||||
}: ICommandCashflowDeletingPayload) {
|
||||
|
||||
@@ -26,7 +26,7 @@ import { OnEvent } from '@nestjs/event-emitter';
|
||||
export class PurchasesTransactionLockingGuardSubscriber {
|
||||
constructor(
|
||||
public readonly purchasesTransactionsLocking: PurchasesTransactionLockingGuard,
|
||||
) {}
|
||||
) { }
|
||||
|
||||
/**
|
||||
* ---------------------------------------------
|
||||
@@ -37,7 +37,7 @@ export class PurchasesTransactionLockingGuardSubscriber {
|
||||
* Transaction locking guard on payment editing.
|
||||
* @param {IBillPaymentEditingPayload}
|
||||
*/
|
||||
@OnEvent(events.billPayment.onEditing)
|
||||
@OnEvent(events.billPayment.onEditing, { suppressErrors: false })
|
||||
public async transactionLockingGuardOnPaymentEditing({
|
||||
oldBillPayment,
|
||||
billPaymentDTO,
|
||||
@@ -56,7 +56,7 @@ export class PurchasesTransactionLockingGuardSubscriber {
|
||||
* Transaction locking guard on payment creating.
|
||||
* @param {IBillPaymentCreatingPayload}
|
||||
*/
|
||||
@OnEvent(events.billPayment.onCreating)
|
||||
@OnEvent(events.billPayment.onCreating, { suppressErrors: false })
|
||||
public async transactionLockingGuardOnPaymentCreating({
|
||||
billPaymentDTO,
|
||||
}: IBillPaymentCreatingPayload) {
|
||||
@@ -69,7 +69,7 @@ export class PurchasesTransactionLockingGuardSubscriber {
|
||||
* Transaction locking guard on payment deleting.
|
||||
* @param {IBillPaymentDeletingPayload} payload -
|
||||
*/
|
||||
@OnEvent(events.billPayment.onDeleting)
|
||||
@OnEvent(events.billPayment.onDeleting, { suppressErrors: false })
|
||||
public async transactionLockingGuardOnPaymentDeleting({
|
||||
oldBillPayment,
|
||||
}: IBillPaymentDeletingPayload) {
|
||||
@@ -88,7 +88,7 @@ export class PurchasesTransactionLockingGuardSubscriber {
|
||||
* Transaction locking guard on bill creating.
|
||||
* @param {IBillCreatingPayload} payload
|
||||
*/
|
||||
@OnEvent(events.bill.onCreating)
|
||||
@OnEvent(events.bill.onCreating, { suppressErrors: false })
|
||||
public async transactionLockingGuardOnBillCreating({
|
||||
billDTO,
|
||||
}: IBillCreatingPayload) {
|
||||
@@ -104,7 +104,7 @@ export class PurchasesTransactionLockingGuardSubscriber {
|
||||
* Transaction locking guard on bill editing.
|
||||
* @param {IBillEditingPayload} payload
|
||||
*/
|
||||
@OnEvent(events.bill.onEditing)
|
||||
@OnEvent(events.bill.onEditing, { suppressErrors: false })
|
||||
public async transactionLockingGuardOnBillEditing({
|
||||
oldBill,
|
||||
billDTO,
|
||||
@@ -126,7 +126,7 @@ export class PurchasesTransactionLockingGuardSubscriber {
|
||||
* Transaction locking guard on bill deleting.
|
||||
* @param {IBillEventDeletingPayload} payload
|
||||
*/
|
||||
@OnEvent(events.bill.onDeleting)
|
||||
@OnEvent(events.bill.onDeleting, { suppressErrors: false })
|
||||
public async transactionLockingGuardOnBillDeleting({
|
||||
oldBill,
|
||||
}: IBillEventDeletingPayload) {
|
||||
@@ -148,7 +148,7 @@ export class PurchasesTransactionLockingGuardSubscriber {
|
||||
* Transaction locking guard on vendor credit creating.
|
||||
* @param {IVendorCreditCreatingPayload} payload
|
||||
*/
|
||||
@OnEvent(events.vendorCredit.onCreating)
|
||||
@OnEvent(events.vendorCredit.onCreating, { suppressErrors: false })
|
||||
public async transactionLockingGuardOnVendorCreditCreating({
|
||||
vendorCreditCreateDTO,
|
||||
}: IVendorCreditCreatingPayload) {
|
||||
@@ -164,7 +164,7 @@ export class PurchasesTransactionLockingGuardSubscriber {
|
||||
* Transaction locking guard on vendor credit deleting.
|
||||
* @param {IVendorCreditDeletingPayload} payload
|
||||
*/
|
||||
@OnEvent(events.vendorCredit.onDeleting)
|
||||
@OnEvent(events.vendorCredit.onDeleting, { suppressErrors: false })
|
||||
public async transactionLockingGuardOnVendorCreditDeleting({
|
||||
oldVendorCredit,
|
||||
}: IVendorCreditDeletingPayload) {
|
||||
@@ -180,7 +180,7 @@ export class PurchasesTransactionLockingGuardSubscriber {
|
||||
* Transaction locking guard on vendor credit editing.
|
||||
* @param {IVendorCreditEditingPayload} payload
|
||||
*/
|
||||
@OnEvent(events.vendorCredit.onEditing)
|
||||
@OnEvent(events.vendorCredit.onEditing, { suppressErrors: false })
|
||||
public async transactionLockingGuardOnVendorCreditEditing({
|
||||
oldVendorCredit,
|
||||
vendorCreditDTO,
|
||||
@@ -202,7 +202,7 @@ export class PurchasesTransactionLockingGuardSubscriber {
|
||||
* Transaction locking guard on refund vendor credit creating.
|
||||
* @param {IRefundVendorCreditCreatingPayload} payload -
|
||||
*/
|
||||
@OnEvent(events.vendorCredit.onRefundCreating)
|
||||
@OnEvent(events.vendorCredit.onRefundCreating, { suppressErrors: false })
|
||||
public async transactionLockingGuardOnRefundVendorCredit({
|
||||
refundVendorCreditDTO,
|
||||
}: IRefundVendorCreditCreatingPayload) {
|
||||
@@ -215,7 +215,7 @@ export class PurchasesTransactionLockingGuardSubscriber {
|
||||
* Transaction locking guard on refund vendor credit deleting.
|
||||
* @param {IRefundVendorCreditDeletingPayload} payload
|
||||
*/
|
||||
@OnEvent(events.vendorCredit.onRefundDeleting)
|
||||
@OnEvent(events.vendorCredit.onRefundDeleting, { suppressErrors: false })
|
||||
public async transactionLockingGuardOnRefundCreditDeleting({
|
||||
oldRefundCredit,
|
||||
}: IRefundVendorCreditDeletingPayload) {
|
||||
|
||||
@@ -37,7 +37,7 @@ import { ISaleReceiptEventClosingPayload } from '@/modules/SaleReceipts/types/Sa
|
||||
export class SalesTransactionLockingGuardSubscriber {
|
||||
constructor(
|
||||
public readonly salesLockingGuard: SalesTransactionLockingGuard,
|
||||
) {}
|
||||
) { }
|
||||
|
||||
/**
|
||||
* ---------------------------------------------
|
||||
@@ -48,7 +48,7 @@ export class SalesTransactionLockingGuardSubscriber {
|
||||
* Transaction locking guard on invoice creating.
|
||||
* @param {ISaleInvoiceCreatingPaylaod} payload
|
||||
*/
|
||||
@OnEvent(events.saleInvoice.onCreating)
|
||||
@OnEvent(events.saleInvoice.onCreating, { suppressErrors: false })
|
||||
public async transactionLockingGuardOnInvoiceCreating({
|
||||
saleInvoiceDTO,
|
||||
}: ISaleInvoiceCreatingPaylaod) {
|
||||
@@ -64,7 +64,7 @@ export class SalesTransactionLockingGuardSubscriber {
|
||||
* Transaction locking guard on invoice editing.
|
||||
* @param {ISaleInvoiceEditingPayload} payload
|
||||
*/
|
||||
@OnEvent(events.saleInvoice.onEditing)
|
||||
@OnEvent(events.saleInvoice.onEditing, { suppressErrors: false })
|
||||
public async transactionLockingGuardOnInvoiceEditing({
|
||||
oldSaleInvoice,
|
||||
saleInvoiceDTO,
|
||||
@@ -86,7 +86,7 @@ export class SalesTransactionLockingGuardSubscriber {
|
||||
* Transaction locking guard on invoice deleting.
|
||||
* @param {ISaleInvoiceDeletePayload} payload
|
||||
*/
|
||||
@OnEvent(events.saleInvoice.onDelete)
|
||||
@OnEvent(events.saleInvoice.onDelete, { suppressErrors: false })
|
||||
public async transactionLockingGuardOnInvoiceDeleting({
|
||||
oldSaleInvoice,
|
||||
}: ISaleInvoiceDeletePayload) {
|
||||
@@ -102,7 +102,7 @@ export class SalesTransactionLockingGuardSubscriber {
|
||||
* Transaction locking guard on invoice writingoff.
|
||||
* @param {ISaleInvoiceWriteoffCreatePayload} payload
|
||||
*/
|
||||
@OnEvent(events.saleInvoice.onWriteoff)
|
||||
@OnEvent(events.saleInvoice.onWriteoff, { suppressErrors: false })
|
||||
public async transactionLockinGuardOnInvoiceWritingoff({
|
||||
saleInvoice,
|
||||
}: ISaleInvoiceWriteoffCreatePayload) {
|
||||
@@ -115,7 +115,7 @@ export class SalesTransactionLockingGuardSubscriber {
|
||||
* Transaciton locking guard on canceling written-off invoice.
|
||||
* @param {ISaleInvoiceWrittenOffCancelPayload} payload
|
||||
*/
|
||||
@OnEvent(events.saleInvoice.onWrittenoffCancel)
|
||||
@OnEvent(events.saleInvoice.onWrittenoffCancel, { suppressErrors: false })
|
||||
public async transactionLockinGuardOnInvoiceWritingoffCanceling({
|
||||
saleInvoice,
|
||||
}: ISaleInvoiceWrittenOffCancelPayload) {
|
||||
@@ -134,7 +134,7 @@ export class SalesTransactionLockingGuardSubscriber {
|
||||
* Transaction locking guard on receipt creating.
|
||||
* @param {ISaleReceiptCreatingPayload}
|
||||
*/
|
||||
@OnEvent(events.saleReceipt.onCreating)
|
||||
@OnEvent(events.saleReceipt.onCreating, { suppressErrors: false })
|
||||
public async transactionLockingGuardOnReceiptCreating({
|
||||
saleReceiptDTO,
|
||||
}: ISaleReceiptCreatingPayload) {
|
||||
@@ -150,7 +150,7 @@ export class SalesTransactionLockingGuardSubscriber {
|
||||
* Transaction locking guard on receipt creating.
|
||||
* @param {ISaleReceiptDeletingPayload}
|
||||
*/
|
||||
@OnEvent(events.saleReceipt.onDeleting)
|
||||
@OnEvent(events.saleReceipt.onDeleting, { suppressErrors: false })
|
||||
public async transactionLockingGuardOnReceiptDeleting({
|
||||
oldSaleReceipt,
|
||||
}: ISaleReceiptDeletingPayload) {
|
||||
@@ -165,7 +165,7 @@ export class SalesTransactionLockingGuardSubscriber {
|
||||
* Transaction locking guard on sale receipt editing.
|
||||
* @param {ISaleReceiptEditingPayload} payload
|
||||
*/
|
||||
@OnEvent(events.saleReceipt.onEditing)
|
||||
@OnEvent(events.saleReceipt.onEditing, { suppressErrors: false })
|
||||
public async transactionLockingGuardOnReceiptEditing({
|
||||
oldSaleReceipt,
|
||||
saleReceiptDTO,
|
||||
@@ -184,7 +184,7 @@ export class SalesTransactionLockingGuardSubscriber {
|
||||
* Transaction locking guard on sale receipt closing.
|
||||
* @param {ISaleReceiptEventClosingPayload} payload
|
||||
*/
|
||||
@OnEvent(events.saleReceipt.onClosing)
|
||||
@OnEvent(events.saleReceipt.onClosing, { suppressErrors: false })
|
||||
public async transactionLockingGuardOnReceiptClosing({
|
||||
oldSaleReceipt,
|
||||
}: ISaleReceiptEventClosingPayload) {
|
||||
@@ -203,7 +203,7 @@ export class SalesTransactionLockingGuardSubscriber {
|
||||
* Transaction locking guard on credit note deleting.
|
||||
* @param {ICreditNoteDeletingPayload} payload -
|
||||
*/
|
||||
@OnEvent(events.creditNote.onDeleting)
|
||||
@OnEvent(events.creditNote.onDeleting, { suppressErrors: false })
|
||||
public async transactionLockingGuardOnCreditDeleting({
|
||||
oldCreditNote,
|
||||
}: ICreditNoteDeletingPayload) {
|
||||
@@ -219,7 +219,7 @@ export class SalesTransactionLockingGuardSubscriber {
|
||||
* Transaction locking guard on credit note creating.
|
||||
* @param {ICreditNoteCreatingPayload} payload
|
||||
*/
|
||||
@OnEvent(events.creditNote.onCreating)
|
||||
@OnEvent(events.creditNote.onCreating, { suppressErrors: false })
|
||||
public async transactionLockingGuardOnCreditCreating({
|
||||
creditNoteDTO,
|
||||
}: ICreditNoteCreatingPayload) {
|
||||
@@ -235,7 +235,7 @@ export class SalesTransactionLockingGuardSubscriber {
|
||||
* Transaction locking guard on credit note editing.
|
||||
* @param {ICreditNoteEditingPayload} payload -
|
||||
*/
|
||||
@OnEvent(events.creditNote.onEditing)
|
||||
@OnEvent(events.creditNote.onEditing, { suppressErrors: false })
|
||||
public async transactionLockingGuardOnCreditEditing({
|
||||
creditNoteEditDTO,
|
||||
oldCreditNote,
|
||||
@@ -257,7 +257,7 @@ export class SalesTransactionLockingGuardSubscriber {
|
||||
* Transaction locking guard on payment deleting.
|
||||
* @param {IRefundCreditNoteDeletingPayload} paylaod -
|
||||
*/
|
||||
@OnEvent(events.creditNote.onRefundDeleting)
|
||||
@OnEvent(events.creditNote.onRefundDeleting, { suppressErrors: false })
|
||||
public async transactionLockingGuardOnCreditRefundDeleteing({
|
||||
oldRefundCredit,
|
||||
}: IRefundCreditNoteDeletingPayload) {
|
||||
@@ -268,7 +268,7 @@ export class SalesTransactionLockingGuardSubscriber {
|
||||
* Transaction locking guard on refund credit note creating.
|
||||
* @param {IRefundCreditNoteCreatingPayload} payload -
|
||||
*/
|
||||
@OnEvent(events.creditNote.onRefundCreating)
|
||||
@OnEvent(events.creditNote.onRefundCreating, { suppressErrors: false })
|
||||
public async transactionLockingGuardOnCreditRefundCreating({
|
||||
newCreditNoteDTO,
|
||||
}: IRefundCreditNoteCreatingPayload) {
|
||||
@@ -284,7 +284,7 @@ export class SalesTransactionLockingGuardSubscriber {
|
||||
* Transaction locking guard on estimate creating.
|
||||
* @param {ISaleEstimateCreatingPayload} payload -
|
||||
*/
|
||||
@OnEvent(events.saleEstimate.onCreating)
|
||||
@OnEvent(events.saleEstimate.onCreating, { suppressErrors: false })
|
||||
public async transactionLockingGuardOnEstimateCreating({
|
||||
estimateDTO,
|
||||
}: ISaleEstimateCreatingPayload) {
|
||||
@@ -300,7 +300,7 @@ export class SalesTransactionLockingGuardSubscriber {
|
||||
* Transaction locking guard on estimate deleting.
|
||||
* @param {ISaleEstimateDeletingPayload} payload
|
||||
*/
|
||||
@OnEvent(events.saleEstimate.onDeleting)
|
||||
@OnEvent(events.saleEstimate.onDeleting, { suppressErrors: false })
|
||||
public async transactionLockingGuardOnEstimateDeleting({
|
||||
oldSaleEstimate,
|
||||
}: ISaleEstimateDeletingPayload) {
|
||||
@@ -316,7 +316,7 @@ export class SalesTransactionLockingGuardSubscriber {
|
||||
* Transaction locking guard on estimate editing.
|
||||
* @param {ISaleEstimateEditingPayload} payload
|
||||
*/
|
||||
@OnEvent(events.saleEstimate.onEditing)
|
||||
@OnEvent(events.saleEstimate.onEditing, { suppressErrors: false })
|
||||
public async transactionLockingGuardOnEstimateEditing({
|
||||
oldSaleEstimate,
|
||||
estimateDTO,
|
||||
@@ -344,7 +344,7 @@ export class SalesTransactionLockingGuardSubscriber {
|
||||
* Transaction locking guard on payment receive editing.
|
||||
* @param {IPaymentReceivedEditingPayload}
|
||||
*/
|
||||
@OnEvent(events.paymentReceive.onEditing)
|
||||
@OnEvent(events.paymentReceive.onEditing, { suppressErrors: false })
|
||||
public async transactionLockingGuardOnPaymentEditing({
|
||||
oldPaymentReceive,
|
||||
paymentReceiveDTO,
|
||||
@@ -363,7 +363,7 @@ export class SalesTransactionLockingGuardSubscriber {
|
||||
* Transaction locking guard on payment creating.
|
||||
* @param {IPaymentReceivedCreatingPayload}
|
||||
*/
|
||||
@OnEvent(events.paymentReceive.onCreating)
|
||||
@OnEvent(events.paymentReceive.onCreating, { suppressErrors: false })
|
||||
public async transactionLockingGuardOnPaymentCreating({
|
||||
paymentReceiveDTO,
|
||||
}: IPaymentReceivedCreatingPayload) {
|
||||
@@ -376,7 +376,7 @@ export class SalesTransactionLockingGuardSubscriber {
|
||||
* Transaction locking guard on payment deleting.
|
||||
* @param {IPaymentReceivedDeletingPayload} payload -
|
||||
*/
|
||||
@OnEvent(events.paymentReceive.onDeleting)
|
||||
@OnEvent(events.paymentReceive.onDeleting, { suppressErrors: false })
|
||||
public async transactionLockingGuardPaymentDeleting({
|
||||
oldPaymentReceive,
|
||||
}: IPaymentReceivedDeletingPayload) {
|
||||
|
||||
@@ -21,9 +21,10 @@ export class SendInviteUserMailProcessor {
|
||||
@Inject(JOB_REF)
|
||||
private readonly jobRef: Job<SendInviteUserMailJobPayload>,
|
||||
private readonly clsService: ClsService,
|
||||
) {}
|
||||
) { }
|
||||
|
||||
@Process(SendInviteUserMailJob)
|
||||
@UseCls()
|
||||
async handleSendInviteMail() {
|
||||
const { fromUser, invite, organizationId, userId } = this.jobRef.data;
|
||||
|
||||
@@ -33,7 +34,8 @@ export class SendInviteUserMailProcessor {
|
||||
try {
|
||||
await this.sendInviteUsersMailService.sendInviteMail(fromUser, invite);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
console.error('Failed to process invite user mail job:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,115 +1,116 @@
|
||||
// import { Service } from 'typedi';
|
||||
// import { IVendor, AccountNormal, ILedgerEntry } from '@/interfaces';
|
||||
// import Ledger from '@/services/Accounting/Ledger';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { AccountNormal } from '@/interfaces/Account';
|
||||
import { ILedgerEntry } from '@/modules/Ledger/types/Ledger.types';
|
||||
import { Ledger } from '@/modules/Ledger/Ledger';
|
||||
import { Vendor } from './models/Vendor';
|
||||
|
||||
// @Service()
|
||||
// export class VendorGLEntries {
|
||||
// /**
|
||||
// * Retrieves the opening balance GL common entry.
|
||||
// * @param {IVendor} vendor -
|
||||
// */
|
||||
// private getOpeningBalanceGLCommonEntry = (vendor: IVendor) => {
|
||||
// return {
|
||||
// exchangeRate: vendor.openingBalanceExchangeRate,
|
||||
// currencyCode: vendor.currencyCode,
|
||||
@Injectable()
|
||||
export class VendorGLEntries {
|
||||
/**
|
||||
* Retrieves the opening balance GL common entry.
|
||||
* @param {Vendor} vendor -
|
||||
*/
|
||||
private getOpeningBalanceGLCommonEntry = (vendor: Vendor) => {
|
||||
return {
|
||||
exchangeRate: vendor.openingBalanceExchangeRate,
|
||||
currencyCode: vendor.currencyCode,
|
||||
|
||||
// transactionType: 'VendorOpeningBalance',
|
||||
// transactionId: vendor.id,
|
||||
transactionType: 'VendorOpeningBalance',
|
||||
transactionId: vendor.id,
|
||||
|
||||
// date: vendor.openingBalanceAt,
|
||||
// userId: vendor.userId,
|
||||
// contactId: vendor.id,
|
||||
date: vendor.openingBalanceAt,
|
||||
contactId: vendor.id,
|
||||
|
||||
// credit: 0,
|
||||
// debit: 0,
|
||||
credit: 0,
|
||||
debit: 0,
|
||||
|
||||
// branchId: vendor.openingBalanceBranchId,
|
||||
// };
|
||||
// };
|
||||
branchId: vendor.openingBalanceBranchId,
|
||||
};
|
||||
};
|
||||
|
||||
// /**
|
||||
// * Retrieves the opening balance GL debit entry.
|
||||
// * @param {number} costAccountId -
|
||||
// * @param {IVendor} vendor
|
||||
// * @returns {ILedgerEntry}
|
||||
// */
|
||||
// private getOpeningBalanceGLDebitEntry = (
|
||||
// costAccountId: number,
|
||||
// vendor: IVendor
|
||||
// ): ILedgerEntry => {
|
||||
// const commonEntry = this.getOpeningBalanceGLCommonEntry(vendor);
|
||||
/**
|
||||
* Retrieves the opening balance GL debit entry.
|
||||
* @param {number} costAccountId -
|
||||
* @param {Vendor} vendor
|
||||
* @returns {ILedgerEntry}
|
||||
*/
|
||||
private getOpeningBalanceGLDebitEntry = (
|
||||
costAccountId: number,
|
||||
vendor: Vendor
|
||||
): ILedgerEntry => {
|
||||
const commonEntry = this.getOpeningBalanceGLCommonEntry(vendor);
|
||||
|
||||
// return {
|
||||
// ...commonEntry,
|
||||
// accountId: costAccountId,
|
||||
// accountNormal: AccountNormal.DEBIT,
|
||||
// debit: vendor.localOpeningBalance,
|
||||
// credit: 0,
|
||||
// index: 2,
|
||||
// };
|
||||
// };
|
||||
return {
|
||||
...commonEntry,
|
||||
accountId: costAccountId,
|
||||
accountNormal: AccountNormal.DEBIT,
|
||||
debit: vendor.localOpeningBalance,
|
||||
credit: 0,
|
||||
index: 2,
|
||||
};
|
||||
};
|
||||
|
||||
// /**
|
||||
// * Retrieves the opening balance GL credit entry.
|
||||
// * @param {number} APAccountId
|
||||
// * @param {IVendor} vendor
|
||||
// * @returns {ILedgerEntry}
|
||||
// */
|
||||
// private getOpeningBalanceGLCreditEntry = (
|
||||
// APAccountId: number,
|
||||
// vendor: IVendor
|
||||
// ): ILedgerEntry => {
|
||||
// const commonEntry = this.getOpeningBalanceGLCommonEntry(vendor);
|
||||
/**
|
||||
* Retrieves the opening balance GL credit entry.
|
||||
* @param {number} APAccountId
|
||||
* @param {Vendor} vendor
|
||||
* @returns {ILedgerEntry}
|
||||
*/
|
||||
private getOpeningBalanceGLCreditEntry = (
|
||||
APAccountId: number,
|
||||
vendor: Vendor
|
||||
): ILedgerEntry => {
|
||||
const commonEntry = this.getOpeningBalanceGLCommonEntry(vendor);
|
||||
|
||||
// return {
|
||||
// ...commonEntry,
|
||||
// accountId: APAccountId,
|
||||
// accountNormal: AccountNormal.CREDIT,
|
||||
// credit: vendor.localOpeningBalance,
|
||||
// index: 1,
|
||||
// };
|
||||
// };
|
||||
return {
|
||||
...commonEntry,
|
||||
accountId: APAccountId,
|
||||
accountNormal: AccountNormal.CREDIT,
|
||||
credit: vendor.localOpeningBalance,
|
||||
index: 1,
|
||||
};
|
||||
};
|
||||
|
||||
// /**
|
||||
// * Retrieves the opening balance GL entries.
|
||||
// * @param {number} APAccountId
|
||||
// * @param {number} costAccountId -
|
||||
// * @param {IVendor} vendor
|
||||
// * @returns {ILedgerEntry[]}
|
||||
// */
|
||||
// public getOpeningBalanceGLEntries = (
|
||||
// APAccountId: number,
|
||||
// costAccountId: number,
|
||||
// vendor: IVendor
|
||||
// ): ILedgerEntry[] => {
|
||||
// const debitEntry = this.getOpeningBalanceGLDebitEntry(
|
||||
// costAccountId,
|
||||
// vendor
|
||||
// );
|
||||
// const creditEntry = this.getOpeningBalanceGLCreditEntry(
|
||||
// APAccountId,
|
||||
// vendor
|
||||
// );
|
||||
// return [debitEntry, creditEntry];
|
||||
// };
|
||||
/**
|
||||
* Retrieves the opening balance GL entries.
|
||||
* @param {number} APAccountId
|
||||
* @param {number} costAccountId -
|
||||
* @param {Vendor} vendor
|
||||
* @returns {ILedgerEntry[]}
|
||||
*/
|
||||
public getOpeningBalanceGLEntries = (
|
||||
APAccountId: number,
|
||||
costAccountId: number,
|
||||
vendor: Vendor
|
||||
): ILedgerEntry[] => {
|
||||
const debitEntry = this.getOpeningBalanceGLDebitEntry(
|
||||
costAccountId,
|
||||
vendor
|
||||
);
|
||||
const creditEntry = this.getOpeningBalanceGLCreditEntry(
|
||||
APAccountId,
|
||||
vendor
|
||||
);
|
||||
return [debitEntry, creditEntry];
|
||||
};
|
||||
|
||||
// /**
|
||||
// * Retrieves the opening balance ledger.
|
||||
// * @param {number} APAccountId
|
||||
// * @param {number} costAccountId -
|
||||
// * @param {IVendor} vendor
|
||||
// * @returns {Ledger}
|
||||
// */
|
||||
// public getOpeningBalanceLedger = (
|
||||
// APAccountId: number,
|
||||
// costAccountId: number,
|
||||
// vendor: IVendor
|
||||
// ) => {
|
||||
// const entries = this.getOpeningBalanceGLEntries(
|
||||
// APAccountId,
|
||||
// costAccountId,
|
||||
// vendor
|
||||
// );
|
||||
// return new Ledger(entries);
|
||||
// };
|
||||
// }
|
||||
/**
|
||||
* Retrieves the opening balance ledger.
|
||||
* @param {number} APAccountId
|
||||
* @param {number} costAccountId -
|
||||
* @param {Vendor} vendor
|
||||
* @returns {Ledger}
|
||||
*/
|
||||
public getOpeningBalanceLedger = (
|
||||
APAccountId: number,
|
||||
costAccountId: number,
|
||||
vendor: Vendor
|
||||
) => {
|
||||
const entries = this.getOpeningBalanceGLEntries(
|
||||
APAccountId,
|
||||
costAccountId,
|
||||
vendor
|
||||
);
|
||||
return new Ledger(entries);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,88 +1,86 @@
|
||||
// import { Knex } from 'knex';
|
||||
// import { Service, Inject } from 'typedi';
|
||||
// import LedgerStorageService from '@/services/Accounting/LedgerStorageService';
|
||||
// import HasTenancyService from '@/services/Tenancy/TenancyService';
|
||||
// import { VendorGLEntries } from './VendorGLEntries';
|
||||
import { Knex } from 'knex';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { LedgerStorageService } from '@/modules/Ledger/LedgerStorage.service';
|
||||
import { AccountRepository } from '@/modules/Accounts/repositories/Account.repository';
|
||||
import { VendorGLEntries } from './VendorGLEntries';
|
||||
import { Vendor } from './models/Vendor';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
// @Service()
|
||||
// export class VendorGLEntriesStorage {
|
||||
// @Inject()
|
||||
// private tenancy: HasTenancyService;
|
||||
@Injectable()
|
||||
export class VendorGLEntriesStorage {
|
||||
constructor(
|
||||
private readonly ledgerStorage: LedgerStorageService,
|
||||
private readonly accountRepository: AccountRepository,
|
||||
private readonly vendorGLEntries: VendorGLEntries,
|
||||
|
||||
// @Inject()
|
||||
// private ledegrRepository: LedgerStorageService;
|
||||
@Inject(Vendor.name)
|
||||
private readonly vendorModel: TenantModelProxy<typeof Vendor>,
|
||||
) { }
|
||||
|
||||
// @Inject()
|
||||
// private vendorGLEntries: VendorGLEntries;
|
||||
/**
|
||||
* Vendor opening balance journals.
|
||||
* @param {number} vendorId
|
||||
* @param {Knex.Transaction} trx
|
||||
*/
|
||||
public writeVendorOpeningBalance = async (
|
||||
vendorId: number,
|
||||
trx?: Knex.Transaction,
|
||||
) => {
|
||||
const vendor = await this.vendorModel()
|
||||
.query(trx)
|
||||
.findById(vendorId);
|
||||
|
||||
// /**
|
||||
// * Vendor opening balance journals.
|
||||
// * @param {number} tenantId
|
||||
// * @param {number} vendorId
|
||||
// * @param {Knex.Transaction} trx
|
||||
// */
|
||||
// public writeVendorOpeningBalance = async (
|
||||
// tenantId: number,
|
||||
// vendorId: number,
|
||||
// trx?: Knex.Transaction
|
||||
// ) => {
|
||||
// const { Vendor } = this.tenancy.models(tenantId);
|
||||
// const { accountRepository } = this.tenancy.repositories(tenantId);
|
||||
// Finds the expense account.
|
||||
const expenseAccount = await this.accountRepository.findOrCreateOtherExpensesAccount(
|
||||
{},
|
||||
trx,
|
||||
);
|
||||
// Find or create the A/P account.
|
||||
const APAccount =
|
||||
await this.accountRepository.findOrCreateAccountsPayable(
|
||||
vendor.currencyCode,
|
||||
{},
|
||||
trx,
|
||||
);
|
||||
// Retrieves the vendor opening balance ledger.
|
||||
const ledger = this.vendorGLEntries.getOpeningBalanceLedger(
|
||||
APAccount.id,
|
||||
expenseAccount.id,
|
||||
vendor,
|
||||
);
|
||||
// Commits the ledger entries to the storage.
|
||||
await this.ledgerStorage.commit(ledger, trx);
|
||||
};
|
||||
|
||||
// const vendor = await Vendor.query(trx).findById(vendorId);
|
||||
/**
|
||||
* Reverts the vendor opening balance GL entries.
|
||||
* @param {number} vendorId
|
||||
* @param {Knex.Transaction} trx
|
||||
*/
|
||||
public revertVendorOpeningBalance = async (
|
||||
vendorId: number,
|
||||
trx?: Knex.Transaction,
|
||||
) => {
|
||||
await this.ledgerStorage.deleteByReference(
|
||||
vendorId,
|
||||
'VendorOpeningBalance',
|
||||
trx,
|
||||
);
|
||||
};
|
||||
|
||||
// // Finds the expense account.
|
||||
// const expenseAccount = await accountRepository.findOne({
|
||||
// slug: 'other-expenses',
|
||||
// });
|
||||
// // Find or create the A/P account.
|
||||
// const APAccount = await accountRepository.findOrCreateAccountsPayable(
|
||||
// vendor.currencyCode,
|
||||
// {},
|
||||
// trx
|
||||
// );
|
||||
// // Retrieves the vendor opening balance ledger.
|
||||
// const ledger = this.vendorGLEntries.getOpeningBalanceLedger(
|
||||
// APAccount.id,
|
||||
// expenseAccount.id,
|
||||
// vendor
|
||||
// );
|
||||
// // Commits the ledger entries to the storage.
|
||||
// await this.ledegrRepository.commit(tenantId, ledger, trx);
|
||||
// };
|
||||
/**
|
||||
* Writes the vendor opening balance GL entries.
|
||||
* @param {number} vendorId
|
||||
* @param {Knex.Transaction} trx
|
||||
*/
|
||||
public rewriteVendorOpeningBalance = async (
|
||||
vendorId: number,
|
||||
trx?: Knex.Transaction,
|
||||
) => {
|
||||
// Reverts the vendor opening balance entries first.
|
||||
await this.revertVendorOpeningBalance(vendorId, trx);
|
||||
|
||||
// /**
|
||||
// * Reverts the vendor opening balance GL entries.
|
||||
// * @param {number} tenantId
|
||||
// * @param {number} vendorId
|
||||
// * @param {Knex.Transaction} trx
|
||||
// */
|
||||
// public revertVendorOpeningBalance = async (
|
||||
// tenantId: number,
|
||||
// vendorId: number,
|
||||
// trx?: Knex.Transaction
|
||||
// ) => {
|
||||
// await this.ledegrRepository.deleteByReference(
|
||||
// tenantId,
|
||||
// vendorId,
|
||||
// 'VendorOpeningBalance',
|
||||
// trx
|
||||
// );
|
||||
// };
|
||||
|
||||
// /**
|
||||
// * Writes the vendor opening balance GL entries.
|
||||
// * @param {number} tenantId
|
||||
// * @param {number} vendorId
|
||||
// * @param {Knex.Transaction} trx
|
||||
// */
|
||||
// public rewriteVendorOpeningBalance = async (
|
||||
// tenantId: number,
|
||||
// vendorId: number,
|
||||
// trx?: Knex.Transaction
|
||||
// ) => {
|
||||
// await this.writeVendorOpeningBalance(tenantId, vendorId, trx);
|
||||
|
||||
// await this.revertVendorOpeningBalance(tenantId, vendorId, trx);
|
||||
// };
|
||||
// }
|
||||
// Write the vendor opening balance entries.
|
||||
await this.writeVendorOpeningBalance(vendorId, trx);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -9,10 +9,7 @@ import {
|
||||
Query,
|
||||
} from '@nestjs/common';
|
||||
import { VendorsApplication } from './VendorsApplication.service';
|
||||
import {
|
||||
IVendorOpeningBalanceEditDTO,
|
||||
IVendorsFilter,
|
||||
} from './types/Vendors.types';
|
||||
import { VendorOpeningBalanceEditDto } from './dtos/VendorOpeningBalanceEdit.dto';
|
||||
import {
|
||||
ApiOperation,
|
||||
ApiResponse,
|
||||
@@ -68,7 +65,7 @@ export class VendorsController {
|
||||
@ApiOperation({ summary: 'Edit the given vendor opening balance.' })
|
||||
editOpeningBalance(
|
||||
@Param('id') vendorId: number,
|
||||
@Body() openingBalanceDTO: IVendorOpeningBalanceEditDTO,
|
||||
@Body() openingBalanceDTO: VendorOpeningBalanceEditDto,
|
||||
) {
|
||||
return this.vendorsApplication.editOpeningBalance(
|
||||
vendorId,
|
||||
|
||||
@@ -18,9 +18,14 @@ import { VendorsExportable } from './VendorsExportable';
|
||||
import { VendorsImportable } from './VendorsImportable';
|
||||
import { BulkDeleteVendorsService } from './BulkDeleteVendors.service';
|
||||
import { ValidateBulkDeleteVendorsService } from './ValidateBulkDeleteVendors.service';
|
||||
import { LedgerModule } from '../Ledger/Ledger.module';
|
||||
import { AccountsModule } from '../Accounts/Accounts.module';
|
||||
import { VendorGLEntries } from './VendorGLEntries';
|
||||
import { VendorGLEntriesStorage } from './VendorGLEntriesStorage';
|
||||
import { VendorsWriteGLOpeningSubscriber } from './subscribers/VendorGLEntriesSubscriber';
|
||||
|
||||
@Module({
|
||||
imports: [TenancyDatabaseModule, DynamicListModule],
|
||||
imports: [TenancyDatabaseModule, DynamicListModule, LedgerModule, AccountsModule],
|
||||
controllers: [VendorsController],
|
||||
providers: [
|
||||
ActivateVendorService,
|
||||
@@ -38,7 +43,10 @@ import { ValidateBulkDeleteVendorsService } from './ValidateBulkDeleteVendors.se
|
||||
TransformerInjectable,
|
||||
TenancyContext,
|
||||
VendorsExportable,
|
||||
VendorsImportable
|
||||
VendorsImportable,
|
||||
VendorGLEntries,
|
||||
VendorGLEntriesStorage,
|
||||
VendorsWriteGLOpeningSubscriber,
|
||||
],
|
||||
})
|
||||
export class VendorsModule {}
|
||||
export class VendorsModule { }
|
||||
|
||||
@@ -5,10 +5,7 @@ import { EditVendorService } from './commands/EditVendor.service';
|
||||
import { DeleteVendorService } from './commands/DeleteVendor.service';
|
||||
import { EditOpeningBalanceVendorService } from './commands/EditOpeningBalanceVendor.service';
|
||||
import { GetVendorService } from './queries/GetVendor';
|
||||
import {
|
||||
IVendorOpeningBalanceEditDTO,
|
||||
IVendorsFilter,
|
||||
} from './types/Vendors.types';
|
||||
import { VendorOpeningBalanceEditDto } from './dtos/VendorOpeningBalanceEdit.dto';
|
||||
import { GetVendorsService } from './queries/GetVendors.service';
|
||||
import { CreateVendorDto } from './dtos/CreateVendor.dto';
|
||||
import { EditVendorDto } from './dtos/EditVendor.dto';
|
||||
@@ -58,14 +55,14 @@ export class VendorsApplication {
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the opening balance of the given customer.
|
||||
* @param {number} vendorId
|
||||
* @param {IVendorOpeningBalanceEditDTO} openingBalanceEditDTO
|
||||
* Changes the opening balance of the given vendor.
|
||||
* @param {number} vendorId
|
||||
* @param {VendorOpeningBalanceEditDto} openingBalanceEditDTO
|
||||
* @returns {Promise<IVendor>}
|
||||
*/
|
||||
public editOpeningBalance(
|
||||
vendorId: number,
|
||||
openingBalanceEditDTO: IVendorOpeningBalanceEditDTO,
|
||||
openingBalanceEditDTO: VendorOpeningBalanceEditDto,
|
||||
) {
|
||||
return this.editOpeningBalanceService.editOpeningBalance(
|
||||
vendorId,
|
||||
@@ -95,10 +92,7 @@ export class VendorsApplication {
|
||||
vendorIds: number[],
|
||||
options?: { skipUndeletable?: boolean },
|
||||
) {
|
||||
return this.bulkDeleteVendorsService.bulkDeleteVendors(
|
||||
vendorIds,
|
||||
options,
|
||||
);
|
||||
return this.bulkDeleteVendorsService.bulkDeleteVendors(vendorIds, options);
|
||||
}
|
||||
|
||||
public validateBulkDeleteVendors(vendorIds: number[]) {
|
||||
|
||||
@@ -2,10 +2,10 @@ import { Knex } from 'knex';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import {
|
||||
IVendorOpeningBalanceEditDTO,
|
||||
IVendorOpeningBalanceEditedPayload,
|
||||
IVendorOpeningBalanceEditingPayload,
|
||||
} from '../types/Vendors.types';
|
||||
import { VendorOpeningBalanceEditDto } from '../dtos/VendorOpeningBalanceEdit.dto';
|
||||
import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service';
|
||||
import { Vendor } from '../models/Vendor';
|
||||
import { events } from '@/common/events/events';
|
||||
@@ -29,12 +29,12 @@ export class EditOpeningBalanceVendorService {
|
||||
/**
|
||||
* Changes the opening balance of the given customer.
|
||||
* @param {number} vendorId
|
||||
* @param {IVendorOpeningBalanceEditDTO} openingBalanceEditDTO
|
||||
* @param {VendorOpeningBalanceEditDto} openingBalanceEditDTO
|
||||
* @returns {Promise<IVendor>}
|
||||
*/
|
||||
public async editOpeningBalance(
|
||||
vendorId: number,
|
||||
openingBalanceEditDTO: IVendorOpeningBalanceEditDTO,
|
||||
openingBalanceEditDTO: VendorOpeningBalanceEditDto,
|
||||
) {
|
||||
// Retrieves the old vendor or throw not found error.
|
||||
const oldVendor = await this.vendorModel()
|
||||
|
||||
@@ -2,11 +2,13 @@ import { ApiProperty } from '@nestjs/swagger';
|
||||
import {
|
||||
IsISO8601,
|
||||
IsInt,
|
||||
IsNotEmpty,
|
||||
IsNumber,
|
||||
Min,
|
||||
IsBoolean,
|
||||
IsEmail,
|
||||
IsString,
|
||||
ValidateIf,
|
||||
} from 'class-validator';
|
||||
import { ContactAddressDto } from '@/modules/Customers/dtos/ContactAddress.dto';
|
||||
import { IsOptional, ToNumber } from '@/common/decorators/Validators';
|
||||
@@ -30,8 +32,12 @@ export class CreateVendorDto extends ContactAddressDto {
|
||||
@ToNumber()
|
||||
openingBalanceExchangeRate?: number;
|
||||
|
||||
@ApiProperty({ required: false, description: 'Date of the opening balance' })
|
||||
@IsOptional()
|
||||
@ApiProperty({
|
||||
required: false,
|
||||
description: 'Date of the opening balance (required when openingBalance is provided)',
|
||||
})
|
||||
@ValidateIf((o) => o.openingBalance != null)
|
||||
@IsNotEmpty({ message: 'openingBalanceAt is required when openingBalance is provided' })
|
||||
@IsISO8601()
|
||||
openingBalanceAt?: Date;
|
||||
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
import { IsNotEmpty, IsNumber, IsString } from 'class-validator';
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsOptional, ToNumber } from '@/common/decorators/Validators';
|
||||
|
||||
export class VendorOpeningBalanceEditDto {
|
||||
@ApiProperty({
|
||||
required: true,
|
||||
description: 'Opening balance',
|
||||
example: 5000.0,
|
||||
})
|
||||
@IsNumber()
|
||||
@IsNotEmpty()
|
||||
@ToNumber()
|
||||
openingBalance: number;
|
||||
|
||||
@ApiProperty({
|
||||
required: false,
|
||||
description: 'Opening balance date',
|
||||
example: '2024-01-01',
|
||||
})
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
openingBalanceAt?: string;
|
||||
|
||||
@ApiProperty({
|
||||
required: false,
|
||||
description: 'Opening balance exchange rate',
|
||||
example: 1.0,
|
||||
})
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
@ToNumber()
|
||||
openingBalanceExchangeRate?: number;
|
||||
|
||||
@ApiProperty({
|
||||
required: false,
|
||||
description: 'Opening balance branch ID',
|
||||
example: 101,
|
||||
})
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
@ToNumber()
|
||||
openingBalanceBranchId?: number;
|
||||
}
|
||||
@@ -36,6 +36,7 @@ export class Vendor extends TenantBaseModel {
|
||||
openingBalance: number;
|
||||
openingBalanceExchangeRate: number;
|
||||
openingBalanceAt: Date | string;
|
||||
openingBalanceBranchId?: number;
|
||||
|
||||
salutation: string;
|
||||
firstName: string;
|
||||
|
||||
@@ -1,91 +1,71 @@
|
||||
// import { Inject, Service } from 'typedi';
|
||||
// import events from '@/subscribers/events';
|
||||
// import { VendorGLEntriesStorage } from '../VendorGLEntriesStorage';
|
||||
// import {
|
||||
// IVendorEventCreatedPayload,
|
||||
// IVendorEventDeletedPayload,
|
||||
// IVendorOpeningBalanceEditedPayload,
|
||||
// } from '@/interfaces';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { OnEvent } from '@nestjs/event-emitter';
|
||||
import { events } from '@/common/events/events';
|
||||
import { VendorGLEntriesStorage } from '../VendorGLEntriesStorage';
|
||||
import {
|
||||
IVendorEventCreatedPayload,
|
||||
IVendorEventDeletedPayload,
|
||||
IVendorOpeningBalanceEditedPayload,
|
||||
} from '../types/Vendors.types';
|
||||
|
||||
// @Service()
|
||||
// export class VendorsWriteGLOpeningSubscriber {
|
||||
// @Inject()
|
||||
// private vendorGLEntriesStorage: VendorGLEntriesStorage;
|
||||
@Injectable()
|
||||
export class VendorsWriteGLOpeningSubscriber {
|
||||
constructor(
|
||||
private readonly vendorGLEntriesStorage: VendorGLEntriesStorage,
|
||||
) {}
|
||||
|
||||
// /**
|
||||
// * Constructor method.
|
||||
// */
|
||||
// public attach(bus) {
|
||||
// bus.subscribe(
|
||||
// events.vendors.onCreated,
|
||||
// this.handleWriteOpeningBalanceEntries
|
||||
// );
|
||||
// bus.subscribe(
|
||||
// events.vendors.onDeleted,
|
||||
// this.handleRevertOpeningBalanceEntries
|
||||
// );
|
||||
// bus.subscribe(
|
||||
// events.vendors.onOpeningBalanceChanged,
|
||||
// this.handleRewriteOpeningEntriesOnChanged
|
||||
// );
|
||||
// }
|
||||
/**
|
||||
* Writes the open balance journal entries once the vendor created.
|
||||
* @param {IVendorEventCreatedPayload} payload -
|
||||
*/
|
||||
@OnEvent(events.vendors.onCreated)
|
||||
public async handleWriteOpeningBalanceEntries({
|
||||
vendor,
|
||||
trx,
|
||||
}: IVendorEventCreatedPayload) {
|
||||
// Writes the vendor opening balance journal entries.
|
||||
if (vendor.openingBalance) {
|
||||
await this.vendorGLEntriesStorage.writeVendorOpeningBalance(
|
||||
vendor.id,
|
||||
trx,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Writes the open balance journal entries once the vendor created.
|
||||
// * @param {IVendorEventCreatedPayload} payload -
|
||||
// */
|
||||
// private handleWriteOpeningBalanceEntries = async ({
|
||||
// tenantId,
|
||||
// vendor,
|
||||
// trx,
|
||||
// }: IVendorEventCreatedPayload) => {
|
||||
// // Writes the vendor opening balance journal entries.
|
||||
// if (vendor.openingBalance) {
|
||||
// await this.vendorGLEntriesStorage.writeVendorOpeningBalance(
|
||||
// tenantId,
|
||||
// vendor.id,
|
||||
// trx
|
||||
// );
|
||||
// }
|
||||
// };
|
||||
/**
|
||||
* Revert the opening balance journal entries once the vendor deleted.
|
||||
* @param {IVendorEventDeletedPayload} payload -
|
||||
*/
|
||||
@OnEvent(events.vendors.onDeleted)
|
||||
public async handleRevertOpeningBalanceEntries({
|
||||
vendorId,
|
||||
trx,
|
||||
}: IVendorEventDeletedPayload) {
|
||||
await this.vendorGLEntriesStorage.revertVendorOpeningBalance(
|
||||
vendorId,
|
||||
trx,
|
||||
);
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Revert the opening balance journal entries once the vendor deleted.
|
||||
// * @param {IVendorEventDeletedPayload} payload -
|
||||
// */
|
||||
// private handleRevertOpeningBalanceEntries = async ({
|
||||
// tenantId,
|
||||
// vendorId,
|
||||
// trx,
|
||||
// }: IVendorEventDeletedPayload) => {
|
||||
// await this.vendorGLEntriesStorage.revertVendorOpeningBalance(
|
||||
// tenantId,
|
||||
// vendorId,
|
||||
// trx
|
||||
// );
|
||||
// };
|
||||
|
||||
// /**
|
||||
// * Handles the rewrite opening balance entries once opening balnace changed.
|
||||
// * @param {ICustomerOpeningBalanceEditedPayload} payload -
|
||||
// */
|
||||
// private handleRewriteOpeningEntriesOnChanged = async ({
|
||||
// tenantId,
|
||||
// vendor,
|
||||
// trx,
|
||||
// }: IVendorOpeningBalanceEditedPayload) => {
|
||||
// if (vendor.openingBalance) {
|
||||
// await this.vendorGLEntriesStorage.rewriteVendorOpeningBalance(
|
||||
// tenantId,
|
||||
// vendor.id,
|
||||
// trx
|
||||
// );
|
||||
// } else {
|
||||
// await this.vendorGLEntriesStorage.revertVendorOpeningBalance(
|
||||
// tenantId,
|
||||
// vendor.id,
|
||||
// trx
|
||||
// );
|
||||
// }
|
||||
// };
|
||||
// }
|
||||
/**
|
||||
* Handles the rewrite opening balance entries once opening balance changed.
|
||||
* @param {IVendorOpeningBalanceEditedPayload} payload -
|
||||
*/
|
||||
@OnEvent(events.vendors.onOpeningBalanceChanged)
|
||||
public async handleRewriteOpeningEntriesOnChanged({
|
||||
vendor,
|
||||
trx,
|
||||
}: IVendorOpeningBalanceEditedPayload) {
|
||||
if (vendor.openingBalance) {
|
||||
await this.vendorGLEntriesStorage.rewriteVendorOpeningBalance(
|
||||
vendor.id,
|
||||
trx,
|
||||
);
|
||||
} else {
|
||||
await this.vendorGLEntriesStorage.revertVendorOpeningBalance(
|
||||
vendor.id,
|
||||
trx,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import { IDynamicListFilter } from '@/modules/DynamicListing/DynamicFilter/Dynam
|
||||
import { IFilterMeta, IPaginationMeta } from '@/interfaces/Model';
|
||||
import { CreateVendorDto } from '../dtos/CreateVendor.dto';
|
||||
import { EditVendorDto } from '../dtos/EditVendor.dto';
|
||||
import { VendorOpeningBalanceEditDto } from '../dtos/VendorOpeningBalanceEdit.dto';
|
||||
|
||||
// ----------------------------------
|
||||
export interface IVendorNewDTO extends IContactAddressDTO {
|
||||
@@ -92,23 +93,16 @@ export interface IVendorEventEditedPayload {
|
||||
trx?: Knex.Transaction;
|
||||
}
|
||||
|
||||
export interface IVendorOpeningBalanceEditDTO {
|
||||
openingBalance: number;
|
||||
openingBalanceAt: Date | string;
|
||||
openingBalanceExchangeRate: number;
|
||||
openingBalanceBranchId?: number;
|
||||
}
|
||||
|
||||
export interface IVendorOpeningBalanceEditingPayload {
|
||||
oldVendor: Vendor;
|
||||
openingBalanceEditDTO: IVendorOpeningBalanceEditDTO;
|
||||
openingBalanceEditDTO: VendorOpeningBalanceEditDto;
|
||||
trx?: Knex.Transaction;
|
||||
}
|
||||
|
||||
export interface IVendorOpeningBalanceEditedPayload {
|
||||
vendor: Vendor;
|
||||
oldVendor: Vendor;
|
||||
openingBalanceEditDTO: IVendorOpeningBalanceEditDTO;
|
||||
openingBalanceEditDTO: VendorOpeningBalanceEditDto;
|
||||
trx: Knex.Transaction;
|
||||
}
|
||||
|
||||
|
||||
@@ -229,7 +229,7 @@ describe('Sale Invoices (e2e)', () => {
|
||||
.send(requestSaleInvoiceBody());
|
||||
|
||||
return request(app.getHttpServer())
|
||||
.put(`/sale-invoices/${response.body.id}/mail`)
|
||||
.post(`/sale-invoices/${response.body.id}/mail`)
|
||||
.set('organization-id', orgainzationId)
|
||||
.set('Authorization', AuthorizationHeader)
|
||||
.send({
|
||||
|
||||
@@ -7,11 +7,12 @@
|
||||
"@bigcapital/pdf-templates": "*",
|
||||
"@bigcapital/utils": "*",
|
||||
"@blueprintjs-formik/core": "^0.3.7",
|
||||
"@blueprintjs-formik/datetime": "^0.3.7",
|
||||
"@blueprintjs-formik/datetime": "^0.4.0",
|
||||
"@blueprintjs-formik/select": "^0.3.5",
|
||||
"@blueprintjs/colors": "4.1.19",
|
||||
"@blueprintjs/core": "^4.20.2",
|
||||
"@blueprintjs/datetime": "^4.4.37",
|
||||
"@blueprintjs/datetime2": "^3.0.10",
|
||||
"@blueprintjs/popover2": "^1.14.11",
|
||||
"@blueprintjs/select": "^4.9.24",
|
||||
"@blueprintjs/table": "^4.10.12",
|
||||
@@ -77,7 +78,7 @@
|
||||
"plaid-threads": "^11.4.3",
|
||||
"polished": "^4.3.1",
|
||||
"prop-types": "15.8.1",
|
||||
"query-string": "^7.1.1",
|
||||
"qs": "^6.14.0",
|
||||
"ramda": "^0.27.1",
|
||||
"react": "^18.2.0",
|
||||
"react-body-classname": "^1.3.1",
|
||||
@@ -108,11 +109,11 @@
|
||||
"react-use": "^13.26.1",
|
||||
"react-use-context-menu": "^0.1.4",
|
||||
"react-virtualized": "^9.22.3",
|
||||
"regenerator-runtime": "^0.14.1",
|
||||
"redux": "^4.2.1",
|
||||
"redux-devtools": "^3.5.0",
|
||||
"redux-persist": "^6.0.0",
|
||||
"redux-thunk": "^2.4.2",
|
||||
"regenerator-runtime": "^0.14.1",
|
||||
"reselect": "4.1.7",
|
||||
"rtl-detect": "^1.0.3",
|
||||
"sass": "^1.68.0",
|
||||
@@ -126,8 +127,8 @@
|
||||
"yup": "^0.28.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-react": "^4.3.4",
|
||||
"@vitejs/plugin-legacy": "^5.4.2",
|
||||
"@vitejs/plugin-react": "^4.3.4",
|
||||
"eslint-config-react-app": "^7.0.1",
|
||||
"vite": "^5.1.6"
|
||||
},
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// @ts-nocheck
|
||||
import React from 'react';
|
||||
import {
|
||||
FormGroup,
|
||||
@@ -12,7 +11,7 @@ import {
|
||||
HTMLSelect,
|
||||
} from '@blueprintjs-formik/core';
|
||||
import { MultiSelect, SuggestField } from '@blueprintjs-formik/select';
|
||||
import { DateInput } from '@blueprintjs-formik/datetime';
|
||||
import { DateInput, TimezoneSelect } from '@blueprintjs-formik/datetime';
|
||||
import { FSelect } from './Select';
|
||||
|
||||
export {
|
||||
@@ -29,4 +28,5 @@ export {
|
||||
TextArea as FTextArea,
|
||||
DateInput as FDateInput,
|
||||
HTMLSelect as FHTMLSelect,
|
||||
TimezoneSelect as FTimezoneSelect,
|
||||
};
|
||||
|
||||
@@ -9,6 +9,7 @@ import UsersActions from '@/containers/Preferences/Users/UsersActions';
|
||||
import CurrenciesActions from '@/containers/Preferences/Currencies/CurrenciesActions';
|
||||
import WarehousesActions from '@/containers/Preferences/Warehouses/WarehousesActions';
|
||||
import BranchesActions from '@/containers/Preferences/Branches/BranchesActions';
|
||||
import ApiKeysActions from '@/containers/Preferences/ApiKeys/ApiKeysActions';
|
||||
import withDashboard from '@/containers/Dashboard/withDashboard';
|
||||
|
||||
import { compose } from '@/utils';
|
||||
@@ -48,6 +49,11 @@ function PreferencesTopbar({ preferencesPageTitle }) {
|
||||
path={'/preferences/branches'}
|
||||
component={BranchesActions}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path={'/preferences/api-keys'}
|
||||
component={ApiKeysActions}
|
||||
/>
|
||||
</Switch>
|
||||
</Route>
|
||||
</div>
|
||||
|
||||
@@ -28,10 +28,11 @@ export function StepperStep({
|
||||
isCompleted={state === StepperStepState.Completed}
|
||||
isActive={state === StepperStepState.Progress}
|
||||
>
|
||||
{state === StepperStepState.Completed && (
|
||||
{state === StepperStepState.Completed ? (
|
||||
<Icon icon={'done'} iconSize={24} />
|
||||
) : (
|
||||
<StepIconText>{step}</StepIconText>
|
||||
)}
|
||||
<StepIconText>{step}</StepIconText>
|
||||
</StepIcon>
|
||||
</StepIconWrap>
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ export const getDefaultAPAgingSummaryQuery = () => {
|
||||
filterByOption: 'without-zero-balance',
|
||||
vendorsIds: [],
|
||||
branchesIds: [],
|
||||
numberFormat: {},
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ export const getDefaultARAgingSummaryQuery = () => {
|
||||
filterByOption: 'without-zero-balance',
|
||||
customersIds: [],
|
||||
branchesIds: [],
|
||||
numberFormat: {},
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import { useBalanceSheetContext } from '../../BalanceSheetProvider';
|
||||
|
||||
export default function BalanceSheetPdfDialogContent() {
|
||||
const { httpQuery } = useBalanceSheetContext();
|
||||
const { isLoading, pdfUrl } = useBalanceSheetPdf({ ...httpQuery });
|
||||
const { isLoading, isLoaded, pdfUrl } = useBalanceSheetPdf({ ...httpQuery });
|
||||
|
||||
return (
|
||||
<DialogContent>
|
||||
@@ -18,8 +18,10 @@ export default function BalanceSheetPdfDialogContent() {
|
||||
<AnchorButton
|
||||
href={pdfUrl}
|
||||
target={'__blank'}
|
||||
minimal={true}
|
||||
outlined={true}
|
||||
disabled={!isLoaded}
|
||||
small
|
||||
minimal
|
||||
outlined
|
||||
>
|
||||
<T id={'pdf_preview.preview.button'} />
|
||||
</AnchorButton>
|
||||
@@ -27,8 +29,11 @@ export default function BalanceSheetPdfDialogContent() {
|
||||
<AnchorButton
|
||||
href={pdfUrl}
|
||||
download={'invoice.pdf'}
|
||||
minimal={true}
|
||||
outlined={true}
|
||||
|
||||
disabled={!isLoaded}
|
||||
small
|
||||
minimal
|
||||
outlined
|
||||
>
|
||||
<T id={'pdf_preview.download.button'} />
|
||||
</AnchorButton>
|
||||
|
||||
@@ -33,6 +33,7 @@ export const getDefaultBalanceSheetQuery = () => ({
|
||||
percentageOfRow: false,
|
||||
|
||||
branchesIds: [],
|
||||
numberFormat: {},
|
||||
});
|
||||
|
||||
/**
|
||||
|
||||
@@ -17,6 +17,7 @@ export const getDefaultCashFlowSheetQuery = () => {
|
||||
displayColumnsType: 'total',
|
||||
filterByOption: 'with-transactions',
|
||||
branchesIds: [],
|
||||
numberFormat: {},
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ export const getInventoryItemDetailsDefaultQuery = () => ({
|
||||
itemsIds: [],
|
||||
warehousesIds: [],
|
||||
branchesIds: [],
|
||||
numberFormat: {},
|
||||
});
|
||||
|
||||
/**
|
||||
|
||||
@@ -35,6 +35,7 @@ export const getDefaultProfitLossQuery = () => ({
|
||||
percentageExpense: false,
|
||||
|
||||
branchesIds: [],
|
||||
numberFormat: {},
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -50,7 +51,6 @@ const parseProfitLossQuery = (locationQuery) => {
|
||||
|
||||
return {
|
||||
...transformed,
|
||||
|
||||
// Ensures the branches ids is always array.
|
||||
branchesIds: castArray(transformed.branchesIds),
|
||||
};
|
||||
|
||||
@@ -17,6 +17,7 @@ export function getDefaultTrialBalanceQuery() {
|
||||
basis: 'accrual',
|
||||
filterByOption: 'with-transactions',
|
||||
branchesIds: [],
|
||||
numberFormat: {},
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -42,7 +42,6 @@ export const transformAccountsFilter = (form) => {
|
||||
*/
|
||||
export const transformFilterFormToQuery = (form) => {
|
||||
return R.compose(
|
||||
R.curry(flatten)({ safe: true }),
|
||||
transfromToSnakeCase,
|
||||
transformAccountsFilter,
|
||||
transformDisplayColumnsType,
|
||||
|
||||
@@ -69,7 +69,7 @@ function GlobalErrors({
|
||||
if (globalErrors.transactionsLocked) {
|
||||
AppToaster.show({
|
||||
message: intl.get('global_error.transactions_locked', {
|
||||
lockedToDate: globalErrors.transactionsLocked.formatted_locked_to_date,
|
||||
lockedToDate: globalErrors.transactionsLocked.formattedLockedToDate,
|
||||
}),
|
||||
intent: Intent.DANGER,
|
||||
onDismiss: () => {
|
||||
|
||||
@@ -23,6 +23,8 @@ export function PaymentInvoicePreviewContent() {
|
||||
termsConditions={sharableLinkMeta?.termsConditions}
|
||||
statement={sharableLinkMeta?.invoiceMessage}
|
||||
companyName={sharableLinkMeta?.companyName}
|
||||
primaryColor={sharableLinkMeta?.brandingTemplate?.primaryColor}
|
||||
secondaryColor={sharableLinkMeta?.brandingTemplate?.secondaryColor}
|
||||
lines={sharableLinkMeta?.entries?.map((entry) => ({
|
||||
item: entry.itemName,
|
||||
description: entry.description,
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
// @ts-nocheck
|
||||
import React from 'react';
|
||||
import { Button, Intent } from '@blueprintjs/core';
|
||||
import { x } from '@xstyled/emotion';
|
||||
import { css } from '@emotion/css';
|
||||
import { useIsDarkMode } from '@/hooks/useDarkMode';
|
||||
|
||||
import WorkflowIcon from './WorkflowIcon';
|
||||
import { FormattedMessage as T } from '@/components';
|
||||
@@ -8,13 +11,12 @@ import { FormattedMessage as T } from '@/components';
|
||||
import withOrganizationActions from '@/containers/Organization/withOrganizationActions';
|
||||
import { compose } from '@/utils';
|
||||
|
||||
import '@/style/pages/Setup/Congrats.scss';
|
||||
|
||||
/**
|
||||
* Setup congrats page.
|
||||
*/
|
||||
function SetupCongratsPage({ setOrganizationSetupCompleted }) {
|
||||
const [isReloading, setIsReloading] = React.useState(false);
|
||||
const isDarkMode = useIsDarkMode();
|
||||
|
||||
const handleBtnClick = () => {
|
||||
setIsReloading(true);
|
||||
@@ -22,30 +24,55 @@ function SetupCongratsPage({ setOrganizationSetupCompleted }) {
|
||||
};
|
||||
|
||||
return (
|
||||
<div class="setup-congrats">
|
||||
<div class="setup-congrats__workflow-pic">
|
||||
<x.div
|
||||
w={'500px'}
|
||||
mx="auto"
|
||||
textAlign="center"
|
||||
pt={'80px'}
|
||||
>
|
||||
<x.div>
|
||||
<WorkflowIcon width="280" height="330" />
|
||||
</div>
|
||||
</x.div>
|
||||
|
||||
<div class="setup-congrats__text">
|
||||
<h1>
|
||||
<T id={'setup.congrats.title'} />
|
||||
</h1>
|
||||
|
||||
<p class="paragraph">
|
||||
<T id={'setup.congrats.description'} />
|
||||
</p>
|
||||
|
||||
<Button
|
||||
intent={Intent.PRIMARY}
|
||||
type="submit"
|
||||
loading={isReloading}
|
||||
onClick={handleBtnClick}
|
||||
<x.div mt={30}>
|
||||
<x.h2
|
||||
color={isDarkMode ? 'rgba(255, 255, 255, 0.85)' : '#2d2b43'}
|
||||
mb={'12px'}
|
||||
>
|
||||
<T id={'setup.congrats.go_to_dashboard'} />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<T id={'setup.congrats.title'} />
|
||||
</x.h2>
|
||||
|
||||
<x.p
|
||||
fontSize={'16px'}
|
||||
opacity={0.85}
|
||||
mb={'14px'}
|
||||
color={isDarkMode ? 'rgba(255, 255, 255, 0.7)' : undefined}
|
||||
>
|
||||
<T id={'setup.congrats.description'} />
|
||||
</x.p>
|
||||
|
||||
<x.div
|
||||
className={css`
|
||||
.bp4-button {
|
||||
height: 38px;
|
||||
padding-left: 25px;
|
||||
padding-right: 25px;
|
||||
font-size: 15px;
|
||||
margin-top: 12px;
|
||||
}
|
||||
`}
|
||||
>
|
||||
<Button
|
||||
intent={Intent.PRIMARY}
|
||||
type="submit"
|
||||
loading={isReloading}
|
||||
onClick={handleBtnClick}
|
||||
>
|
||||
<T id={'setup.congrats.go_to_dashboard'} />
|
||||
</Button>
|
||||
</x.div>
|
||||
</x.div>
|
||||
</x.div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user