mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-19 06:10:31 +00:00
refactor(nestjs): import module
This commit is contained in:
@@ -164,6 +164,7 @@ export interface IModelMetaRelationField2 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type IModelMetaField2 = IModelMetaFieldCommon2 &
|
export type IModelMetaField2 = IModelMetaFieldCommon2 &
|
||||||
|
IModelMetaFieldWithFields &
|
||||||
(
|
(
|
||||||
| IModelMetaFieldText
|
| IModelMetaFieldText
|
||||||
| IModelMetaFieldNumber
|
| IModelMetaFieldNumber
|
||||||
|
|||||||
@@ -59,8 +59,8 @@ export class BillPaymentsApplication {
|
|||||||
/**
|
/**
|
||||||
* Retrieves bill payments list.
|
* Retrieves bill payments list.
|
||||||
*/
|
*/
|
||||||
public getBillPayments(filterDTO: IBillPaymentsFilter) {
|
public getBillPayments() {
|
||||||
return this.getBillPaymentsService.getBillPayments(filterDTO);
|
// return this.getBillPaymentsService.getBillPayments(filterDTO);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ export class BillPaymentsExportable extends Exportable {
|
|||||||
* @param {number} tenantId
|
* @param {number} tenantId
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
public exportable(query: any) {
|
public async exportable(query: any) {
|
||||||
const filterQuery = (builder) => {
|
const filterQuery = (builder) => {
|
||||||
builder.withGraphFetched('entries.bill');
|
builder.withGraphFetched('entries.bill');
|
||||||
builder.withGraphFetched('branch');
|
builder.withGraphFetched('branch');
|
||||||
|
|||||||
@@ -1,46 +1,46 @@
|
|||||||
// import { Inject, Service } from 'typedi';
|
import { Knex } from 'knex';
|
||||||
// import { Knex } from 'knex';
|
import { CreateBill } from './CreateBill.service';
|
||||||
// import { Importable } from '@/services/Import/Importable';
|
import { BillsSampleData } from '../Bills.constants';
|
||||||
// import { CreateBill } from './CreateBill.service';
|
import { Injectable } from '@nestjs/common';
|
||||||
// import { IBillDTO } from '@/interfaces';
|
import { Importable } from '@/modules/Import/Importable';
|
||||||
// import { BillsSampleData } from '../Bills.constants';
|
import { CreateBillDto } from '../dtos/Bill.dto';
|
||||||
|
|
||||||
// @Service()
|
@Injectable()
|
||||||
// export class BillsImportable extends Importable {
|
export class BillsImportable extends Importable {
|
||||||
// @Inject()
|
constructor(
|
||||||
// private createBillService: CreateBill;
|
private readonly createBillService: CreateBill,
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
// /**
|
/**
|
||||||
// * Importing to account service.
|
* Importing to account service.
|
||||||
// * @param {number} tenantId
|
* @param {number} tenantId
|
||||||
// * @param {IAccountCreateDTO} createAccountDTO
|
* @param {IAccountCreateDTO} createAccountDTO
|
||||||
// * @returns
|
* @returns
|
||||||
// */
|
*/
|
||||||
// public importable(
|
public importable(
|
||||||
// tenantId: number,
|
createBillDto: CreateBillDto,
|
||||||
// createAccountDTO: IBillDTO,
|
trx?: Knex.Transaction
|
||||||
// trx?: Knex.Transaction
|
) {
|
||||||
// ) {
|
return this.createBillService.createBill(
|
||||||
// return this.createBillService.createBill(
|
createBillDto,
|
||||||
// tenantId,
|
trx
|
||||||
// createAccountDTO,
|
);
|
||||||
// {},
|
}
|
||||||
// trx
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
|
|
||||||
// /**
|
/**
|
||||||
// * Concurrrency controlling of the importing process.
|
* Concurrrency controlling of the importing process.
|
||||||
// * @returns {number}
|
* @returns {number}
|
||||||
// */
|
*/
|
||||||
// public get concurrency() {
|
public get concurrency() {
|
||||||
// return 1;
|
return 1;
|
||||||
// }
|
}
|
||||||
|
|
||||||
// /**
|
/**
|
||||||
// * Retrieves the sample data that used to download accounts sample sheet.
|
* Retrieves the sample data that used to download accounts sample sheet.
|
||||||
// */
|
*/
|
||||||
// public sampleData(): any[] {
|
public sampleData(): any[] {
|
||||||
// return BillsSampleData;
|
return BillsSampleData;
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ export class ExportAls {
|
|||||||
* @returns The result of the callback function.
|
* @returns The result of the callback function.
|
||||||
*/
|
*/
|
||||||
public run<T>(callback: () => T): T {
|
public run<T>(callback: () => T): T {
|
||||||
return this.als.run<T>(new Map(), () => {
|
return this.als.run<T, []>(new Map(), () => {
|
||||||
this.markAsExport();
|
this.markAsExport();
|
||||||
|
|
||||||
return callback();
|
return callback();
|
||||||
|
|||||||
@@ -1,16 +1,15 @@
|
|||||||
// @ts-nocheck
|
import { Injectable } from '@nestjs/common';
|
||||||
import xlsx from 'xlsx';
|
import xlsx from 'xlsx';
|
||||||
import * as R from 'ramda';
|
import * as R from 'ramda';
|
||||||
import { get } from 'lodash';
|
import { get } from 'lodash';
|
||||||
import { sanitizeResourceName } from '../Import/_utils';
|
import { sanitizeResourceName } from '../Import/_utils';
|
||||||
import { ExportableResources } from './ExportResources';
|
import { ExportableResources } from './ExportResources';
|
||||||
import { ServiceError } from '@/exceptions';
|
|
||||||
import { Errors, ExportFormat } from './common';
|
import { Errors, ExportFormat } from './common';
|
||||||
import { IModelMeta, IModelMetaColumn } from '@/interfaces';
|
|
||||||
import { flatDataCollections, getDataAccessor } from './utils';
|
import { flatDataCollections, getDataAccessor } from './utils';
|
||||||
import { ExportPdf } from './ExportPdf';
|
import { ExportPdf } from './ExportPdf';
|
||||||
import { ExportAls } from './ExportAls';
|
import { ExportAls } from './ExportAls';
|
||||||
import { Injectable } from '@nestjs/common';
|
import { IModelMeta, IModelMetaColumn } from '@/interfaces/Model';
|
||||||
|
import { ServiceError } from '../Items/ServiceError';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ExportResourceService {
|
export class ExportResourceService {
|
||||||
|
|||||||
@@ -1,8 +1,34 @@
|
|||||||
import { Module } from '@nestjs/common';
|
import { Module } from '@nestjs/common';
|
||||||
import { ImportAls } from './ImportALS';
|
import { ImportAls } from './ImportALS';
|
||||||
|
import { ImportSampleService } from './ImportSample';
|
||||||
|
import { ImportResourceApplication } from './ImportResourceApplication';
|
||||||
|
import { ImportDeleteExpiredFiles } from './ImportRemoveExpiredFiles';
|
||||||
|
import { ImportFileUploadService } from './ImportFileUpload';
|
||||||
|
import { ImportFileProcessCommit } from './ImportFileProcessCommit';
|
||||||
|
import { ImportFileProcess } from './ImportFileProcess';
|
||||||
|
import { ImportFilePreview } from './ImportFilePreview';
|
||||||
|
import { ImportFileMeta } from './ImportFileMeta';
|
||||||
|
import { ImportFileMapping } from './ImportFileMapping';
|
||||||
|
import { ImportFileDataValidator } from './ImportFileDataValidator';
|
||||||
|
import { ImportFileDataTransformer } from './ImportFileDataTransformer';
|
||||||
|
import { ImportFileCommon } from './ImportFileCommon';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
providers: [ImportAls],
|
providers: [
|
||||||
|
ImportAls,
|
||||||
|
ImportSampleService,
|
||||||
|
ImportResourceApplication,
|
||||||
|
ImportDeleteExpiredFiles,
|
||||||
|
ImportFileUploadService,
|
||||||
|
ImportFileProcessCommit,
|
||||||
|
ImportFileProcess,
|
||||||
|
ImportFilePreview,
|
||||||
|
ImportFileMeta,
|
||||||
|
ImportFileMapping,
|
||||||
|
ImportFileDataValidator,
|
||||||
|
ImportFileDataTransformer,
|
||||||
|
ImportFileCommon
|
||||||
|
],
|
||||||
exports: [ImportAls],
|
exports: [ImportAls],
|
||||||
})
|
})
|
||||||
export class ImportModule {}
|
export class ImportModule {}
|
||||||
|
|||||||
@@ -12,9 +12,9 @@ import {
|
|||||||
import { getUniqueImportableValue, trimObject } from './_utils';
|
import { getUniqueImportableValue, trimObject } from './_utils';
|
||||||
import { ImportableResources } from './ImportableResources';
|
import { ImportableResources } from './ImportableResources';
|
||||||
import { ResourceService } from '../Resource/ResourceService';
|
import { ResourceService } from '../Resource/ResourceService';
|
||||||
import { Import } from '@/system/models';
|
|
||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
import { ServiceError } from '../Items/ServiceError';
|
import { ServiceError } from '../Items/ServiceError';
|
||||||
|
import { ImportModelShape } from './models/Import';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ImportFileCommon {
|
export class ImportFileCommon {
|
||||||
@@ -32,7 +32,7 @@ export class ImportFileCommon {
|
|||||||
* @returns {Promise<[ImportOperSuccess[], ImportOperError[]]>}
|
* @returns {Promise<[ImportOperSuccess[], ImportOperError[]]>}
|
||||||
*/
|
*/
|
||||||
public async import(
|
public async import(
|
||||||
importFile: Import,
|
importFile: ImportModelShape,
|
||||||
parsedData: Record<string, any>[],
|
parsedData: Record<string, any>[],
|
||||||
trx?: Knex.Transaction,
|
trx?: Knex.Transaction,
|
||||||
): Promise<[ImportOperSuccess[], ImportOperError[]]> {
|
): Promise<[ImportOperSuccess[], ImportOperError[]]> {
|
||||||
@@ -68,7 +68,6 @@ export class ImportFileCommon {
|
|||||||
try {
|
try {
|
||||||
// Run the importable function and listen to the errors.
|
// Run the importable function and listen to the errors.
|
||||||
const data = await importable.importable(
|
const data = await importable.importable(
|
||||||
tenantId,
|
|
||||||
transformedDTO,
|
transformedDTO,
|
||||||
trx,
|
trx,
|
||||||
);
|
);
|
||||||
@@ -135,14 +134,13 @@ export class ImportFileCommon {
|
|||||||
* @param {Record<string, any>} params
|
* @param {Record<string, any>} params
|
||||||
*/
|
*/
|
||||||
public async validateParams(
|
public async validateParams(
|
||||||
tenantId: number,
|
|
||||||
resourceName: string,
|
resourceName: string,
|
||||||
params: Record<string, any>,
|
params: Record<string, any>,
|
||||||
) {
|
) {
|
||||||
const ImportableRegistry = this.importable.registry;
|
const ImportableRegistry = this.importable.registry;
|
||||||
const importable = ImportableRegistry.getImportable(resourceName);
|
const importable = ImportableRegistry.getImportable(resourceName);
|
||||||
|
|
||||||
await importable.validateParams(tenantId, params);
|
await importable.validateParams(params);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
import { fromPairs, isUndefined } from 'lodash';
|
import { fromPairs, isUndefined } from 'lodash';
|
||||||
import {
|
import {
|
||||||
ImportDateFormats,
|
ImportDateFormats,
|
||||||
@@ -8,15 +8,19 @@ import {
|
|||||||
import { ResourceService } from '../Resource/ResourceService';
|
import { ResourceService } from '../Resource/ResourceService';
|
||||||
import { ServiceError } from '../Items/ServiceError';
|
import { ServiceError } from '../Items/ServiceError';
|
||||||
import { ERRORS } from './_utils';
|
import { ERRORS } from './_utils';
|
||||||
import { Import } from './models/Import';
|
import { ImportModel } from './models/Import';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ImportFileMapping {
|
export class ImportFileMapping {
|
||||||
constructor(private readonly resource: ResourceService) {}
|
constructor(
|
||||||
|
private readonly resource: ResourceService,
|
||||||
|
|
||||||
|
@Inject(ImportModel.name)
|
||||||
|
private readonly importModel: () => typeof ImportModel,
|
||||||
|
) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mapping the excel sheet columns with resource columns.
|
* Mapping the excel sheet columns with resource columns.
|
||||||
* @param {number} tenantId
|
|
||||||
* @param {number} importId
|
* @param {number} importId
|
||||||
* @param {ImportMappingAttr} maps
|
* @param {ImportMappingAttr} maps
|
||||||
*/
|
*/
|
||||||
@@ -24,7 +28,8 @@ export class ImportFileMapping {
|
|||||||
importId: string,
|
importId: string,
|
||||||
maps: ImportMappingAttr[],
|
maps: ImportMappingAttr[],
|
||||||
): Promise<ImportFileMapPOJO> {
|
): Promise<ImportFileMapPOJO> {
|
||||||
const importFile = await Import.query()
|
const importFile = await this.importModel()
|
||||||
|
.query()
|
||||||
.findOne('filename', importId)
|
.findOne('filename', importId)
|
||||||
.throwIfNotFound();
|
.throwIfNotFound();
|
||||||
|
|
||||||
@@ -41,7 +46,7 @@ export class ImportFileMapping {
|
|||||||
|
|
||||||
const mappingStringified = JSON.stringify(maps);
|
const mappingStringified = JSON.stringify(maps);
|
||||||
|
|
||||||
await Import.query().findById(importFile.id).patch({
|
await this.importModel().query().findById(importFile.id).patch({
|
||||||
mapping: mappingStringified,
|
mapping: mappingStringified,
|
||||||
});
|
});
|
||||||
return {
|
return {
|
||||||
@@ -54,7 +59,6 @@ export class ImportFileMapping {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Validate the mapping attributes.
|
* Validate the mapping attributes.
|
||||||
* @param {number} tenantId -
|
|
||||||
* @param {} importFile -
|
* @param {} importFile -
|
||||||
* @param {ImportMappingAttr[]} maps
|
* @param {ImportMappingAttr[]} maps
|
||||||
* @throws {ServiceError(ERRORS.INVALID_MAP_ATTRS)}
|
* @throws {ServiceError(ERRORS.INVALID_MAP_ATTRS)}
|
||||||
@@ -116,7 +120,6 @@ export class ImportFileMapping {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Validates the date format mapping.
|
* Validates the date format mapping.
|
||||||
* @param {number} tenantId
|
|
||||||
* @param {string} resource
|
* @param {string} resource
|
||||||
* @param {ImportMappingAttr[]} maps
|
* @param {ImportMappingAttr[]} maps
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,20 +1,29 @@
|
|||||||
import { Import } from './models/Import';
|
import { ImportModel } from './models/Import';
|
||||||
import { ImportFileMetaTransformer } from './ImportFileMetaTransformer';
|
import { ImportFileMetaTransformer } from './ImportFileMetaTransformer';
|
||||||
import { Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
import { TransformerInjectable } from '../Transformer/TransformerInjectable.service';
|
import { TransformerInjectable } from '../Transformer/TransformerInjectable.service';
|
||||||
|
import { TenancyContext } from '../Tenancy/TenancyContext.service';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ImportFileMeta {
|
export class ImportFileMeta {
|
||||||
constructor(private readonly transformer: TransformerInjectable) {}
|
constructor(
|
||||||
|
private readonly transformer: TransformerInjectable,
|
||||||
|
private readonly tenancyContext: TenancyContext,
|
||||||
|
|
||||||
|
@Inject(ImportModel.name)
|
||||||
|
private readonly importModel: () => typeof ImportModel,
|
||||||
|
) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the import meta of the given import model id.
|
* Retrieves the import meta of the given import model id.
|
||||||
* @param {number} tenantId
|
|
||||||
* @param {number} importId
|
* @param {number} importId
|
||||||
* @returns {}
|
|
||||||
*/
|
*/
|
||||||
async getImportMeta(importId: string) {
|
async getImportMeta(importId: string) {
|
||||||
const importFile = await Import.query()
|
const tenant = await this.tenancyContext.getTenant();
|
||||||
|
const tenantId = tenant.id;
|
||||||
|
|
||||||
|
const importFile = await this.importModel()
|
||||||
|
.query()
|
||||||
.where('tenantId', tenantId)
|
.where('tenantId', tenantId)
|
||||||
.findOne('importId', importId);
|
.findOne('importId', importId);
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,18 @@
|
|||||||
|
import { Knex } from 'knex';
|
||||||
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
import { ImportFilePreviewPOJO } from './interfaces';
|
import { ImportFilePreviewPOJO } from './interfaces';
|
||||||
import { ImportFileProcess } from './ImportFileProcess';
|
import { ImportFileProcess } from './ImportFileProcess';
|
||||||
import { ImportAls } from './ImportALS';
|
import { ImportAls } from './ImportALS';
|
||||||
import { Injectable } from '@nestjs/common';
|
import { TENANCY_DB_CONNECTION } from '../Tenancy/TenancyDB/TenancyDB.constants';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ImportFilePreview {
|
export class ImportFilePreview {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly importFile: ImportFileProcess,
|
private readonly importFile: ImportFileProcess,
|
||||||
private readonly importAls: ImportAls,
|
private readonly importAls: ImportAls,
|
||||||
|
|
||||||
|
@Inject(TENANCY_DB_CONNECTION)
|
||||||
|
private readonly tenantKnex: () => Knex
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -27,8 +32,7 @@ export class ImportFilePreview {
|
|||||||
* @returns {Promise<ImportFilePreviewPOJO>}
|
* @returns {Promise<ImportFilePreviewPOJO>}
|
||||||
*/
|
*/
|
||||||
public async previewAlsRun(importId: string): Promise<ImportFilePreviewPOJO> {
|
public async previewAlsRun(importId: string): Promise<ImportFilePreviewPOJO> {
|
||||||
const knex = this.tenancy.knex(tenantId);
|
const trx = await this.tenantKnex().transaction({ isolationLevel: 'read uncommitted' });
|
||||||
const trx = await knex.transaction({ isolationLevel: 'read uncommitted' });
|
|
||||||
|
|
||||||
const meta = await this.importFile.import(importId, trx);
|
const meta = await this.importFile.import(importId, trx);
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,16 @@
|
|||||||
import { chain } from 'lodash';
|
import { chain } from 'lodash';
|
||||||
import { Knex } from 'knex';
|
import { Knex } from 'knex';
|
||||||
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
import { ERRORS, getUnmappedSheetColumns, readImportFile } from './_utils';
|
import { ERRORS, getUnmappedSheetColumns, readImportFile } from './_utils';
|
||||||
import { ImportFileCommon } from './ImportFileCommon';
|
import { ImportFileCommon } from './ImportFileCommon';
|
||||||
import { ImportFileDataTransformer } from './ImportFileDataTransformer';
|
import { ImportFileDataTransformer } from './ImportFileDataTransformer';
|
||||||
import { ImportFilePreviewPOJO } from './interfaces';
|
import { ImportFilePreviewPOJO } from './interfaces';
|
||||||
import { parseSheetData } from './sheet_utils';
|
import { parseSheetData } from './sheet_utils';
|
||||||
import { Injectable } from '@nestjs/common';
|
|
||||||
import { ResourceService } from '../Resource/ResourceService';
|
import { ResourceService } from '../Resource/ResourceService';
|
||||||
import { UnitOfWork } from '../Tenancy/TenancyDB/UnitOfWork.service';
|
import { UnitOfWork } from '../Tenancy/TenancyDB/UnitOfWork.service';
|
||||||
import { ServiceError } from '../Items/ServiceError';
|
import { ServiceError } from '../Items/ServiceError';
|
||||||
|
import { ImportModel } from './models/Import';
|
||||||
|
import { TenancyContext } from '../Tenancy/TenancyContext.service';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ImportFileProcess {
|
export class ImportFileProcess {
|
||||||
@@ -17,6 +19,10 @@ export class ImportFileProcess {
|
|||||||
private readonly importCommon: ImportFileCommon,
|
private readonly importCommon: ImportFileCommon,
|
||||||
private readonly importParser: ImportFileDataTransformer,
|
private readonly importParser: ImportFileDataTransformer,
|
||||||
private readonly uow: UnitOfWork,
|
private readonly uow: UnitOfWork,
|
||||||
|
private readonly tenancyContext: TenancyContext,
|
||||||
|
|
||||||
|
@Inject(ImportModel.name)
|
||||||
|
private readonly importModel: typeof ImportModel,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -29,7 +35,11 @@ export class ImportFileProcess {
|
|||||||
importId: string,
|
importId: string,
|
||||||
trx?: Knex.Transaction,
|
trx?: Knex.Transaction,
|
||||||
): Promise<ImportFilePreviewPOJO> {
|
): Promise<ImportFilePreviewPOJO> {
|
||||||
const importFile = await Import.query()
|
const tenant = await this.tenancyContext.getTenant();
|
||||||
|
const tenantId = tenant.id;
|
||||||
|
|
||||||
|
const importFile = await this.importModel
|
||||||
|
.query()
|
||||||
.findOne('importId', importId)
|
.findOne('importId', importId)
|
||||||
.where('tenantId', tenantId)
|
.where('tenantId', tenantId)
|
||||||
.throwIfNotFound();
|
.throwIfNotFound();
|
||||||
@@ -48,28 +58,21 @@ export class ImportFileProcess {
|
|||||||
|
|
||||||
// Runs the importing operation with ability to return errors that will happen.
|
// Runs the importing operation with ability to return errors that will happen.
|
||||||
const [successedImport, failedImport, allData] =
|
const [successedImport, failedImport, allData] =
|
||||||
await this.uow.withTransaction(
|
await this.uow.withTransaction(async (trx: Knex.Transaction) => {
|
||||||
tenantId,
|
// Prases the sheet json data.
|
||||||
async (trx: Knex.Transaction) => {
|
const parsedData = await this.importParser.parseSheetData(
|
||||||
// Prases the sheet json data.
|
importFile,
|
||||||
const parsedData = await this.importParser.parseSheetData(
|
resourceFields,
|
||||||
tenantId,
|
sheetData,
|
||||||
importFile,
|
trx,
|
||||||
resourceFields,
|
);
|
||||||
sheetData,
|
const [successedImport, failedImport] = await this.importCommon.import(
|
||||||
trx,
|
importFile,
|
||||||
);
|
parsedData,
|
||||||
const [successedImport, failedImport] =
|
trx,
|
||||||
await this.importCommon.import(
|
);
|
||||||
tenantId,
|
return [successedImport, failedImport, parsedData];
|
||||||
importFile,
|
}, trx);
|
||||||
parsedData,
|
|
||||||
trx,
|
|
||||||
);
|
|
||||||
return [successedImport, failedImport, parsedData];
|
|
||||||
},
|
|
||||||
trx,
|
|
||||||
);
|
|
||||||
const mapping = importFile.mappingParsed;
|
const mapping = importFile.mappingParsed;
|
||||||
const errors = chain(failedImport)
|
const errors = chain(failedImport)
|
||||||
.map((oper) => oper.error)
|
.map((oper) => oper.error)
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
import { ImportFilePreviewPOJO } from './interfaces';
|
import { Knex } from 'knex';
|
||||||
|
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||||
|
import { IImportFileCommitedEventPayload, ImportFilePreviewPOJO } from './interfaces';
|
||||||
import { ImportFileProcess } from './ImportFileProcess';
|
import { ImportFileProcess } from './ImportFileProcess';
|
||||||
import { ImportAls } from './ImportALS';
|
import { ImportAls } from './ImportALS';
|
||||||
import { Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
|
||||||
import { events } from '@/common/events/events';
|
import { events } from '@/common/events/events';
|
||||||
|
import { TENANCY_DB_CONNECTION } from '../Tenancy/TenancyDB/TenancyDB.constants';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ImportFileProcessCommit {
|
export class ImportFileProcessCommit {
|
||||||
@@ -11,6 +13,9 @@ export class ImportFileProcessCommit {
|
|||||||
private readonly importFile: ImportFileProcess,
|
private readonly importFile: ImportFileProcess,
|
||||||
private readonly importAls: ImportAls,
|
private readonly importAls: ImportAls,
|
||||||
private readonly eventEmitter: EventEmitter2,
|
private readonly eventEmitter: EventEmitter2,
|
||||||
|
|
||||||
|
@Inject(TENANCY_DB_CONNECTION)
|
||||||
|
private readonly tenantKnex: () => Knex,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -30,8 +35,9 @@ export class ImportFileProcessCommit {
|
|||||||
* @returns {Promise<ImportFilePreviewPOJO>}
|
* @returns {Promise<ImportFilePreviewPOJO>}
|
||||||
*/
|
*/
|
||||||
public async commitAlsRun(importId: string): Promise<ImportFilePreviewPOJO> {
|
public async commitAlsRun(importId: string): Promise<ImportFilePreviewPOJO> {
|
||||||
const trx = await knex.transaction({ isolationLevel: 'read uncommitted' });
|
const trx = await this.tenantKnex().transaction({
|
||||||
|
isolationLevel: 'read uncommitted',
|
||||||
|
});
|
||||||
const meta = await this.importFile.import(importId, trx);
|
const meta = await this.importFile.import(importId, trx);
|
||||||
|
|
||||||
// Commit the successed transaction.
|
// Commit the successed transaction.
|
||||||
|
|||||||
@@ -9,9 +9,10 @@ import { ResourceService } from '../Resource/ResourceService';
|
|||||||
import { ImportFileCommon } from './ImportFileCommon';
|
import { ImportFileCommon } from './ImportFileCommon';
|
||||||
import { ImportFileDataValidator } from './ImportFileDataValidator';
|
import { ImportFileDataValidator } from './ImportFileDataValidator';
|
||||||
import { ImportFileUploadPOJO } from './interfaces';
|
import { ImportFileUploadPOJO } from './interfaces';
|
||||||
import { Import } from '@/system/models';
|
|
||||||
import { parseSheetData } from './sheet_utils';
|
import { parseSheetData } from './sheet_utils';
|
||||||
import { Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
|
import { ImportModel } from './models/Import';
|
||||||
|
import { TenancyContext } from '../Tenancy/TenancyContext.service';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ImportFileUploadService {
|
export class ImportFileUploadService {
|
||||||
@@ -19,6 +20,10 @@ export class ImportFileUploadService {
|
|||||||
private resourceService: ResourceService,
|
private resourceService: ResourceService,
|
||||||
private importFileCommon: ImportFileCommon,
|
private importFileCommon: ImportFileCommon,
|
||||||
private importValidator: ImportFileDataValidator,
|
private importValidator: ImportFileDataValidator,
|
||||||
|
private tenancyContext: TenancyContext,
|
||||||
|
|
||||||
|
@Inject(ImportModel.name)
|
||||||
|
private readonly importModel: typeof ImportModel,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -36,12 +41,7 @@ export class ImportFileUploadService {
|
|||||||
params: Record<string, number | string>,
|
params: Record<string, number | string>,
|
||||||
): Promise<ImportFileUploadPOJO> {
|
): Promise<ImportFileUploadPOJO> {
|
||||||
try {
|
try {
|
||||||
return await this.importUnhandled(
|
return await this.importUnhandled(resourceName, filename, params);
|
||||||
tenantId,
|
|
||||||
resourceName,
|
|
||||||
filename,
|
|
||||||
params,
|
|
||||||
);
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
deleteImportFile(filename);
|
deleteImportFile(filename);
|
||||||
throw err;
|
throw err;
|
||||||
@@ -81,15 +81,18 @@ export class ImportFileUploadService {
|
|||||||
await this.importFileCommon.validateParamsSchema(resource, params);
|
await this.importFileCommon.validateParamsSchema(resource, params);
|
||||||
|
|
||||||
// Validates importable params asyncly.
|
// Validates importable params asyncly.
|
||||||
await this.importFileCommon.validateParams(tenantId, resource, params);
|
await this.importFileCommon.validateParams(resource, params);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
const _params = this.importFileCommon.transformParams(resource, params);
|
const _params = this.importFileCommon.transformParams(resource, params);
|
||||||
const paramsStringified = JSON.stringify(_params);
|
const paramsStringified = JSON.stringify(_params);
|
||||||
|
|
||||||
|
const tenant = await this.tenancyContext.getTenant();
|
||||||
|
const tenantId = tenant.id;
|
||||||
|
|
||||||
// Store the import model with related metadata.
|
// Store the import model with related metadata.
|
||||||
const importFile = await Import.query().insert({
|
const importFile = await this.importModel.query().insert({
|
||||||
filename,
|
filename,
|
||||||
resource,
|
resource,
|
||||||
tenantId,
|
tenantId,
|
||||||
@@ -97,10 +100,8 @@ export class ImportFileUploadService {
|
|||||||
columns: coumnsStringified,
|
columns: coumnsStringified,
|
||||||
params: paramsStringified,
|
params: paramsStringified,
|
||||||
});
|
});
|
||||||
const resourceColumnsMap = this.resourceService.getResourceFields2(
|
const resourceColumnsMap =
|
||||||
tenantId,
|
this.resourceService.getResourceFields2(resource);
|
||||||
resource,
|
|
||||||
);
|
|
||||||
const resourceColumns = getResourceColumns(resourceColumnsMap);
|
const resourceColumns = getResourceColumns(resourceColumnsMap);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -1,34 +1,36 @@
|
|||||||
import * as moment from 'moment';
|
import * as moment from 'moment';
|
||||||
import bluebird from 'bluebird';
|
import bluebird from 'bluebird';
|
||||||
import { deleteImportFile } from './_utils';
|
import { deleteImportFile } from './_utils';
|
||||||
import { Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
import { Import } from './models/Import';
|
import { ImportModel } from './models/Import';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ImportDeleteExpiredFiles {
|
export class ImportDeleteExpiredFiles {
|
||||||
|
constructor(
|
||||||
|
@Inject(ImportModel.name)
|
||||||
|
private readonly importModel: typeof ImportModel,
|
||||||
|
) {}
|
||||||
/**
|
/**
|
||||||
* Delete expired files.
|
* Delete expired files.
|
||||||
*/
|
*/
|
||||||
async deleteExpiredFiles() {
|
async deleteExpiredFiles() {
|
||||||
const yesterday = moment().subtract(1, 'hour').format('YYYY-MM-DD HH:mm');
|
const yesterday = moment().subtract(1, 'hour').format('YYYY-MM-DD HH:mm');
|
||||||
|
|
||||||
const expiredImports = await Import.query().where(
|
const expiredImports = await this.importModel
|
||||||
'createdAt',
|
.query()
|
||||||
'<',
|
.where('createdAt', '<', yesterday);
|
||||||
yesterday
|
|
||||||
);
|
|
||||||
await bluebird.map(
|
await bluebird.map(
|
||||||
expiredImports,
|
expiredImports,
|
||||||
async (expiredImport) => {
|
async (expiredImport) => {
|
||||||
await deleteImportFile(expiredImport.filename);
|
await deleteImportFile(expiredImport.filename);
|
||||||
},
|
},
|
||||||
{ concurrency: 10 }
|
{ concurrency: 10 },
|
||||||
);
|
);
|
||||||
const expiredImportsIds = expiredImports.map(
|
const expiredImportsIds = expiredImports.map(
|
||||||
(expiredImport) => expiredImport.id
|
(expiredImport) => expiredImport.id,
|
||||||
);
|
);
|
||||||
if (expiredImportsIds.length > 0) {
|
if (expiredImportsIds.length > 0) {
|
||||||
await Import.query().whereIn('id', expiredImportsIds).delete();
|
await this.importModel.query().whereIn('id', expiredImportsIds).delete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -111,6 +111,7 @@ export const convertFieldsToYupValidation = (fields: ResourceMetaFieldsMap) => {
|
|||||||
} else if (field.fieldType === 'url') {
|
} else if (field.fieldType === 'url') {
|
||||||
fieldSchema = fieldSchema.url();
|
fieldSchema = fieldSchema.url();
|
||||||
} else if (field.fieldType === 'collection') {
|
} else if (field.fieldType === 'collection') {
|
||||||
|
// @ts-expect-error
|
||||||
const nestedFieldShema = convertFieldsToYupValidation(field.fields);
|
const nestedFieldShema = convertFieldsToYupValidation(field.fields);
|
||||||
fieldSchema = Yup.array().label(field.name);
|
fieldSchema = Yup.array().label(field.name);
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { IModelMetaField2 } from "@/interfaces/Model";
|
import { IModelMetaField2 } from "@/interfaces/Model";
|
||||||
import { Import } from "./models/Import";
|
import { ImportModelShape } from "./models/Import";
|
||||||
|
|
||||||
export interface ImportMappingAttr {
|
export interface ImportMappingAttr {
|
||||||
from: string;
|
from: string;
|
||||||
@@ -65,7 +65,7 @@ export interface ImportOperError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface ImportableContext {
|
export interface ImportableContext {
|
||||||
import: Import;
|
import: ImportModelShape;
|
||||||
rowIndex: number;
|
rowIndex: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,3 +75,9 @@ export const ImportDateFormats = [
|
|||||||
'MM/dd/yy',
|
'MM/dd/yy',
|
||||||
'dd/MMM/yyyy',
|
'dd/MMM/yyyy',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
|
export interface IImportFileCommitedEventPayload {
|
||||||
|
importId: string;
|
||||||
|
meta: ImportFilePreviewPOJO;
|
||||||
|
}
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
import { Model, ModelObject } from 'objection';
|
import { Model, ModelObject } from 'objection';
|
||||||
// import SystemModel from './SystemModel';
|
|
||||||
import { BaseModel } from '@/models/Model';
|
import { BaseModel } from '@/models/Model';
|
||||||
|
|
||||||
export class Import extends BaseModel {
|
export class ImportModel extends BaseModel {
|
||||||
resource: string;
|
resource!: string;
|
||||||
tenantId: number;
|
tenantId!: number;
|
||||||
|
filename!: string;
|
||||||
mapping!: string;
|
mapping!: string;
|
||||||
columns!: string;
|
columns!: string;
|
||||||
params!: string;
|
params!: string;
|
||||||
@@ -85,4 +85,4 @@ export class Import extends BaseModel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ImportShape = ModelObject<Import>;
|
export type ImportModelShape = ModelObject<ImportModel>;
|
||||||
|
|||||||
Reference in New Issue
Block a user