refactor(nestjs): export and import module

This commit is contained in:
Ahmed Bouhuolia
2025-04-09 18:35:17 +02:00
parent d851e5b646
commit ab49113d5a
38 changed files with 2403 additions and 117 deletions

View File

@@ -4,9 +4,34 @@ import { ExportResourceService } from './ExportService';
import { ExportPdf } from './ExportPdf';
import { ExportAls } from './ExportAls';
import { ExportApplication } from './ExportApplication';
import { ResourceModule } from '../Resource/Resource.module';
import { RegisterTenancyModel } from '../Tenancy/TenancyModels/Tenancy.module';
import { ImportModel } from '../Import/models/Import';
import { ExportableResources } from './ExportResources';
import { ExportableRegistry } from './ExportRegistery';
import { TemplateInjectableModule } from '../TemplateInjectable/TemplateInjectable.module';
import { ChromiumlyTenancyModule } from '../ChromiumlyTenancy/ChromiumlyTenancy.module';
import { AccountsModule } from '../Accounts/Accounts.module';
const models = [RegisterTenancyModel(ImportModel)];
@Module({
providers: [ExportResourceService, ExportPdf, ExportAls, ExportApplication],
imports: [
...models,
ResourceModule,
TemplateInjectableModule,
ChromiumlyTenancyModule,
AccountsModule
],
providers: [
ExportResourceService,
ExportPdf,
ExportAls,
ExportApplication,
ExportableResources,
ExportableRegistry
],
exports: [...models],
controllers: [ExportController],
})
export class ExportModule {}

View File

@@ -3,6 +3,7 @@ import { ExportFormat } from './common';
export const convertAcceptFormatToFormat = (accept: string): ExportFormat => {
switch (accept) {
default:
case ACCEPT_TYPE.APPLICATION_CSV:
return ExportFormat.Csv;
case ACCEPT_TYPE.APPLICATION_PDF:

View File

@@ -1,56 +0,0 @@
import { Injectable } from "@nestjs/common";
import { ExportableRegistry } from "./ExportRegistery";
import { AccountsExportable } from "../Accounts/AccountsExportable.service";
@Injectable()
export class ExportableResources {
constructor(
private readonly exportRegistry: ExportableRegistry,
) {
this.boot();
}
/**
* Importable instances.
*/
private importables = [
// { resource: 'Account', exportable: AccountsExportable },
// { resource: 'Item', exportable: ItemsExportable },
// { resource: 'ItemCategory', exportable: ItemCategoriesExportable },
// { resource: 'Customer', exportable: CustomersExportable },
// { resource: 'Vendor', exportable: VendorsExportable },
// { resource: 'Expense', exportable: ExpensesExportable },
// { resource: 'SaleInvoice', exportable: SaleInvoicesExportable },
// { resource: 'SaleEstimate', exportable: SaleEstimatesExportable },
// { resource: 'SaleReceipt', exportable: SaleReceiptsExportable },
// { resource: 'Bill', exportable: BillsExportable },
// { resource: 'PaymentReceive', exportable: PaymentsReceivedExportable },
// { resource: 'BillPayment', exportable: BillPaymentExportable },
// { resource: 'ManualJournal', exportable: ManualJournalsExportable },
// { resource: 'CreditNote', exportable: CreditNotesExportable },
// { resource: 'VendorCredit', exportable: VendorCreditsExportable },
// { resource: 'TaxRate', exportable: TaxRatesExportable },
];
/**
*
*/
public get registry() {
return ExportableResources.registry;
}
/**
* Boots all the registered importables.
*/
public boot() {
if (!ExportableResources.registry) {
const instance = ExportableRegistry.getInstance();
this.importables.forEach((importable) => {
const importableInstance = Container.get(importable.exportable);
instance.registerExportable(importable.resource, importableInstance);
});
ExportableResources.registry = instance;
}
}
}

View File

@@ -1,5 +1,5 @@
import { Injectable } from '@nestjs/common';
import xlsx from 'xlsx';
import * as xlsx from 'xlsx';
import * as R from 'ramda';
import { get } from 'lodash';
import { sanitizeResourceName } from '../Import/_utils';
@@ -10,6 +10,9 @@ import { ExportPdf } from './ExportPdf';
import { ExportAls } from './ExportAls';
import { IModelMeta, IModelMetaColumn } from '@/interfaces/Model';
import { ServiceError } from '../Items/ServiceError';
import { ResourceService } from '../Resource/ResourceService';
import { getExportableService } from './decorators/ExportableModel.decorator';
import { ContextIdFactory, ModuleRef } from '@nestjs/core';
@Injectable()
export class ExportResourceService {
@@ -18,6 +21,7 @@ export class ExportResourceService {
private readonly exportPdf: ExportPdf,
private readonly exportableResources: ExportableResources,
private readonly resourceService: ResourceService,
private readonly moduleRef: ModuleRef,
) {}
/**
@@ -27,11 +31,9 @@ export class ExportResourceService {
*/
public async export(
resourceName: string,
format: ExportFormat = ExportFormat.Csv
format: ExportFormat = ExportFormat.Csv,
) {
return this.exportAls.run(() =>
this.exportAlsRun(resourceName, format)
);
return this.exportAls.run(() => this.exportAlsRun(resourceName, format));
}
/**
@@ -41,18 +43,19 @@ export class ExportResourceService {
*/
public async exportAlsRun(
resourceName: string,
format: ExportFormat = ExportFormat.Csv
format: ExportFormat = ExportFormat.Csv,
) {
const resource = sanitizeResourceName(resourceName);
const resourceMeta = this.getResourceMeta(resource);
const resourceColumns = this.resourceService.getResourceColumns(
resource
);
const resourceColumns = this.resourceService.getResourceColumns(resource);
this.validateResourceMeta(resourceMeta);
const data = await this.getExportableData(resource);
const transformed = this.transformExportedData(resource, data);
console.log(format);
// Returns the csv, xlsx format.
if (format === ExportFormat.Csv || format === ExportFormat.Xlsx) {
const exportableColumns = this.getExportableColumns(resourceColumns);
@@ -66,7 +69,7 @@ export class ExportResourceService {
return this.exportPdf.pdf(
printableColumns,
transformed,
resourceMeta?.print?.pageTitle
resourceMeta?.print?.pageTitle,
);
}
}
@@ -102,14 +105,14 @@ export class ExportResourceService {
*/
private transformExportedData(
resource: string,
data: Array<Record<string, any>>
data: Array<Record<string, any>>,
): Array<Record<string, any>> {
const resourceMeta = this.getResourceMeta(resource);
return R.when<Array<Record<string, any>>, Array<Record<string, any>>>(
R.always(Boolean(resourceMeta.exportFlattenOn)),
(data) => flatDataCollections(data, resourceMeta.exportFlattenOn),
data
data,
);
}
/**
@@ -119,10 +122,14 @@ export class ExportResourceService {
* @returns A promise that resolves to the exportable data.
*/
private async getExportableData(resource: string) {
const exportable =
this.exportableResources.registry.getExportable(resource);
return exportable.exportable({});
const exportable = getExportableService(resource);
const contextId = ContextIdFactory.create();
const exportableInstance = await this.moduleRef.resolve(
exportable,
contextId,
{ strict: false },
);
return exportableInstance.exportable({});
}
/**
@@ -133,7 +140,7 @@ export class ExportResourceService {
private getExportableColumns(resourceColumns: any) {
const processColumns = (
columns: { [key: string]: IModelMetaColumn },
parent = ''
parent = '',
) => {
return Object.entries(columns)
.filter(([_, value]) => value.exportable !== false)
@@ -159,9 +166,10 @@ export class ExportResourceService {
private getPrintableColumns(resourceMeta: IModelMeta) {
const processColumns = (
columns: { [key: string]: IModelMetaColumn },
parent = ''
parent = '',
) => {
return Object.entries(columns)
// @ts-expect-error
.filter(([_, value]) => value.printable !== false)
.flatMap(([key, value]) => {
if (value.type === 'collection' && value.collectionOf === 'object') {
@@ -191,7 +199,7 @@ export class ExportResourceService {
private createWorkbook(data: any[], exportableColumns: any[]) {
const workbook = xlsx.utils.book_new();
const worksheetData = data.map((item) =>
exportableColumns.map((col) => get(item, getDataAccessor(col)))
exportableColumns.map((col) => get(item, getDataAccessor(col))),
);
worksheetData.unshift(exportableColumns.map((col) => col.name));

View File

@@ -4,8 +4,4 @@ export class ExportQuery {
@IsString()
@IsNotEmpty()
resource: string;
@IsString()
@IsNotEmpty()
format: string;
}