feat: wip export resource data

This commit is contained in:
Ahmed Bouhuolia
2024-05-01 00:20:13 +02:00
parent 8a96c41258
commit 7e89966f20
34 changed files with 1259 additions and 30 deletions

View File

@@ -0,0 +1,29 @@
import { Inject, Service } from 'typedi';
import { IItemsFilter } from '@/interfaces';
import { CustomersApplication } from './CustomersApplication';
import { Exportable } from '@/services/Export/Exportable';
@Service()
export class CustomersExportable extends Exportable {
@Inject()
private customersApplication: CustomersApplication;
/**
* Retrieves the accounts data to exportable sheet.
* @param {number} tenantId
* @returns
*/
public exportable(tenantId: number, query: IItemsFilter) {
const parsedQuery = {
sortOrder: 'DESC',
columnSortBy: 'created_at',
page: 1,
...query,
pageSize: 12,
} as IItemsFilter;
return this.customersApplication
.getCustomers(tenantId, parsedQuery)
.then((output) => output.customers);
}
}

View File

@@ -0,0 +1,29 @@
import { Inject, Service } from 'typedi';
import { IItemsFilter } from '@/interfaces';
import { Exportable } from '@/services/Export/Exportable';
import { VendorsApplication } from './VendorsApplication';
@Service()
export class VendorsExportable extends Exportable {
@Inject()
private vendorsApplication: VendorsApplication;
/**
* Retrieves the accounts data to exportable sheet.
* @param {number} tenantId
* @returns
*/
public exportable(tenantId: number, query: IItemsFilter) {
const parsedQuery = {
sortOrder: 'DESC',
columnSortBy: 'created_at',
page: 1,
...query,
pageSize: 12,
} as IItemsFilter;
return this.vendorsApplication
.getVendors(tenantId, parsedQuery)
.then((output) => output.vendors);
}
}

View File

@@ -0,0 +1,26 @@
import { Inject, Service } from 'typedi';
import { ICreditNotesQueryDTO } from '@/interfaces';
import { Exportable } from '@/services/Export/Exportable';
import ListCreditNotes from './ListCreditNotes';
@Service()
export class CreditNotesExportable extends Exportable {
@Inject()
private getCreditNotes: ListCreditNotes;
/**
* Retrieves the accounts data to exportable sheet.
* @param {number} tenantId -
* @param {IVendorCreditsQueryDTO} query -
* @returns {}
*/
public exportable(tenantId: number, query: ICreditNotesQueryDTO) {
const parsedQuery = {
...query,
} as ICreditNotesQueryDTO;
return this.getCreditNotes
.getCreditNotesList(tenantId, parsedQuery)
.then((output) => output.creditNotes);
}
}

View File

@@ -0,0 +1,25 @@
import { Inject, Service } from 'typedi';
import { Exportable } from '../Export/Exportable';
import { IExpensesFilter } from '@/interfaces';
import { ExpensesApplication } from './ExpensesApplication';
@Service()
export class ExpensesExportable extends Exportable {
@Inject()
private expensesApplication: ExpensesApplication;
/**
* Retrieves the accounts data to exportable sheet.
* @param {number} tenantId
* @returns
*/
public exportable(tenantId: number, query: IExpensesFilter) {
const parsedQuery = {
...query,
} as IExpensesFilter;
return this.expensesApplication
.getExpenses(tenantId, parsedQuery)
.then((output) => output.expenses);
}
}

View File

@@ -1,13 +1,27 @@
import Container, { Service } from 'typedi';
import { AccountsExportable } from '../Accounts/AccountsExportable';
import { ExportableRegistry } from './ExportRegistery';
import { ItemsImportable } from '../Items/ItemsImportable';
import { ItemsExportable } from '../Items/ItemsExportable';
import { CustomersExportable } from '../Contacts/Customers/CustomersExportable';
import { VendorsExportable } from '../Contacts/Vendors/VendorsExportable';
import { ExpensesExportable } from '../Expenses/ExpensesExportable';
import { SaleInvoicesExportable } from '../Sales/Invoices/SaleInvoicesExportable';
import { SaleEstimatesExportable } from '../Sales/Estimates/SaleEstimatesExportable';
import { SaleReceiptsExportable } from '../Sales/Receipts/SaleReceiptsExportable';
import { BillsExportable } from '../Purchases/Bills/BillsExportable';
import { PaymentsReceivedExportable } from '../Sales/PaymentReceives/PaymentsReceivedExportable';
import { BillPaymentExportable } from '../Purchases/BillPayments/BillPaymentExportable';
import { ManualJournalsExportable } from '../ManualJournals/ManualJournalExportable';
import { CreditNotesExportable } from '../CreditNotes/CreditNotesExportable';
import { VendorCreditsExportable } from '../Purchases/VendorCredits/VendorCreditsExportable';
@Service()
export class ExportableResources {
private static registry: ExportableRegistry;
/**
* Consttuctor method.
*/
constructor() {
this.boot();
}
@@ -18,6 +32,18 @@ export class ExportableResources {
private importables = [
{ resource: 'Account', exportable: AccountsExportable },
{ resource: 'Item', exportable: ItemsExportable },
{ 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 }
];
/**

View File

@@ -3,6 +3,8 @@ import xlsx from 'xlsx';
import { sanitizeResourceName } from '../Import/_utils';
import ResourceService from '../Resource/ResourceService';
import { ExportableResources } from './ExportResources';
import { ServiceError } from '@/exceptions';
import { Errors } from './common';
@Service()
export class ExportResourceService {
@@ -13,10 +15,10 @@ export class ExportResourceService {
private exportableResources: ExportableResources;
/**
*
* @param {number} tenantId
* @param {string} resourceName
* @param {string} format
* Exports the given resource data through csv, xlsx or pdf.
* @param {number} tenantId - Tenant id.
* @param {string} resourceName - Resource name.
* @param {string} format - File format.
*/
async export(tenantId: number, resourceName: string, format: string = 'csv') {
const resource = sanitizeResourceName(resourceName);
@@ -27,24 +29,25 @@ export class ExportResourceService {
const exportable =
this.exportableResources.registry.getExportable(resource);
if (!resourceMeta.exportable) {
throw new ServiceError(Errors.RESOURCE_NOT_EXPORTABLE);
}
const data = await exportable.exportable(tenantId, {});
const exportableColumns = [
{
label: 'Account Normal',
accessor: 'accountNormalFormatted',
},
{
label: 'Account Type',
accessor: 'accountTypeFormatted',
},
];
const exportableColumns = Object.entries(resourceMeta.columns)
.filter(([_, value]) => value.exportable)
.map(([key, value]) => ({
name: value.name,
type: value.type,
accessor: value.accessor || key,
}));
const workbook = xlsx.utils.book_new();
const worksheetData = data.map((item) =>
exportableColumns.map((col) => item[col.accessor])
);
worksheetData.unshift(exportableColumns.map((col) => col.label)); // Add header row
worksheetData.unshift(exportableColumns.map((col) => col.name)); // Add header row
const worksheet = xlsx.utils.aoa_to_sheet(worksheetData);
xlsx.utils.book_append_sheet(workbook, worksheet, 'Exported Data');

View File

@@ -0,0 +1,3 @@
export enum Errors {
RESOURCE_NOT_EXPORTABLE = 'RESOURCE_NOT_EXPORTABLE',
}

View File

@@ -0,0 +1,29 @@
import { Inject, Service } from 'typedi';
import { Exportable } from '../Export/Exportable';
import { IAccountsFilter, IAccountsStructureType } from '@/interfaces';
import ItemCategoriesService from './ItemCategoriesService';
@Service()
export class ItemCategoriesExportable extends Exportable {
@Inject()
private itemCategoriesApplication: ItemCategoriesService;
/**
* Retrieves the accounts data to exportable sheet.
* @param {number} tenantId
* @returns
*/
public exportable(tenantId: number, query: IAccountsFilter) {
const parsedQuery = {
sortOrder: 'desc',
columnSortBy: 'created_at',
inactiveMode: false,
...query,
structure: IAccountsStructureType.Flat,
} as IAccountsFilter;
return this.itemCategoriesApplication
.getItemCategoriesList(tenantId, parsedQuery, {})
.then((output) => output.itemCategories);
}
}

View File

@@ -14,7 +14,13 @@ export class ItemsExportable extends Exportable {
* @returns
*/
public exportable(tenantId: number, query: IItemsFilter) {
const parsedQuery = {} as IItemsFilter;
const parsedQuery = {
sortOrder: 'DESC',
columnSortBy: 'created_at',
page: 1,
...query,
pageSize: 12,
} as IItemsFilter;
return this.itemsApplication
.getItems(tenantId, parsedQuery)

View File

@@ -0,0 +1,29 @@
import { Inject, Service } from 'typedi';
import { IManualJournalsFilter } from '@/interfaces';
import { Exportable } from '../Export/Exportable';
import { ManualJournalsApplication } from './ManualJournalsApplication';
@Service()
export class ManualJournalsExportable extends Exportable {
@Inject()
private manualJournalsApplication: ManualJournalsApplication;
/**
* Retrieves the accounts data to exportable sheet.
* @param {number} tenantId
* @returns
*/
public exportable(tenantId: number, query: IManualJournalsFilter) {
const parsedQuery = {
sortOrder: 'desc',
columnSortBy: 'created_at',
...query,
page: 1,
pageSize: 12000,
} as IManualJournalsFilter;
return this.manualJournalsApplication
.getManualJournals(tenantId, parsedQuery)
.then((output) => output.manualJournals);
}
}

View File

@@ -0,0 +1,24 @@
import { Inject, Service } from 'typedi';
import { Exportable } from '@/services/Export/Exportable';
import { BillPaymentsApplication } from './BillPaymentsApplication';
@Service()
export class BillPaymentExportable extends Exportable {
@Inject()
private billPaymentsApplication: BillPaymentsApplication;
/**
* Retrieves the accounts data to exportable sheet.
* @param {number} tenantId
* @returns
*/
public exportable(tenantId: number, query: any) {
const parsedQuery = {
...query,
} as any;
return this.billPaymentsApplication
.getBillPayments(tenantId, parsedQuery)
.then((output) => output.billPayments);
}
}

View File

@@ -0,0 +1,25 @@
import { Inject, Service } from 'typedi';
import { IBillsFilter } from '@/interfaces';
import { Exportable } from '@/services/Export/Exportable';
import { BillsApplication } from './BillsApplication';
@Service()
export class BillsExportable extends Exportable {
@Inject()
private billsApplication: BillsApplication;
/**
* Retrieves the accounts data to exportable sheet.
* @param {number} tenantId
* @returns
*/
public exportable(tenantId: number, query: IBillsFilter) {
const parsedQuery = {
...query,
} as IBillsFilter;
return this.billsApplication
.getBills(tenantId, parsedQuery)
.then((output) => output.bills);
}
}

View File

@@ -0,0 +1,26 @@
import { Inject, Service } from 'typedi';
import { IVendorCreditsQueryDTO } from '@/interfaces';
import ListVendorCredits from './ListVendorCredits';
import { Exportable } from '@/services/Export/Exportable';
@Service()
export class VendorCreditsExportable extends Exportable {
@Inject()
private getVendorCredits: ListVendorCredits;
/**
* Retrieves the accounts data to exportable sheet.
* @param {number} tenantId -
* @param {IVendorCreditsQueryDTO} query -
* @returns {}
*/
public exportable(tenantId: number, query: IVendorCreditsQueryDTO) {
const parsedQuery = {
...query,
} as IVendorCreditsQueryDTO;
return this.getVendorCredits
.getVendorCredits(tenantId, parsedQuery)
.then((output) => output.vendorCredits);
}
}

View File

@@ -113,6 +113,7 @@ export default class ResourceService {
['fields2', qim.$each, 'name'],
['fields2', qim.$each, $enumerationType, 'options', qim.$each, 'label'],
['fields2', qim.$each, $hasFields, 'fields', qim.$each, 'name'],
['columns', qim.$each, 'name'],
];
return this.i18nService.i18nApply(naviagations, meta, tenantId);
}

View File

@@ -0,0 +1,25 @@
import { Inject, Service } from 'typedi';
import { ISalesInvoicesFilter } from '@/interfaces';
import { Exportable } from '@/services/Export/Exportable';
import { SaleEstimatesApplication } from './SaleEstimatesApplication';
@Service()
export class SaleEstimatesExportable extends Exportable {
@Inject()
private saleEstimatesApplication: SaleEstimatesApplication;
/**
* Retrieves the accounts data to exportable sheet.
* @param {number} tenantId
* @returns
*/
public exportable(tenantId: number, query: ISalesInvoicesFilter) {
const parsedQuery = {
...query,
} as ISalesInvoicesFilter;
return this.saleEstimatesApplication
.getSaleEstimates(tenantId, parsedQuery)
.then((output) => output.salesEstimates);
}
}

View File

@@ -0,0 +1,25 @@
import { Inject, Service } from 'typedi';
import { ISalesInvoicesFilter } from '@/interfaces';
import { SaleInvoiceApplication } from './SaleInvoicesApplication';
import { Exportable } from '@/services/Export/Exportable';
@Service()
export class SaleInvoicesExportable extends Exportable {
@Inject()
private saleInvoicesApplication: SaleInvoiceApplication;
/**
* Retrieves the accounts data to exportable sheet.
* @param {number} tenantId
* @returns
*/
public exportable(tenantId: number, query: ISalesInvoicesFilter) {
const parsedQuery = {
...query,
} as ISalesInvoicesFilter;
return this.saleInvoicesApplication
.getSaleInvoices(tenantId, parsedQuery)
.then((output) => output.salesInvoices);
}
}

View File

@@ -0,0 +1,30 @@
import { Inject, Service } from 'typedi';
import { IAccountsStructureType, IPaymentReceivesFilter } from '@/interfaces';
import { Exportable } from '@/services/Export/Exportable';
import { PaymentReceivesApplication } from './PaymentReceivesApplication';
@Service()
export class PaymentsReceivedExportable extends Exportable {
@Inject()
private paymentReceivedApp: PaymentReceivesApplication;
/**
* Retrieves the accounts data to exportable sheet.
* @param {number} tenantId
* @param {IPaymentReceivesFilter} query -
* @returns
*/
public exportable(tenantId: number, query: IPaymentReceivesFilter) {
const parsedQuery = {
sortOrder: 'desc',
columnSortBy: 'created_at',
inactiveMode: false,
...query,
structure: IAccountsStructureType.Flat,
} as IPaymentReceivesFilter;
return this.paymentReceivedApp
.getPaymentReceives(tenantId, parsedQuery)
.then((output) => output.paymentReceives);
}
}

View File

@@ -0,0 +1,25 @@
import { Inject, Service } from 'typedi';
import { ISalesInvoicesFilter, ISalesReceiptsFilter } from '@/interfaces';
import { Exportable } from '@/services/Export/Exportable';
import { SaleReceiptApplication } from './SaleReceiptApplication';
@Service()
export class SaleReceiptsExportable extends Exportable {
@Inject()
private saleReceiptsApp: SaleReceiptApplication;
/**
* Retrieves the accounts data to exportable sheet.
* @param {number} tenantId
* @returns
*/
public exportable(tenantId: number, query: ISalesReceiptsFilter) {
const parsedQuery = {
...query,
} as ISalesInvoicesFilter;
return this.saleReceiptsApp
.getSaleReceipts(tenantId, parsedQuery)
.then((output) => output.data);
}
}