diff --git a/packages/server-nest/src/modules/App/App.module.ts b/packages/server-nest/src/modules/App/App.module.ts index 06f34f83e..9fd739684 100644 --- a/packages/server-nest/src/modules/App/App.module.ts +++ b/packages/server-nest/src/modules/App/App.module.ts @@ -37,13 +37,15 @@ import { TaxRatesModule } from '../TaxRates/TaxRate.module'; import { PdfTemplatesModule } from '../PdfTemplate/PdfTemplates.module'; import { BranchesModule } from '../Branches/Branches.module'; import { WarehousesModule } from '../Warehouses/Warehouses.module'; -import { SaleEstimatesModule } from '../SaleEstimates/SaleEstimates.module'; import { SerializeInterceptor } from '@/common/interceptors/serialize.interceptor'; import { ChromiumlyTenancyModule } from '../ChromiumlyTenancy/ChromiumlyTenancy.module'; import { CustomersModule } from '../Customers/Customers.module'; import { VendorsModule } from '../Vendors/Vendors.module'; +import { SaleEstimatesModule } from '../SaleEstimates/SaleEstimates.module'; import { BillsModule } from '../Bills/Bills.module'; -import { BillPaymentsModule } from '../BillPayments/BillPayments.module'; +import { SaleInvoicesModule } from '../SaleInvoices/SaleInvoices.module'; +import { SaleReceiptsModule } from '../SaleReceipts/SaleReceipts.module'; +// import { BillPaymentsModule } from '../BillPayments/BillPayments.module'; @Module({ imports: [ @@ -109,9 +111,11 @@ import { BillPaymentsModule } from '../BillPayments/BillPayments.module'; WarehousesModule, CustomersModule, VendorsModule, + SaleInvoicesModule, SaleEstimatesModule, + SaleReceiptsModule, BillsModule, - BillPaymentsModule, + // BillPaymentsModule, ], controllers: [AppController], providers: [ diff --git a/packages/server-nest/src/modules/AutoIncrementOrders/AutoIncrementOrders.module.ts b/packages/server-nest/src/modules/AutoIncrementOrders/AutoIncrementOrders.module.ts index 324c285b6..fb979df3f 100644 --- a/packages/server-nest/src/modules/AutoIncrementOrders/AutoIncrementOrders.module.ts +++ b/packages/server-nest/src/modules/AutoIncrementOrders/AutoIncrementOrders.module.ts @@ -6,7 +6,7 @@ import { AutoIncrementOrdersService } from './AutoIncrementOrders.service'; @Module({ imports: [TenancyDatabaseModule], controllers: [], - providers: [AutoIncrementOrdersService, TransformerInjectable], + providers: [AutoIncrementOrdersService], exports: [AutoIncrementOrdersService], }) export class AutoIncrementOrdersModule {} diff --git a/packages/server-nest/src/modules/BillLandedCosts/BillLandedCosts.module.ts b/packages/server-nest/src/modules/BillLandedCosts/BillLandedCosts.module.ts new file mode 100644 index 000000000..67c95a8a7 --- /dev/null +++ b/packages/server-nest/src/modules/BillLandedCosts/BillLandedCosts.module.ts @@ -0,0 +1,8 @@ +import { Module } from '@nestjs/common'; +import { TransactionLandedCostEntriesService } from './TransactionLandedCostEntries.service'; + +@Module({ + providers: [TransactionLandedCostEntriesService], + exports: [TransactionLandedCostEntriesService], +}) +export class BillLandedCostsModule {} diff --git a/packages/server-nest/src/modules/BillLandedCosts/TransactionLandedCostEntries.service.ts b/packages/server-nest/src/modules/BillLandedCosts/TransactionLandedCostEntries.service.ts new file mode 100644 index 000000000..a78dbb1a0 --- /dev/null +++ b/packages/server-nest/src/modules/BillLandedCosts/TransactionLandedCostEntries.service.ts @@ -0,0 +1,75 @@ +import { Injectable } from '@nestjs/common'; +import { ServiceError } from '../Items/ServiceError'; +import { transformToMap } from '@/utils/transform-to-key'; +import { ICommonLandedCostEntry, ICommonLandedCostEntryDTO } from './types/BillLandedCosts.types'; + +const ERRORS = { + ENTRIES_ALLOCATED_COST_COULD_NOT_DELETED: + 'ENTRIES_ALLOCATED_COST_COULD_NOT_DELETED', + LOCATED_COST_ENTRIES_SHOULD_BIGGE_THAN_NEW_ENTRIES: + 'LOCATED_COST_ENTRIES_SHOULD_BIGGE_THAN_NEW_ENTRIES', +}; + +@Injectable() +export class TransactionLandedCostEntriesService { + /** + * Validates bill entries that has allocated landed cost amount not deleted. + * @param {ICommonLandedCostEntry[]} oldCommonEntries - + * @param {ICommonLandedCostEntryDTO[]} newBillEntries - + */ + public getLandedCostEntriesDeleted( + oldCommonEntries: ICommonLandedCostEntry[], + newCommonEntriesDTO: ICommonLandedCostEntryDTO[] + ): ICommonLandedCostEntry[] { + const newBillEntriesById = transformToMap(newCommonEntriesDTO, 'id'); + + return oldCommonEntries.filter((entry) => { + const newEntry = newBillEntriesById.get(entry.id); + + if (entry.allocatedCostAmount > 0 && typeof newEntry === 'undefined') { + return true; + } + return false; + }); + } + + /** + * Validates the bill entries that have located cost amount should not be deleted. + * @param {ICommonLandedCostEntry[]} oldCommonEntries - Old bill entries. + * @param {ICommonLandedCostEntryDTO[]} newBillEntries - New DTO bill entries. + */ + public validateLandedCostEntriesNotDeleted( + oldCommonEntries: ICommonLandedCostEntry[], + newCommonEntriesDTO: ICommonLandedCostEntryDTO[] + ): void { + const entriesDeleted = this.getLandedCostEntriesDeleted( + oldCommonEntries, + newCommonEntriesDTO + ); + if (entriesDeleted.length > 0) { + throw new ServiceError(ERRORS.ENTRIES_ALLOCATED_COST_COULD_NOT_DELETED); + } + } + + /** + * Validate allocated cost amount entries should be smaller than new entries amount. + * @param {ICommonLandedCostEntry[]} oldCommonEntries - Old bill entries. + * @param {ICommonLandedCostEntryDTO[]} newBillEntries - New DTO bill entries. + */ + public validateLocatedCostEntriesSmallerThanNewEntries( + oldCommonEntries: ICommonLandedCostEntry[], + newCommonEntriesDTO: ICommonLandedCostEntryDTO[] + ): void { + const oldBillEntriesById = transformToMap(oldCommonEntries, 'id'); + + newCommonEntriesDTO.forEach((entry) => { + const oldEntry = oldBillEntriesById.get(entry.id); + + if (oldEntry && oldEntry.allocatedCostAmount > entry.amount) { + throw new ServiceError( + ERRORS.LOCATED_COST_ENTRIES_SHOULD_BIGGE_THAN_NEW_ENTRIES + ); + } + }); + } +} diff --git a/packages/server-nest/src/modules/BillLandedCosts/models/BillLandedCost.ts b/packages/server-nest/src/modules/BillLandedCosts/models/BillLandedCost.ts index 07bfc2f44..7373d9ada 100644 --- a/packages/server-nest/src/modules/BillLandedCosts/models/BillLandedCost.ts +++ b/packages/server-nest/src/modules/BillLandedCosts/models/BillLandedCost.ts @@ -4,15 +4,15 @@ import { lowerCase } from 'lodash'; import { BaseModel } from '@/models/Model'; export class BillLandedCost extends BaseModel { - amount: number; - fromTransactionId: number; - fromTransactionType: string; - fromTransactionEntryId: number; - allocationMethod: string; - costAccountId: number; - description: string; - billId: number; - exchangeRate: number; + amount!: number; + fromTransactionId!: number; + fromTransactionType!: string; + fromTransactionEntryId!: number; + allocationMethod!: string; + costAccountId!: number; + description!: string; + billId!: number; + exchangeRate!: number; /** * Table name @@ -60,15 +60,19 @@ export class BillLandedCost extends BaseModel { * Relationship mapping. */ static get relationMappings() { - const BillLandedCostEntry = require('models/BillLandedCostEntry'); - const Bill = require('models/Bill'); - const ItemEntry = require('models/ItemEntry'); - const ExpenseCategory = require('models/ExpenseCategory'); + const { BillLandedCostEntry } = require('./BillLandedCostEntry'); + const { Bill } = require('../../Bills/models/Bill'); + const { + ItemEntry, + } = require('../../TransactionItemEntry/models/ItemEntry'); + const { + ExpenseCategory, + } = require('../../Expenses/models/ExpenseCategory.model'); return { bill: { relation: Model.BelongsToOneRelation, - modelClass: Bill.default, + modelClass: Bill, join: { from: 'bill_located_costs.billId', to: 'bills.id', @@ -76,7 +80,7 @@ export class BillLandedCost extends BaseModel { }, allocateEntries: { relation: Model.HasManyRelation, - modelClass: BillLandedCostEntry.default, + modelClass: BillLandedCostEntry, join: { from: 'bill_located_costs.id', to: 'bill_located_cost_entries.billLocatedCostId', @@ -84,7 +88,7 @@ export class BillLandedCost extends BaseModel { }, allocatedFromBillEntry: { relation: Model.BelongsToOneRelation, - modelClass: ItemEntry.default, + modelClass: ItemEntry, join: { from: 'bill_located_costs.fromTransactionEntryId', to: 'items_entries.id', @@ -92,7 +96,7 @@ export class BillLandedCost extends BaseModel { }, allocatedFromExpenseEntry: { relation: Model.BelongsToOneRelation, - modelClass: ExpenseCategory.default, + modelClass: ExpenseCategory, join: { from: 'bill_located_costs.fromTransactionEntryId', to: 'expense_transaction_categories.id', diff --git a/packages/server-nest/src/modules/BillLandedCosts/models/BillLandedCostEntry.ts b/packages/server-nest/src/modules/BillLandedCosts/models/BillLandedCostEntry.ts index 049bef1c5..02a4cf233 100644 --- a/packages/server-nest/src/modules/BillLandedCosts/models/BillLandedCostEntry.ts +++ b/packages/server-nest/src/modules/BillLandedCosts/models/BillLandedCostEntry.ts @@ -1,7 +1,11 @@ +import { BaseModel } from '@/models/Model'; import { Model } from 'objection'; -import TenantModel from 'models/TenantModel'; -export default class BillLandedCostEntry extends TenantModel { +export class BillLandedCostEntry extends BaseModel { + cost!: number; + entryId!: number; + billLocatedCostId!: number; + /** * Table name */ @@ -13,12 +17,14 @@ export default class BillLandedCostEntry extends TenantModel { * Relationship mapping. */ static get relationMappings() { - const ItemEntry = require('models/ItemEntry'); + const { + ItemEntry, + } = require('../../TransactionItemEntry/models/ItemEntry'); return { itemEntry: { relation: Model.BelongsToOneRelation, - modelClass: ItemEntry.default, + modelClass: ItemEntry, join: { from: 'bill_located_cost_entries.entryId', to: 'items_entries.id', diff --git a/packages/server-nest/src/modules/BillLandedCosts/types/BillLandedCosts.types.ts b/packages/server-nest/src/modules/BillLandedCosts/types/BillLandedCosts.types.ts new file mode 100644 index 000000000..912660a40 --- /dev/null +++ b/packages/server-nest/src/modules/BillLandedCosts/types/BillLandedCosts.types.ts @@ -0,0 +1,144 @@ +import { Knex } from 'knex'; +import { Bill } from '@/modules/Bills/models/Bill'; + +export interface ILandedCostItemDTO { + entryId: number; + cost: number; +} +export type ILandedCostType = 'Expense' | 'Bill'; + +export interface ILandedCostDTO { + transactionType: ILandedCostType; + transactionId: number; + transactionEntryId: number; + allocationMethod: string; + description: string; + items: ILandedCostItemDTO[]; +} + +export interface ILandedCostQueryDTO { + vendorId: number; + fromDate: Date; + toDate: Date; +} + +export interface IUnallocatedListCost { + costNumber: string; + costAmount: number; + unallocatedAmount: number; +} + +export interface ILandedCostTransactionsQueryDTO { + transactionType: string; + date: Date; +} + +export interface ILandedCostEntriesQueryDTO { + transactionType: string; + transactionId: number; +} + +export interface ILandedCostTransaction { + id: number; + name: string; + amount: number; + allocatedCostAmount: number; + unallocatedCostAmount: number; + currencyCode: string; + exchangeRate: number; + // formattedAllocatedCostAmount: string; + // formattedAmount: string; + // formattedUnallocatedCostAmount: string; + transactionType: string; + entries?: ILandedCostTransactionEntry[]; +} + +export interface ILandedCostTransactionEntry { + id: number; + name: string; + code: string; + amount: number; + unallocatedCostAmount: number; + allocatedCostAmount: number; + description: string; + costAccountId: number; +} + +export interface ILandedCostTransactionEntryDOJO + extends ILandedCostTransactionEntry { + formattedAmount: string; + formattedUnallocatedCostAmount: string; + formattedAllocatedCostAmount: string; +} +export interface ILandedCostTransactionDOJO extends ILandedCostTransaction { + formattedAmount: string; + formattedUnallocatedCostAmount: string; + formattedAllocatedCostAmount: string; +} + +interface ILandedCostEntry { + id: number; + landedCost?: boolean; +} + +export interface IBillLandedCostTransaction { + id: number; + fromTransactionId: number; + fromTransactionType: string; + fromTransactionEntryId: number; + + billId: number; + allocationMethod: string; + costAccountId: number; + description: string; + + amount: number; + localAmount?: number; + currencyCode: string; + exchangeRate: number; + + allocateEntries?: IBillLandedCostTransactionEntry[]; +} + +export interface IBillLandedCostTransactionEntry { + cost: number; + entryId: number; + billLocatedCostId: number; +} + +export interface IAllocatedLandedCostDeletedPayload { + tenantId: number; + oldBillLandedCost: IBillLandedCostTransaction; + billId: number; + trx: Knex.Transaction; +} + +export interface IAllocatedLandedCostCreatedPayload { + tenantId: number; + bill: Bill; + billLandedCostId: number; + billLandedCost: IBillLandedCostTransaction; + trx: Knex.Transaction; +} + +export interface IBillAssociatedLandedCostTransactions {} + + +interface ICommonEntry { + id?: number; + amount: number; +} + +export interface ICommonLandedCostEntry extends ICommonEntry { + landedCost: boolean; + allocatedCostAmount: number; +} + +interface ICommonEntryDTO { + id?: number; + amount: number; +} + +export interface ICommonLandedCostEntryDTO extends ICommonEntryDTO { + landedCost?: boolean; +} diff --git a/packages/server-nest/src/modules/BillPayments/BillPayments.module.ts b/packages/server-nest/src/modules/BillPayments/BillPayments.module.ts index 18cf55270..dfd502e7b 100644 --- a/packages/server-nest/src/modules/BillPayments/BillPayments.module.ts +++ b/packages/server-nest/src/modules/BillPayments/BillPayments.module.ts @@ -4,6 +4,13 @@ import { CreateBillPaymentService } from './commands/CreateBillPayment.service'; import { EditBillPayment } from './commands/EditBillPayment.service'; import { GetBillPayment } from './queries/GetBillPayment.service'; import { DeleteBillPayment } from './commands/DeleteBillPayment.service'; +import { BillPaymentBillSync } from './commands/BillPaymentBillSync.service'; +import { GetPaymentBills } from './queries/GetPaymentBills.service'; +import { BillPaymentValidators } from './commands/BillPaymentValidators.service'; +import { CommandBillPaymentDTOTransformer } from './commands/CommandBillPaymentDTOTransformer.service'; +import { TenancyContext } from '../Tenancy/TenancyContext.service'; +import { BranchTransactionDTOTransformer } from '../Branches/integrations/BranchTransactionDTOTransform'; +import { BranchesSettingsService } from '../Branches/BranchesSettings'; @Module({ providers: [ @@ -12,6 +19,13 @@ import { DeleteBillPayment } from './commands/DeleteBillPayment.service'; EditBillPayment, GetBillPayment, DeleteBillPayment, + BillPaymentBillSync, + GetPaymentBills, + BillPaymentValidators, + CommandBillPaymentDTOTransformer, + BranchTransactionDTOTransformer, + BranchesSettingsService, + TenancyContext ], controllers: [], }) diff --git a/packages/server-nest/src/modules/BillPayments/BillPaymentsApplication.service.ts b/packages/server-nest/src/modules/BillPayments/BillPaymentsApplication.service.ts index 2a21b9ce3..cf4159e8f 100644 --- a/packages/server-nest/src/modules/BillPayments/BillPaymentsApplication.service.ts +++ b/packages/server-nest/src/modules/BillPayments/BillPaymentsApplication.service.ts @@ -2,7 +2,7 @@ import { Injectable } from '@nestjs/common'; import { CreateBillPaymentService } from './commands/CreateBillPayment.service'; import { DeleteBillPayment } from './commands/DeleteBillPayment.service'; import { EditBillPayment } from './commands/EditBillPayment.service'; -import { GetBillPayments } from './GetBillPayments'; +// import { GetBillPayments } from './GetBillPayments'; import { GetBillPayment } from './queries/GetBillPayment.service'; import { GetPaymentBills } from './queries/GetPaymentBills.service'; import { IBillPaymentDTO } from './types/BillPayments.types'; @@ -17,7 +17,7 @@ export class BillPaymentsApplication { private createBillPaymentService: CreateBillPaymentService, private deleteBillPaymentService: DeleteBillPayment, private editBillPaymentService: EditBillPayment, - private getBillPaymentsService: GetBillPayments, + // private getBillPaymentsService: GetBillPayments, private getBillPaymentService: GetBillPayment, private getPaymentBillsService: GetPaymentBills, ) {} diff --git a/packages/server-nest/src/modules/BillPayments/GetBillPayments.ts b/packages/server-nest/src/modules/BillPayments/GetBillPayments.ts index 23a78dbcd..fea76eb64 100644 --- a/packages/server-nest/src/modules/BillPayments/GetBillPayments.ts +++ b/packages/server-nest/src/modules/BillPayments/GetBillPayments.ts @@ -1,75 +1,75 @@ -import { Inject, Service } from 'typedi'; -import * as R from 'ramda'; -import { - IBillPayment, - IBillPaymentsFilter, - IPaginationMeta, - IFilterMeta, -} from '@/interfaces'; -import { BillPaymentTransformer } from './queries/BillPaymentTransformer'; -import DynamicListingService from '@/services/DynamicListing/DynamicListService'; -import HasTenancyService from '@/services/Tenancy/TenancyService'; -import { TransformerInjectable } from '@/lib/Transformer/TransformerInjectable'; +// import { Inject, Service } from 'typedi'; +// import * as R from 'ramda'; +// import { +// IBillPayment, +// IBillPaymentsFilter, +// IPaginationMeta, +// IFilterMeta, +// } from '@/interfaces'; +// import { BillPaymentTransformer } from './queries/BillPaymentTransformer'; +// import DynamicListingService from '@/services/DynamicListing/DynamicListService'; +// import HasTenancyService from '@/services/Tenancy/TenancyService'; +// import { TransformerInjectable } from '@/lib/Transformer/TransformerInjectable'; -@Service() -export class GetBillPayments { - @Inject() - private tenancy: HasTenancyService; +// @Service() +// export class GetBillPayments { +// @Inject() +// private tenancy: HasTenancyService; - @Inject() - private dynamicListService: DynamicListingService; +// @Inject() +// private dynamicListService: DynamicListingService; - @Inject() - private transformer: TransformerInjectable; +// @Inject() +// private transformer: TransformerInjectable; - /** - * Retrieve bill payment paginted and filterable list. - * @param {number} tenantId - * @param {IBillPaymentsFilter} billPaymentsFilter - */ - public async getBillPayments( - tenantId: number, - filterDTO: IBillPaymentsFilter - ): Promise<{ - billPayments: IBillPayment[]; - pagination: IPaginationMeta; - filterMeta: IFilterMeta; - }> { - const { BillPayment } = this.tenancy.models(tenantId); +// /** +// * Retrieve bill payment paginted and filterable list. +// * @param {number} tenantId +// * @param {IBillPaymentsFilter} billPaymentsFilter +// */ +// public async getBillPayments( +// tenantId: number, +// filterDTO: IBillPaymentsFilter +// ): Promise<{ +// billPayments: IBillPayment[]; +// pagination: IPaginationMeta; +// filterMeta: IFilterMeta; +// }> { +// const { BillPayment } = this.tenancy.models(tenantId); - // Parses filter DTO. - const filter = this.parseListFilterDTO(filterDTO); +// // Parses filter DTO. +// const filter = this.parseListFilterDTO(filterDTO); - // Dynamic list service. - const dynamicList = await this.dynamicListService.dynamicList( - tenantId, - BillPayment, - filter - ); - const { results, pagination } = await BillPayment.query() - .onBuild((builder) => { - builder.withGraphFetched('vendor'); - builder.withGraphFetched('paymentAccount'); +// // Dynamic list service. +// const dynamicList = await this.dynamicListService.dynamicList( +// tenantId, +// BillPayment, +// filter +// ); +// const { results, pagination } = await BillPayment.query() +// .onBuild((builder) => { +// builder.withGraphFetched('vendor'); +// builder.withGraphFetched('paymentAccount'); - dynamicList.buildQuery()(builder); - filter?.filterQuery && filter?.filterQuery(builder); - }) - .pagination(filter.page - 1, filter.pageSize); +// dynamicList.buildQuery()(builder); +// filter?.filterQuery && filter?.filterQuery(builder); +// }) +// .pagination(filter.page - 1, filter.pageSize); - // Transformes the bill payments models to POJO. - const billPayments = await this.transformer.transform( - tenantId, - results, - new BillPaymentTransformer() - ); - return { - billPayments, - pagination, - filterMeta: dynamicList.getResponseMeta(), - }; - } +// // Transformes the bill payments models to POJO. +// const billPayments = await this.transformer.transform( +// tenantId, +// results, +// new BillPaymentTransformer() +// ); +// return { +// billPayments, +// pagination, +// filterMeta: dynamicList.getResponseMeta(), +// }; +// } - private parseListFilterDTO(filterDTO) { - return R.compose(this.dynamicListService.parseStringifiedFilter)(filterDTO); - } -} +// private parseListFilterDTO(filterDTO) { +// return R.compose(this.dynamicListService.parseStringifiedFilter)(filterDTO); +// } +// } diff --git a/packages/server-nest/src/modules/BillPayments/commands/BillPaymentBillSync.service.ts b/packages/server-nest/src/modules/BillPayments/commands/BillPaymentBillSync.service.ts index 49e990550..3e0f3e1d2 100644 --- a/packages/server-nest/src/modules/BillPayments/commands/BillPaymentBillSync.service.ts +++ b/packages/server-nest/src/modules/BillPayments/commands/BillPaymentBillSync.service.ts @@ -1,11 +1,16 @@ -import { Injectable } from '@nestjs/common'; +import { Inject, Injectable } from '@nestjs/common'; import { Knex } from 'knex'; import { Bill } from '../../Bills/models/Bill'; import { IBillPaymentEntryDTO } from '../types/BillPayments.types'; +import { entriesAmountDiff } from '@/utils/entries-amount-diff'; +import Objection from 'objection'; @Injectable() export class BillPaymentBillSync { - constructor(private readonly bill: typeof Bill) {} + constructor( + @Inject(Bill.name) + private readonly bill: typeof Bill + ) {} /** * Saves bills payment amount changes different. @@ -18,7 +23,7 @@ export class BillPaymentBillSync { oldPaymentMadeEntries?: IBillPaymentEntryDTO[], trx?: Knex.Transaction, ): Promise { - const opers: Promise[] = []; + const opers: Objection.QueryBuilder[] = []; const diffEntries = entriesAmountDiff( paymentMadeEntries, diff --git a/packages/server-nest/src/modules/BillPayments/commands/BillPaymentsPages.service.ts b/packages/server-nest/src/modules/BillPayments/commands/BillPaymentsPages.service.ts index 2bf45bc5a..2b41fb013 100644 --- a/packages/server-nest/src/modules/BillPayments/commands/BillPaymentsPages.service.ts +++ b/packages/server-nest/src/modules/BillPayments/commands/BillPaymentsPages.service.ts @@ -1,7 +1,6 @@ -import { Inject, Service } from 'typedi'; import { omit } from 'lodash'; import { ERRORS } from '../constants'; -import { Injectable } from '@nestjs/common'; +import { Inject, Injectable } from '@nestjs/common'; import { Bill } from '../../Bills/models/Bill'; import { BillPayment } from '../models/BillPayment'; import { IBillReceivePageEntry } from '../types/BillPayments.types'; diff --git a/packages/server-nest/src/modules/BillPayments/commands/CreateBillPayment.service.ts b/packages/server-nest/src/modules/BillPayments/commands/CreateBillPayment.service.ts index eff867c11..eb9f01a6e 100644 --- a/packages/server-nest/src/modules/BillPayments/commands/CreateBillPayment.service.ts +++ b/packages/server-nest/src/modules/BillPayments/commands/CreateBillPayment.service.ts @@ -58,7 +58,7 @@ export class CreateBillPaymentService { public async createBillPayment( billPaymentDTO: IBillPaymentDTO, trx?: Knex.Transaction, - ): Promise { + ): Promise { const tenantMeta = await this.tenancyContext.getTenant(true); // Retrieves the payment vendor or throw not found error. diff --git a/packages/server-nest/src/modules/BillPayments/models/BillPayment.ts b/packages/server-nest/src/modules/BillPayments/models/BillPayment.ts index dab8d8f16..db27dd530 100644 --- a/packages/server-nest/src/modules/BillPayments/models/BillPayment.ts +++ b/packages/server-nest/src/modules/BillPayments/models/BillPayment.ts @@ -6,6 +6,9 @@ import { Model, mixin } from 'objection'; // import { DEFAULT_VIEWS } from '@/services/Sales/PaymentReceived/constants'; // import ModelSearchable from './ModelSearchable'; import { BaseModel } from '@/models/Model'; +import { BillPaymentEntry } from './BillPaymentEntry'; +import { Vendor } from '@/modules/Vendors/models/Vendor'; +import { Document } from '@/modules/ChromiumlyTenancy/models/Document'; export class BillPayment extends BaseModel{ vendorId: number; @@ -23,6 +26,12 @@ export class BillPayment extends BaseModel{ createdAt?: Date; updatedAt?: Date; + branchId?: number; + + entries?: BillPaymentEntry[]; + vendor?: Vendor; + attachments?: Document[]; + /** * Table name */ diff --git a/packages/server-nest/src/modules/BillPayments/models/BillPaymentEntry.ts b/packages/server-nest/src/modules/BillPayments/models/BillPaymentEntry.ts index f586990a5..3f3cfd1ae 100644 --- a/packages/server-nest/src/modules/BillPayments/models/BillPaymentEntry.ts +++ b/packages/server-nest/src/modules/BillPayments/models/BillPaymentEntry.ts @@ -1,6 +1,8 @@ import { Model } from 'objection'; // import TenantModel from 'models/TenantModel'; import { BaseModel } from '@/models/Model'; +import { Bill } from '@/modules/Bills/models/Bill'; +import { BillPayment } from './BillPayment'; export class BillPaymentEntry extends BaseModel { public billPaymentId: number; @@ -8,6 +10,9 @@ export class BillPaymentEntry extends BaseModel { public paymentAmount: number; public index: number; + bill?: Bill; + payment?: BillPayment; + /** * Table name */ @@ -32,7 +37,7 @@ export class BillPaymentEntry extends BaseModel { return { payment: { relation: Model.BelongsToOneRelation, - modelClass: BillPayment.default, + modelClass: BillPayment, join: { from: 'bills_payments_entries.billPaymentId', to: 'bills_payments.id', @@ -40,7 +45,7 @@ export class BillPaymentEntry extends BaseModel { }, bill: { relation: Model.BelongsToOneRelation, - modelClass: Bill.default, + modelClass: Bill, join: { from: 'bills_payments_entries.billId', to: 'bills.id', diff --git a/packages/server-nest/src/modules/BillPayments/types/BillPayments.types.ts b/packages/server-nest/src/modules/BillPayments/types/BillPayments.types.ts index 6b706a647..a5fccc643 100644 --- a/packages/server-nest/src/modules/BillPayments/types/BillPayments.types.ts +++ b/packages/server-nest/src/modules/BillPayments/types/BillPayments.types.ts @@ -1,15 +1,14 @@ import { Knex } from 'knex'; -import { IBill } from './Bill'; -import { AttachmentLinkDTO } from './Attachments'; +import { Bill } from '@/modules/Bills/models/Bill'; import { BillPayment } from '../models/BillPayment'; +import { AttachmentLinkDTO } from '@/modules/Attachments/Attachments.types'; export interface IBillPaymentEntry { id?: number; billPaymentId: number; billId: number; paymentAmount: number; - - bill?: IBill; + bill?: Bill; } export interface IBillPayment { @@ -39,6 +38,7 @@ export interface IBillPaymentEntryDTO { export interface IBillPaymentDTO { vendorId: number; + amount: number; paymentAccountId: number; paymentNumber?: string; paymentDate: Date; @@ -96,7 +96,7 @@ export interface IBillPaymentEventEditedPayload { } export interface IBillPaymentEventDeletedPayload { - // tenantId: number; + // tenantId: number; billPaymentId: number; oldBillPayment: BillPayment; trx: Knex.Transaction; diff --git a/packages/server-nest/src/modules/Bills/Bills.application.ts b/packages/server-nest/src/modules/Bills/Bills.application.ts index eb9693161..3272309f3 100644 --- a/packages/server-nest/src/modules/Bills/Bills.application.ts +++ b/packages/server-nest/src/modules/Bills/Bills.application.ts @@ -23,7 +23,7 @@ export class BillsApplication { private deleteBillService: DeleteBill, private getDueBillsService: GetDueBills, private openBillService: OpenBillService, - private getBillPaymentsService: GetBillPayments, + // private getBillPaymentsService: GetBillPayments, ) {} /** @@ -99,7 +99,7 @@ export class BillsApplication { * @param {number} tenantId * @param {number} billId */ - public getBillPayments(billId: number) { - return this.getBillPaymentsService.getBillPayments(billId); - } + // public getBillPayments(billId: number) { + // return this.getBillPaymentsService.getBillPayments(billId); + // } } diff --git a/packages/server-nest/src/modules/Bills/Bills.controller.ts b/packages/server-nest/src/modules/Bills/Bills.controller.ts new file mode 100644 index 000000000..6c37a2fea --- /dev/null +++ b/packages/server-nest/src/modules/Bills/Bills.controller.ts @@ -0,0 +1,48 @@ +import { + Controller, + Post, + Body, + Put, + Param, + Delete, + Get, +} from '@nestjs/common'; +import { BillsApplication } from './Bills.application'; +import { IBillDTO, IBillEditDTO } from './Bills.types'; +import { PublicRoute } from '../Auth/Jwt.guard'; + +@Controller('bills') +@PublicRoute() +export class BillsController { + constructor(private billsApplication: BillsApplication) {} + + @Post() + createBill(@Body() billDTO: IBillDTO) { + return this.billsApplication.createBill(billDTO); + } + + @Put(':id') + editBill(@Param('id') billId: number, @Body() billDTO: IBillEditDTO) { + return this.billsApplication.editBill(billId, billDTO); + } + + @Delete(':id') + deleteBill(@Param('id') billId: number) { + return this.billsApplication.deleteBill(billId); + } + + @Get(':id') + getBill(@Param('id') billId: number) { + return this.billsApplication.getBill(billId); + } + + @Post(':id/open') + openBill(@Param('id') billId: number) { + return this.billsApplication.openBill(billId); + } + + @Get('due') + getDueBills(@Body('vendorId') vendorId?: number) { + return this.billsApplication.getDueBills(vendorId); + } +} diff --git a/packages/server-nest/src/modules/Bills/Bills.module.ts b/packages/server-nest/src/modules/Bills/Bills.module.ts index 1583d40ab..a55f49285 100644 --- a/packages/server-nest/src/modules/Bills/Bills.module.ts +++ b/packages/server-nest/src/modules/Bills/Bills.module.ts @@ -4,14 +4,40 @@ import { CreateBill } from './commands/CreateBill.service'; import { DeleteBill } from './commands/DeleteBill.service'; import { GetBill } from './queries/GetBill'; import { BillDTOTransformer } from './commands/BillDTOTransformer.service'; +import { EditBillService } from './commands/EditBill.service'; +import { GetDueBills } from './queries/GetDueBills.service'; +import { OpenBillService } from './commands/OpenBill.service'; +import { BillsValidators } from './commands/BillsValidators.service'; +import { ItemsEntriesService } from '../Items/ItemsEntries.service'; +import { BranchTransactionDTOTransformer } from '../Branches/integrations/BranchTransactionDTOTransform'; +import { BranchesSettingsService } from '../Branches/BranchesSettings'; +import { WarehouseTransactionDTOTransform } from '../Warehouses/Integrations/WarehouseTransactionDTOTransform'; +import { WarehousesSettings } from '../Warehouses/WarehousesSettings'; +import { ItemEntriesTaxTransactions } from '../TaxRates/ItemEntriesTaxTransactions.service'; +import { TenancyContext } from '../Tenancy/TenancyContext.service'; +import { BillsController } from './Bills.controller'; +import { BillLandedCostsModule } from '../BillLandedCosts/BillLandedCosts.module'; @Module({ + imports: [BillLandedCostsModule], providers: [ + TenancyContext, BillsApplication, + BranchTransactionDTOTransformer, + WarehouseTransactionDTOTransform, + WarehousesSettings, + ItemEntriesTaxTransactions, + BranchesSettingsService, CreateBill, + EditBillService, + GetDueBills, + OpenBillService, GetBill, DeleteBill, BillDTOTransformer, + BillsValidators, + ItemsEntriesService ], + controllers: [BillsController], }) export class BillsModule {} diff --git a/packages/server-nest/src/modules/Bills/Bills.types.ts b/packages/server-nest/src/modules/Bills/Bills.types.ts index 522976bac..56f0bab21 100644 --- a/packages/server-nest/src/modules/Bills/Bills.types.ts +++ b/packages/server-nest/src/modules/Bills/Bills.types.ts @@ -53,7 +53,7 @@ export interface IBillCreatedPayload { // tenantId: number; bill: Bill; billDTO: IBillDTO; - billId: number; + // billId: number; trx?: Knex.Transaction; } diff --git a/packages/server-nest/src/modules/Bills/commands/BillDTOTransformer.service.ts b/packages/server-nest/src/modules/Bills/commands/BillDTOTransformer.service.ts index fb04a9b53..260013310 100644 --- a/packages/server-nest/src/modules/Bills/commands/BillDTOTransformer.service.ts +++ b/packages/server-nest/src/modules/Bills/commands/BillDTOTransformer.service.ts @@ -1,16 +1,16 @@ +import { Inject, Injectable } from '@nestjs/common'; import { omit, sumBy } from 'lodash'; import moment from 'moment'; -import { Inject, Injectable } from '@nestjs/common'; import * as R from 'ramda'; +import * as composeAsync from 'async/compose'; import { formatDateFields } from '@/utils/format-date-fields'; -import composeAsync from 'async/compose'; import { BranchTransactionDTOTransformer } from '@/modules/Branches/integrations/BranchTransactionDTOTransform'; import { WarehouseTransactionDTOTransform } from '@/modules/Warehouses/Integrations/WarehouseTransactionDTOTransform'; import { ItemEntry } from '@/modules/Items/models/ItemEntry'; import { Item } from '@/modules/Items/models/Item'; +import { Vendor } from '@/modules/Vendors/models/Vendor'; import { ItemEntriesTaxTransactions } from '@/modules/TaxRates/ItemEntriesTaxTransactions.service'; import { IBillDTO } from '../Bills.types'; -import { Vendor } from '@/modules/Vendors/models/Vendor'; import { Bill } from '../models/Bill'; import { assocItemEntriesDefaultIndex } from '@/utils/associate-item-entries-index'; import { TenancyContext } from '@/modules/Tenancy/TenancyContext.service'; @@ -23,8 +23,8 @@ export class BillDTOTransformer { private taxDTOTransformer: ItemEntriesTaxTransactions, private tenancyContext: TenancyContext, - @Inject(ItemEntry) private itemEntryModel: typeof ItemEntry, - @Inject(Item) private itemModel: typeof Item, + @Inject(ItemEntry.name) private itemEntryModel: typeof ItemEntry, + @Inject(Item.name) private itemModel: typeof Item, ) {} /** @@ -44,7 +44,9 @@ export class BillDTOTransformer { private getBillLandedCostAmount(billDTO: IBillDTO): number { const costEntries = billDTO.entries.filter((entry) => entry.landedCost); - return this.getBillEntriesTotal(costEntries); + // return this.getBillEntriesTotal(costEntries); + + return 0; } /** @@ -57,7 +59,7 @@ export class BillDTOTransformer { billDTO: IBillDTO, vendor: Vendor, oldBill?: Bill, - ) { + ): Promise { const amount = sumBy(billDTO.entries, (e) => this.itemEntryModel.calcAmount(e), ); @@ -112,9 +114,9 @@ export class BillDTOTransformer { return R.compose( // Associates tax amount withheld to the model. this.taxDTOTransformer.assocTaxAmountWithheldFromEntries, - this.branchDTOTransform.transformDTO, - this.warehouseDTOTransform.transformDTO, - )(initialDTO); + this.branchDTOTransform.transformDTO, + this.warehouseDTOTransform.transformDTO, + )(initialDTO) as Bill; } /** diff --git a/packages/server-nest/src/modules/Bills/commands/BillsValidators.service.ts b/packages/server-nest/src/modules/Bills/commands/BillsValidators.service.ts index 50068bbef..f8a8ca6cf 100644 --- a/packages/server-nest/src/modules/Bills/commands/BillsValidators.service.ts +++ b/packages/server-nest/src/modules/Bills/commands/BillsValidators.service.ts @@ -6,6 +6,8 @@ import { IItemEntryDTO } from '@/modules/TransactionItemEntry/ItemEntry.types'; import { Item } from '@/modules/Items/models/Item'; import { BillPaymentEntry } from '@/modules/BillPayments/models/BillPaymentEntry'; import { BillLandedCost } from '@/modules/BillLandedCosts/models/BillLandedCost'; +import { VendorCreditAppliedBill } from '@/modules/VendorCredit/models/VendorCreditAppliedBill'; +import { transformToMap } from '@/utils/transform-to-key'; @Injectable() export class BillsValidators { diff --git a/packages/server-nest/src/modules/Bills/commands/CreateBill.service.ts b/packages/server-nest/src/modules/Bills/commands/CreateBill.service.ts index 0368f70e1..e92de344c 100644 --- a/packages/server-nest/src/modules/Bills/commands/CreateBill.service.ts +++ b/packages/server-nest/src/modules/Bills/commands/CreateBill.service.ts @@ -27,7 +27,7 @@ export class CreateBill { private billModel: typeof Bill, @Inject(Vendor.name) - private contactModel: typeof Vendor, + private vendorModel: typeof Vendor, ) {} /** @@ -49,9 +49,8 @@ export class CreateBill { trx?: Knex.Transaction, ): Promise { // Retrieves the given bill vendor or throw not found error. - const vendor = await this.contactModel + const vendor = await this.vendorModel .query() - .modify('vendor') .findById(billDTO.vendorId) .throwIfNotFound(); @@ -70,10 +69,7 @@ export class CreateBill { billDTO.entries, ); // Transform the bill DTO to model object. - const billObj = await this.transformerDTO.billDTOToModel( - billDTO, - vendor, - ); + const billObj = await this.transformerDTO.billDTOToModel(billDTO, vendor); // Write new bill transaction with associated transactions under UOW env. return this.uow.withTransaction(async (trx: Knex.Transaction) => { @@ -84,12 +80,11 @@ export class CreateBill { } as IBillCreatingPayload); // Inserts the bill graph object to the storage. - const bill = await this.billModel.query(trx).upsertGraph(billObj); + const bill = await this.billModel.query(trx).upsertGraphAndFetch(billObj); // Triggers `onBillCreated` event. await this.eventPublisher.emitAsync(events.bill.onCreated, { bill, - billId: bill.id, billDTO, trx, } as IBillCreatedPayload); diff --git a/packages/server-nest/src/modules/Bills/commands/DeleteBill.service.ts b/packages/server-nest/src/modules/Bills/commands/DeleteBill.service.ts index 7e21be56a..3297a6e8a 100644 --- a/packages/server-nest/src/modules/Bills/commands/DeleteBill.service.ts +++ b/packages/server-nest/src/modules/Bills/commands/DeleteBill.service.ts @@ -55,7 +55,7 @@ export class DeleteBill { } as IBillEventDeletingPayload); // Delete all associated bill entries. - await ItemEntry.query(trx) + await this.itemEntryModel.query(trx) .where('reference_type', 'Bill') .where('reference_id', billId) .delete(); diff --git a/packages/server-nest/src/modules/Bills/commands/EditBill.service.ts b/packages/server-nest/src/modules/Bills/commands/EditBill.service.ts index 74b22de0a..86ed34d8f 100644 --- a/packages/server-nest/src/modules/Bills/commands/EditBill.service.ts +++ b/packages/server-nest/src/modules/Bills/commands/EditBill.service.ts @@ -12,7 +12,8 @@ import { BillDTOTransformer } from './BillDTOTransformer.service'; import { Bill } from '../models/Bill'; import { events } from '@/common/events/events'; import { Vendor } from '@/modules/Vendors/models/Vendor'; - +import { Knex } from 'knex'; +import { TransactionLandedCostEntriesService } from '@/modules/BillLandedCosts/TransactionLandedCostEntries.service'; @Injectable() export class EditBillService { @@ -21,7 +22,7 @@ export class EditBillService { private itemsEntriesService: ItemsEntriesService, private uow: UnitOfWork, private eventPublisher: EventEmitter2, - private entriesService: ItemEntries, + private transactionLandedCostEntries: TransactionLandedCostEntriesService, private transformerDTO: BillDTOTransformer, @Inject(Bill.name) private billModel: typeof Bill, @Inject(Vendor.name) private contactModel: typeof Vendor, @@ -97,12 +98,12 @@ export class EditBillService { oldBill.paymentAmount ); // Validate landed cost entries that have allocated cost could not be deleted. - await this.entriesService.validateLandedCostEntriesNotDeleted( + await this.transactionLandedCostEntries.validateLandedCostEntriesNotDeleted( oldBill.entries, billObj.entries ); // Validate new landed cost entries should be bigger than new entries. - await this.entriesService.validateLocatedCostEntriesSmallerThanNewEntries( + await this.transactionLandedCostEntries.validateLocatedCostEntriesSmallerThanNewEntries( oldBill.entries, billObj.entries ); diff --git a/packages/server-nest/src/modules/Bills/models/Bill.ts b/packages/server-nest/src/modules/Bills/models/Bill.ts index 696c2dd3d..2c4b13d40 100644 --- a/packages/server-nest/src/modules/Bills/models/Bill.ts +++ b/packages/server-nest/src/modules/Bills/models/Bill.ts @@ -8,6 +8,7 @@ import moment from 'moment'; // import { DEFAULT_VIEWS } from '@/services/Purchases/Bills/constants'; // import ModelSearchable from './ModelSearchable'; import { BaseModel } from '@/models/Model'; +import { ItemEntry } from '@/modules/Items/models/ItemEntry'; export class Bill extends BaseModel{ public amount: number; @@ -31,9 +32,14 @@ export class Bill extends BaseModel{ public openedAt: Date | string; public userId: number; + public branchId: number; + public warehouseId: number; + public createdAt: Date; public updatedAt: Date | null; + public entries?: ItemEntry[]; + /** * Timestamps columns. */ @@ -410,125 +416,125 @@ export class Bill extends BaseModel{ /** * Relationship mapping. */ - static get relationMappings() { - const Vendor = require('models/Vendor'); - const ItemEntry = require('models/ItemEntry'); - const BillLandedCost = require('models/BillLandedCost'); - const Branch = require('models/Branch'); - const Warehouse = require('models/Warehouse'); - const TaxRateTransaction = require('models/TaxRateTransaction'); - const Document = require('models/Document'); - const { MatchedBankTransaction } = require('models/MatchedBankTransaction'); + // static get relationMappings() { + // const Vendor = require('models/Vendor'); + // const ItemEntry = require('models/ItemEntry'); + // const BillLandedCost = require('models/BillLandedCost'); + // const Branch = require('models/Branch'); + // const Warehouse = require('models/Warehouse'); + // const TaxRateTransaction = require('models/TaxRateTransaction'); + // const Document = require('models/Document'); + // const { MatchedBankTransaction } = require('models/MatchedBankTransaction'); - return { - vendor: { - relation: Model.BelongsToOneRelation, - modelClass: Vendor.default, - join: { - from: 'bills.vendorId', - to: 'contacts.id', - }, - filter(query) { - query.where('contact_service', 'vendor'); - }, - }, + // return { + // vendor: { + // relation: Model.BelongsToOneRelation, + // modelClass: Vendor.default, + // join: { + // from: 'bills.vendorId', + // to: 'contacts.id', + // }, + // filter(query) { + // query.where('contact_service', 'vendor'); + // }, + // }, - entries: { - relation: Model.HasManyRelation, - modelClass: ItemEntry.default, - join: { - from: 'bills.id', - to: 'items_entries.referenceId', - }, - filter(builder) { - builder.where('reference_type', 'Bill'); - builder.orderBy('index', 'ASC'); - }, - }, + // entries: { + // relation: Model.HasManyRelation, + // modelClass: ItemEntry.default, + // join: { + // from: 'bills.id', + // to: 'items_entries.referenceId', + // }, + // filter(builder) { + // builder.where('reference_type', 'Bill'); + // builder.orderBy('index', 'ASC'); + // }, + // }, - locatedLandedCosts: { - relation: Model.HasManyRelation, - modelClass: BillLandedCost.default, - join: { - from: 'bills.id', - to: 'bill_located_costs.billId', - }, - }, + // locatedLandedCosts: { + // relation: Model.HasManyRelation, + // modelClass: BillLandedCost.default, + // join: { + // from: 'bills.id', + // to: 'bill_located_costs.billId', + // }, + // }, - /** - * Bill may belongs to associated branch. - */ - branch: { - relation: Model.BelongsToOneRelation, - modelClass: Branch.default, - join: { - from: 'bills.branchId', - to: 'branches.id', - }, - }, + // /** + // * Bill may belongs to associated branch. + // */ + // branch: { + // relation: Model.BelongsToOneRelation, + // modelClass: Branch.default, + // join: { + // from: 'bills.branchId', + // to: 'branches.id', + // }, + // }, - /** - * Bill may has associated warehouse. - */ - warehouse: { - relation: Model.BelongsToOneRelation, - modelClass: Warehouse.default, - join: { - from: 'bills.warehouseId', - to: 'warehouses.id', - }, - }, + // /** + // * Bill may has associated warehouse. + // */ + // warehouse: { + // relation: Model.BelongsToOneRelation, + // modelClass: Warehouse.default, + // join: { + // from: 'bills.warehouseId', + // to: 'warehouses.id', + // }, + // }, - /** - * Bill may has associated tax rate transactions. - */ - taxes: { - relation: Model.HasManyRelation, - modelClass: TaxRateTransaction.default, - join: { - from: 'bills.id', - to: 'tax_rate_transactions.referenceId', - }, - filter(builder) { - builder.where('reference_type', 'Bill'); - }, - }, + // /** + // * Bill may has associated tax rate transactions. + // */ + // taxes: { + // relation: Model.HasManyRelation, + // modelClass: TaxRateTransaction.default, + // join: { + // from: 'bills.id', + // to: 'tax_rate_transactions.referenceId', + // }, + // filter(builder) { + // builder.where('reference_type', 'Bill'); + // }, + // }, - /** - * Bill may has many attached attachments. - */ - attachments: { - relation: Model.ManyToManyRelation, - modelClass: Document.default, - join: { - from: 'bills.id', - through: { - from: 'document_links.modelId', - to: 'document_links.documentId', - }, - to: 'documents.id', - }, - filter(query) { - query.where('model_ref', 'Bill'); - }, - }, + // /** + // * Bill may has many attached attachments. + // */ + // attachments: { + // relation: Model.ManyToManyRelation, + // modelClass: Document.default, + // join: { + // from: 'bills.id', + // through: { + // from: 'document_links.modelId', + // to: 'document_links.documentId', + // }, + // to: 'documents.id', + // }, + // filter(query) { + // query.where('model_ref', 'Bill'); + // }, + // }, - /** - * Bill may belongs to matched bank transaction. - */ - matchedBankTransaction: { - relation: Model.HasManyRelation, - modelClass: MatchedBankTransaction, - join: { - from: 'bills.id', - to: 'matched_bank_transactions.referenceId', - }, - filter(query) { - query.where('reference_type', 'Bill'); - }, - }, - }; - } + // /** + // * Bill may belongs to matched bank transaction. + // */ + // matchedBankTransaction: { + // relation: Model.HasManyRelation, + // modelClass: MatchedBankTransaction, + // join: { + // from: 'bills.id', + // to: 'matched_bank_transactions.referenceId', + // }, + // filter(query) { + // query.where('reference_type', 'Bill'); + // }, + // }, + // }; + // } /** * Retrieve the not found bills ids as array that associated to the given vendor. diff --git a/packages/server-nest/src/modules/Bills/queries/GetDueBills.service.ts b/packages/server-nest/src/modules/Bills/queries/GetDueBills.service.ts index 4a6825a5d..264c71a2b 100644 --- a/packages/server-nest/src/modules/Bills/queries/GetDueBills.service.ts +++ b/packages/server-nest/src/modules/Bills/queries/GetDueBills.service.ts @@ -1,9 +1,12 @@ -import { Injectable } from '@nestjs/common'; +import { Inject, Injectable } from '@nestjs/common'; import { Bill } from '../models/Bill'; @Injectable() export class GetDueBills { - constructor(private billModel: typeof Bill) {} + constructor( + @Inject(Bill.name) + private billModel: typeof Bill, + ) {} /** * Retrieve all due bills or for specific given vendor id. diff --git a/packages/server-nest/src/modules/Branches/Branches.module.ts b/packages/server-nest/src/modules/Branches/Branches.module.ts index 7f8b2fe0d..81dc1085a 100644 --- a/packages/server-nest/src/modules/Branches/Branches.module.ts +++ b/packages/server-nest/src/modules/Branches/Branches.module.ts @@ -13,6 +13,7 @@ import { ActivateBranches } from './commands/ActivateBranchesFeature.service'; import { BranchesApplication } from './BranchesApplication.service'; import { BranchesSettingsService } from './BranchesSettings'; import { BranchCommandValidator } from './commands/BranchCommandValidator.service'; +import { BranchTransactionDTOTransformer } from './integrations/BranchTransactionDTOTransform'; @Module({ imports: [TenancyDatabaseModule], @@ -29,7 +30,9 @@ import { BranchCommandValidator } from './commands/BranchCommandValidator.servic BranchesSettingsService, TenancyContext, TransformerInjectable, - BranchCommandValidator + BranchCommandValidator, + BranchTransactionDTOTransformer ], + exports: [BranchTransactionDTOTransformer], }) export class BranchesModule {} diff --git a/packages/server-nest/src/modules/ChromiumlyTenancy/ChromiumlyTenancy.module.ts b/packages/server-nest/src/modules/ChromiumlyTenancy/ChromiumlyTenancy.module.ts index 64e10cf3e..57ea678ba 100644 --- a/packages/server-nest/src/modules/ChromiumlyTenancy/ChromiumlyTenancy.module.ts +++ b/packages/server-nest/src/modules/ChromiumlyTenancy/ChromiumlyTenancy.module.ts @@ -4,5 +4,6 @@ import { ChromiumlyTenancy } from './ChromiumlyTenancy.service'; @Module({ providers: [ChromiumlyHtmlConvert, ChromiumlyTenancy], + exports: [ChromiumlyHtmlConvert, ChromiumlyTenancy], }) export class ChromiumlyTenancyModule {} diff --git a/packages/server-nest/src/modules/CreditNotes/models/CreditNote.ts b/packages/server-nest/src/modules/CreditNotes/models/CreditNote.ts index db3d0daa7..29bc5f97e 100644 --- a/packages/server-nest/src/modules/CreditNotes/models/CreditNote.ts +++ b/packages/server-nest/src/modules/CreditNotes/models/CreditNote.ts @@ -181,12 +181,12 @@ export class CreditNote extends BaseModel { * Relationship mapping. */ static get relationMappings() { - const AccountTransaction = require('models/AccountTransaction'); - const ItemEntry = require('models/ItemEntry'); - const Customer = require('models/Customer'); - const Branch = require('models/Branch'); - const Document = require('models/Document'); - const Warehouse = require('models/Warehouse'); + const { AccountTransaction } = require('../../Accounts/models/AccountTransaction.model'); + const { ItemEntry } = require('../../TransactionItemEntry/models/ItemEntry'); + const { Customer } = require('../../Customers/models/Customer'); + const { Branch } = require('../../Branches/models/Branch.model'); + const { Document } = require('../../ChromiumlyTenancy/models/Document'); + const { Warehouse } = require('../../Warehouses/models/Warehouse.model'); return { /** @@ -194,7 +194,7 @@ export class CreditNote extends BaseModel { */ entries: { relation: Model.HasManyRelation, - modelClass: ItemEntry.default, + modelClass: ItemEntry, join: { from: 'credit_notes.id', to: 'items_entries.referenceId', @@ -210,7 +210,7 @@ export class CreditNote extends BaseModel { */ customer: { relation: Model.BelongsToOneRelation, - modelClass: Customer.default, + modelClass: Customer, join: { from: 'credit_notes.customerId', to: 'contacts.id', @@ -225,7 +225,7 @@ export class CreditNote extends BaseModel { */ transactions: { relation: Model.HasManyRelation, - modelClass: AccountTransaction.default, + modelClass: AccountTransaction, join: { from: 'credit_notes.id', to: 'accounts_transactions.referenceId', @@ -240,7 +240,7 @@ export class CreditNote extends BaseModel { */ branch: { relation: Model.BelongsToOneRelation, - modelClass: Branch.default, + modelClass: Branch, join: { from: 'credit_notes.branchId', to: 'branches.id', @@ -252,7 +252,7 @@ export class CreditNote extends BaseModel { */ warehouse: { relation: Model.BelongsToOneRelation, - modelClass: Warehouse.default, + modelClass: Warehouse, join: { from: 'credit_notes.warehouseId', to: 'warehouses.id', @@ -264,7 +264,7 @@ export class CreditNote extends BaseModel { */ attachments: { relation: Model.ManyToManyRelation, - modelClass: Document.default, + modelClass: Document, join: { from: 'credit_notes.id', through: { diff --git a/packages/server-nest/src/modules/CreditNotes/models/CreditNoteAppliedInvoice.ts b/packages/server-nest/src/modules/CreditNotes/models/CreditNoteAppliedInvoice.ts index f302bcedb..74b8517a0 100644 --- a/packages/server-nest/src/modules/CreditNotes/models/CreditNoteAppliedInvoice.ts +++ b/packages/server-nest/src/modules/CreditNotes/models/CreditNoteAppliedInvoice.ts @@ -24,13 +24,13 @@ export class CreditNoteAppliedInvoice extends BaseModel { * Relationship mapping. */ static get relationMappings() { - const SaleInvoice = require('models/SaleInvoice'); - const CreditNote = require('models/CreditNote'); + const { SaleInvoice } = require('../../SaleInvoices/models/SaleInvoice'); + const { CreditNote } = require('../../CreditNotes/models/CreditNote'); return { saleInvoice: { relation: Model.BelongsToOneRelation, - modelClass: SaleInvoice.default, + modelClass: SaleInvoice, join: { from: 'credit_note_applied_invoice.invoiceId', to: 'sales_invoices.id', @@ -39,7 +39,7 @@ export class CreditNoteAppliedInvoice extends BaseModel { creditNote: { relation: Model.BelongsToOneRelation, - modelClass: CreditNote.default, + modelClass: CreditNote, join: { from: 'credit_note_applied_invoice.creditNoteId', to: 'credit_notes.id', diff --git a/packages/server-nest/src/modules/Customers/Customers.controller.ts b/packages/server-nest/src/modules/Customers/Customers.controller.ts index b26d9a206..32ce6c376 100644 --- a/packages/server-nest/src/modules/Customers/Customers.controller.ts +++ b/packages/server-nest/src/modules/Customers/Customers.controller.ts @@ -13,8 +13,10 @@ import { ICustomerNewDTO, ICustomerOpeningBalanceEditDTO, } from './types/Customers.types'; +import { PublicRoute } from '../Auth/Jwt.guard'; @Controller('customers') +@PublicRoute() export class CustomersController { constructor(private customersApplication: CustomersApplication) {} diff --git a/packages/server-nest/src/modules/Customers/commands/DeleteCustomer.service.ts b/packages/server-nest/src/modules/Customers/commands/DeleteCustomer.service.ts index eea015cab..623bbc474 100644 --- a/packages/server-nest/src/modules/Customers/commands/DeleteCustomer.service.ts +++ b/packages/server-nest/src/modules/Customers/commands/DeleteCustomer.service.ts @@ -19,7 +19,7 @@ export class DeleteCustomer { constructor( private uow: UnitOfWork, private eventPublisher: EventEmitter2, - @Inject(Customer.name) private contactModel: typeof Customer, + @Inject(Customer.name) private customerModel: typeof Customer, ) {} /** @@ -31,10 +31,9 @@ export class DeleteCustomer { customerId: number, ): Promise { // Retrieve the customer or throw not found service error. - const oldCustomer = await this.contactModel + const oldCustomer = await this.customerModel .query() .findById(customerId) - .modify('customer') .throwIfNotFound(); // .queryAndThrowIfHasRelations({ // type: ERRORS.CUSTOMER_HAS_TRANSACTIONS, @@ -49,7 +48,7 @@ export class DeleteCustomer { // Deletes the customer and associated entities under UOW transaction. return this.uow.withTransaction(async (trx: Knex.Transaction) => { // Delete the customer from the storage. - await this.contactModel.query(trx).findById(customerId).delete(); + await this.customerModel.query(trx).findById(customerId).delete(); // Throws `onCustomerDeleted` event. await this.eventPublisher.emitAsync(events.customers.onDeleted, { diff --git a/packages/server-nest/src/modules/Customers/commands/EditCustomer.service.ts b/packages/server-nest/src/modules/Customers/commands/EditCustomer.service.ts index 6d72e91b5..1cfdcca56 100644 --- a/packages/server-nest/src/modules/Customers/commands/EditCustomer.service.ts +++ b/packages/server-nest/src/modules/Customers/commands/EditCustomer.service.ts @@ -23,7 +23,7 @@ export class EditCustomer { private uow: UnitOfWork, private eventPublisher: EventEmitter2, private customerDTO: CreateEditCustomerDTO, - @Inject(Customer.name) private contactModel: typeof Customer, + @Inject(Customer.name) private customerModel: typeof Customer, ) {} /** @@ -37,10 +37,9 @@ export class EditCustomer { customerDTO: ICustomerEditDTO, ): Promise { // Retrieve the customer or throw not found error. - const oldCustomer = await this.contactModel + const oldCustomer = await this.customerModel .query() .findById(customerId) - .modify('customer') .throwIfNotFound(); // Transforms the given customer DTO to object. @@ -56,7 +55,7 @@ export class EditCustomer { } as ICustomerEventEditingPayload); // Edits the customer details on the storage. - const customer = await this.contactModel + const customer = await this.customerModel .query() .updateAndFetchById(customerId, { ...customerObj, diff --git a/packages/server-nest/src/modules/Expenses/commands/DeleteExpense.service.ts b/packages/server-nest/src/modules/Expenses/commands/DeleteExpense.service.ts index 72edd12e9..b7f8620d3 100644 --- a/packages/server-nest/src/modules/Expenses/commands/DeleteExpense.service.ts +++ b/packages/server-nest/src/modules/Expenses/commands/DeleteExpense.service.ts @@ -4,7 +4,7 @@ import { CommandExpenseValidator } from './CommandExpenseValidator.service'; import { EventEmitter2 } from '@nestjs/event-emitter'; import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service'; import { Expense } from '../models/Expense.model'; -import ExpenseCategory from '../models/ExpenseCategory.model'; +import { ExpenseCategory } from '../models/ExpenseCategory.model'; import { events } from '@/common/events/events'; import { IExpenseEventDeletePayload, diff --git a/packages/server-nest/src/modules/Expenses/models/ExpenseCategory.model.ts b/packages/server-nest/src/modules/Expenses/models/ExpenseCategory.model.ts index d78b32b9c..ecd7230fa 100644 --- a/packages/server-nest/src/modules/Expenses/models/ExpenseCategory.model.ts +++ b/packages/server-nest/src/modules/Expenses/models/ExpenseCategory.model.ts @@ -1,10 +1,10 @@ import { Model } from 'objection'; import { BaseModel } from '@/models/Model'; -export default class ExpenseCategory extends BaseModel { +export class ExpenseCategory extends BaseModel { amount!: number; allocatedCostAmount!: number; - + /** * Table name */ @@ -31,12 +31,12 @@ export default class ExpenseCategory extends BaseModel { * Relationship mapping. */ static get relationMappings() { - const Account = require('models/Account'); - + const { Account } = require('../../Accounts/models/Account.model'); + return { expenseAccount: { relation: Model.BelongsToOneRelation, - modelClass: Account.default, + modelClass: Account, join: { from: 'expense_transaction_categories.expenseAccountId', to: 'accounts.id', diff --git a/packages/server-nest/src/modules/Expenses/queries/ExpenseCategory.transformer.ts b/packages/server-nest/src/modules/Expenses/queries/ExpenseCategory.transformer.ts index e2f2befb8..ded66bf63 100644 --- a/packages/server-nest/src/modules/Expenses/queries/ExpenseCategory.transformer.ts +++ b/packages/server-nest/src/modules/Expenses/queries/ExpenseCategory.transformer.ts @@ -1,6 +1,6 @@ import { Transformer } from '@/modules/Transformer/Transformer'; -import ExpenseCategory from '../models/ExpenseCategory.model'; +import { ExpenseCategory } from '../models/ExpenseCategory.model'; export class ExpenseCategoryTransformer extends Transformer { /** diff --git a/packages/server-nest/src/modules/Items/Items.module.ts b/packages/server-nest/src/modules/Items/Items.module.ts index d85f6bf81..649088ac6 100644 --- a/packages/server-nest/src/modules/Items/Items.module.ts +++ b/packages/server-nest/src/modules/Items/Items.module.ts @@ -12,6 +12,7 @@ import { ItemsApplicationService } from './ItemsApplication.service'; import { ItemTransactionsService } from './ItemTransactions.service'; import { GetItemService } from './GetItem.service'; import { TransformerInjectable } from '../Transformer/TransformerInjectable.service'; +import { ItemsEntriesService } from './ItemsEntries.service'; @Module({ imports: [TenancyDatabaseModule], @@ -28,6 +29,8 @@ import { TransformerInjectable } from '../Transformer/TransformerInjectable.serv ItemTransactionsService, TenancyContext, TransformerInjectable, + ItemsEntriesService ], + exports: [ItemsEntriesService] }) export class ItemsModule {} diff --git a/packages/server-nest/src/modules/Items/ItemsEntries.service.ts b/packages/server-nest/src/modules/Items/ItemsEntries.service.ts index d70440039..df53cca8b 100644 --- a/packages/server-nest/src/modules/Items/ItemsEntries.service.ts +++ b/packages/server-nest/src/modules/Items/ItemsEntries.service.ts @@ -213,7 +213,7 @@ export class ItemsEntriesService { /** * Sets the cost/sell accounts to the invoice entries. */ - public async setItemsEntriesDefaultAccounts(entries: ItemEntry[]) { + public setItemsEntriesDefaultAccounts = async (entries: ItemEntry[]) => { const entriesItemsIds = entries.map((e) => e.itemId); const items = await this.itemModel.query().whereIn('id', entriesItemsIds); diff --git a/packages/server-nest/src/modules/Items/models/ItemEntry.ts b/packages/server-nest/src/modules/Items/models/ItemEntry.ts index 0dd260618..5485d01b5 100644 --- a/packages/server-nest/src/modules/Items/models/ItemEntry.ts +++ b/packages/server-nest/src/modules/Items/models/ItemEntry.ts @@ -13,6 +13,9 @@ export class ItemEntry extends BaseModel { public costAccountId: number; public taxRateId: number; + public landedCost!: boolean; + public allocatedCostAmount!: number; + /** * Table name. * @returns {string} diff --git a/packages/server-nest/src/modules/PaymentReceived/commands/PaymentReceivedDTOTransformer.ts b/packages/server-nest/src/modules/PaymentReceived/commands/PaymentReceivedDTOTransformer.ts index 971508164..56783a619 100644 --- a/packages/server-nest/src/modules/PaymentReceived/commands/PaymentReceivedDTOTransformer.ts +++ b/packages/server-nest/src/modules/PaymentReceived/commands/PaymentReceivedDTOTransformer.ts @@ -1,7 +1,7 @@ import * as R from 'ramda'; import { Inject, Injectable } from '@nestjs/common'; import { omit, sumBy } from 'lodash'; -import composeAsync from 'async/compose'; +import * as composeAsync from 'async/compose'; import { IPaymentReceivedCreateDTO, IPaymentReceivedEditDTO, @@ -78,6 +78,6 @@ export class PaymentReceiveDTOTransformer { return R.compose( this.branchDTOTransform.transformDTO - )(initialAsyncDTO); + )(initialAsyncDTO) as PaymentReceived; } } diff --git a/packages/server-nest/src/modules/PaymentReceived/PaymentReceivedGLEntries.ts b/packages/server-nest/src/modules/PaymentReceived/commands/PaymentReceivedGLEntries.ts similarity index 100% rename from packages/server-nest/src/modules/PaymentReceived/PaymentReceivedGLEntries.ts rename to packages/server-nest/src/modules/PaymentReceived/commands/PaymentReceivedGLEntries.ts diff --git a/packages/server-nest/src/modules/PaymentReceived/PaymentReceivedMailNotification.ts b/packages/server-nest/src/modules/PaymentReceived/commands/PaymentReceivedMailNotification.ts similarity index 100% rename from packages/server-nest/src/modules/PaymentReceived/PaymentReceivedMailNotification.ts rename to packages/server-nest/src/modules/PaymentReceived/commands/PaymentReceivedMailNotification.ts diff --git a/packages/server-nest/src/modules/PaymentReceived/PaymentReceivedMailNotificationJob.ts b/packages/server-nest/src/modules/PaymentReceived/commands/PaymentReceivedMailNotificationJob.ts similarity index 100% rename from packages/server-nest/src/modules/PaymentReceived/PaymentReceivedMailNotificationJob.ts rename to packages/server-nest/src/modules/PaymentReceived/commands/PaymentReceivedMailNotificationJob.ts diff --git a/packages/server-nest/src/modules/PaymentReceived/PaymentReceivedSmsNotify.ts b/packages/server-nest/src/modules/PaymentReceived/commands/PaymentReceivedSmsNotify.ts similarity index 100% rename from packages/server-nest/src/modules/PaymentReceived/PaymentReceivedSmsNotify.ts rename to packages/server-nest/src/modules/PaymentReceived/commands/PaymentReceivedSmsNotify.ts diff --git a/packages/server-nest/src/modules/PaymentReceived/PaymentReceivedSmsSubscriber.ts b/packages/server-nest/src/modules/PaymentReceived/commands/PaymentReceivedSmsSubscriber.ts similarity index 100% rename from packages/server-nest/src/modules/PaymentReceived/PaymentReceivedSmsSubscriber.ts rename to packages/server-nest/src/modules/PaymentReceived/commands/PaymentReceivedSmsSubscriber.ts diff --git a/packages/server-nest/src/modules/PaymentReceived/PaymentsReceivedExportable.ts b/packages/server-nest/src/modules/PaymentReceived/commands/PaymentsReceivedExportable.ts similarity index 100% rename from packages/server-nest/src/modules/PaymentReceived/PaymentsReceivedExportable.ts rename to packages/server-nest/src/modules/PaymentReceived/commands/PaymentsReceivedExportable.ts diff --git a/packages/server-nest/src/modules/PaymentReceived/PaymentsReceivedImportable.ts b/packages/server-nest/src/modules/PaymentReceived/commands/PaymentsReceivedImportable.ts similarity index 100% rename from packages/server-nest/src/modules/PaymentReceived/PaymentsReceivedImportable.ts rename to packages/server-nest/src/modules/PaymentReceived/commands/PaymentsReceivedImportable.ts diff --git a/packages/server-nest/src/modules/PaymentReceived/models/PaymentReceived.ts b/packages/server-nest/src/modules/PaymentReceived/models/PaymentReceived.ts index 04873fd9c..5f51011ad 100644 --- a/packages/server-nest/src/modules/PaymentReceived/models/PaymentReceived.ts +++ b/packages/server-nest/src/modules/PaymentReceived/models/PaymentReceived.ts @@ -6,6 +6,7 @@ import { Model, mixin } from 'objection'; // import { DEFAULT_VIEWS } from '@/services/Sales/PaymentReceived/constants'; // import ModelSearchable from './ModelSearchable'; import { BaseModel } from '@/models/Model'; +import { PaymentReceivedEntry } from './PaymentReceivedEntry'; export class PaymentReceived extends BaseModel { customerId: number; @@ -25,6 +26,8 @@ export class PaymentReceived extends BaseModel { createdAt: string; updatedAt: string; + entries?: PaymentReceivedEntry[]; + /** * Table name. */ @@ -65,17 +68,17 @@ export class PaymentReceived extends BaseModel { * Relationship mapping. */ static get relationMappings() { - const PaymentReceiveEntry = require('models/PaymentReceiveEntry'); - const AccountTransaction = require('models/AccountTransaction'); - const Customer = require('models/Customer'); - const Account = require('models/Account'); - const Branch = require('models/Branch'); - const Document = require('models/Document'); + const { PaymentReceivedEntry } = require('./PaymentReceivedEntry'); + const { AccountTransaction } = require('../../Accounts/models/AccountTransaction.model'); + const { Customer } = require('../../Customers/models/Customer'); + const { Account } = require('../../Accounts/models/Account.model'); + const { Branch } = require('../../Branches/models/Branch.model'); + // const Document = require('../../Documents/models/Document'); return { customer: { relation: Model.BelongsToOneRelation, - modelClass: Customer.default, + modelClass: Customer, join: { from: 'payment_receives.customerId', to: 'contacts.id', @@ -84,17 +87,19 @@ export class PaymentReceived extends BaseModel { query.where('contact_service', 'customer'); }, }, + depositAccount: { relation: Model.BelongsToOneRelation, - modelClass: Account.default, + modelClass: Account, join: { from: 'payment_receives.depositAccountId', to: 'accounts.id', }, }, + entries: { relation: Model.HasManyRelation, - modelClass: PaymentReceiveEntry.default, + modelClass: PaymentReceivedEntry, join: { from: 'payment_receives.id', to: 'payment_receives_entries.paymentReceiveId', @@ -103,9 +108,10 @@ export class PaymentReceived extends BaseModel { query.orderBy('index', 'ASC'); }, }, + transactions: { relation: Model.HasManyRelation, - modelClass: AccountTransaction.default, + modelClass: AccountTransaction, join: { from: 'payment_receives.id', to: 'accounts_transactions.referenceId', @@ -120,7 +126,7 @@ export class PaymentReceived extends BaseModel { */ branch: { relation: Model.BelongsToOneRelation, - modelClass: Branch.default, + modelClass: Branch, join: { from: 'payment_receives.branchId', to: 'branches.id', @@ -130,21 +136,21 @@ export class PaymentReceived extends BaseModel { /** * Payment transaction may has many attached attachments. */ - attachments: { - relation: Model.ManyToManyRelation, - modelClass: Document.default, - join: { - from: 'payment_receives.id', - through: { - from: 'document_links.modelId', - to: 'document_links.documentId', - }, - to: 'documents.id', - }, - filter(query) { - query.where('model_ref', 'PaymentReceive'); - }, - }, + // attachments: { + // relation: Model.ManyToManyRelation, + // modelClass: Document.default, + // join: { + // from: 'payment_receives.id', + // through: { + // from: 'document_links.modelId', + // to: 'document_links.documentId', + // }, + // to: 'documents.id', + // }, + // filter(query) { + // query.where('model_ref', 'PaymentReceive'); + // }, + // }, }; } diff --git a/packages/server-nest/src/modules/PaymentReceived/models/PaymentReceivedEntry.ts b/packages/server-nest/src/modules/PaymentReceived/models/PaymentReceivedEntry.ts index 920419cf3..0db87aca0 100644 --- a/packages/server-nest/src/modules/PaymentReceived/models/PaymentReceivedEntry.ts +++ b/packages/server-nest/src/modules/PaymentReceived/models/PaymentReceivedEntry.ts @@ -1,10 +1,14 @@ import { BaseModel } from '@/models/Model'; -import { Model, mixin } from 'objection'; +import { SaleInvoice } from '@/modules/SaleInvoices/models/SaleInvoice'; +import { Model } from 'objection'; export class PaymentReceivedEntry extends BaseModel { paymentReceiveId: number; invoiceId: number; paymentAmount: number; + index: number; + + invoice?: SaleInvoice; /** * Table name @@ -24,15 +28,15 @@ export class PaymentReceivedEntry extends BaseModel { * Relationship mapping. */ static get relationMappings() { - const PaymentReceive = require('models/PaymentReceive'); - const SaleInvoice = require('models/SaleInvoice'); + const { PaymentReceived } = require('./PaymentReceived'); + const { SaleInvoice } = require('../../SaleInvoices/models/SaleInvoice'); return { /** */ payment: { relation: Model.BelongsToOneRelation, - modelClass: PaymentReceive.default, + modelClass: PaymentReceived, join: { from: 'payment_receives_entries.paymentReceiveId', to: 'payment_receives.id', @@ -44,7 +48,7 @@ export class PaymentReceivedEntry extends BaseModel { */ invoice: { relation: Model.BelongsToOneRelation, - modelClass: SaleInvoice.default, + modelClass: SaleInvoice, join: { from: 'payment_receives_entries.invoiceId', to: 'sales_invoices.id', diff --git a/packages/server-nest/src/modules/PaymentReceived/queries/PaymentsReceivedPages.service.ts b/packages/server-nest/src/modules/PaymentReceived/queries/PaymentsReceivedPages.service.ts index 9603f5f90..d14b9b6b4 100644 --- a/packages/server-nest/src/modules/PaymentReceived/queries/PaymentsReceivedPages.service.ts +++ b/packages/server-nest/src/modules/PaymentReceived/queries/PaymentsReceivedPages.service.ts @@ -1,8 +1,7 @@ -import { Inject, Service } from 'typedi'; +import { Inject, Injectable } from '@nestjs/common'; import { omit } from 'lodash'; import { IPaymentReceivePageEntry } from '../types/PaymentReceived.types'; import { ERRORS } from '../constants'; -import { Injectable } from '@nestjs/common'; import { SaleInvoice } from '@/modules/SaleInvoices/models/SaleInvoice'; import { PaymentReceived } from '../models/PaymentReceived'; import { ServiceError } from '@/modules/Items/ServiceError'; diff --git a/packages/server-nest/src/modules/PaymentReceived/utils.ts b/packages/server-nest/src/modules/PaymentReceived/utils.ts index dfa03f409..7bb14dbd6 100644 --- a/packages/server-nest/src/modules/PaymentReceived/utils.ts +++ b/packages/server-nest/src/modules/PaymentReceived/utils.ts @@ -1,3 +1,4 @@ +// @ts-nocheck import { PaymentReceived } from './models/PaymentReceived'; import { PaymentReceivedPdfTemplateAttributes, diff --git a/packages/server-nest/src/modules/PaymentServices/PaymentServices.module.ts b/packages/server-nest/src/modules/PaymentServices/PaymentServices.module.ts new file mode 100644 index 000000000..ce9ac93eb --- /dev/null +++ b/packages/server-nest/src/modules/PaymentServices/PaymentServices.module.ts @@ -0,0 +1,7 @@ + + + + + + +export class PaymentServicesModule {} \ No newline at end of file diff --git a/packages/server-nest/src/modules/PaymentServices/models/PaymentIntegration.model.ts b/packages/server-nest/src/modules/PaymentServices/models/PaymentIntegration.model.ts new file mode 100644 index 000000000..71763e807 --- /dev/null +++ b/packages/server-nest/src/modules/PaymentServices/models/PaymentIntegration.model.ts @@ -0,0 +1,60 @@ +import { BaseModel } from "@/models/Model"; + +export class PaymentIntegration extends BaseModel { + paymentEnabled!: boolean; + payoutEnabled!: boolean; + + static get tableName() { + return 'payment_integrations'; + } + + static get idColumn() { + return 'id'; + } + + static get virtualAttributes() { + return ['fullEnabled']; + } + + static get jsonAttributes() { + return ['options']; + } + + get fullEnabled() { + return this.paymentEnabled && this.payoutEnabled; + } + + static get modifiers() { + return { + /** + * Query to filter enabled payment and payout. + */ + fullEnabled(query) { + query.where('paymentEnabled', true).andWhere('payoutEnabled', true); + }, + }; + } + + static get jsonSchema() { + return { + type: 'object', + required: ['name', 'service'], + properties: { + id: { type: 'integer' }, + service: { type: 'string' }, + paymentEnabled: { type: 'boolean' }, + payoutEnabled: { type: 'boolean' }, + accountId: { type: 'string' }, + options: { + type: 'object', + properties: { + bankAccountId: { type: 'number' }, + clearingAccountId: { type: 'number' }, + }, + }, + createdAt: { type: 'string', format: 'date-time' }, + updatedAt: { type: 'string', format: 'date-time' }, + }, + }; + } +} diff --git a/packages/server-nest/src/modules/PaymentServices/models/TransactionPaymentServiceEntry.model.ts b/packages/server-nest/src/modules/PaymentServices/models/TransactionPaymentServiceEntry.model.ts new file mode 100644 index 000000000..fd98aeb00 --- /dev/null +++ b/packages/server-nest/src/modules/PaymentServices/models/TransactionPaymentServiceEntry.model.ts @@ -0,0 +1,47 @@ +import { Model } from 'objection'; +import { BaseModel } from '@/models/Model'; + +export class TransactionPaymentServiceEntry extends BaseModel { + /** + * Table name + */ + static get tableName() { + return 'transactions_payment_methods'; + } + + /** + * Json schema of the model. + */ + static get jsonSchema() { + return { + type: 'object', + required: ['paymentIntegrationId'], + properties: { + id: { type: 'integer' }, + referenceId: { type: 'integer' }, + referenceType: { type: 'string' }, + paymentIntegrationId: { type: 'integer' }, + enable: { type: 'boolean' }, + options: { type: 'object' }, + }, + }; + } + + /** + * Relationship mapping. + */ + static get relationMappings() { + const { PaymentIntegration } = require('./PaymentIntegration.model'); + + return { + paymentIntegration: { + relation: Model.BelongsToOneRelation, + modelClass: PaymentIntegration, + join: { + from: 'transactions_payment_methods.paymentIntegrationId', + to: 'payment_integrations.id', + }, + }, + }; + } +} diff --git a/packages/server-nest/src/modules/PdfTemplate/PdfTemplates.module.ts b/packages/server-nest/src/modules/PdfTemplate/PdfTemplates.module.ts index c58765230..75d0aa9ac 100644 --- a/packages/server-nest/src/modules/PdfTemplate/PdfTemplates.module.ts +++ b/packages/server-nest/src/modules/PdfTemplate/PdfTemplates.module.ts @@ -9,8 +9,15 @@ import { EditPdfTemplateService } from './commands/EditPdfTemplate.service'; import { PdfTemplateApplication } from './PdfTemplate.application'; import { PdfTemplatesController } from './PdfTemplates.controller'; import { GetPdfTemplateService } from './queries/GetPdfTemplate.service'; +import { BrandingTemplateDTOTransformer } from './BrandingTemplateDTOTransformer'; +import { GetOrganizationBrandingAttributesService } from './queries/GetOrganizationBrandingAttributes.service'; @Module({ + exports: [ + GetPdfTemplateService, + BrandingTemplateDTOTransformer, + GetOrganizationBrandingAttributesService, + ], imports: [TenancyDatabaseModule], controllers: [PdfTemplatesController], providers: [ @@ -22,6 +29,8 @@ import { GetPdfTemplateService } from './queries/GetPdfTemplate.service'; AssignPdfTemplateDefaultService, TenancyContext, TransformerInjectable, + BrandingTemplateDTOTransformer, + GetOrganizationBrandingAttributesService, ], }) export class PdfTemplatesModule {} diff --git a/packages/server-nest/src/modules/SaleEstimates/models/SaleEstimate.ts b/packages/server-nest/src/modules/SaleEstimates/models/SaleEstimate.ts index 2789b4722..7d6dedb93 100644 --- a/packages/server-nest/src/modules/SaleEstimates/models/SaleEstimate.ts +++ b/packages/server-nest/src/modules/SaleEstimates/models/SaleEstimate.ts @@ -208,23 +208,23 @@ export class SaleEstimate extends BaseModel { */ static get relationMappings() { const { ItemEntry } = require('../../Items/models/ItemEntry'); - // const Customer = require('models/Customer'); - // const Branch = require('models/Branch'); - // const Warehouse = require('models/Warehouse'); - // const Document = require('models/Document'); + const { Customer } = require('../../Customers/models/Customer'); + const { Branch } = require('../../Branches/models/Branch.model'); + const { Warehouse } = require('../../Warehouses/models/Warehouse.model'); + const { Document } = require('../../ChromiumlyTenancy/models/Document'); return { - // customer: { - // relation: Model.BelongsToOneRelation, - // modelClass: Customer.default, - // join: { - // from: 'sales_estimates.customerId', - // to: 'contacts.id', - // }, - // filter(query) { - // query.where('contact_service', 'customer'); - // }, - // }, + customer: { + relation: Model.BelongsToOneRelation, + modelClass: Customer, + join: { + from: 'sales_estimates.customerId', + to: 'contacts.id', + }, + filter(query) { + query.where('contact_service', 'customer'); + }, + }, entries: { relation: Model.HasManyRelation, modelClass: ItemEntry, @@ -239,48 +239,48 @@ export class SaleEstimate extends BaseModel { }, }, - // /** - // * Sale estimate may belongs to branch. - // */ - // branch: { - // relation: Model.BelongsToOneRelation, - // modelClass: Branch.default, - // join: { - // from: 'sales_estimates.branchId', - // to: 'branches.id', - // }, - // }, + /** + * Sale estimate may belongs to branch. + */ + branch: { + relation: Model.BelongsToOneRelation, + modelClass: Branch, + join: { + from: 'sales_estimates.branchId', + to: 'branches.id', + }, + }, - // /** - // * Sale estimate may has associated warehouse. - // */ - // warehouse: { - // relation: Model.BelongsToOneRelation, - // modelClass: Warehouse.default, - // join: { - // from: 'sales_estimates.warehouseId', - // to: 'warehouses.id', - // }, - // }, + /** + * Sale estimate may has associated warehouse. + */ + warehouse: { + relation: Model.BelongsToOneRelation, + modelClass: Warehouse, + join: { + from: 'sales_estimates.warehouseId', + to: 'warehouses.id', + }, + }, - // /** - // * Sale estimate transaction may has many attached attachments. - // */ - // attachments: { - // relation: Model.ManyToManyRelation, - // modelClass: Document.default, - // join: { - // from: 'sales_estimates.id', - // through: { - // from: 'document_links.modelId', - // to: 'document_links.documentId', - // }, - // to: 'documents.id', - // }, - // filter(query) { - // query.where('model_ref', 'SaleEstimate'); - // }, - // }, + /** + * Sale estimate transaction may has many attached attachments. + */ + attachments: { + relation: Model.ManyToManyRelation, + modelClass: Document, + join: { + from: 'sales_estimates.id', + through: { + from: 'document_links.modelId', + to: 'document_links.documentId', + }, + to: 'documents.id', + }, + filter(query) { + query.where('model_ref', 'SaleEstimate'); + }, + }, }; } diff --git a/packages/server-nest/src/modules/SaleInvoices/SaleInvoice.types.ts b/packages/server-nest/src/modules/SaleInvoices/SaleInvoice.types.ts index bdfb51f27..1dc5bdbb0 100644 --- a/packages/server-nest/src/modules/SaleInvoices/SaleInvoice.types.ts +++ b/packages/server-nest/src/modules/SaleInvoices/SaleInvoice.types.ts @@ -1,8 +1,9 @@ import { Knex } from 'knex'; import { IItemEntryDTO } from '../TransactionItemEntry/ItemEntry.types'; import { AttachmentLinkDTO } from '../Attachments/Attachments.types'; -import SaleInvoice from './models/SaleInvoice'; -import { SystemUser } from '../System/models/SystemUser'; +import { SaleInvoice } from './models/SaleInvoice'; +// import SaleInvoice from './models/SaleInvoice'; +// import { SystemUser } from '../System/models/SystemUser'; // import { ISystemUser, IAccount, ITaxTransaction } from '@/interfaces'; // import { CommonMailOptions, CommonMailOptionsDTO } from './Mailable'; // import { IDynamicListFilter } from '@/interfaces/DynamicFilter'; diff --git a/packages/server-nest/src/modules/SaleInvoices/SaleInvoices.controller.ts b/packages/server-nest/src/modules/SaleInvoices/SaleInvoices.controller.ts index 94de97af7..d0a121cd8 100644 --- a/packages/server-nest/src/modules/SaleInvoices/SaleInvoices.controller.ts +++ b/packages/server-nest/src/modules/SaleInvoices/SaleInvoices.controller.ts @@ -16,8 +16,10 @@ import { InvoiceNotificationType, } from './SaleInvoice.types'; import { SaleInvoiceApplication } from './SaleInvoices.application'; +import { PublicRoute } from '../Auth/Jwt.guard'; @Controller('sale-invoices') +@PublicRoute() export class SaleInvoicesController { constructor(private saleInvoiceApplication: SaleInvoiceApplication) {} diff --git a/packages/server-nest/src/modules/SaleInvoices/SaleInvoices.module.ts b/packages/server-nest/src/modules/SaleInvoices/SaleInvoices.module.ts index 90bbd13c9..1d495762e 100644 --- a/packages/server-nest/src/modules/SaleInvoices/SaleInvoices.module.ts +++ b/packages/server-nest/src/modules/SaleInvoices/SaleInvoices.module.ts @@ -16,10 +16,33 @@ import { GetSaleInvoicesPayable } from './queries/GetSaleInvoicesPayable.service import { GetSaleInvoiceState } from './queries/GetSaleInvoiceState.service'; import { SaleInvoicePdf } from './queries/SaleInvoicePdf.service'; import { SaleInvoiceApplication } from './SaleInvoices.application'; +import { ItemsEntriesService } from '../Items/ItemsEntries.service'; +import { CommandSaleInvoiceValidators } from './commands/CommandSaleInvoiceValidators.service'; +import { CommandSaleInvoiceDTOTransformer } from './commands/CommandSaleInvoiceDTOTransformer.service'; +import { SaleEstimateValidators } from '../SaleEstimates/commands/SaleEstimateValidators.service'; +import { UnlinkConvertedSaleEstimate } from '../SaleEstimates/commands/UnlinkConvertedSaleEstimate.service'; +import { PdfTemplatesModule } from '../PdfTemplate/PdfTemplates.module'; +import { AutoIncrementOrdersModule } from '../AutoIncrementOrders/AutoIncrementOrders.module'; +import { ChromiumlyTenancyModule } from '../ChromiumlyTenancy/ChromiumlyTenancy.module'; +import { SaleInvoicePdfTemplate } from './queries/SaleInvoicePdfTemplate.service'; +import { WriteoffSaleInvoice } from './commands/WriteoffSaleInvoice.service'; +import { GetInvoicePaymentsService } from './queries/GetInvoicePayments.service'; +import { BranchesModule } from '../Branches/Branches.module'; +import { WarehousesModule } from '../Warehouses/Warehouses.module'; +import { TaxRatesModule } from '../TaxRates/TaxRate.module'; +import { SaleInvoicesController } from './SaleInvoices.controller'; @Module({ - imports: [TenancyDatabaseModule], - controllers: [], + imports: [ + TenancyDatabaseModule, + PdfTemplatesModule, + AutoIncrementOrdersModule, + ChromiumlyTenancyModule, + BranchesModule, + WarehousesModule, + TaxRatesModule, + ], + controllers: [SaleInvoicesController], providers: [ CreateSaleInvoice, EditSaleInvoice, @@ -37,6 +60,14 @@ import { SaleInvoiceApplication } from './SaleInvoices.application'; SaleInvoiceApplication, TenancyContext, TransformerInjectable, + ItemsEntriesService, + CommandSaleInvoiceValidators, + CommandSaleInvoiceDTOTransformer, + SaleEstimateValidators, + UnlinkConvertedSaleEstimate, + SaleInvoicePdfTemplate, + WriteoffSaleInvoice, + GetInvoicePaymentsService, ], }) export class SaleInvoicesModule {} diff --git a/packages/server-nest/src/modules/SaleInvoices/commands/CommandSaleInvoiceDTOTransformer.service.ts b/packages/server-nest/src/modules/SaleInvoices/commands/CommandSaleInvoiceDTOTransformer.service.ts index 637c5da67..c399f5852 100644 --- a/packages/server-nest/src/modules/SaleInvoices/commands/CommandSaleInvoiceDTOTransformer.service.ts +++ b/packages/server-nest/src/modules/SaleInvoices/commands/CommandSaleInvoiceDTOTransformer.service.ts @@ -1,8 +1,8 @@ import { Inject, Injectable } from '@nestjs/common'; import { omit, sumBy } from 'lodash'; import * as R from 'ramda'; -import moment from 'moment'; -import composeAsync from 'async/compose'; +import * as moment from 'moment'; +import * as composeAsync from 'async/compose'; import { ISaleInvoiceCreateDTO, ISaleInvoiceEditDTO, diff --git a/packages/server-nest/src/modules/SaleInvoices/commands/CommandSaleInvoiceValidators.service.ts b/packages/server-nest/src/modules/SaleInvoices/commands/CommandSaleInvoiceValidators.service.ts index 8ff18a951..31333f903 100644 --- a/packages/server-nest/src/modules/SaleInvoices/commands/CommandSaleInvoiceValidators.service.ts +++ b/packages/server-nest/src/modules/SaleInvoices/commands/CommandSaleInvoiceValidators.service.ts @@ -1,11 +1,14 @@ -import { Injectable } from '@nestjs/common'; +import { Inject, Injectable } from '@nestjs/common'; import { SaleInvoice } from '../models/SaleInvoice'; import { ServiceError } from '@/modules/Items/ServiceError'; import { ERRORS } from '../constants'; @Injectable() export class CommandSaleInvoiceValidators { - constructor(private readonly saleInvoiceModel: typeof SaleInvoice) {} + constructor( + @Inject(SaleInvoice.name) + private readonly saleInvoiceModel: typeof SaleInvoice, + ) {} /** * Validates the given invoice is existance. diff --git a/packages/server-nest/src/modules/SaleInvoices/commands/DeleteSaleInvoice.service.ts b/packages/server-nest/src/modules/SaleInvoices/commands/DeleteSaleInvoice.service.ts index 1c676264c..e69467c16 100644 --- a/packages/server-nest/src/modules/SaleInvoices/commands/DeleteSaleInvoice.service.ts +++ b/packages/server-nest/src/modules/SaleInvoices/commands/DeleteSaleInvoice.service.ts @@ -14,22 +14,23 @@ import { ServiceError } from '@/modules/Items/ServiceError'; import { ERRORS } from '../constants'; import { events } from '@/common/events/events'; import { PaymentReceivedEntry } from '@/modules/PaymentReceived/models/PaymentReceivedEntry'; -import CreditNoteAppliedInvoice from '@/modules/CreditNotes/models/CreditNoteAppliedInvoice'; +import { CreditNoteAppliedInvoice } from '@/modules/CreditNotes/models/CreditNoteAppliedInvoice'; @Injectable() export class DeleteSaleInvoice { constructor( - @Inject(PaymentReceivedEntry) - private paymentReceivedEntryModel: typeof PaymentReceivedEntry, - - @Inject(CreditNoteAppliedInvoice) - private creditNoteAppliedInvoiceModel: typeof CreditNoteAppliedInvoice, - - @Inject(SaleInvoice) - private saleInvoiceModel: typeof SaleInvoice, private unlockEstimateFromInvoice: UnlinkConvertedSaleEstimate, private eventPublisher: EventEmitter2, private uow: UnitOfWork, + + @Inject(PaymentReceivedEntry.name) + private paymentReceivedEntryModel: typeof PaymentReceivedEntry, + + @Inject(CreditNoteAppliedInvoice.name) + private creditNoteAppliedInvoiceModel: typeof CreditNoteAppliedInvoice, + + @Inject(SaleInvoice.name) + private saleInvoiceModel: typeof SaleInvoice, ) {} /** @@ -41,8 +42,8 @@ export class DeleteSaleInvoice { const entries = await this.paymentReceivedEntryModel .query() .where('invoice_id', saleInvoiceId); - - if (entries.length > 0) { + + if (entries.length > 0) { throw new ServiceError(ERRORS.INVOICE_HAS_ASSOCIATED_PAYMENT_ENTRIES); } return entries; diff --git a/packages/server-nest/src/modules/SaleInvoices/commands/GenerateInvoicePaymentLink.service.ts b/packages/server-nest/src/modules/SaleInvoices/commands/GenerateInvoicePaymentLink.service.ts index d5558499e..15765852b 100644 --- a/packages/server-nest/src/modules/SaleInvoices/commands/GenerateInvoicePaymentLink.service.ts +++ b/packages/server-nest/src/modules/SaleInvoices/commands/GenerateInvoicePaymentLink.service.ts @@ -16,8 +16,8 @@ export class GenerateShareLink { private uow: UnitOfWork, private eventPublisher: EventEmitter2, private transformer: TransformerInjectable, - @Inject(SaleInvoice) private saleInvoiceModel: typeof SaleInvoice, - @Inject(PaymentLink) private paymentLinkModel: typeof PaymentLink, + @Inject(SaleInvoice.name) private saleInvoiceModel: typeof SaleInvoice, + @Inject(PaymentLink.name) private paymentLinkModel: typeof PaymentLink, ) {} /** diff --git a/packages/server-nest/src/modules/SaleInvoices/SaleInvoiceWriteoffGLEntries.ts b/packages/server-nest/src/modules/SaleInvoices/commands/SaleInvoiceWriteoffGLEntries.ts similarity index 100% rename from packages/server-nest/src/modules/SaleInvoices/SaleInvoiceWriteoffGLEntries.ts rename to packages/server-nest/src/modules/SaleInvoices/commands/SaleInvoiceWriteoffGLEntries.ts diff --git a/packages/server-nest/src/modules/SaleInvoices/SaleInvoiceWriteoffGLStorage.ts b/packages/server-nest/src/modules/SaleInvoices/commands/SaleInvoiceWriteoffGLStorage.ts similarity index 100% rename from packages/server-nest/src/modules/SaleInvoices/SaleInvoiceWriteoffGLStorage.ts rename to packages/server-nest/src/modules/SaleInvoices/commands/SaleInvoiceWriteoffGLStorage.ts diff --git a/packages/server-nest/src/modules/SaleInvoices/SaleInvoicesExportable.ts b/packages/server-nest/src/modules/SaleInvoices/commands/SaleInvoicesExportable.ts similarity index 100% rename from packages/server-nest/src/modules/SaleInvoices/SaleInvoicesExportable.ts rename to packages/server-nest/src/modules/SaleInvoices/commands/SaleInvoicesExportable.ts diff --git a/packages/server-nest/src/modules/SaleInvoices/SaleInvoicesImportable.ts b/packages/server-nest/src/modules/SaleInvoices/commands/SaleInvoicesImportable.ts similarity index 100% rename from packages/server-nest/src/modules/SaleInvoices/SaleInvoicesImportable.ts rename to packages/server-nest/src/modules/SaleInvoices/commands/SaleInvoicesImportable.ts diff --git a/packages/server-nest/src/modules/SaleInvoices/models/SaleInvoice.ts b/packages/server-nest/src/modules/SaleInvoices/models/SaleInvoice.ts index c376f7afc..df3a7b349 100644 --- a/packages/server-nest/src/modules/SaleInvoices/models/SaleInvoice.ts +++ b/packages/server-nest/src/modules/SaleInvoices/models/SaleInvoice.ts @@ -1,6 +1,6 @@ import { mixin, Model, raw } from 'objection'; import { castArray, takeWhile } from 'lodash'; -import moment from 'moment'; +import moment, { MomentInput, unitOfTime } from 'moment'; // import TenantModel from 'models/TenantModel'; // import ModelSetting from './ModelSetting'; // import SaleInvoiceMeta from './SaleInvoice.Settings'; @@ -9,17 +9,17 @@ import moment from 'moment'; // import ModelSearchable from './ModelSearchable'; import { BaseModel } from '@/models/Model'; -export class SaleInvoice extends BaseModel{ +export class SaleInvoice extends BaseModel { public taxAmountWithheld: number; public balance: number; public paymentAmount: number; public exchangeRate: number; - + public creditedAmount: number; public isInclusiveTax: boolean; - + public dueDate: Date; - public deliveredAt: Date; + public deliveredAt: Date | string; public currencyCode: string; public invoiceDate: Date; @@ -262,13 +262,18 @@ export class SaleInvoice extends BaseModel{ COALESCE(PAYMENT_AMOUNT, 0) - COALESCE(WRITTENOFF_AMOUNT, 0) - COALESCE(CREDITED_AMOUNT, 0) > 0 - `) + `), ); }, /** * Filters the invoices between the given date range. */ - filterDateRange(query, startDate, endDate, type = 'day') { + filterDateRange( + query, + startDate: MomentInput, + endDate?: MomentInput, + type: unitOfTime.StartOf = 'day', + ) { const dateFormat = 'YYYY-MM-DD'; const fromDate = moment(startDate).startOf(type).format(dateFormat); const toDate = moment(endDate).endOf(type).format(dateFormat); @@ -418,213 +423,221 @@ export class SaleInvoice extends BaseModel{ /** * Relationship mapping. */ - // static get relationMappings() { - // const AccountTransaction = require('models/AccountTransaction'); - // const ItemEntry = require('models/ItemEntry'); - // const Customer = require('models/Customer'); - // const InventoryCostLotTracker = require('models/InventoryCostLotTracker'); - // const PaymentReceiveEntry = require('models/PaymentReceiveEntry'); - // const Branch = require('models/Branch'); - // const Warehouse = require('models/Warehouse'); - // const Account = require('models/Account'); - // const TaxRateTransaction = require('models/TaxRateTransaction'); - // const Document = require('models/Document'); - // const { MatchedBankTransaction } = require('models/MatchedBankTransaction'); - // const { - // TransactionPaymentServiceEntry, - // } = require('models/TransactionPaymentServiceEntry'); - // const { PdfTemplate } = require('models/PdfTemplate'); + static get relationMappings() { + const { + AccountTransaction, + } = require('../../Accounts/models/AccountTransaction.model'); + const { + ItemEntry, + } = require('../../TransactionItemEntry/models/ItemEntry'); + const { Customer } = require('../../Customers/models/Customer'); + // const InventoryCostLotTracker = require('models/InventoryCostLotTracker'); + const { + PaymentReceivedEntry, + } = require('../../PaymentReceived/models/PaymentReceivedEntry'); + const { Branch } = require('../../Branches/models/Branch.model'); + const { Warehouse } = require('../../Warehouses/models/Warehouse.model'); + const { Account } = require('../../Accounts/models/Account.model'); + // const TaxRateTransaction = require('../../Tax'); + const { Document } = require('../../ChromiumlyTenancy/models/Document'); + // const { MatchedBankTransaction } = require('models/MatchedBankTransaction'); + const { + TransactionPaymentServiceEntry, + } = require('../../PaymentServices/models/TransactionPaymentServiceEntry.model'); + const { + PdfTemplateModel, + } = require('../../PdfTemplate/models/PdfTemplate'); - // return { - // /** - // * Sale invoice associated entries. - // */ - // entries: { - // relation: Model.HasManyRelation, - // modelClass: ItemEntry.default, - // join: { - // from: 'sales_invoices.id', - // to: 'items_entries.referenceId', - // }, - // filter(builder) { - // builder.where('reference_type', 'SaleInvoice'); - // builder.orderBy('index', 'ASC'); - // }, - // }, + return { + /** + * Sale invoice associated entries. + */ + entries: { + relation: Model.HasManyRelation, + modelClass: ItemEntry, + join: { + from: 'sales_invoices.id', + to: 'items_entries.referenceId', + }, + filter(builder) { + builder.where('reference_type', 'SaleInvoice'); + builder.orderBy('index', 'ASC'); + }, + }, - // /** - // * Belongs to customer model. - // */ - // customer: { - // relation: Model.BelongsToOneRelation, - // modelClass: Customer.default, - // join: { - // from: 'sales_invoices.customerId', - // to: 'contacts.id', - // }, - // filter(query) { - // query.where('contact_service', 'Customer'); - // }, - // }, + /** + * Belongs to customer model. + */ + customer: { + relation: Model.BelongsToOneRelation, + modelClass: Customer, + join: { + from: 'sales_invoices.customerId', + to: 'contacts.id', + }, + filter(query) { + query.where('contact_service', 'Customer'); + }, + }, - // /** - // * Invoice has associated account transactions. - // */ - // transactions: { - // relation: Model.HasManyRelation, - // modelClass: AccountTransaction.default, - // join: { - // from: 'sales_invoices.id', - // to: 'accounts_transactions.referenceId', - // }, - // filter(builder) { - // builder.where('reference_type', 'SaleInvoice'); - // }, - // }, + /** + * Invoice has associated account transactions. + */ + transactions: { + relation: Model.HasManyRelation, + modelClass: AccountTransaction, + join: { + from: 'sales_invoices.id', + to: 'accounts_transactions.referenceId', + }, + filter(builder) { + builder.where('reference_type', 'SaleInvoice'); + }, + }, - // /** - // * Invoice may has associated cost transactions. - // */ - // costTransactions: { - // relation: Model.HasManyRelation, - // modelClass: InventoryCostLotTracker.default, - // join: { - // from: 'sales_invoices.id', - // to: 'inventory_cost_lot_tracker.transactionId', - // }, - // filter(builder) { - // builder.where('transaction_type', 'SaleInvoice'); - // }, - // }, + /** + * Invoice may has associated cost transactions. + */ + // costTransactions: { + // relation: Model.HasManyRelation, + // modelClass: InventoryCostLotTracker.default, + // join: { + // from: 'sales_invoices.id', + // to: 'inventory_cost_lot_tracker.transactionId', + // }, + // filter(builder) { + // builder.where('transaction_type', 'SaleInvoice'); + // }, + // }, - // /** - // * Invoice may has associated payment entries. - // */ - // paymentEntries: { - // relation: Model.HasManyRelation, - // modelClass: PaymentReceiveEntry.default, - // join: { - // from: 'sales_invoices.id', - // to: 'payment_receives_entries.invoiceId', - // }, - // }, + /** + * Invoice may has associated payment entries. + */ + paymentEntries: { + relation: Model.HasManyRelation, + modelClass: PaymentReceivedEntry, + join: { + from: 'sales_invoices.id', + to: 'payment_receives_entries.invoiceId', + }, + }, - // /** - // * Invoice may has associated branch. - // */ - // branch: { - // relation: Model.BelongsToOneRelation, - // modelClass: Branch.default, - // join: { - // from: 'sales_invoices.branchId', - // to: 'branches.id', - // }, - // }, + /** + * Invoice may has associated branch. + */ + branch: { + relation: Model.BelongsToOneRelation, + modelClass: Branch, + join: { + from: 'sales_invoices.branchId', + to: 'branches.id', + }, + }, - // /** - // * Invoice may has associated warehouse. - // */ - // warehouse: { - // relation: Model.BelongsToOneRelation, - // modelClass: Warehouse.default, - // join: { - // from: 'sales_invoices.warehouseId', - // to: 'warehouses.id', - // }, - // }, + /** + * Invoice may has associated warehouse. + */ + warehouse: { + relation: Model.BelongsToOneRelation, + modelClass: Warehouse, + join: { + from: 'sales_invoices.warehouseId', + to: 'warehouses.id', + }, + }, - // /** - // * Invoice may has associated written-off expense account. - // */ - // writtenoffExpenseAccount: { - // relation: Model.BelongsToOneRelation, - // modelClass: Account.default, - // join: { - // from: 'sales_invoices.writtenoffExpenseAccountId', - // to: 'accounts.id', - // }, - // }, + /** + * Invoice may has associated written-off expense account. + */ + writtenoffExpenseAccount: { + relation: Model.BelongsToOneRelation, + modelClass: Account, + join: { + from: 'sales_invoices.writtenoffExpenseAccountId', + to: 'accounts.id', + }, + }, - // /** - // * Invoice may has associated tax rate transactions. - // */ - // taxes: { - // relation: Model.HasManyRelation, - // modelClass: TaxRateTransaction.default, - // join: { - // from: 'sales_invoices.id', - // to: 'tax_rate_transactions.referenceId', - // }, - // filter(builder) { - // builder.where('reference_type', 'SaleInvoice'); - // }, - // }, + /** + * Invoice may has associated tax rate transactions. + */ + // taxes: { + // relation: Model.HasManyRelation, + // modelClass: TaxRateTransaction.default, + // join: { + // from: 'sales_invoices.id', + // to: 'tax_rate_transactions.referenceId', + // }, + // filter(builder) { + // builder.where('reference_type', 'SaleInvoice'); + // }, + // }, - // /** - // * Sale invoice transaction may has many attached attachments. - // */ - // attachments: { - // relation: Model.ManyToManyRelation, - // modelClass: Document.default, - // join: { - // from: 'sales_invoices.id', - // through: { - // from: 'document_links.modelId', - // to: 'document_links.documentId', - // }, - // to: 'documents.id', - // }, - // filter(query) { - // query.where('model_ref', 'SaleInvoice'); - // }, - // }, + /** + * Sale invoice transaction may has many attached attachments. + */ + attachments: { + relation: Model.ManyToManyRelation, + modelClass: Document, + join: { + from: 'sales_invoices.id', + through: { + from: 'document_links.modelId', + to: 'document_links.documentId', + }, + to: 'documents.id', + }, + filter(query) { + query.where('model_ref', 'SaleInvoice'); + }, + }, - // /** - // * Sale invocie may belongs to matched bank transaction. - // */ - // matchedBankTransaction: { - // relation: Model.HasManyRelation, - // modelClass: MatchedBankTransaction, - // join: { - // from: 'sales_invoices.id', - // to: 'matched_bank_transactions.referenceId', - // }, - // filter(query) { - // query.where('reference_type', 'SaleInvoice'); - // }, - // }, + /** + * Sale invocie may belongs to matched bank transaction. + */ + // matchedBankTransaction: { + // relation: Model.HasManyRelation, + // modelClass: MatchedBankTransaction, + // join: { + // from: 'sales_invoices.id', + // to: 'matched_bank_transactions.referenceId', + // }, + // filter(query) { + // query.where('reference_type', 'SaleInvoice'); + // }, + // }, - // /** - // * Sale invoice may belongs to payment methods entries. - // */ - // paymentMethods: { - // relation: Model.HasManyRelation, - // modelClass: TransactionPaymentServiceEntry, - // join: { - // from: 'sales_invoices.id', - // to: 'transactions_payment_methods.referenceId', - // }, - // beforeInsert: (model) => { - // model.referenceType = 'SaleInvoice'; - // }, - // filter: (query) => { - // query.where('reference_type', 'SaleInvoice'); - // }, - // }, + /** + * Sale invoice may belongs to payment methods entries. + */ + paymentMethods: { + relation: Model.HasManyRelation, + modelClass: TransactionPaymentServiceEntry, + join: { + from: 'sales_invoices.id', + to: 'transactions_payment_methods.referenceId', + }, + beforeInsert: (model) => { + model.referenceType = 'SaleInvoice'; + }, + filter: (query) => { + query.where('reference_type', 'SaleInvoice'); + }, + }, - // /** - // * Sale invoice may belongs to pdf branding template. - // */ - // pdfTemplate: { - // relation: Model.BelongsToOneRelation, - // modelClass: PdfTemplate, - // join: { - // from: 'sales_invoices.pdfTemplateId', - // to: 'pdf_templates.id', - // } - // }, - // }; - // } + /** + * Sale invoice may belongs to pdf branding template. + */ + pdfTemplate: { + relation: Model.BelongsToOneRelation, + modelClass: PdfTemplateModel, + join: { + from: 'sales_invoices.pdfTemplateId', + to: 'pdf_templates.id', + }, + }, + }; + } /** * Change payment amount. @@ -642,9 +655,9 @@ export class SaleInvoice extends BaseModel{ /** * Sale invoice meta. */ - static get meta() { - return SaleInvoiceMeta; - } + // static get meta() { + // return SaleInvoiceMeta; + // } static dueAmountFieldSortQuery(query, role) { query.modify('sortByDueAmount', role.order); @@ -653,9 +666,9 @@ export class SaleInvoice extends BaseModel{ /** * Retrieve the default custom views, roles and columns. */ - static get defaultViews() { - return DEFAULT_VIEWS; - } + // static get defaultViews() { + // return DEFAULT_VIEWS; + // } /** * Model searchable. diff --git a/packages/server-nest/src/modules/SaleInvoices/queries/SaleInvoicePdf.service.ts b/packages/server-nest/src/modules/SaleInvoices/queries/SaleInvoicePdf.service.ts index 320a6d873..183a0ca9d 100644 --- a/packages/server-nest/src/modules/SaleInvoices/queries/SaleInvoicePdf.service.ts +++ b/packages/server-nest/src/modules/SaleInvoices/queries/SaleInvoicePdf.service.ts @@ -47,7 +47,7 @@ export class SaleInvoicePdf { public async getSaleInvoicePdf(invoiceId: number): Promise<[Buffer, string]> { const filename = await this.getInvoicePdfFilename(invoiceId); - const htmlContent = await this.saleInvoiceHtml(invoiceId); + const htmlContent = await this.getSaleInvoiceHtml(invoiceId); // Converts the given html content to pdf document. const buffer = await this.chromiumlyTenancy.convertHtmlContent(htmlContent); diff --git a/packages/server-nest/src/modules/SaleInvoices/SaleInvoiceWriteoffSubscriber.ts b/packages/server-nest/src/modules/SaleInvoices/subscribers/SaleInvoiceWriteoffSubscriber.ts similarity index 100% rename from packages/server-nest/src/modules/SaleInvoices/SaleInvoiceWriteoffSubscriber.ts rename to packages/server-nest/src/modules/SaleInvoices/subscribers/SaleInvoiceWriteoffSubscriber.ts diff --git a/packages/server-nest/src/modules/SaleInvoices/utils.ts b/packages/server-nest/src/modules/SaleInvoices/utils.ts index 0db99bf55..da2b16a87 100644 --- a/packages/server-nest/src/modules/SaleInvoices/utils.ts +++ b/packages/server-nest/src/modules/SaleInvoices/utils.ts @@ -1,3 +1,4 @@ +// @ts-nocheck import { pickBy } from 'lodash'; import { InvoicePdfTemplateAttributes, ISaleInvoice } from '@/interfaces'; import { contactAddressTextFormat } from '@/utils/address-text-format'; diff --git a/packages/server-nest/src/modules/SaleReceipts/SaleReceipts.controller.ts b/packages/server-nest/src/modules/SaleReceipts/SaleReceipts.controller.ts new file mode 100644 index 000000000..da67ca9f0 --- /dev/null +++ b/packages/server-nest/src/modules/SaleReceipts/SaleReceipts.controller.ts @@ -0,0 +1,57 @@ +import { + Body, + Controller, + Delete, + Get, + Param, + ParseIntPipe, + Post, + Put, +} from '@nestjs/common'; +import { ISaleReceiptDTO } from './types/SaleReceipts.types'; +import { SaleReceiptApplication } from './SaleReceiptApplication.service'; +import { PublicRoute } from '../Auth/Jwt.guard'; + +@Controller('sale-receipts') +@PublicRoute() +export class SaleReceiptsController { + constructor(private saleReceiptApplication: SaleReceiptApplication) {} + + @Post() + createSaleReceipt(@Body() saleReceiptDTO: ISaleReceiptDTO) { + return this.saleReceiptApplication.createSaleReceipt(saleReceiptDTO); + } + + @Put(':id') + editSaleReceipt( + @Param('id', ParseIntPipe) id: number, + @Body() saleReceiptDTO: ISaleReceiptDTO, + ) { + return this.saleReceiptApplication.editSaleReceipt(id, saleReceiptDTO); + } + + @Get(':id') + getSaleReceipt(@Param('id', ParseIntPipe) id: number) { + return this.saleReceiptApplication.getSaleReceipt(id); + } + + @Delete(':id') + deleteSaleReceipt(@Param('id', ParseIntPipe) id: number) { + return this.saleReceiptApplication.deleteSaleReceipt(id); + } + + @Post(':id/close') + closeSaleReceipt(@Param('id', ParseIntPipe) id: number) { + return this.saleReceiptApplication.closeSaleReceipt(id); + } + + @Get(':id/pdf') + getSaleReceiptPdf(@Param('id', ParseIntPipe) id: number) { + return this.saleReceiptApplication.getSaleReceiptPdf(0, id); + } + + @Get('state') + getSaleReceiptState() { + return this.saleReceiptApplication.getSaleReceiptState(); + } +} diff --git a/packages/server-nest/src/modules/SaleReceipts/SaleReceipts.module.ts b/packages/server-nest/src/modules/SaleReceipts/SaleReceipts.module.ts index 9b7f8b69a..f38ffd261 100644 --- a/packages/server-nest/src/modules/SaleReceipts/SaleReceipts.module.ts +++ b/packages/server-nest/src/modules/SaleReceipts/SaleReceipts.module.ts @@ -5,15 +5,47 @@ import { EditSaleReceipt } from './commands/EditSaleReceipt.service'; import { GetSaleReceipt } from './queries/GetSaleReceipt.service'; import { DeleteSaleReceipt } from './commands/DeleteSaleReceipt.service'; import { CloseSaleReceipt } from './commands/CloseSaleReceipt.service'; +import { SaleReceiptsPdfService } from './queries/SaleReceiptsPdf.service'; +import { GetSaleReceiptState } from './queries/GetSaleReceiptState.service'; +import { ItemsModule } from '../Items/items.module'; +import { SaleReceiptDTOTransformer } from './commands/SaleReceiptDTOTransformer.service'; +import { SaleReceiptValidators } from './commands/SaleReceiptValidators.service'; +import { ChromiumlyTenancyModule } from '../ChromiumlyTenancy/ChromiumlyTenancy.module'; +import { TemplateInjectableModule } from '../TemplateInjectable/TemplateInjectable.module'; +import { TenancyContext } from '../Tenancy/TenancyContext.service'; +import { SaleReceiptBrandingTemplate } from './queries/SaleReceiptBrandingTemplate.service'; +import { BranchesModule } from '../Branches/Branches.module'; +import { WarehousesModule } from '../Warehouses/Warehouses.module'; +import { SaleReceiptIncrement } from './commands/SaleReceiptIncrement.service'; +import { PdfTemplatesModule } from '../PdfTemplate/PdfTemplates.module'; +import { AutoIncrementOrdersModule } from '../AutoIncrementOrders/AutoIncrementOrders.module'; +import { SaleReceiptsController } from './SaleReceipts.controller'; @Module({ + controllers: [SaleReceiptsController], + imports: [ + ItemsModule, + ChromiumlyTenancyModule, + TemplateInjectableModule, + BranchesModule, + WarehousesModule, + PdfTemplatesModule, + AutoIncrementOrdersModule + ], providers: [ + TenancyContext, + SaleReceiptValidators, SaleReceiptApplication, CreateSaleReceipt, EditSaleReceipt, GetSaleReceipt, DeleteSaleReceipt, CloseSaleReceipt, + SaleReceiptsPdfService, + GetSaleReceiptState, + SaleReceiptDTOTransformer, + SaleReceiptBrandingTemplate, + SaleReceiptIncrement, ], }) export class SaleReceiptsModule {} diff --git a/packages/server-nest/src/modules/SaleReceipts/commands/SaleReceiptDTOTransformer.service.ts b/packages/server-nest/src/modules/SaleReceipts/commands/SaleReceiptDTOTransformer.service.ts index 36cbae751..5f05ac367 100644 --- a/packages/server-nest/src/modules/SaleReceipts/commands/SaleReceiptDTOTransformer.service.ts +++ b/packages/server-nest/src/modules/SaleReceipts/commands/SaleReceiptDTOTransformer.service.ts @@ -1,7 +1,7 @@ import { Inject, Injectable } from '@nestjs/common'; import * as R from 'ramda'; import { sumBy, omit } from 'lodash'; -import composeAsync from 'async/compose'; +import * as composeAsync from 'async/compose'; import moment from 'moment'; import { SaleReceiptIncrement } from './SaleReceiptIncrement.service'; import { ItemsEntriesService } from '@/modules/Items/ItemsEntries.service'; @@ -18,6 +18,15 @@ import { Customer } from '@/modules/Customers/models/Customer'; @Injectable() export class SaleReceiptDTOTransformer { + /** + * @param {ItemsEntriesService} itemsEntriesService - Items entries service. + * @param {BranchTransactionDTOTransformer} branchDTOTransform - Branch transaction DTO transformer. + * @param {WarehouseTransactionDTOTransform} warehouseDTOTransform - Warehouse transaction DTO transformer. + * @param {SaleReceiptValidators} validators - Sale receipt validators. + * @param {SaleReceiptIncrement} receiptIncrement - Sale receipt increment. + * @param {BrandingTemplateDTOTransformer} brandingTemplatesTransformer - Branding template DTO transformer. + * @param {typeof ItemEntry} itemEntryModel - Item entry model. + */ constructor( private readonly itemsEntriesService: ItemsEntriesService, private readonly branchDTOTransform: BranchTransactionDTOTransformer, @@ -60,10 +69,9 @@ export class SaleReceiptDTOTransformer { reference_type: 'SaleReceipt', ...entry, })); - const asyncEntries = await composeAsync( // Sets default cost and sell account to receipt items entries. - this.itemsEntriesService.setItemsEntriesDefaultAccounts(), + this.itemsEntriesService.setItemsEntriesDefaultAccounts, )(initialEntries); const entries = R.compose( @@ -97,6 +105,6 @@ export class SaleReceiptDTOTransformer { return R.compose( this.branchDTOTransform.transformDTO, this.warehouseDTOTransform.transformDTO, - )(initialAsyncDTO); + )(initialAsyncDTO) as SaleReceipt; } } diff --git a/packages/server-nest/src/modules/SaleReceipts/commands/SaleReceiptValidators.service.ts b/packages/server-nest/src/modules/SaleReceipts/commands/SaleReceiptValidators.service.ts index 3068929cb..58f0eafc3 100644 --- a/packages/server-nest/src/modules/SaleReceipts/commands/SaleReceiptValidators.service.ts +++ b/packages/server-nest/src/modules/SaleReceipts/commands/SaleReceiptValidators.service.ts @@ -12,8 +12,8 @@ export class SaleReceiptValidators { * @param {typeof Account} accountModel - Account model. */ constructor( - @Inject(SaleReceipt) private saleReceiptModel: typeof SaleReceipt, - @Inject(Account) private accountModel: typeof Account, + @Inject(SaleReceipt.name) private saleReceiptModel: typeof SaleReceipt, + @Inject(Account.name) private accountModel: typeof Account, ) {} /** diff --git a/packages/server-nest/src/modules/SaleReceipts/models/SaleReceipt.ts b/packages/server-nest/src/modules/SaleReceipts/models/SaleReceipt.ts index 8f8b784ff..8b572fd4e 100644 --- a/packages/server-nest/src/modules/SaleReceipts/models/SaleReceipt.ts +++ b/packages/server-nest/src/modules/SaleReceipts/models/SaleReceipt.ts @@ -119,18 +119,18 @@ export class SaleReceipt extends BaseModel { * Relationship mapping. */ static get relationMappings() { - const Customer = require('@/modules/Customers/models/Customer'); - const Account = require('@/modules/Accounts/models/Account.model'); - const AccountTransaction = require('@/modules/AccountsTransactions/models/AccountTransaction.model'); - const ItemEntry = require('@/modules/ItemsEntries/models/ItemEntry'); - const Branch = require('@/modules/Branches/models/Branch'); - const Document = require('@/modules/Documents/models/Document'); - const Warehouse = require('@/modules/Warehouses/models/Warehouse'); + const { Customer } = require('../../Customers/models/Customer'); + const { Account } = require('../../Accounts/models/Account.model'); + const { AccountTransaction } = require('../../Accounts/models/AccountTransaction.model'); + const { ItemEntry } = require('../../TransactionItemEntry/models/ItemEntry'); + const { Branch } = require('../../Branches/models/Branch.model'); + const { Document } = require('../../ChromiumlyTenancy/models/Document'); + const { Warehouse } = require('../../Warehouses/models/Warehouse.model'); return { customer: { relation: Model.BelongsToOneRelation, - modelClass: Customer.default, + modelClass: Customer, join: { from: 'sales_receipts.customerId', to: 'contacts.id', @@ -142,7 +142,7 @@ export class SaleReceipt extends BaseModel { depositAccount: { relation: Model.BelongsToOneRelation, - modelClass: Account.default, + modelClass: Account, join: { from: 'sales_receipts.depositAccountId', to: 'accounts.id', @@ -151,7 +151,7 @@ export class SaleReceipt extends BaseModel { entries: { relation: Model.HasManyRelation, - modelClass: ItemEntry.default, + modelClass: ItemEntry, join: { from: 'sales_receipts.id', to: 'items_entries.referenceId', @@ -164,7 +164,7 @@ export class SaleReceipt extends BaseModel { transactions: { relation: Model.HasManyRelation, - modelClass: AccountTransaction.default, + modelClass: AccountTransaction, join: { from: 'sales_receipts.id', to: 'accounts_transactions.referenceId', @@ -179,7 +179,7 @@ export class SaleReceipt extends BaseModel { */ branch: { relation: Model.BelongsToOneRelation, - modelClass: Branch.default, + modelClass: Branch, join: { from: 'sales_receipts.branchId', to: 'branches.id', @@ -191,7 +191,7 @@ export class SaleReceipt extends BaseModel { */ warehouse: { relation: Model.BelongsToOneRelation, - modelClass: Warehouse.default, + modelClass: Warehouse, join: { from: 'sales_receipts.warehouseId', to: 'warehouses.id', @@ -203,7 +203,7 @@ export class SaleReceipt extends BaseModel { */ attachments: { relation: Model.ManyToManyRelation, - modelClass: Document.default, + modelClass: Document, join: { from: 'sales_receipts.id', through: { diff --git a/packages/server-nest/src/modules/SaleReceipts/queries/GetSaleReceipt.service.ts b/packages/server-nest/src/modules/SaleReceipts/queries/GetSaleReceipt.service.ts index ad3a7174b..ca58148ed 100644 --- a/packages/server-nest/src/modules/SaleReceipts/queries/GetSaleReceipt.service.ts +++ b/packages/server-nest/src/modules/SaleReceipts/queries/GetSaleReceipt.service.ts @@ -1,4 +1,4 @@ -import { Injectable } from '@nestjs/common'; +import { Inject, Injectable } from '@nestjs/common'; import { SaleReceiptTransformer } from './SaleReceiptTransformer'; import { SaleReceiptValidators } from '../commands/SaleReceiptValidators.service'; import { SaleReceipt } from '../models/SaleReceipt'; @@ -7,6 +7,7 @@ import { TransformerInjectable } from '@/modules/Transformer/TransformerInjectab @Injectable() export class GetSaleReceipt { constructor( + @Inject(SaleReceipt.name) private readonly saleReceiptModel: typeof SaleReceipt, private readonly transformer: TransformerInjectable, private readonly validators: SaleReceiptValidators, @@ -26,11 +27,11 @@ export class GetSaleReceipt { .withGraphFetched('depositAccount') .withGraphFetched('branch') .withGraphFetched('attachments') - .throwIfNotFound() + .throwIfNotFound(); return this.transformer.transform( saleReceipt, - new SaleReceiptTransformer() + new SaleReceiptTransformer(), ); } } diff --git a/packages/server-nest/src/modules/TaxRates/ItemEntriesTaxTransactions.service.ts b/packages/server-nest/src/modules/TaxRates/ItemEntriesTaxTransactions.service.ts index 760b6bccb..be8948e91 100644 --- a/packages/server-nest/src/modules/TaxRates/ItemEntriesTaxTransactions.service.ts +++ b/packages/server-nest/src/modules/TaxRates/ItemEntriesTaxTransactions.service.ts @@ -15,7 +15,7 @@ export class ItemEntriesTaxTransactions { * @param model * @returns */ - public assocTaxAmountWithheldFromEntries(model: any) { + public assocTaxAmountWithheldFromEntries = (model: any) => { const entries = model.entries.map((entry) => this.itemEntryModel.fromJson(entry), ); diff --git a/packages/server-nest/src/modules/TaxRates/TaxRate.module.ts b/packages/server-nest/src/modules/TaxRates/TaxRate.module.ts index 493baf713..b07e6a9c9 100644 --- a/packages/server-nest/src/modules/TaxRates/TaxRate.module.ts +++ b/packages/server-nest/src/modules/TaxRates/TaxRate.module.ts @@ -10,6 +10,7 @@ import { EditTaxRateService } from './commands/EditTaxRate.service'; import { CommandTaxRatesValidators } from './commands/CommandTaxRatesValidator.service'; import { TenancyContext } from '../Tenancy/TenancyContext.service'; import { TaxRatesApplication } from './TaxRate.application'; +import { ItemEntriesTaxTransactions } from './ItemEntriesTaxTransactions.service'; @Module({ imports: [], @@ -24,7 +25,9 @@ import { TaxRatesApplication } from './TaxRate.application'; CommandTaxRatesValidators, TransformerInjectable, TenancyContext, - TaxRatesApplication + TaxRatesApplication, + ItemEntriesTaxTransactions ], + exports: [ItemEntriesTaxTransactions], }) export class TaxRatesModule {} diff --git a/packages/server-nest/src/modules/TemplateInjectable/TemplateInjectable.module.ts b/packages/server-nest/src/modules/TemplateInjectable/TemplateInjectable.module.ts index 362147d80..1e37c3c6f 100644 --- a/packages/server-nest/src/modules/TemplateInjectable/TemplateInjectable.module.ts +++ b/packages/server-nest/src/modules/TemplateInjectable/TemplateInjectable.module.ts @@ -1,7 +1,9 @@ import { Module } from '@nestjs/common'; import { TemplateInjectable } from './TemplateInjectable.service'; +import { TenancyContext } from '../Tenancy/TenancyContext.service'; @Module({ - providers: [TemplateInjectable], + providers: [TemplateInjectable, TenancyContext], + exports: [TemplateInjectable] }) export class TemplateInjectableModule {} diff --git a/packages/server-nest/src/modules/Tenancy/TenancyModels/Tenancy.module.ts b/packages/server-nest/src/modules/Tenancy/TenancyModels/Tenancy.module.ts index 4f85a051b..086b84a1e 100644 --- a/packages/server-nest/src/modules/Tenancy/TenancyModels/Tenancy.module.ts +++ b/packages/server-nest/src/modules/Tenancy/TenancyModels/Tenancy.module.ts @@ -7,7 +7,7 @@ import { Account } from '@/modules/Accounts/models/Account.model'; import { ItemEntry } from '@/modules/Items/models/ItemEntry'; import { AccountTransaction } from '@/modules/Accounts/models/AccountTransaction.model'; import { Expense } from '@/modules/Expenses/models/Expense.model'; -import ExpenseCategory from '@/modules/Expenses/models/ExpenseCategory.model'; +import { ExpenseCategory } from '@/modules/Expenses/models/ExpenseCategory.model'; import { ItemCategory } from '@/modules/ItemCategories/models/ItemCategory.model'; import { TaxRateModel } from '@/modules/TaxRates/models/TaxRate.model'; import { PdfTemplateModel } from '@/modules/PdfTemplate/models/PdfTemplate'; @@ -20,6 +20,18 @@ import { Contact } from '@/modules/Contacts/models/Contact'; import { Document } from '@/modules/ChromiumlyTenancy/models/Document'; import { DocumentLink } from '@/modules/ChromiumlyTenancy/models/DocumentLink'; import { Vendor } from '@/modules/Vendors/models/Vendor'; +import { Bill } from '@/modules/Bills/models/Bill'; +import { BillPayment } from '@/modules/BillPayments/models/BillPayment'; +import { BillPaymentEntry } from '@/modules/BillPayments/models/BillPaymentEntry'; +import { BillLandedCostEntry } from '@/modules/BillLandedCosts/models/BillLandedCostEntry'; +import { BillLandedCost } from '@/modules/BillLandedCosts/models/BillLandedCost'; +import { VendorCreditAppliedBill } from '@/modules/VendorCredit/models/VendorCreditAppliedBill'; +import { SaleInvoice } from '@/modules/SaleInvoices/models/SaleInvoice'; +import { PaymentReceivedEntry } from '@/modules/PaymentReceived/models/PaymentReceivedEntry'; +import { CreditNoteAppliedInvoice } from '@/modules/CreditNotes/models/CreditNoteAppliedInvoice'; +import { CreditNote } from '@/modules/CreditNotes/models/CreditNote'; +import { PaymentLink } from '@/modules/PaymentLinks/models/PaymentLink'; +import { SaleReceipt } from '@/modules/SaleReceipts/models/SaleReceipt'; const models = [ Item, @@ -39,7 +51,19 @@ const models = [ Contact, Document, DocumentLink, - Vendor + Vendor, + Bill, + BillPayment, + BillPaymentEntry, + BillLandedCost, + BillLandedCostEntry, + VendorCreditAppliedBill, + SaleInvoice, + PaymentReceivedEntry, + CreditNoteAppliedInvoice, + CreditNote, + PaymentLink, + SaleReceipt ]; const modelProviders = models.map((model) => { diff --git a/packages/server-nest/src/modules/TransactionItemEntry/models/ItemEntry.ts b/packages/server-nest/src/modules/TransactionItemEntry/models/ItemEntry.ts index 2e7ce0430..443df65f3 100644 --- a/packages/server-nest/src/modules/TransactionItemEntry/models/ItemEntry.ts +++ b/packages/server-nest/src/modules/TransactionItemEntry/models/ItemEntry.ts @@ -124,121 +124,121 @@ export class ItemEntry extends BaseModel { /** * Item entry relations. */ - static get relationMappings() { - const Item = require('models/Item'); - const BillLandedCostEntry = require('models/BillLandedCostEntry'); - const SaleInvoice = require('models/SaleInvoice'); - const Bill = require('models/Bill'); - const SaleReceipt = require('models/SaleReceipt'); - const SaleEstimate = require('models/SaleEstimate'); - const ProjectTask = require('models/Task'); - const Expense = require('models/Expense'); - const TaxRate = require('models/TaxRate'); + // static get relationMappings() { + // const Item = require('models/Item'); + // const BillLandedCostEntry = require('models/BillLandedCostEntry'); + // const SaleInvoice = require('models/SaleInvoice'); + // const Bill = require('models/Bill'); + // const SaleReceipt = require('models/SaleReceipt'); + // const SaleEstimate = require('models/SaleEstimate'); + // const ProjectTask = require('models/Task'); + // const Expense = require('models/Expense'); + // const TaxRate = require('models/TaxRate'); - return { - item: { - relation: Model.BelongsToOneRelation, - modelClass: Item.default, - join: { - from: 'items_entries.itemId', - to: 'items.id', - }, - }, - allocatedCostEntries: { - relation: Model.HasManyRelation, - modelClass: BillLandedCostEntry.default, - join: { - from: 'items_entries.referenceId', - to: 'bill_located_cost_entries.entryId', - }, - }, + // return { + // item: { + // relation: Model.BelongsToOneRelation, + // modelClass: Item.default, + // join: { + // from: 'items_entries.itemId', + // to: 'items.id', + // }, + // }, + // allocatedCostEntries: { + // relation: Model.HasManyRelation, + // modelClass: BillLandedCostEntry.default, + // join: { + // from: 'items_entries.referenceId', + // to: 'bill_located_cost_entries.entryId', + // }, + // }, - invoice: { - relation: Model.BelongsToOneRelation, - modelClass: SaleInvoice.default, - join: { - from: 'items_entries.referenceId', - to: 'sales_invoices.id', - }, - }, + // invoice: { + // relation: Model.BelongsToOneRelation, + // modelClass: SaleInvoice.default, + // join: { + // from: 'items_entries.referenceId', + // to: 'sales_invoices.id', + // }, + // }, - bill: { - relation: Model.BelongsToOneRelation, - modelClass: Bill.default, - join: { - from: 'items_entries.referenceId', - to: 'bills.id', - }, - }, + // bill: { + // relation: Model.BelongsToOneRelation, + // modelClass: Bill.default, + // join: { + // from: 'items_entries.referenceId', + // to: 'bills.id', + // }, + // }, - estimate: { - relation: Model.BelongsToOneRelation, - modelClass: SaleEstimate.default, - join: { - from: 'items_entries.referenceId', - to: 'sales_estimates.id', - }, - }, + // estimate: { + // relation: Model.BelongsToOneRelation, + // modelClass: SaleEstimate.default, + // join: { + // from: 'items_entries.referenceId', + // to: 'sales_estimates.id', + // }, + // }, - /** - * Sale receipt reference. - */ - receipt: { - relation: Model.BelongsToOneRelation, - modelClass: SaleReceipt.default, - join: { - from: 'items_entries.referenceId', - to: 'sales_receipts.id', - }, - }, + // /** + // * Sale receipt reference. + // */ + // receipt: { + // relation: Model.BelongsToOneRelation, + // modelClass: SaleReceipt.default, + // join: { + // from: 'items_entries.referenceId', + // to: 'sales_receipts.id', + // }, + // }, - /** - * Project task reference. - */ - projectTaskRef: { - relation: Model.HasManyRelation, - modelClass: ProjectTask.default, - join: { - from: 'items_entries.projectRefId', - to: 'tasks.id', - }, - }, + // /** + // * Project task reference. + // */ + // projectTaskRef: { + // relation: Model.HasManyRelation, + // modelClass: ProjectTask.default, + // join: { + // from: 'items_entries.projectRefId', + // to: 'tasks.id', + // }, + // }, - /** - * Project expense reference. - */ - projectExpenseRef: { - relation: Model.HasManyRelation, - modelClass: Expense.default, - join: { - from: 'items_entries.projectRefId', - to: 'expenses_transactions.id', - }, - }, + // /** + // * Project expense reference. + // */ + // projectExpenseRef: { + // relation: Model.HasManyRelation, + // modelClass: Expense.default, + // join: { + // from: 'items_entries.projectRefId', + // to: 'expenses_transactions.id', + // }, + // }, - /** - * Project bill reference. - */ - projectBillRef: { - relation: Model.HasManyRelation, - modelClass: Bill.default, - join: { - from: 'items_entries.projectRefId', - to: 'bills.id', - }, - }, + // /** + // * Project bill reference. + // */ + // projectBillRef: { + // relation: Model.HasManyRelation, + // modelClass: Bill.default, + // join: { + // from: 'items_entries.projectRefId', + // to: 'bills.id', + // }, + // }, - /** - * Tax rate reference. - */ - tax: { - relation: Model.HasOneRelation, - modelClass: TaxRate.default, - join: { - from: 'items_entries.taxRateId', - to: 'tax_rates.id', - }, - }, - }; - } + // /** + // * Tax rate reference. + // */ + // tax: { + // relation: Model.HasOneRelation, + // modelClass: TaxRate.default, + // join: { + // from: 'items_entries.taxRateId', + // to: 'tax_rates.id', + // }, + // }, + // }; + // } } diff --git a/packages/server-nest/src/modules/Transformer/Transformer.module.ts b/packages/server-nest/src/modules/Transformer/Transformer.module.ts index 457c7d5f0..d9fa90cbb 100644 --- a/packages/server-nest/src/modules/Transformer/Transformer.module.ts +++ b/packages/server-nest/src/modules/Transformer/Transformer.module.ts @@ -4,8 +4,8 @@ import { TenancyContext } from '../Tenancy/TenancyContext.service'; @Global() @Module({ - providers: [TransformerInjectable], + providers: [TransformerInjectable, TenancyContext], exports: [TransformerInjectable], - imports: [TenancyContext], + imports: [], }) export class TransformerModule {} diff --git a/packages/server-nest/src/modules/VendorCredit/models/VendorCredit.ts b/packages/server-nest/src/modules/VendorCredit/models/VendorCredit.ts new file mode 100644 index 000000000..b95d0924a --- /dev/null +++ b/packages/server-nest/src/modules/VendorCredit/models/VendorCredit.ts @@ -0,0 +1,296 @@ +import { Model, raw, mixin } from 'objection'; +// import TenantModel from 'models/TenantModel'; +// import BillSettings from './Bill.Settings'; +// import ModelSetting from './ModelSetting'; +// import CustomViewBaseModel from './CustomViewBaseModel'; +// import { DEFAULT_VIEWS } from '@/services/Purchases/VendorCredits/constants'; +// import ModelSearchable from './ModelSearchable'; +// import VendorCreditMeta from './VendorCredit.Meta'; +import { BaseModel } from '@/models/Model'; + +export class VendorCredit extends BaseModel { + vendorId: number; + amount: number; + currencyCode: string; + vendorCreditDate: Date; + vendorCreditNumber: string; + referenceNo: string; + refundedAmount: number; + invoicedAmount: number; + exchangeRate: number; + note: string; + openedAt: Date; + userId: number; + + /** + * Table name + */ + static get tableName() { + return 'vendor_credits'; + } + + /** + * Vendor credit amount in local currency. + * @returns {number} + */ + get localAmount() { + return this.amount * this.exchangeRate; + } + + /** + * Model modifiers. + */ + static get modifiers() { + return { + /** + * Filters the credit notes in draft status. + */ + draft(query) { + query.where('opened_at', null); + }, + + /** + * Filters the published vendor credits. + */ + published(query) { + query.whereNot('opened_at', null); + }, + + /** + * Filters the open vendor credits. + */ + open(query) { + query + .where( + raw(`COALESCE(REFUNDED_AMOUNT) + COALESCE(INVOICED_AMOUNT) < + COALESCE(AMOUNT)`), + ) + .modify('published'); + }, + + /** + * Filters the closed vendor credits. + */ + closed(query) { + query + .where( + raw(`COALESCE(REFUNDED_AMOUNT) + COALESCE(INVOICED_AMOUNT) = + COALESCE(AMOUNT)`), + ) + .modify('published'); + }, + + /** + * Status filter. + */ + filterByStatus(query, filterType) { + switch (filterType) { + case 'draft': + query.modify('draft'); + break; + case 'published': + query.modify('published'); + break; + case 'open': + default: + query.modify('open'); + break; + case 'closed': + query.modify('closed'); + break; + } + }, + + /** + * + */ + sortByStatus(query, order) { + query.orderByRaw( + `COALESCE(REFUNDED_AMOUNT) + COALESCE(INVOICED_AMOUNT) = COALESCE(AMOUNT) ${order}`, + ); + }, + }; + } + + /** + * Timestamps columns. + */ + get timestamps() { + return ['createdAt', 'updatedAt']; + } + + /** + * Virtual attributes. + */ + static get virtualAttributes() { + return [ + 'localAmount', + 'isDraft', + 'isPublished', + 'isOpen', + 'isClosed', + 'creditsRemaining', + ]; + } + + /** + * Detarmines whether the vendor credit is draft. + * @returns {boolean} + */ + get isDraft() { + return !this.openedAt; + } + + /** + * Detarmines whether vendor credit is published. + * @returns {boolean} + */ + get isPublished() { + return !!this.openedAt; + } + + /** + * Detarmines whether the credit note is open. + * @return {boolean} + */ + get isOpen() { + return !!this.openedAt && this.creditsRemaining > 0; + } + + /** + * Detarmines whether the credit note is closed. + * @return {boolean} + */ + get isClosed() { + return this.openedAt && this.creditsRemaining === 0; + } + + /** + * Retrieve the credits remaining. + * @returns {number} + */ + get creditsRemaining() { + return Math.max(this.amount - this.refundedAmount - this.invoicedAmount, 0); + } + + /** + * Bill model settings. + */ + // static get meta() { + // return BillSettings; + // } + + /** + * Relationship mapping. + */ + // static get relationMappings() { + // const Vendor = require('models/Vendor'); + // const ItemEntry = require('models/ItemEntry'); + // const Branch = require('models/Branch'); + // const Document = require('models/Document'); + // const Warehouse = require('models/Warehouse'); + + // return { + // vendor: { + // relation: Model.BelongsToOneRelation, + // modelClass: Vendor.default, + // join: { + // from: 'vendor_credits.vendorId', + // to: 'contacts.id', + // }, + // filter(query) { + // query.where('contact_service', 'vendor'); + // }, + // }, + + // entries: { + // relation: Model.HasManyRelation, + // modelClass: ItemEntry.default, + // join: { + // from: 'vendor_credits.id', + // to: 'items_entries.referenceId', + // }, + // filter(builder) { + // builder.where('reference_type', 'VendorCredit'); + // builder.orderBy('index', 'ASC'); + // }, + // }, + + // /** + // * Vendor credit may belongs to branch. + // */ + // branch: { + // relation: Model.BelongsToOneRelation, + // modelClass: Branch.default, + // join: { + // from: 'vendor_credits.branchId', + // to: 'branches.id', + // }, + // }, + + // /** + // * Vendor credit may has associated warehouse. + // */ + // warehouse: { + // relation: Model.BelongsToOneRelation, + // modelClass: Warehouse.default, + // join: { + // from: 'vendor_credits.warehouseId', + // to: 'warehouses.id', + // }, + // }, + + // /** + // * Vendor credit may has many attached attachments. + // */ + // attachments: { + // relation: Model.ManyToManyRelation, + // modelClass: Document.default, + // join: { + // from: 'vendor_credits.id', + // through: { + // from: 'document_links.modelId', + // to: 'document_links.documentId', + // }, + // to: 'documents.id', + // }, + // filter(query) { + // query.where('model_ref', 'VendorCredit'); + // }, + // }, + // }; + // } + + /** + * + */ + // static get meta() { + // return VendorCreditMeta; + // } + + /** + * Retrieve the default custom views, roles and columns. + */ + // static get defaultViews() { + // return DEFAULT_VIEWS; + // } + + /** + * Model search attributes. + */ + static get searchRoles() { + return [ + { fieldKey: 'credit_number', comparator: 'contains' }, + { condition: 'or', fieldKey: 'reference_no', comparator: 'contains' }, + { condition: 'or', fieldKey: 'amount', comparator: 'equals' }, + ]; + } + + /** + * Prevents mutate base currency since the model is not empty. + * @returns {boolean} + */ + static get preventMutateBaseCurrency() { + return true; + } +} diff --git a/packages/server-nest/src/modules/VendorCredit/models/VendorCreditAppliedBill.ts b/packages/server-nest/src/modules/VendorCredit/models/VendorCreditAppliedBill.ts new file mode 100644 index 000000000..a74895958 --- /dev/null +++ b/packages/server-nest/src/modules/VendorCredit/models/VendorCreditAppliedBill.ts @@ -0,0 +1,50 @@ +import { mixin, Model } from 'objection'; +// import TenantModel from 'models/TenantModel'; +// import ModelSetting from './ModelSetting'; +// import CustomViewBaseModel from './CustomViewBaseModel'; +// import ModelSearchable from './ModelSearchable'; +import { BaseModel } from '@/models/Model'; + +export class VendorCreditAppliedBill extends BaseModel { + /** + * Table name + */ + static get tableName() { + return 'vendor_credit_applied_bill'; + } + + /** + * Timestamps columns. + */ + get timestamps() { + return ['created_at', 'updated_at']; + } + + /** + * Relationship mapping. + */ + static get relationMappings() { + const { Bill } = require('../../Bills/models/Bill'); + const { VendorCredit } = require('../../VendorCredit/models/VendorCredit'); + + return { + bill: { + relation: Model.BelongsToOneRelation, + modelClass: Bill, + join: { + from: 'vendor_credit_applied_bill.billId', + to: 'bills.id', + }, + }, + + vendorCredit: { + relation: Model.BelongsToOneRelation, + modelClass: VendorCredit, + join: { + from: 'vendor_credit_applied_bill.vendorCreditId', + to: 'vendor_credits.id', + }, + }, + }; + } +} diff --git a/packages/server-nest/src/modules/Vendors/Vendors.controller.ts b/packages/server-nest/src/modules/Vendors/Vendors.controller.ts index a98951e7f..7d7bb68ee 100644 --- a/packages/server-nest/src/modules/Vendors/Vendors.controller.ts +++ b/packages/server-nest/src/modules/Vendors/Vendors.controller.ts @@ -13,8 +13,10 @@ import { IVendorNewDTO, IVendorOpeningBalanceEditDTO, } from './types/Vendors.types'; +import { PublicRoute } from '../Auth/Jwt.guard'; @Controller('vendors') +@PublicRoute() export class VendorsController { constructor(private vendorsApplication: VendorsApplication) {} diff --git a/packages/server-nest/src/modules/Vendors/commands/DeleteVendor.service.ts b/packages/server-nest/src/modules/Vendors/commands/DeleteVendor.service.ts index 49b3ab82e..0fc84c78f 100644 --- a/packages/server-nest/src/modules/Vendors/commands/DeleteVendor.service.ts +++ b/packages/server-nest/src/modules/Vendors/commands/DeleteVendor.service.ts @@ -19,7 +19,7 @@ export class DeleteVendorService { constructor( private eventPublisher: EventEmitter2, private uow: UnitOfWork, - @Inject(Vendor.name) private contactModel: typeof Vendor, + @Inject(Vendor.name) private vendorModel: typeof Vendor, ) {} /** @@ -29,9 +29,8 @@ export class DeleteVendorService { */ public async deleteVendor(vendorId: number) { // Retrieves the old vendor or throw not found service error. - const oldVendor = await this.contactModel + const oldVendor = await this.vendorModel .query() - .modify('vendor') .findById(vendorId) .throwIfNotFound(); // .queryAndThrowIfHasRelations({ @@ -47,7 +46,7 @@ export class DeleteVendorService { // Deletes vendor contact under unit-of-work. return this.uow.withTransaction(async (trx: Knex.Transaction) => { // Deletes the vendor contact from the storage. - await this.contactModel.query(trx).findById(vendorId).delete(); + await this.vendorModel.query(trx).findById(vendorId).delete(); // Triggers `onVendorDeleted` event. await this.eventPublisher.emitAsync(events.vendors.onDeleted, { diff --git a/packages/server-nest/src/modules/Vendors/models/Vendor.ts b/packages/server-nest/src/modules/Vendors/models/Vendor.ts index 36be15685..c8746d191 100644 --- a/packages/server-nest/src/modules/Vendors/models/Vendor.ts +++ b/packages/server-nest/src/modules/Vendors/models/Vendor.ts @@ -170,7 +170,7 @@ export class Vendor extends BaseModel { return { bills: { relation: Model.HasManyRelation, - modelClass: Bill.default, + modelClass: Bill, join: { from: 'contacts.id', to: 'bills.vendorId', @@ -178,7 +178,7 @@ export class Vendor extends BaseModel { }, overdueBills: { relation: Model.HasManyRelation, - modelClass: Bill.default, + modelClass: Bill, join: { from: 'contacts.id', to: 'bills.vendorId', diff --git a/packages/server-nest/src/modules/Vendors/queries/GetVendor.ts b/packages/server-nest/src/modules/Vendors/queries/GetVendor.ts index bd29569ac..aa9b9a4d3 100644 --- a/packages/server-nest/src/modules/Vendors/queries/GetVendor.ts +++ b/packages/server-nest/src/modules/Vendors/queries/GetVendor.ts @@ -18,7 +18,6 @@ export class GetVendorService { const vendor = await this.vendorModel .query() .findById(vendorId) - .modify('vendor') .throwIfNotFound(); // Transformes the vendor. diff --git a/packages/server-nest/src/modules/Warehouses/Warehouses.module.ts b/packages/server-nest/src/modules/Warehouses/Warehouses.module.ts index ebff07373..bf44b13da 100644 --- a/packages/server-nest/src/modules/Warehouses/Warehouses.module.ts +++ b/packages/server-nest/src/modules/Warehouses/Warehouses.module.ts @@ -16,6 +16,7 @@ import { ActivateWarehousesService } from './commands/ActivateWarehouses.service import { CreateInitialWarehouse } from './commands/CreateInitialWarehouse.service'; import { WarehousesSettings } from './WarehousesSettings'; import { I18nContext } from 'nestjs-i18n'; +import { WarehouseTransactionDTOTransform } from './Integrations/WarehouseTransactionDTOTransform'; @Module({ imports: [TenancyDatabaseModule], @@ -36,6 +37,8 @@ import { I18nContext } from 'nestjs-i18n'; I18nContext, TenancyContext, TransformerInjectable, + WarehouseTransactionDTOTransform ], + exports: [WarehouseTransactionDTOTransform], }) export class WarehousesModule {} diff --git a/packages/server-nest/src/utils/transform-to-key.ts b/packages/server-nest/src/utils/transform-to-key.ts new file mode 100644 index 000000000..dc9783c58 --- /dev/null +++ b/packages/server-nest/src/utils/transform-to-key.ts @@ -0,0 +1,9 @@ + +export const transformToMap = (objects, key) => { + const map = new Map(); + + objects.forEach((object) => { + map.set(object[key], object); + }); + return map; +}; diff --git a/packages/server-nest/test/customers.e2e-spec.ts b/packages/server-nest/test/customers.e2e-spec.ts new file mode 100644 index 000000000..25e370d32 --- /dev/null +++ b/packages/server-nest/test/customers.e2e-spec.ts @@ -0,0 +1,82 @@ +import * as request from 'supertest'; +import { faker } from '@faker-js/faker'; +import { app } from './init-app-test'; + +describe('Customers (e2e)', () => { + it('/customers (POST)', () => { + return request(app.getHttpServer()) + .post('/customers') + .set('organization-id', '4064541lv40nhca') + .send({ + customerType: 'business', + displayName: faker.commerce.productName(), + email: faker.internet.email(), + firstName: faker.person.firstName(), + lastName: faker.person.lastName(), + }) + .expect(201); + }); + + it('/customers/:id (GET)', async () => { + const response = await request(app.getHttpServer()) + .post('/customers') + .set('organization-id', '4064541lv40nhca') + .send({ + customerType: 'business', + displayName: faker.commerce.productName(), + email: faker.internet.email(), + firstName: faker.person.firstName(), + lastName: faker.person.lastName(), + }); + const customerId = response.body.id; + + return request(app.getHttpServer()) + .get(`/customers/${customerId}`) + .set('organization-id', '4064541lv40nhca') + .expect(200); + }); + + it('/customers/:id (DELETE)', async () => { + const response = await request(app.getHttpServer()) + .post('/customers') + .set('organization-id', '4064541lv40nhca') + .send({ + customerType: 'business', + displayName: faker.commerce.productName(), + email: faker.internet.email(), + firstName: faker.person.firstName(), + lastName: faker.person.lastName(), + }); + const customerId = response.body.id; + + return request(app.getHttpServer()) + .delete(`/customers/${customerId}`) + .set('organization-id', '4064541lv40nhca') + .expect(200); + }); + + it('/customers/:id (PUT)', async () => { + const response = await request(app.getHttpServer()) + .post('/customers') + .set('organization-id', '4064541lv40nhca') + .send({ + customerType: 'business', + displayName: faker.commerce.productName(), + email: faker.internet.email(), + firstName: faker.person.firstName(), + lastName: faker.person.lastName(), + }); + const customerId = response.body.id; + + return request(app.getHttpServer()) + .put(`/customers/${customerId}`) + .set('organization-id', '4064541lv40nhca') + .send({ + displayName: faker.commerce.productName(), + email: faker.internet.email(), + firstName: faker.person.firstName(), + lastName: faker.person.lastName(), + }) + .expect(200); + }); +}); diff --git a/packages/server-nest/test/sale-invoices.e2e-spec.ts b/packages/server-nest/test/sale-invoices.e2e-spec.ts new file mode 100644 index 000000000..355b4ac4b --- /dev/null +++ b/packages/server-nest/test/sale-invoices.e2e-spec.ts @@ -0,0 +1,33 @@ +import * as request from 'supertest'; +import { faker } from '@faker-js/faker'; +import { app } from './init-app-test'; + +describe('Sale Invoices (e2e)', () => { + it('/sale-invoices (POST)', () => { + return request(app.getHttpServer()) + .post('/sale-invoices') + .set('organization-id', '4064541lv40nhca') + .send({ + customerId: 2, + invoiceDate: '2023-01-01', + dueDate: '2023-02-01', + invoiceNo: 'INV-002005', + referenceNo: 'REF-000201', + delivered: true, + discountType: 'percentage', + discount: 10, + branchId: 1, + warehouseId: 1, + entries: [ + { + index: 1, + itemId: 1001, + quantity: 2, + rate: 1000, + description: 'Item description...', + }, + ], + }) + .expect(201); + }); +}); diff --git a/packages/server-nest/test/sale-receipts.e2e-spec.ts b/packages/server-nest/test/sale-receipts.e2e-spec.ts new file mode 100644 index 000000000..a652103a5 --- /dev/null +++ b/packages/server-nest/test/sale-receipts.e2e-spec.ts @@ -0,0 +1,80 @@ +import * as request from 'supertest'; +import { faker } from '@faker-js/faker'; +import { app } from './init-app-test'; + +const receiptRequest = { + customerId: 2, + depositAccountId: 1000, + receiptDate: '2022-02-02', + referenceNo: '123', + receiptNumber: faker.string.uuid(), + branchId: 1, + warehouseId: 1, + discount: 100, + discountType: 'amount', + entries: [ + { + index: 1, + itemId: 1001, + quantity: 1, + rate: 2000, + description: 'asdfsadf', + }, + ], +}; + +describe('Sale Receipts (e2e)', () => { + it('/sale-reeipts (POST)', () => { + return request(app.getHttpServer()) + .post('/sale-receipts') + .set('organization-id', '4064541lv40nhca') + .send(receiptRequest) + .expect(201); + }); + + it('/sale-receipts/:id (DELETE)', async () => { + const response = await request(app.getHttpServer()) + .post('/sale-receipts') + .set('organization-id', '4064541lv40nhca') + .send(receiptRequest); + + const receiptId = response.body.id; + + return request(app.getHttpServer()) + .delete(`/sale-receipts/${receiptId}`) + .set('organization-id', '4064541lv40nhca') + .send(); + }); + + it('/sale-receipts/:id (PUT)', async () => { + const response = await request(app.getHttpServer()) + .post('/sale-receipts') + .set('organization-id', '4064541lv40nhca') + .send(receiptRequest); + + const receiptId = response.body.id; + + return request(app.getHttpServer()) + .delete(`/sale-receipts/${receiptId}`) + .set('organization-id', '4064541lv40nhca') + .send({ + ...receiptRequest, + referenceNo: '321', + }) + .expect(200); + }); + + it('/sale-receipts/:id (GET)', async () => { + const response = await request(app.getHttpServer()) + .post('/sale-receipts') + .set('organization-id', '4064541lv40nhca') + .send(receiptRequest); + + const receiptId = response.body.id; + + return request(app.getHttpServer()) + .get(`/sale-receipts/${receiptId}`) + .set('organization-id', '4064541lv40nhca') + .expect(200); + }); +}); diff --git a/packages/server-nest/test/vendors.e2e-spec.ts b/packages/server-nest/test/vendors.e2e-spec.ts new file mode 100644 index 000000000..74ae3f261 --- /dev/null +++ b/packages/server-nest/test/vendors.e2e-spec.ts @@ -0,0 +1,75 @@ +import * as request from 'supertest'; +import { faker } from '@faker-js/faker'; +import { app } from './init-app-test'; + +describe('Vendors (e2e)', () => { + it('/vendors (POST)', () => { + return request(app.getHttpServer()) + .post('/vendors') + .set('organization-id', '4064541lv40nhca') + .send({ + displayName: faker.commerce.productName(), + email: faker.internet.email(), + firstName: faker.person.firstName(), + lastName: faker.person.lastName(), + }) + .expect(201); + }); + + it('/vendors/:id (PUT)', async () => { + const response = await request(app.getHttpServer()) + .post('/vendors') + .set('organization-id', '4064541lv40nhca') + .send({ + displayName: faker.commerce.productName(), + email: faker.internet.email(), + firstName: faker.person.firstName(), + lastName: faker.person.lastName(), + }); + const vendorId = response.body.id; + + return request(app.getHttpServer()) + .put(`/vendors/${vendorId}`) + .set('organization-id', '4064541lv40nhca') + .send({ + displayName: faker.commerce.productName(), + email: faker.internet.email(), + firstName: faker.person.firstName(), + lastName: faker.person.lastName(), + }) + .expect(200); + }); + + it('/vendors/:id (GET)', async () => { + const response = await request(app.getHttpServer()) + .post('/vendors') + .set('organization-id', '4064541lv40nhca') + .send({ + displayName: faker.commerce.productName(), + email: faker.internet.email(), + firstName: faker.person.firstName(), + lastName: faker.person.lastName(), + }); + const vendorId = response.body.id; + + return request(app.getHttpServer()) + .get(`/vendors/${vendorId}`) + .set('organization-id', '4064541lv40nhca') + .expect(200); + }); + + it('/vendors/:id (DELETE)', async () => { + const response = await request(app.getHttpServer()) + .post('/vendors') + .set('organization-id', '4064541lv40nhca') + .send({ + displayName: faker.commerce.productName(), + }); + const vendorId = response.body.id; + + return request(app.getHttpServer()) + .delete(`/vendors/${vendorId}`) + .set('organization-id', '4064541lv40nhca') + .expect(200); + }); +});