mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-15 20:30:33 +00:00
refactor(nestjs): export and import module
This commit is contained in:
@@ -18,7 +18,6 @@ import { BankAccount } from '../BankingTransactions/models/BankAccount';
|
||||
import { GetAccountsService } from './GetAccounts.service';
|
||||
import { DynamicListModule } from '../DynamicListing/DynamicList.module';
|
||||
import { AccountsExportable } from './AccountsExportable.service';
|
||||
// import { GetAccountsService } from './GetAccounts.service';
|
||||
|
||||
const models = [RegisterTenancyModel(BankAccount)];
|
||||
|
||||
@@ -39,8 +38,13 @@ const models = [RegisterTenancyModel(BankAccount)];
|
||||
GetAccountTypesService,
|
||||
GetAccountTransactionsService,
|
||||
GetAccountsService,
|
||||
AccountsExportable
|
||||
AccountsExportable,
|
||||
],
|
||||
exports: [
|
||||
AccountRepository,
|
||||
CreateAccountService,
|
||||
...models,
|
||||
AccountsExportable,
|
||||
],
|
||||
exports: [AccountRepository, CreateAccountService, ...models],
|
||||
})
|
||||
export class AccountsModule {}
|
||||
|
||||
@@ -2,12 +2,13 @@ import { AccountsApplication } from './AccountsApplication.service';
|
||||
import { Exportable } from '../Export/Exportable';
|
||||
import { EXPORT_SIZE_LIMIT } from '../Export/constants';
|
||||
import { IAccountsFilter, IAccountsStructureType } from './Accounts.types';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { Global, Injectable } from '@nestjs/common';
|
||||
import { ExportableService } from '../Export/decorators/ExportableModel.decorator';
|
||||
import { Account } from './models/Account.model';
|
||||
|
||||
@Injectable()
|
||||
@ExportableService({ name: Account.name })
|
||||
@Global()
|
||||
export class AccountsExportable extends Exportable {
|
||||
/**
|
||||
* @param {AccountsApplication} accountsApplication
|
||||
|
||||
199
packages/server/src/modules/Accounts/models/Account.meta.ts
Normal file
199
packages/server/src/modules/Accounts/models/Account.meta.ts
Normal file
@@ -0,0 +1,199 @@
|
||||
import { ACCOUNT_TYPES } from "../Accounts.constants";
|
||||
|
||||
export const AccountMeta = {
|
||||
defaultFilterField: 'name',
|
||||
defaultSort: {
|
||||
sortOrder: 'DESC',
|
||||
sortField: 'name',
|
||||
},
|
||||
importable: true,
|
||||
exportable: true,
|
||||
print: {
|
||||
pageTitle: 'Chart of Accounts',
|
||||
},
|
||||
fields: {
|
||||
name: {
|
||||
name: 'account.field.name',
|
||||
column: 'name',
|
||||
fieldType: 'text',
|
||||
},
|
||||
description: {
|
||||
name: 'account.field.description',
|
||||
column: 'description',
|
||||
fieldType: 'text',
|
||||
},
|
||||
slug: {
|
||||
name: 'account.field.slug',
|
||||
column: 'slug',
|
||||
fieldType: 'text',
|
||||
columnable: false,
|
||||
filterable: false,
|
||||
},
|
||||
code: {
|
||||
name: 'account.field.code',
|
||||
column: 'code',
|
||||
fieldType: 'text',
|
||||
},
|
||||
root_type: {
|
||||
name: 'account.field.root_type',
|
||||
fieldType: 'enumeration',
|
||||
options: [
|
||||
{ key: 'asset', label: 'Asset' },
|
||||
{ key: 'liability', label: 'Liability' },
|
||||
{ key: 'equity', label: 'Equity' },
|
||||
{ key: 'Income', label: 'Income' },
|
||||
{ key: 'expense', label: 'Expense' },
|
||||
],
|
||||
filterCustomQuery: RootTypeFieldFilterQuery,
|
||||
sortable: false,
|
||||
},
|
||||
normal: {
|
||||
name: 'account.field.normal',
|
||||
fieldType: 'enumeration',
|
||||
options: [
|
||||
{ key: 'debit', label: 'account.field.normal.debit' },
|
||||
{ key: 'credit', label: 'account.field.normal.credit' },
|
||||
],
|
||||
filterCustomQuery: NormalTypeFieldFilterQuery,
|
||||
sortable: false,
|
||||
},
|
||||
type: {
|
||||
name: 'account.field.type',
|
||||
column: 'account_type',
|
||||
fieldType: 'enumeration',
|
||||
options: ACCOUNT_TYPES.map((accountType) => ({
|
||||
label: accountType.label,
|
||||
key: accountType.key,
|
||||
})),
|
||||
},
|
||||
active: {
|
||||
name: 'account.field.active',
|
||||
column: 'active',
|
||||
fieldType: 'boolean',
|
||||
filterable: false,
|
||||
},
|
||||
balance: {
|
||||
name: 'account.field.balance',
|
||||
column: 'amount',
|
||||
fieldType: 'number',
|
||||
},
|
||||
currency: {
|
||||
name: 'account.field.currency',
|
||||
column: 'currency_code',
|
||||
fieldType: 'text',
|
||||
filterable: false,
|
||||
},
|
||||
created_at: {
|
||||
name: 'account.field.created_at',
|
||||
column: 'created_at',
|
||||
fieldType: 'date',
|
||||
},
|
||||
},
|
||||
columns: {
|
||||
name: {
|
||||
name: 'account.field.name',
|
||||
type: 'text',
|
||||
},
|
||||
code: {
|
||||
name: 'account.field.code',
|
||||
type: 'text',
|
||||
},
|
||||
rootType: {
|
||||
name: 'account.field.root_type',
|
||||
type: 'text',
|
||||
accessor: 'accountRootType',
|
||||
},
|
||||
accountType: {
|
||||
name: 'account.field.type',
|
||||
accessor: 'accountTypeLabel',
|
||||
type: 'text',
|
||||
},
|
||||
accountNormal: {
|
||||
name: 'account.field.normal',
|
||||
accessor: 'accountNormalFormatted',
|
||||
},
|
||||
currencyCode: {
|
||||
name: 'account.field.currency',
|
||||
type: 'text',
|
||||
},
|
||||
bankBalance: {
|
||||
name: 'account.field.bank_balance',
|
||||
accessor: 'bankBalanceFormatted',
|
||||
type: 'text',
|
||||
exportable: true,
|
||||
},
|
||||
balance: {
|
||||
name: 'account.field.balance',
|
||||
accessor: 'formattedAmount',
|
||||
},
|
||||
description: {
|
||||
name: 'account.field.description',
|
||||
type: 'text',
|
||||
},
|
||||
active: {
|
||||
name: 'account.field.active',
|
||||
type: 'boolean',
|
||||
},
|
||||
createdAt: {
|
||||
name: 'account.field.created_at',
|
||||
printable: false,
|
||||
},
|
||||
},
|
||||
fields2: {
|
||||
name: {
|
||||
name: 'account.field.name',
|
||||
fieldType: 'text',
|
||||
unique: true,
|
||||
required: true,
|
||||
},
|
||||
description: {
|
||||
name: 'account.field.description',
|
||||
fieldType: 'text',
|
||||
},
|
||||
code: {
|
||||
name: 'account.field.code',
|
||||
fieldType: 'text',
|
||||
minLength: 3,
|
||||
maxLength: 6,
|
||||
unique: true,
|
||||
importHint: 'Unique number to identify the account.',
|
||||
},
|
||||
accountType: {
|
||||
name: 'account.field.type',
|
||||
fieldType: 'enumeration',
|
||||
options: ACCOUNT_TYPES.map((accountType) => ({
|
||||
label: accountType.label,
|
||||
key: accountType.key,
|
||||
})),
|
||||
required: true,
|
||||
},
|
||||
active: {
|
||||
name: 'account.field.active',
|
||||
fieldType: 'boolean',
|
||||
},
|
||||
currencyCode: {
|
||||
name: 'account.field.currency',
|
||||
fieldType: 'text',
|
||||
},
|
||||
parentAccountId: {
|
||||
name: 'account.field.parent_account',
|
||||
fieldType: 'relation',
|
||||
relationModel: 'Account',
|
||||
relationImportMatch: ['name', 'code'],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Filter query of root type field .
|
||||
*/
|
||||
function RootTypeFieldFilterQuery(query, role) {
|
||||
query.modify('filterByRootType', role.value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter query of normal field .
|
||||
*/
|
||||
function NormalTypeFieldFilterQuery(query, role) {
|
||||
query.modify('filterByAccountNormal', role.value);
|
||||
}
|
||||
@@ -1,27 +1,27 @@
|
||||
/* eslint-disable global-require */
|
||||
// import { mixin, Model } from 'objection';
|
||||
import { castArray } from 'lodash';
|
||||
import { Model } from 'objection';
|
||||
import DependencyGraph from '@/libs/dependency-graph';
|
||||
import {
|
||||
ACCOUNT_TYPES,
|
||||
getAccountsSupportsMultiCurrency,
|
||||
} from '@/constants/accounts';
|
||||
import { TenantModel } from '@/modules/System/models/TenantModel';
|
||||
// import { SearchableModel } from '@/modules/Search/SearchableMdel';
|
||||
// import { CustomViewBaseModel } from '@/modules/CustomViews/CustomViewBaseModel';
|
||||
// import { ModelSettings } from '@/modules/Settings/ModelSettings';
|
||||
import { AccountTypesUtils } from '@/libs/accounts-utils/AccountTypesUtils';
|
||||
import { Model } from 'objection';
|
||||
import { PlaidItem } from '@/modules/BankingPlaid/models/PlaidItem';
|
||||
import { TenantBaseModel } from '@/modules/System/models/TenantBaseModel';
|
||||
import { flatToNestedArray } from '@/utils/flat-to-nested-array';
|
||||
import { ExportableModel } from '../../Export/decorators/ExportableModel.decorator';
|
||||
import { AccountMeta } from './Account.meta';
|
||||
import { InjectModelMeta } from '@/modules/Tenancy/TenancyModels/decorators/InjectModelMeta.decorator';
|
||||
// import AccountSettings from './Account.Settings';
|
||||
// import { DEFAULT_VIEWS } from '@/modules/Accounts/constants';
|
||||
// import { buildFilterQuery, buildSortColumnQuery } from '@/lib/ViewRolesBuilder';
|
||||
// import { flatToNestedArray } from 'utils';
|
||||
|
||||
@ExportableModel()
|
||||
@InjectModelMeta(AccountMeta)
|
||||
export class Account extends TenantBaseModel {
|
||||
public name!: string;
|
||||
public slug!: string;
|
||||
|
||||
@@ -80,6 +80,7 @@ import { LoopsModule } from '../Loops/Loops.module';
|
||||
import { AttachmentsModule } from '../Attachments/Attachment.module';
|
||||
import { S3Module } from '../S3/S3.module';
|
||||
import { ExportModule } from '../Export/Export.module';
|
||||
import { ImportModule } from '../Import/Import.module';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
@@ -194,7 +195,8 @@ import { ExportModule } from '../Export/Export.module';
|
||||
LoopsModule,
|
||||
AttachmentsModule,
|
||||
S3Module,
|
||||
ExportModule
|
||||
ExportModule,
|
||||
ImportModule
|
||||
],
|
||||
controllers: [AppController],
|
||||
providers: [
|
||||
|
||||
@@ -17,6 +17,7 @@ import { BillPaymentGLEntriesSubscriber } from './subscribers/BillPaymentGLEntri
|
||||
import { LedgerModule } from '../Ledger/Ledger.module';
|
||||
import { AccountsModule } from '../Accounts/Accounts.module';
|
||||
import { BillPaymentsExportable } from './queries/BillPaymentsExportable';
|
||||
import { GetBillPayments } from '../Bills/queries/GetBillPayments';
|
||||
|
||||
@Module({
|
||||
imports: [LedgerModule, AccountsModule],
|
||||
@@ -35,6 +36,7 @@ import { BillPaymentsExportable } from './queries/BillPaymentsExportable';
|
||||
TenancyContext,
|
||||
BillPaymentGLEntries,
|
||||
BillPaymentGLEntriesSubscriber,
|
||||
GetBillPayments,
|
||||
BillPaymentsExportable
|
||||
],
|
||||
exports: [BillPaymentValidators, CreateBillPaymentService],
|
||||
|
||||
286
packages/server/src/modules/Bills/models/Bill.meta.ts
Normal file
286
packages/server/src/modules/Bills/models/Bill.meta.ts
Normal file
@@ -0,0 +1,286 @@
|
||||
import { Features } from "@/common/types/Features";
|
||||
|
||||
export const BillMeta = {
|
||||
defaultFilterField: 'vendor',
|
||||
defaultSort: {
|
||||
sortOrder: 'DESC',
|
||||
sortField: 'bill_date',
|
||||
},
|
||||
importable: true,
|
||||
exportFlattenOn: 'entries',
|
||||
exportable: true,
|
||||
importAggregator: 'group',
|
||||
importAggregateOn: 'entries',
|
||||
importAggregateBy: 'billNumber',
|
||||
print: {
|
||||
pageTitle: 'Bills',
|
||||
},
|
||||
fields: {
|
||||
vendor: {
|
||||
name: 'bill.field.vendor',
|
||||
column: 'vendor_id',
|
||||
fieldType: 'relation',
|
||||
|
||||
relationType: 'enumeration',
|
||||
relationKey: 'vendor',
|
||||
|
||||
relationEntityLabel: 'display_name',
|
||||
relationEntityKey: 'id',
|
||||
},
|
||||
bill_number: {
|
||||
name: 'bill.field.bill_number',
|
||||
column: 'bill_number',
|
||||
columnable: true,
|
||||
fieldType: 'text',
|
||||
},
|
||||
bill_date: {
|
||||
name: 'bill.field.bill_date',
|
||||
column: 'bill_date',
|
||||
columnable: true,
|
||||
fieldType: 'date',
|
||||
},
|
||||
due_date: {
|
||||
name: 'bill.field.due_date',
|
||||
column: 'due_date',
|
||||
columnable: true,
|
||||
fieldType: 'date',
|
||||
},
|
||||
reference_no: {
|
||||
name: 'bill.field.reference_no',
|
||||
column: 'reference_no',
|
||||
columnable: true,
|
||||
fieldType: 'text',
|
||||
},
|
||||
status: {
|
||||
name: 'bill.field.status',
|
||||
fieldType: 'enumeration',
|
||||
columnable: true,
|
||||
options: [
|
||||
{ label: 'bill.field.status.paid', key: 'paid' },
|
||||
{ label: 'bill.field.status.partially-paid', key: 'partially-paid' },
|
||||
{ label: 'bill.field.status.overdue', key: 'overdue' },
|
||||
{ label: 'bill.field.status.unpaid', key: 'unpaid' },
|
||||
{ label: 'bill.field.status.opened', key: 'opened' },
|
||||
{ label: 'bill.field.status.draft', key: 'draft' },
|
||||
],
|
||||
filterCustomQuery: StatusFieldFilterQuery,
|
||||
sortCustomQuery: StatusFieldSortQuery,
|
||||
},
|
||||
amount: {
|
||||
name: 'bill.field.amount',
|
||||
column: 'amount',
|
||||
fieldType: 'number',
|
||||
},
|
||||
payment_amount: {
|
||||
name: 'bill.field.payment_amount',
|
||||
column: 'payment_amount',
|
||||
fieldType: 'number',
|
||||
},
|
||||
note: {
|
||||
name: 'bill.field.note',
|
||||
column: 'note',
|
||||
fieldType: 'text',
|
||||
},
|
||||
created_at: {
|
||||
name: 'bill.field.created_at',
|
||||
column: 'created_at',
|
||||
fieldType: 'date',
|
||||
},
|
||||
},
|
||||
columns: {
|
||||
billDate: {
|
||||
name: 'Date',
|
||||
accessor: 'formattedBillDate',
|
||||
},
|
||||
billNumber: {
|
||||
name: 'Bill No.',
|
||||
type: 'text',
|
||||
},
|
||||
referenceNo: {
|
||||
name: 'Reference No.',
|
||||
type: 'text',
|
||||
},
|
||||
dueDate: {
|
||||
name: 'Due Date',
|
||||
type: 'date',
|
||||
accessor: 'formattedDueDate',
|
||||
},
|
||||
vendorId: {
|
||||
name: 'Vendor',
|
||||
accessor: 'vendor.displayName',
|
||||
type: 'text',
|
||||
},
|
||||
amount: {
|
||||
name: 'Amount',
|
||||
accessor: 'formattedAmount',
|
||||
},
|
||||
exchangeRate: {
|
||||
name: 'Exchange Rate',
|
||||
type: 'number',
|
||||
printable: false,
|
||||
},
|
||||
currencyCode: {
|
||||
name: 'Currency Code',
|
||||
type: 'text',
|
||||
printable: false,
|
||||
},
|
||||
dueAmount: {
|
||||
name: 'Due Amount',
|
||||
accessor: 'formattedDueAmount',
|
||||
},
|
||||
paidAmount: {
|
||||
name: 'Paid Amount',
|
||||
accessor: 'formattedPaymentAmount',
|
||||
},
|
||||
note: {
|
||||
name: 'Note',
|
||||
type: 'text',
|
||||
printable: false,
|
||||
},
|
||||
open: {
|
||||
name: 'Open',
|
||||
type: 'boolean',
|
||||
printable: false,
|
||||
},
|
||||
entries: {
|
||||
name: 'Entries',
|
||||
accessor: 'entries',
|
||||
type: 'collection',
|
||||
collectionOf: 'object',
|
||||
columns: {
|
||||
itemName: {
|
||||
name: 'Item Name',
|
||||
accessor: 'item.name',
|
||||
},
|
||||
rate: {
|
||||
name: 'Item Rate',
|
||||
accessor: 'rateFormatted',
|
||||
},
|
||||
quantity: {
|
||||
name: 'Item Quantity',
|
||||
accessor: 'quantityFormatted',
|
||||
},
|
||||
description: {
|
||||
name: 'Item Description',
|
||||
},
|
||||
amount: {
|
||||
name: 'Item Amount',
|
||||
accessor: 'totalFormatted',
|
||||
},
|
||||
},
|
||||
},
|
||||
branch: {
|
||||
name: 'Branch',
|
||||
type: 'text',
|
||||
accessor: 'branch.name',
|
||||
features: [Features.BRANCHES],
|
||||
},
|
||||
warehouse: {
|
||||
name: 'Warehouse',
|
||||
type: 'text',
|
||||
accessor: 'warehouse.name',
|
||||
features: [Features.BRANCHES],
|
||||
},
|
||||
},
|
||||
fields2: {
|
||||
billNumber: {
|
||||
name: 'Bill No.',
|
||||
fieldType: 'text',
|
||||
required: true,
|
||||
},
|
||||
referenceNo: {
|
||||
name: 'Reference No.',
|
||||
fieldType: 'text',
|
||||
},
|
||||
billDate: {
|
||||
name: 'Date',
|
||||
fieldType: 'date',
|
||||
required: true,
|
||||
},
|
||||
dueDate: {
|
||||
name: 'Due Date',
|
||||
fieldType: 'date',
|
||||
required: true,
|
||||
},
|
||||
vendorId: {
|
||||
name: 'Vendor',
|
||||
fieldType: 'relation',
|
||||
relationModel: 'Contact',
|
||||
relationImportMatch: 'displayName',
|
||||
required: true,
|
||||
},
|
||||
exchangeRate: {
|
||||
name: 'Exchange Rate',
|
||||
fieldType: 'number',
|
||||
},
|
||||
note: {
|
||||
name: 'Note',
|
||||
fieldType: 'text',
|
||||
},
|
||||
open: {
|
||||
name: 'Open',
|
||||
fieldType: 'boolean',
|
||||
},
|
||||
entries: {
|
||||
name: 'Entries',
|
||||
fieldType: 'collection',
|
||||
collectionOf: 'object',
|
||||
collectionMinLength: 1,
|
||||
required: true,
|
||||
fields: {
|
||||
itemId: {
|
||||
name: 'Item',
|
||||
fieldType: 'relation',
|
||||
relationModel: 'Item',
|
||||
relationImportMatch: ['name', 'code'],
|
||||
required: true,
|
||||
importHint: 'Matches the item name or code.',
|
||||
},
|
||||
rate: {
|
||||
name: 'Rate',
|
||||
fieldType: 'number',
|
||||
required: true,
|
||||
},
|
||||
quantity: {
|
||||
name: 'Quantity',
|
||||
fieldType: 'number',
|
||||
required: true,
|
||||
},
|
||||
description: {
|
||||
name: 'Line Description',
|
||||
fieldType: 'text',
|
||||
},
|
||||
},
|
||||
},
|
||||
branchId: {
|
||||
name: 'Branch',
|
||||
fieldType: 'relation',
|
||||
relationModel: 'Branch',
|
||||
relationImportMatch: ['name', 'code'],
|
||||
features: [Features.BRANCHES],
|
||||
required: true,
|
||||
},
|
||||
warehouseId: {
|
||||
name: 'Warehouse',
|
||||
fieldType: 'relation',
|
||||
relationModel: 'Warehouse',
|
||||
relationImportMatch: ['name', 'code'],
|
||||
features: [Features.WAREHOUSES],
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Status field filter custom query.
|
||||
*/
|
||||
function StatusFieldFilterQuery(query, role) {
|
||||
query.modify('statusFilter', role.value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Status field sort custom query.
|
||||
*/
|
||||
function StatusFieldSortQuery(query, role) {
|
||||
query.modify('sortByStatus', role.order);
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Model, raw, mixin } from 'objection';
|
||||
import type { Knex } from 'knex';
|
||||
import { Model, raw } from 'objection';
|
||||
import { castArray, difference, defaultTo } from 'lodash';
|
||||
import * as moment from 'moment';
|
||||
import * as R from 'ramda';
|
||||
@@ -12,11 +13,13 @@ import { BaseModel, PaginationQueryBuilderType } from '@/models/Model';
|
||||
import { ItemEntry } from '@/modules/TransactionItemEntry/models/ItemEntry';
|
||||
import { BillLandedCost } from '@/modules/BillLandedCosts/models/BillLandedCost';
|
||||
import { DiscountType } from '@/common/types/Discount';
|
||||
import type { Knex, QueryBuilder } from 'knex';
|
||||
import { TenantBaseModel } from '@/modules/System/models/TenantBaseModel';
|
||||
import { ExportableModel } from '@/modules/Export/decorators/ExportableModel.decorator';
|
||||
import { InjectModelMeta } from '@/modules/Tenancy/TenancyModels/decorators/InjectModelMeta.decorator';
|
||||
import { BillMeta } from './Bill.meta';
|
||||
|
||||
@ExportableModel()
|
||||
@InjectModelMeta(BillMeta)
|
||||
export class Bill extends TenantBaseModel {
|
||||
public amount: number;
|
||||
public paymentAmount: number;
|
||||
|
||||
11
packages/server/src/modules/Branches/models/Branch.meta.ts
Normal file
11
packages/server/src/modules/Branches/models/Branch.meta.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
export const BranchMeta = {
|
||||
fields2: {
|
||||
name: {
|
||||
name: 'Name',
|
||||
fieldType: 'text',
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
columns: {},
|
||||
fields: {}
|
||||
};
|
||||
@@ -3,7 +3,10 @@
|
||||
// import BranchMetadata from './Branch.settings';
|
||||
// import ModelSetting from './ModelSetting';
|
||||
import { BaseModel } from '@/models/Model';
|
||||
import { InjectModelMeta } from '@/modules/Tenancy/TenancyModels/decorators/InjectModelMeta.decorator';
|
||||
import { BranchMeta } from './Branch.meta';
|
||||
|
||||
@InjectModelMeta(BranchMeta)
|
||||
export class Branch extends BaseModel{
|
||||
name!: string;
|
||||
code!: string;
|
||||
|
||||
@@ -14,9 +14,11 @@ import { CustomersApplication } from './CustomersApplication.service';
|
||||
import { DeleteCustomer } from './commands/DeleteCustomer.service';
|
||||
import { CustomersExportable } from './CustomersExportable';
|
||||
import { CustomersImportable } from './CustomersImportable';
|
||||
import { GetCustomers } from './queries/GetCustomers.service';
|
||||
import { DynamicListModule } from '../DynamicListing/DynamicList.module';
|
||||
|
||||
@Module({
|
||||
imports: [TenancyDatabaseModule],
|
||||
imports: [TenancyDatabaseModule, DynamicListModule],
|
||||
controllers: [CustomersController],
|
||||
providers: [
|
||||
ActivateCustomer,
|
||||
@@ -33,7 +35,8 @@ import { CustomersImportable } from './CustomersImportable';
|
||||
TransformerInjectable,
|
||||
GetCustomerService,
|
||||
CustomersExportable,
|
||||
CustomersImportable
|
||||
CustomersImportable,
|
||||
GetCustomers
|
||||
],
|
||||
})
|
||||
export class CustomersModule {}
|
||||
|
||||
422
packages/server/src/modules/Customers/models/Customer.meta.ts
Normal file
422
packages/server/src/modules/Customers/models/Customer.meta.ts
Normal file
@@ -0,0 +1,422 @@
|
||||
export const CustomerMeta = {
|
||||
importable: true,
|
||||
exportable: true,
|
||||
defaultFilterField: 'displayName',
|
||||
defaultSort: {
|
||||
sortOrder: 'DESC',
|
||||
sortField: 'created_at',
|
||||
},
|
||||
print: {
|
||||
pageTitle: 'Customers',
|
||||
},
|
||||
fields: {
|
||||
first_name: {
|
||||
name: 'vendor.field.first_name',
|
||||
column: 'first_name',
|
||||
fieldType: 'text',
|
||||
},
|
||||
last_name: {
|
||||
name: 'vendor.field.last_name',
|
||||
column: 'last_name',
|
||||
fieldType: 'text',
|
||||
},
|
||||
display_name: {
|
||||
name: 'vendor.field.display_name',
|
||||
column: 'display_name',
|
||||
fieldType: 'text',
|
||||
},
|
||||
email: {
|
||||
name: 'vendor.field.email',
|
||||
column: 'email',
|
||||
fieldType: 'text',
|
||||
},
|
||||
work_phone: {
|
||||
name: 'vendor.field.work_phone',
|
||||
column: 'work_phone',
|
||||
fieldType: 'text',
|
||||
},
|
||||
personal_phone: {
|
||||
name: 'vendor.field.personal_pone',
|
||||
column: 'personal_phone',
|
||||
fieldType: 'text',
|
||||
},
|
||||
company_name: {
|
||||
name: 'vendor.field.company_name',
|
||||
column: 'company_name',
|
||||
fieldType: 'text',
|
||||
},
|
||||
website: {
|
||||
name: 'vendor.field.website',
|
||||
column: 'website',
|
||||
fieldType: 'text',
|
||||
},
|
||||
created_at: {
|
||||
name: 'vendor.field.created_at',
|
||||
column: 'created_at',
|
||||
fieldType: 'date',
|
||||
},
|
||||
balance: {
|
||||
name: 'vendor.field.balance',
|
||||
column: 'balance',
|
||||
fieldType: 'number',
|
||||
},
|
||||
opening_balance: {
|
||||
name: 'vendor.field.opening_balance',
|
||||
column: 'opening_balance',
|
||||
fieldType: 'number',
|
||||
},
|
||||
opening_balance_at: {
|
||||
name: 'vendor.field.opening_balance_at',
|
||||
column: 'opening_balance_at',
|
||||
fieldType: 'date',
|
||||
},
|
||||
currency_code: {
|
||||
name: 'vendor.field.currency',
|
||||
column: 'currency_code',
|
||||
fieldType: 'text',
|
||||
},
|
||||
status: {
|
||||
name: 'vendor.field.status',
|
||||
type: 'enumeration',
|
||||
options: [
|
||||
{ key: 'overdue', label: 'vendor.field.status.overdue' },
|
||||
{ key: 'unpaid', label: 'vendor.field.status.unpaid' },
|
||||
],
|
||||
filterCustomQuery: (query, role) => {
|
||||
switch (role.value) {
|
||||
case 'overdue':
|
||||
query.modify('overdue');
|
||||
break;
|
||||
case 'unpaid':
|
||||
query.modify('unpaid');
|
||||
break;
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
columns: {
|
||||
customerType: {
|
||||
name: 'Customer Type',
|
||||
type: 'text',
|
||||
accessor: 'formattedCustomerType',
|
||||
},
|
||||
firstName: {
|
||||
name: 'vendor.field.first_name',
|
||||
type: 'text',
|
||||
},
|
||||
lastName: {
|
||||
name: 'vendor.field.last_name',
|
||||
type: 'text',
|
||||
},
|
||||
displayName: {
|
||||
name: 'vendor.field.display_name',
|
||||
type: 'text',
|
||||
},
|
||||
email: {
|
||||
name: 'vendor.field.email',
|
||||
type: 'text',
|
||||
},
|
||||
workPhone: {
|
||||
name: 'vendor.field.work_phone',
|
||||
type: 'text',
|
||||
},
|
||||
personalPhone: {
|
||||
name: 'vendor.field.personal_phone',
|
||||
type: 'text',
|
||||
},
|
||||
companyName: {
|
||||
name: 'vendor.field.company_name',
|
||||
type: 'text',
|
||||
},
|
||||
website: {
|
||||
name: 'vendor.field.website',
|
||||
type: 'text',
|
||||
},
|
||||
balance: {
|
||||
name: 'vendor.field.balance',
|
||||
type: 'number',
|
||||
accessor: 'formattedBalance',
|
||||
},
|
||||
openingBalance: {
|
||||
name: 'vendor.field.opening_balance',
|
||||
type: 'number',
|
||||
printable: false,
|
||||
},
|
||||
openingBalanceAt: {
|
||||
name: 'vendor.field.opening_balance_at',
|
||||
type: 'date',
|
||||
printable: false,
|
||||
accessor: 'formattedOpeningBalanceAt'
|
||||
},
|
||||
currencyCode: {
|
||||
name: 'vendor.field.currency',
|
||||
type: 'text',
|
||||
printable: false,
|
||||
},
|
||||
status: {
|
||||
name: 'vendor.field.status',
|
||||
printable: false,
|
||||
},
|
||||
note: {
|
||||
name: 'vendor.field.note',
|
||||
printable: false,
|
||||
},
|
||||
// Billing Address
|
||||
billingAddress1: {
|
||||
name: 'Billing Address 1',
|
||||
column: 'billing_address1',
|
||||
type: 'text',
|
||||
printable: false,
|
||||
},
|
||||
billingAddress2: {
|
||||
name: 'Billing Address 2',
|
||||
column: 'billing_address2',
|
||||
type: 'text',
|
||||
printable: false,
|
||||
},
|
||||
billingAddressCity: {
|
||||
name: 'Billing Address City',
|
||||
column: 'billing_address_city',
|
||||
type: 'text',
|
||||
printable: false,
|
||||
},
|
||||
billingAddressCountry: {
|
||||
name: 'Billing Address Country',
|
||||
column: 'billing_address_country',
|
||||
type: 'text',
|
||||
printable: false,
|
||||
},
|
||||
billingAddressPostcode: {
|
||||
name: 'Billing Address Postcode',
|
||||
column: 'billing_address_postcode',
|
||||
type: 'text',
|
||||
printable: false,
|
||||
},
|
||||
billingAddressState: {
|
||||
name: 'Billing Address State',
|
||||
column: 'billing_address_state',
|
||||
type: 'text',
|
||||
printable: false,
|
||||
},
|
||||
billingAddressPhone: {
|
||||
name: 'Billing Address Phone',
|
||||
column: 'billing_address_phone',
|
||||
type: 'text',
|
||||
printable: false,
|
||||
},
|
||||
// Shipping Address
|
||||
shippingAddress1: {
|
||||
name: 'Shipping Address 1',
|
||||
column: 'shipping_address1',
|
||||
type: 'text',
|
||||
printable: false,
|
||||
},
|
||||
shippingAddress2: {
|
||||
name: 'Shipping Address 2',
|
||||
column: 'shipping_address2',
|
||||
type: 'text',
|
||||
printable: false,
|
||||
},
|
||||
shippingAddressCity: {
|
||||
name: 'Shipping Address City',
|
||||
column: 'shipping_address_city',
|
||||
type: 'text',
|
||||
printable: false,
|
||||
},
|
||||
shippingAddressCountry: {
|
||||
name: 'Shipping Address Country',
|
||||
column: 'shipping_address_country',
|
||||
type: 'text',
|
||||
printable: false,
|
||||
},
|
||||
shippingAddressPostcode: {
|
||||
name: 'Shipping Address Postcode',
|
||||
column: 'shipping_address_postcode',
|
||||
type: 'text',
|
||||
printable: false,
|
||||
},
|
||||
shippingAddressPhone: {
|
||||
name: 'Shipping Address Phone',
|
||||
column: 'shipping_address_phone',
|
||||
type: 'text',
|
||||
printable: false,
|
||||
},
|
||||
shippingAddressState: {
|
||||
name: 'Shipping Address State',
|
||||
column: 'shipping_address_state',
|
||||
type: 'text',
|
||||
printable: false,
|
||||
},
|
||||
createdAt: {
|
||||
name: 'vendor.field.created_at',
|
||||
type: 'date',
|
||||
printable: false,
|
||||
},
|
||||
},
|
||||
fields2: {
|
||||
customerType: {
|
||||
name: 'Customer Type',
|
||||
fieldType: 'enumeration',
|
||||
options: [
|
||||
{ key: 'business', label: 'Business' },
|
||||
{ key: 'individual', label: 'Individual' },
|
||||
],
|
||||
required: true,
|
||||
},
|
||||
firstName: {
|
||||
name: 'customer.field.first_name',
|
||||
column: 'first_name',
|
||||
fieldType: 'text',
|
||||
},
|
||||
lastName: {
|
||||
name: 'customer.field.last_name',
|
||||
column: 'last_name',
|
||||
fieldType: 'text',
|
||||
},
|
||||
displayName: {
|
||||
name: 'customer.field.display_name',
|
||||
column: 'display_name',
|
||||
fieldType: 'text',
|
||||
required: true,
|
||||
},
|
||||
email: {
|
||||
name: 'customer.field.email',
|
||||
column: 'email',
|
||||
fieldType: 'text',
|
||||
},
|
||||
workPhone: {
|
||||
name: 'customer.field.work_phone',
|
||||
column: 'work_phone',
|
||||
fieldType: 'text',
|
||||
},
|
||||
personalPhone: {
|
||||
name: 'customer.field.personal_phone',
|
||||
column: 'personal_phone',
|
||||
fieldType: 'text',
|
||||
},
|
||||
companyName: {
|
||||
name: 'customer.field.company_name',
|
||||
column: 'company_name',
|
||||
fieldType: 'text',
|
||||
},
|
||||
website: {
|
||||
name: 'customer.field.website',
|
||||
column: 'website',
|
||||
fieldType: 'url',
|
||||
},
|
||||
openingBalance: {
|
||||
name: 'customer.field.opening_balance',
|
||||
column: 'opening_balance',
|
||||
fieldType: 'number',
|
||||
},
|
||||
openingBalanceAt: {
|
||||
name: 'customer.field.opening_balance_at',
|
||||
column: 'opening_balance_at',
|
||||
filterable: false,
|
||||
fieldType: 'date',
|
||||
},
|
||||
openingBalanceExchangeRate: {
|
||||
name: 'Opening Balance Ex. Rate',
|
||||
column: 'opening_balance_exchange_rate',
|
||||
fieldType: 'number',
|
||||
},
|
||||
currencyCode: {
|
||||
name: 'customer.field.currency',
|
||||
column: 'currency_code',
|
||||
fieldType: 'text',
|
||||
},
|
||||
note: {
|
||||
name: 'Note',
|
||||
column: 'note',
|
||||
fieldType: 'text',
|
||||
},
|
||||
active: {
|
||||
name: 'Active',
|
||||
column: 'active',
|
||||
fieldType: 'boolean',
|
||||
},
|
||||
// Billing Address
|
||||
billingAddress1: {
|
||||
name: 'Billing Address 1',
|
||||
column: 'billing_address1',
|
||||
fieldType: 'text',
|
||||
},
|
||||
billingAddress2: {
|
||||
name: 'Billing Address 2',
|
||||
column: 'billing_address2',
|
||||
fieldType: 'text',
|
||||
},
|
||||
billingAddressCity: {
|
||||
name: 'Billing Address City',
|
||||
column: 'billing_address_city',
|
||||
fieldType: 'text',
|
||||
},
|
||||
billingAddressCountry: {
|
||||
name: 'Billing Address Country',
|
||||
column: 'billing_address_country',
|
||||
fieldType: 'text',
|
||||
},
|
||||
billingAddressPostcode: {
|
||||
name: 'Billing Address Postcode',
|
||||
column: 'billing_address_postcode',
|
||||
fieldType: 'text',
|
||||
},
|
||||
billingAddressState: {
|
||||
name: 'Billing Address State',
|
||||
column: 'billing_address_state',
|
||||
fieldType: 'text',
|
||||
},
|
||||
billingAddressPhone: {
|
||||
name: 'Billing Address Phone',
|
||||
column: 'billing_address_phone',
|
||||
fieldType: 'text',
|
||||
},
|
||||
// Shipping Address
|
||||
shippingAddress1: {
|
||||
name: 'Shipping Address 1',
|
||||
column: 'shipping_address1',
|
||||
fieldType: 'text',
|
||||
},
|
||||
shippingAddress2: {
|
||||
name: 'Shipping Address 2',
|
||||
column: 'shipping_address2',
|
||||
fieldType: 'text',
|
||||
},
|
||||
shippingAddressCity: {
|
||||
name: 'Shipping Address City',
|
||||
column: 'shipping_address_city',
|
||||
fieldType: 'text',
|
||||
},
|
||||
shippingAddressCountry: {
|
||||
name: 'Shipping Address Country',
|
||||
column: 'shipping_address_country',
|
||||
fieldType: 'text',
|
||||
},
|
||||
shippingAddressPostcode: {
|
||||
name: 'Shipping Address Postcode',
|
||||
column: 'shipping_address_postcode',
|
||||
fieldType: 'text',
|
||||
},
|
||||
shippingAddressPhone: {
|
||||
name: 'Shipping Address Phone',
|
||||
column: 'shipping_address_phone',
|
||||
fieldType: 'text',
|
||||
},
|
||||
shippingAddressState: {
|
||||
name: 'Shipping Address State',
|
||||
column: 'shipping_address_state',
|
||||
fieldType: 'text',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
function statusFieldFilterQuery(query, role) {
|
||||
switch (role.value) {
|
||||
case 'overdue':
|
||||
query.modify('overdue');
|
||||
break;
|
||||
case 'unpaid':
|
||||
query.modify('unpaid');
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,9 @@
|
||||
import { TenantBaseModel } from '@/modules/System/models/TenantBaseModel';
|
||||
import { InjectModelMeta } from '@/modules/Tenancy/TenancyModels/decorators/InjectModelMeta.decorator';
|
||||
import { CustomerMeta } from './Customer.meta';
|
||||
|
||||
|
||||
@InjectModelMeta(CustomerMeta)
|
||||
export class Customer extends TenantBaseModel{
|
||||
contactService: string;
|
||||
contactType: string;
|
||||
|
||||
@@ -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 {}
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
|
||||
|
||||
@@ -4,8 +4,4 @@ export class ExportQuery {
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
resource: string;
|
||||
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
format: string;
|
||||
}
|
||||
|
||||
@@ -12,11 +12,17 @@ import { ImportFileMapping } from './ImportFileMapping';
|
||||
import { ImportFileDataValidator } from './ImportFileDataValidator';
|
||||
import { ImportFileDataTransformer } from './ImportFileDataTransformer';
|
||||
import { ImportFileCommon } from './ImportFileCommon';
|
||||
import { ImportableResources } from './ImportableResources';
|
||||
import { ResourceModule } from '../Resource/Resource.module';
|
||||
import { TenancyModule } from '../Tenancy/Tenancy.module';
|
||||
import { AccountsModule } from '../Accounts/Accounts.module';
|
||||
|
||||
@Module({
|
||||
imports: [ResourceModule, TenancyModule, AccountsModule],
|
||||
providers: [
|
||||
ImportAls,
|
||||
ImportSampleService,
|
||||
ImportableResources,
|
||||
ImportResourceApplication,
|
||||
ImportDeleteExpiredFiles,
|
||||
ImportFileUploadService,
|
||||
@@ -27,7 +33,7 @@ import { ImportFileCommon } from './ImportFileCommon';
|
||||
ImportFileMapping,
|
||||
ImportFileDataValidator,
|
||||
ImportFileDataTransformer,
|
||||
ImportFileCommon
|
||||
ImportFileCommon,
|
||||
],
|
||||
exports: [ImportAls],
|
||||
})
|
||||
|
||||
@@ -35,7 +35,7 @@ export class ImportableResources {
|
||||
// resource: 'UncategorizedCashflowTransaction',
|
||||
// importable: UncategorizedTransactionsImportable,
|
||||
// },
|
||||
// { resource: 'Customer', importable: CustomersImportable },
|
||||
// { resource: 'Customer', importable: CustomersImportable },
|
||||
// { resource: 'Vendor', importable: VendorsImportable },
|
||||
// { resource: 'Item', importable: ItemsImportable },
|
||||
// { resource: 'ItemCategory', importable: ItemCategoriesImportable },
|
||||
|
||||
@@ -2,8 +2,8 @@ import * as Yup from 'yup';
|
||||
import * as moment from 'moment';
|
||||
import * as R from 'ramda';
|
||||
import { Knex } from 'knex';
|
||||
import fs from 'fs/promises';
|
||||
import path from 'path';
|
||||
import * as fs from 'fs/promises';
|
||||
import * as path from 'path';
|
||||
import {
|
||||
defaultTo,
|
||||
upperFirst,
|
||||
@@ -18,7 +18,7 @@ import {
|
||||
split,
|
||||
last,
|
||||
} from 'lodash';
|
||||
import pluralize from 'pluralize';
|
||||
import * as pluralize from 'pluralize';
|
||||
import { ResourceMetaFieldsMap } from './interfaces';
|
||||
import { multiNumberParse } from '@/utils/multi-number-parse';
|
||||
import { ServiceError } from '../Items/ServiceError';
|
||||
@@ -70,13 +70,13 @@ export const convertFieldsToYupValidation = (fields: ResourceMetaFieldsMap) => {
|
||||
if (!isUndefined(field.minLength)) {
|
||||
fieldSchema = fieldSchema.min(
|
||||
field.minLength,
|
||||
`Minimum length is ${field.minLength} characters`
|
||||
`Minimum length is ${field.minLength} characters`,
|
||||
);
|
||||
}
|
||||
if (!isUndefined(field.maxLength)) {
|
||||
fieldSchema = fieldSchema.max(
|
||||
field.maxLength,
|
||||
`Maximum length is ${field.maxLength} characters`
|
||||
`Maximum length is ${field.maxLength} characters`,
|
||||
);
|
||||
}
|
||||
} else if (field.fieldType === 'number') {
|
||||
@@ -106,7 +106,7 @@ export const convertFieldsToYupValidation = (fields: ResourceMetaFieldsMap) => {
|
||||
return true;
|
||||
}
|
||||
return moment(val, 'YYYY-MM-DD', true).isValid();
|
||||
}
|
||||
},
|
||||
);
|
||||
} else if (field.fieldType === 'url') {
|
||||
fieldSchema = fieldSchema.url();
|
||||
@@ -150,12 +150,12 @@ const parseFieldName = (fieldName: string, field: IModelMetaField) => {
|
||||
*/
|
||||
export const getUnmappedSheetColumns = (columns, mapping) => {
|
||||
return columns.filter(
|
||||
(column) => !mapping.some((map) => map.from === column)
|
||||
(column) => !mapping.some((map) => map.from === column),
|
||||
);
|
||||
};
|
||||
|
||||
export const sanitizeResourceName = (resourceName: string) => {
|
||||
return upperFirst(camelCase(pluralize.singular(resourceName)));
|
||||
return upperFirst(camelCase(pluralize(resourceName, 1)));
|
||||
};
|
||||
|
||||
export const getSheetColumns = (sheetData: unknown[]) => {
|
||||
@@ -171,11 +171,11 @@ export const getSheetColumns = (sheetData: unknown[]) => {
|
||||
*/
|
||||
export const getUniqueImportableValue = (
|
||||
importableFields: { [key: string]: IModelMetaField2 },
|
||||
objectDTO: Record<string, any>
|
||||
objectDTO: Record<string, any>,
|
||||
) => {
|
||||
const uniqueImportableValue = pickBy(
|
||||
importableFields,
|
||||
(field) => field.unique
|
||||
(field) => field.unique,
|
||||
);
|
||||
const uniqueImportableKeys = Object.keys(uniqueImportableValue);
|
||||
const uniqueImportableKey = first(uniqueImportableKeys);
|
||||
@@ -255,7 +255,7 @@ export const getResourceColumns = (resourceColumns: {
|
||||
(group: string) =>
|
||||
([fieldKey, { name, importHint, required, order, ...field }]: [
|
||||
string,
|
||||
IModelMetaField2
|
||||
IModelMetaField2,
|
||||
]) => {
|
||||
const extra: Record<string, any> = {};
|
||||
const key = fieldKey;
|
||||
@@ -300,7 +300,7 @@ export const valueParser =
|
||||
// Parses the enumeration value.
|
||||
} else if (field.fieldType === 'enumeration') {
|
||||
const option = get(field, 'options', []).find(
|
||||
(option) => option.label?.toLowerCase() === value?.toLowerCase()
|
||||
(option) => option.label?.toLowerCase() === value?.toLowerCase(),
|
||||
);
|
||||
_value = get(option, 'key');
|
||||
// Parses the numeric value.
|
||||
@@ -356,7 +356,7 @@ export const parseKey = R.curry(
|
||||
}
|
||||
}
|
||||
return _key;
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
/**
|
||||
@@ -399,11 +399,11 @@ export const getFieldKey = (input: string) => {
|
||||
export function aggregate(
|
||||
input: Array<any>,
|
||||
comparatorAttr: string,
|
||||
groupOn: string
|
||||
groupOn: string,
|
||||
): Array<Record<string, any>> {
|
||||
return input.reduce((acc, curr) => {
|
||||
const existingEntry = acc.find(
|
||||
(entry) => entry[comparatorAttr] === curr[comparatorAttr]
|
||||
(entry) => entry[comparatorAttr] === curr[comparatorAttr],
|
||||
);
|
||||
|
||||
if (existingEntry) {
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
|
||||
|
||||
export const ItemCategoryMeta = {
|
||||
defaultFilterField: 'name',
|
||||
defaultSort: {
|
||||
sortField: 'name',
|
||||
sortOrder: 'DESC',
|
||||
},
|
||||
importable: true,
|
||||
exportable: true,
|
||||
fields: {
|
||||
name: {
|
||||
name: 'item_category.field.name',
|
||||
column: 'name',
|
||||
fieldType: 'text',
|
||||
},
|
||||
description: {
|
||||
name: 'item_category.field.description',
|
||||
column: 'description',
|
||||
fieldType: 'text',
|
||||
},
|
||||
count: {
|
||||
name: 'item_category.field.count',
|
||||
column: 'count',
|
||||
fieldType: 'number',
|
||||
virtualColumn: true,
|
||||
},
|
||||
created_at: {
|
||||
name: 'item_category.field.created_at',
|
||||
column: 'created_at',
|
||||
columnType: 'date',
|
||||
},
|
||||
},
|
||||
columns: {
|
||||
name: {
|
||||
name: 'item_category.field.name',
|
||||
type: 'text',
|
||||
},
|
||||
description: {
|
||||
name: 'item_category.field.description',
|
||||
type: 'text',
|
||||
},
|
||||
count: {
|
||||
name: 'item_category.field.count',
|
||||
type: 'text',
|
||||
},
|
||||
createdAt: {
|
||||
name: 'item_category.field.created_at',
|
||||
type: 'text',
|
||||
},
|
||||
},
|
||||
fields2: {
|
||||
name: {
|
||||
name: 'item_category.field.name',
|
||||
column: 'name',
|
||||
fieldType: 'text',
|
||||
},
|
||||
description: {
|
||||
name: 'item_category.field.description',
|
||||
column: 'description',
|
||||
fieldType: 'text',
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -1,8 +1,11 @@
|
||||
import { Model } from 'objection';
|
||||
import { ExportableModel } from '@/modules/Export/decorators/ExportableModel.decorator';
|
||||
import { TenantBaseModel } from '@/modules/System/models/TenantBaseModel';
|
||||
import { Model } from 'objection';
|
||||
import { InjectModelMeta } from '@/modules/Tenancy/TenancyModels/decorators/InjectModelMeta.decorator';
|
||||
import { ItemCategoryMeta } from './ItemCategory.meta';
|
||||
|
||||
@ExportableModel()
|
||||
@InjectModelMeta(ItemCategoryMeta)
|
||||
export class ItemCategory extends TenantBaseModel {
|
||||
name!: string;
|
||||
description!: string;
|
||||
|
||||
309
packages/server/src/modules/Items/models/Item.meta.ts
Normal file
309
packages/server/src/modules/Items/models/Item.meta.ts
Normal file
@@ -0,0 +1,309 @@
|
||||
export const ItemMeta = {
|
||||
importable: true,
|
||||
exportable: true,
|
||||
defaultFilterField: 'name',
|
||||
defaultSort: {
|
||||
sortField: 'name',
|
||||
sortOrder: 'DESC',
|
||||
},
|
||||
print: {
|
||||
pageTitle: 'Items',
|
||||
},
|
||||
fields: {
|
||||
type: {
|
||||
name: 'item.field.type',
|
||||
column: 'type',
|
||||
fieldType: 'enumeration',
|
||||
options: [
|
||||
{ key: 'inventory', label: 'item.field.type.inventory' },
|
||||
{ key: 'service', label: 'item.field.type.service' },
|
||||
{ key: 'non-inventory', label: 'item.field.type.non-inventory' },
|
||||
],
|
||||
},
|
||||
name: {
|
||||
name: 'item.field.name',
|
||||
column: 'name',
|
||||
fieldType: 'text',
|
||||
},
|
||||
code: {
|
||||
name: 'item.field.code',
|
||||
column: 'code',
|
||||
fieldType: 'text',
|
||||
},
|
||||
sellable: {
|
||||
name: 'item.field.sellable',
|
||||
column: 'sellable',
|
||||
fieldType: 'boolean',
|
||||
},
|
||||
purchasable: {
|
||||
name: 'item.field.purchasable',
|
||||
column: 'purchasable',
|
||||
fieldType: 'boolean',
|
||||
},
|
||||
sell_price: {
|
||||
name: 'item.field.sell_price',
|
||||
column: 'sell_price',
|
||||
fieldType: 'number',
|
||||
},
|
||||
cost_price: {
|
||||
name: 'item.field.cost_price',
|
||||
column: 'cost_price',
|
||||
fieldType: 'number',
|
||||
},
|
||||
cost_account: {
|
||||
name: 'item.field.cost_account',
|
||||
column: 'cost_account_id',
|
||||
fieldType: 'relation',
|
||||
|
||||
relationType: 'enumeration',
|
||||
relationKey: 'costAccount',
|
||||
|
||||
relationEntityLabel: 'name',
|
||||
relationEntityKey: 'slug',
|
||||
},
|
||||
sell_account: {
|
||||
name: 'item.field.sell_account',
|
||||
column: 'sell_account_id',
|
||||
fieldType: 'relation',
|
||||
|
||||
relationType: 'enumeration',
|
||||
relationKey: 'sellAccount',
|
||||
|
||||
relationEntityLabel: 'name',
|
||||
relationEntityKey: 'slug',
|
||||
},
|
||||
inventory_account: {
|
||||
name: 'item.field.inventory_account',
|
||||
column: 'inventory_account_id',
|
||||
|
||||
relationType: 'enumeration',
|
||||
relationKey: 'inventoryAccount',
|
||||
|
||||
relationEntityLabel: 'name',
|
||||
relationEntityKey: 'slug',
|
||||
},
|
||||
sell_description: {
|
||||
name: 'Sell description',
|
||||
column: 'sell_description',
|
||||
fieldType: 'text',
|
||||
},
|
||||
purchase_description: {
|
||||
name: 'Purchase description',
|
||||
column: 'purchase_description',
|
||||
fieldType: 'text',
|
||||
},
|
||||
quantity_on_hand: {
|
||||
name: 'item.field.quantity_on_hand',
|
||||
column: 'quantity_on_hand',
|
||||
fieldType: 'number',
|
||||
},
|
||||
note: {
|
||||
name: 'item.field.note',
|
||||
column: 'note',
|
||||
fieldType: 'text',
|
||||
},
|
||||
category: {
|
||||
name: 'item.field.category',
|
||||
column: 'category_id',
|
||||
|
||||
relationType: 'enumeration',
|
||||
relationKey: 'category',
|
||||
|
||||
relationEntityLabel: 'name',
|
||||
relationEntityKey: 'id',
|
||||
},
|
||||
active: {
|
||||
name: 'item.field.active',
|
||||
column: 'active',
|
||||
fieldType: 'boolean',
|
||||
filterable: false,
|
||||
},
|
||||
created_at: {
|
||||
name: 'item.field.created_at',
|
||||
column: 'created_at',
|
||||
columnType: 'date',
|
||||
fieldType: 'date',
|
||||
},
|
||||
},
|
||||
columns: {
|
||||
type: {
|
||||
name: 'item.field.type',
|
||||
type: 'text',
|
||||
exportable: true,
|
||||
accessor: 'typeFormatted',
|
||||
},
|
||||
name: {
|
||||
name: 'item.field.name',
|
||||
type: 'text',
|
||||
exportable: true,
|
||||
},
|
||||
code: {
|
||||
name: 'item.field.code',
|
||||
type: 'text',
|
||||
exportable: true,
|
||||
},
|
||||
sellable: {
|
||||
name: 'item.field.sellable',
|
||||
type: 'boolean',
|
||||
exportable: true,
|
||||
printable: false,
|
||||
},
|
||||
purchasable: {
|
||||
name: 'item.field.purchasable',
|
||||
type: 'boolean',
|
||||
exportable: true,
|
||||
printable: false,
|
||||
},
|
||||
sellPrice: {
|
||||
name: 'item.field.sell_price',
|
||||
type: 'number',
|
||||
exportable: true,
|
||||
},
|
||||
costPrice: {
|
||||
name: 'item.field.cost_price',
|
||||
type: 'number',
|
||||
exportable: true,
|
||||
},
|
||||
costAccount: {
|
||||
name: 'item.field.cost_account',
|
||||
type: 'text',
|
||||
accessor: 'costAccount.name',
|
||||
exportable: true,
|
||||
printable: false,
|
||||
},
|
||||
sellAccount: {
|
||||
name: 'item.field.sell_account',
|
||||
type: 'text',
|
||||
accessor: 'sellAccount.name',
|
||||
exportable: true,
|
||||
printable: false,
|
||||
},
|
||||
inventoryAccount: {
|
||||
name: 'item.field.inventory_account',
|
||||
type: 'text',
|
||||
accessor: 'inventoryAccount.name',
|
||||
exportable: true,
|
||||
},
|
||||
sellDescription: {
|
||||
name: 'Sell description',
|
||||
type: 'text',
|
||||
exportable: true,
|
||||
printable: false,
|
||||
},
|
||||
purchaseDescription: {
|
||||
name: 'Purchase description',
|
||||
type: 'text',
|
||||
exportable: true,
|
||||
printable: false,
|
||||
},
|
||||
quantityOnHand: {
|
||||
name: 'item.field.quantity_on_hand',
|
||||
type: 'number',
|
||||
exportable: true,
|
||||
},
|
||||
note: {
|
||||
name: 'item.field.note',
|
||||
type: 'text',
|
||||
exportable: true,
|
||||
},
|
||||
category: {
|
||||
name: 'item.field.category',
|
||||
type: 'text',
|
||||
accessor: 'category.name',
|
||||
exportable: true,
|
||||
},
|
||||
active: {
|
||||
name: 'item.field.active',
|
||||
fieldType: 'boolean',
|
||||
exportable: true,
|
||||
printable: false,
|
||||
},
|
||||
createdAt: {
|
||||
name: 'item.field.created_at',
|
||||
type: 'date',
|
||||
exportable: true,
|
||||
printable: false,
|
||||
},
|
||||
},
|
||||
fields2: {
|
||||
type: {
|
||||
name: 'item.field.type',
|
||||
fieldType: 'enumeration',
|
||||
options: [
|
||||
{ key: 'inventory', label: 'item.field.type.inventory' },
|
||||
{ key: 'service', label: 'item.field.type.service' },
|
||||
{ key: 'non-inventory', label: 'item.field.type.non-inventory' },
|
||||
],
|
||||
required: true,
|
||||
},
|
||||
name: {
|
||||
name: 'item.field.name',
|
||||
fieldType: 'text',
|
||||
required: true,
|
||||
},
|
||||
code: {
|
||||
name: 'item.field.code',
|
||||
fieldType: 'text',
|
||||
},
|
||||
sellable: {
|
||||
name: 'item.field.sellable',
|
||||
fieldType: 'boolean',
|
||||
},
|
||||
purchasable: {
|
||||
name: 'item.field.purchasable',
|
||||
fieldType: 'boolean',
|
||||
},
|
||||
sellPrice: {
|
||||
name: 'item.field.sell_price',
|
||||
fieldType: 'number',
|
||||
},
|
||||
costPrice: {
|
||||
name: 'item.field.cost_price',
|
||||
fieldType: 'number',
|
||||
},
|
||||
costAccountId: {
|
||||
name: 'item.field.cost_account',
|
||||
fieldType: 'relation',
|
||||
relationModel: 'Account',
|
||||
relationImportMatch: ['name', 'code'],
|
||||
importHint: 'Matches the account name or code.',
|
||||
},
|
||||
sellAccountId: {
|
||||
name: 'item.field.sell_account',
|
||||
fieldType: 'relation',
|
||||
relationModel: 'Account',
|
||||
relationImportMatch: ['name', 'code'],
|
||||
importHint: 'Matches the account name or code.',
|
||||
},
|
||||
inventoryAccountId: {
|
||||
name: 'item.field.inventory_account',
|
||||
fieldType: 'relation',
|
||||
relationModel: 'Account',
|
||||
relationImportMatch: ['name', 'code'],
|
||||
importHint: 'Matches the account name or code.',
|
||||
},
|
||||
sellDescription: {
|
||||
name: 'Sell Description',
|
||||
fieldType: 'text',
|
||||
},
|
||||
purchaseDescription: {
|
||||
name: 'Purchase Description',
|
||||
fieldType: 'text',
|
||||
},
|
||||
note: {
|
||||
name: 'item.field.note',
|
||||
fieldType: 'text',
|
||||
},
|
||||
categoryId: {
|
||||
name: 'item.field.category',
|
||||
fieldType: 'relation',
|
||||
relationModel: 'ItemCategory',
|
||||
relationImportMatch: ['name'],
|
||||
importHint: 'Matches the category name.',
|
||||
},
|
||||
active: {
|
||||
name: 'item.field.active',
|
||||
fieldType: 'boolean',
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -2,8 +2,11 @@ import { Warehouse } from '@/modules/Warehouses/models/Warehouse.model';
|
||||
import { TenantBaseModel } from '@/modules/System/models/TenantBaseModel';
|
||||
import { Model } from 'objection';
|
||||
import { ExportableModel } from '@/modules/Export/decorators/ExportableModel.decorator';
|
||||
import { InjectModelMeta } from '@/modules/Tenancy/TenancyModels/decorators/InjectModelMeta.decorator';
|
||||
import { ItemMeta } from './Item.meta';
|
||||
|
||||
@ExportableModel()
|
||||
@InjectModelMeta(ItemMeta)
|
||||
export class Item extends TenantBaseModel {
|
||||
public readonly quantityOnHand: number;
|
||||
public readonly name: string;
|
||||
|
||||
@@ -17,9 +17,11 @@ import { ManualJournalGLEntries } from './commands/ManualJournalGLEntries';
|
||||
import { LedgerModule } from '../Ledger/Ledger.module';
|
||||
import { ManualJournalsExportable } from './commands/ManualJournalExportable';
|
||||
import { ManualJournalImportable } from './commands/ManualJournalsImport';
|
||||
import { GetManualJournals } from './queries/GetManualJournals.service';
|
||||
import { DynamicListModule } from '../DynamicListing/DynamicList.module';
|
||||
|
||||
@Module({
|
||||
imports: [BranchesModule, LedgerModule],
|
||||
imports: [BranchesModule, LedgerModule, DynamicListModule],
|
||||
controllers: [ManualJournalsController],
|
||||
providers: [
|
||||
TenancyContext,
|
||||
@@ -34,6 +36,7 @@ import { ManualJournalImportable } from './commands/ManualJournalsImport';
|
||||
AutoIncrementOrdersService,
|
||||
ManualJournalsApplication,
|
||||
GetManualJournal,
|
||||
GetManualJournals,
|
||||
ManualJournalGLEntries,
|
||||
ManualJournalWriteGLSubscriber,
|
||||
ManualJournalsExportable,
|
||||
|
||||
@@ -0,0 +1,230 @@
|
||||
export const ManualJournalMeta = {
|
||||
defaultFilterField: 'date',
|
||||
defaultSort: {
|
||||
sortOrder: 'DESC',
|
||||
sortField: 'name',
|
||||
},
|
||||
importable: true,
|
||||
exportFlattenOn: 'entries',
|
||||
|
||||
exportable: true,
|
||||
importAggregator: 'group',
|
||||
importAggregateOn: 'entries',
|
||||
importAggregateBy: 'journalNumber',
|
||||
|
||||
print: {
|
||||
pageTitle: 'Manual Journals',
|
||||
},
|
||||
|
||||
fields: {
|
||||
date: {
|
||||
name: 'manual_journal.field.date',
|
||||
column: 'date',
|
||||
fieldType: 'date',
|
||||
},
|
||||
journal_number: {
|
||||
name: 'manual_journal.field.journal_number',
|
||||
column: 'journal_number',
|
||||
fieldType: 'text',
|
||||
},
|
||||
reference: {
|
||||
name: 'manual_journal.field.reference',
|
||||
column: 'reference',
|
||||
fieldType: 'text',
|
||||
},
|
||||
journal_type: {
|
||||
name: 'manual_journal.field.journal_type',
|
||||
column: 'journal_type',
|
||||
fieldType: 'text',
|
||||
},
|
||||
amount: {
|
||||
name: 'manual_journal.field.amount',
|
||||
column: 'amount',
|
||||
fieldType: 'number',
|
||||
},
|
||||
description: {
|
||||
name: 'manual_journal.field.description',
|
||||
column: 'description',
|
||||
fieldType: 'text',
|
||||
},
|
||||
status: {
|
||||
name: 'manual_journal.field.status',
|
||||
column: 'status',
|
||||
fieldType: 'enumeration',
|
||||
options: [
|
||||
{ key: 'draft', label: 'Draft' },
|
||||
{ key: 'published', label: 'published' },
|
||||
],
|
||||
filterCustomQuery: StatusFieldFilterQuery,
|
||||
sortCustomQuery: StatusFieldSortQuery,
|
||||
},
|
||||
created_at: {
|
||||
name: 'manual_journal.field.created_at',
|
||||
column: 'created_at',
|
||||
fieldType: 'date',
|
||||
},
|
||||
},
|
||||
columns: {
|
||||
date: {
|
||||
name: 'manual_journal.field.date',
|
||||
type: 'date',
|
||||
accessor: 'formattedDate',
|
||||
},
|
||||
journalNumber: {
|
||||
name: 'manual_journal.field.journal_number',
|
||||
type: 'text',
|
||||
},
|
||||
reference: {
|
||||
name: 'manual_journal.field.reference',
|
||||
type: 'text',
|
||||
},
|
||||
journalType: {
|
||||
name: 'manual_journal.field.journal_type',
|
||||
type: 'text',
|
||||
},
|
||||
amount: {
|
||||
name: 'Amount',
|
||||
accessor: 'formattedAmount',
|
||||
},
|
||||
currencyCode: {
|
||||
name: 'manual_journal.field.currency',
|
||||
type: 'text',
|
||||
printable: false,
|
||||
},
|
||||
exchangeRate: {
|
||||
name: 'manual_journal.field.exchange_rate',
|
||||
type: 'number',
|
||||
printable: false,
|
||||
},
|
||||
description: {
|
||||
name: 'manual_journal.field.description',
|
||||
type: 'text',
|
||||
},
|
||||
entries: {
|
||||
name: 'Entries',
|
||||
type: 'collection',
|
||||
collectionOf: 'object',
|
||||
columns: {
|
||||
credit: {
|
||||
name: 'Credit',
|
||||
type: 'text',
|
||||
},
|
||||
debit: {
|
||||
name: 'Debit',
|
||||
type: 'text',
|
||||
},
|
||||
account: {
|
||||
name: 'Account',
|
||||
accessor: 'account.name',
|
||||
},
|
||||
contact: {
|
||||
name: 'Contact',
|
||||
accessor: 'contact.displayName',
|
||||
},
|
||||
note: {
|
||||
name: 'Note',
|
||||
},
|
||||
},
|
||||
publish: {
|
||||
name: 'Publish',
|
||||
type: 'boolean',
|
||||
printable: false,
|
||||
},
|
||||
publishedAt: {
|
||||
name: 'Published At',
|
||||
printable: false,
|
||||
},
|
||||
},
|
||||
createdAt: {
|
||||
name: 'Created At',
|
||||
accessor: 'formattedCreatedAt',
|
||||
printable: false,
|
||||
},
|
||||
},
|
||||
fields2: {
|
||||
date: {
|
||||
name: 'manual_journal.field.date',
|
||||
fieldType: 'date',
|
||||
required: true,
|
||||
},
|
||||
journalNumber: {
|
||||
name: 'manual_journal.field.journal_number',
|
||||
fieldType: 'text',
|
||||
required: true,
|
||||
},
|
||||
reference: {
|
||||
name: 'manual_journal.field.reference',
|
||||
fieldType: 'text',
|
||||
},
|
||||
journalType: {
|
||||
name: 'manual_journal.field.journal_type',
|
||||
fieldType: 'text',
|
||||
},
|
||||
currencyCode: {
|
||||
name: 'manual_journal.field.currency',
|
||||
fieldType: 'text',
|
||||
},
|
||||
exchange_rate: {
|
||||
name: 'manual_journal.field.exchange_rate',
|
||||
fieldType: 'number',
|
||||
},
|
||||
description: {
|
||||
name: 'manual_journal.field.description',
|
||||
fieldType: 'text',
|
||||
},
|
||||
entries: {
|
||||
name: 'Entries',
|
||||
fieldType: 'collection',
|
||||
collectionOf: 'object',
|
||||
collectionMinLength: 2,
|
||||
required: true,
|
||||
fields: {
|
||||
credit: {
|
||||
name: 'Credit',
|
||||
fieldType: 'number',
|
||||
required: true,
|
||||
},
|
||||
debit: {
|
||||
name: 'Debit',
|
||||
fieldType: 'number',
|
||||
required: true,
|
||||
},
|
||||
accountId: {
|
||||
name: 'Account',
|
||||
fieldType: 'relation',
|
||||
relationModel: 'Account',
|
||||
relationImportMatch: ['name', 'code'],
|
||||
required: true,
|
||||
},
|
||||
contact: {
|
||||
name: 'Contact',
|
||||
fieldType: 'relation',
|
||||
relationModel: 'Contact',
|
||||
relationImportMatch: 'displayName',
|
||||
},
|
||||
note: {
|
||||
name: 'Note',
|
||||
fieldType: 'text',
|
||||
},
|
||||
},
|
||||
},
|
||||
publish: {
|
||||
name: 'Publish',
|
||||
fieldType: 'boolean',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Status field sorting custom query.
|
||||
*/
|
||||
function StatusFieldSortQuery(query, role) {
|
||||
return query.modify('sortByStatus', role.order);
|
||||
}
|
||||
|
||||
/**
|
||||
* Status field filter custom query.
|
||||
*/
|
||||
function StatusFieldFilterQuery(query, role) {
|
||||
query.modify('filterByStatus', role.value);
|
||||
}
|
||||
@@ -10,8 +10,11 @@ import { ManualJournalEntry } from './ManualJournalEntry';
|
||||
import { Document } from '@/modules/ChromiumlyTenancy/models/Document';
|
||||
import { TenantBaseModel } from '@/modules/System/models/TenantBaseModel';
|
||||
import { ExportableModel } from '@/modules/Export/decorators/ExportableModel.decorator';
|
||||
import { InjectModelMeta } from '@/modules/Tenancy/TenancyModels/decorators/InjectModelMeta.decorator';
|
||||
import { ManualJournalMeta } from './ManualJournal.meta';
|
||||
|
||||
@ExportableModel()
|
||||
@InjectModelMeta(ManualJournalMeta)
|
||||
export class ManualJournal extends TenantBaseModel {
|
||||
date: Date;
|
||||
journalNumber: string;
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { ResourceService } from './ResourceService';
|
||||
import { BranchesModule } from '../Branches/Branches.module';
|
||||
import { WarehousesModule } from '../Warehouses/Warehouses.module';
|
||||
import { AccountsExportable } from '../Accounts/AccountsExportable.service';
|
||||
import { AccountsModule } from '../Accounts/Accounts.module';
|
||||
|
||||
@Module({
|
||||
imports: [BranchesModule, WarehousesModule, AccountsModule],
|
||||
providers: [ResourceService],
|
||||
exports: [ResourceService],
|
||||
})
|
||||
|
||||
@@ -28,7 +28,7 @@ export class ResourceService {
|
||||
*/
|
||||
public getResourceModel(inputModelName: string) {
|
||||
const modelName = resourceToModelName(inputModelName);
|
||||
const resourceModel = this.moduleRef.get(modelName);
|
||||
const resourceModel = this.moduleRef.get(modelName, { strict: false });
|
||||
|
||||
if (!resourceModel) {
|
||||
throw new ServiceError(ERRORS.RESOURCE_MODEL_NOT_FOUND);
|
||||
@@ -46,7 +46,7 @@ export class ResourceService {
|
||||
const resourceModel = this.getResourceModel(modelName);
|
||||
|
||||
// Retrieve the resource meta.
|
||||
const resourceMeta = resourceModel.getMeta(metakey);
|
||||
const resourceMeta = resourceModel().getMeta(metakey);
|
||||
|
||||
// Localization the fields names.
|
||||
return resourceMeta;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { camelCase, upperFirst } from 'lodash';
|
||||
import pluralize from 'pluralize';
|
||||
import * as pluralize from 'pluralize';
|
||||
|
||||
export const resourceToModelName = (resourceName: string): string => {
|
||||
return upperFirst(camelCase(pluralize.singular(resourceName)));
|
||||
|
||||
@@ -0,0 +1,316 @@
|
||||
import { Features } from "@/common/types/Features";
|
||||
|
||||
export const SaleInvoiceMeta = {
|
||||
defaultFilterField: 'customer',
|
||||
defaultSort: {
|
||||
sortOrder: 'DESC',
|
||||
sortField: 'created_at',
|
||||
},
|
||||
exportable: true,
|
||||
exportFlattenOn: 'entries',
|
||||
|
||||
importable: true,
|
||||
importAggregator: 'group',
|
||||
importAggregateOn: 'entries',
|
||||
importAggregateBy: 'invoiceNo',
|
||||
|
||||
print: {
|
||||
pageTitle: 'Sale invoices',
|
||||
},
|
||||
fields: {
|
||||
customer: {
|
||||
name: 'invoice.field.customer',
|
||||
column: 'customer_id',
|
||||
fieldType: 'relation',
|
||||
|
||||
relationType: 'enumeration',
|
||||
relationKey: 'customer',
|
||||
|
||||
relationEntityLabel: 'display_name',
|
||||
relationEntityKey: 'id',
|
||||
},
|
||||
invoice_date: {
|
||||
name: 'invoice.field.invoice_date',
|
||||
column: 'invoice_date',
|
||||
fieldType: 'date',
|
||||
},
|
||||
due_date: {
|
||||
name: 'invoice.field.due_date',
|
||||
column: 'due_date',
|
||||
fieldType: 'date',
|
||||
},
|
||||
invoice_no: {
|
||||
name: 'invoice.field.invoice_no',
|
||||
column: 'invoice_no',
|
||||
fieldType: 'text',
|
||||
},
|
||||
reference_no: {
|
||||
name: 'invoice.field.reference_no',
|
||||
column: 'reference_no',
|
||||
fieldType: 'text',
|
||||
},
|
||||
invoice_message: {
|
||||
name: 'invoice.field.invoice_message',
|
||||
column: 'invoice_message',
|
||||
fieldType: 'text',
|
||||
},
|
||||
terms_conditions: {
|
||||
name: 'invoice.field.terms_conditions',
|
||||
column: 'terms_conditions',
|
||||
fieldType: 'text',
|
||||
},
|
||||
amount: {
|
||||
name: 'invoice.field.amount',
|
||||
column: 'balance',
|
||||
fieldType: 'number',
|
||||
},
|
||||
payment_amount: {
|
||||
name: 'invoice.field.payment_amount',
|
||||
column: 'payment_amount',
|
||||
fieldType: 'number',
|
||||
},
|
||||
due_amount: {
|
||||
// calculated.
|
||||
name: 'invoice.field.due_amount',
|
||||
column: 'due_amount',
|
||||
fieldType: 'number',
|
||||
virtualColumn: true,
|
||||
},
|
||||
status: {
|
||||
name: 'invoice.field.status',
|
||||
fieldType: 'enumeration',
|
||||
options: [
|
||||
{ key: 'draft', label: 'invoice.field.status.draft' },
|
||||
{ key: 'delivered', label: 'invoice.field.status.delivered' },
|
||||
{ key: 'unpaid', label: 'invoice.field.status.unpaid' },
|
||||
{ key: 'overdue', label: 'invoice.field.status.overdue' },
|
||||
{ key: 'partially-paid', label: 'invoice.field.status.partially-paid' },
|
||||
{ key: 'paid', label: 'invoice.field.status.paid' },
|
||||
],
|
||||
filterCustomQuery: StatusFieldFilterQuery,
|
||||
sortCustomQuery: StatusFieldSortQuery,
|
||||
},
|
||||
created_at: {
|
||||
name: 'invoice.field.created_at',
|
||||
column: 'created_at',
|
||||
fieldType: 'date',
|
||||
},
|
||||
},
|
||||
columns: {
|
||||
invoiceDate: {
|
||||
name: 'invoice.field.invoice_date',
|
||||
type: 'date',
|
||||
accessor: 'invoiceDateFormatted',
|
||||
},
|
||||
dueDate: {
|
||||
name: 'invoice.field.due_date',
|
||||
type: 'date',
|
||||
accessor: 'dueDateFormatted',
|
||||
},
|
||||
referenceNo: {
|
||||
name: 'invoice.field.reference_no',
|
||||
type: 'text',
|
||||
},
|
||||
invoiceNo: {
|
||||
name: 'invoice.field.invoice_no',
|
||||
type: 'text',
|
||||
},
|
||||
customer: {
|
||||
name: 'invoice.field.customer',
|
||||
type: 'text',
|
||||
accessor: 'customer.displayName',
|
||||
},
|
||||
amount: {
|
||||
name: 'invoice.field.amount',
|
||||
type: 'text',
|
||||
accessor: 'balanceAmountFormatted',
|
||||
},
|
||||
exchangeRate: {
|
||||
name: 'invoice.field.exchange_rate',
|
||||
type: 'number',
|
||||
printable: false,
|
||||
},
|
||||
currencyCode: {
|
||||
name: 'invoice.field.currency',
|
||||
type: 'text',
|
||||
printable: false,
|
||||
},
|
||||
paidAmount: {
|
||||
name: 'Paid Amount',
|
||||
accessor: 'paymentAmountFormatted',
|
||||
},
|
||||
dueAmount: {
|
||||
name: 'Due Amount',
|
||||
accessor: 'dueAmountFormatted',
|
||||
},
|
||||
invoiceMessage: {
|
||||
name: 'invoice.field.invoice_message',
|
||||
type: 'text',
|
||||
printable: false,
|
||||
},
|
||||
termsConditions: {
|
||||
name: 'invoice.field.terms_conditions',
|
||||
type: 'text',
|
||||
printable: false,
|
||||
},
|
||||
delivered: {
|
||||
name: 'invoice.field.delivered',
|
||||
type: 'boolean',
|
||||
printable: false,
|
||||
accessor: 'isDelivered',
|
||||
},
|
||||
entries: {
|
||||
name: 'Entries',
|
||||
accessor: 'entries',
|
||||
type: 'collection',
|
||||
collectionOf: 'object',
|
||||
columns: {
|
||||
itemName: {
|
||||
name: 'Item Name',
|
||||
accessor: 'item.name',
|
||||
},
|
||||
rate: {
|
||||
name: 'Item Rate',
|
||||
accessor: 'rateFormatted',
|
||||
},
|
||||
quantity: {
|
||||
name: 'Item Quantity',
|
||||
accessor: 'quantityFormatted',
|
||||
},
|
||||
description: {
|
||||
name: 'Item Description',
|
||||
printable: false,
|
||||
},
|
||||
amount: {
|
||||
name: 'Item Amount',
|
||||
accessor: 'totalFormatted',
|
||||
},
|
||||
},
|
||||
},
|
||||
branch: {
|
||||
name: 'Branch',
|
||||
type: 'text',
|
||||
accessor: 'branch.name',
|
||||
features: [Features.BRANCHES],
|
||||
},
|
||||
warehouse: {
|
||||
name: 'Warehouse',
|
||||
type: 'text',
|
||||
accessor: 'warehouse.name',
|
||||
features: [Features.BRANCHES],
|
||||
},
|
||||
},
|
||||
fields2: {
|
||||
invoiceDate: {
|
||||
name: 'invoice.field.invoice_date',
|
||||
fieldType: 'date',
|
||||
required: true,
|
||||
},
|
||||
dueDate: {
|
||||
name: 'invoice.field.due_date',
|
||||
fieldType: 'date',
|
||||
required: true,
|
||||
},
|
||||
referenceNo: {
|
||||
name: 'invoice.field.reference_no',
|
||||
fieldType: 'text',
|
||||
},
|
||||
invoiceNo: {
|
||||
name: 'invoice.field.invoice_no',
|
||||
fieldType: 'text',
|
||||
},
|
||||
customerId: {
|
||||
name: 'invoice.field.customer',
|
||||
fieldType: 'relation',
|
||||
relationModel: 'Contact',
|
||||
relationImportMatch: 'displayName',
|
||||
required: true,
|
||||
},
|
||||
exchangeRate: {
|
||||
name: 'invoice.field.exchange_rate',
|
||||
fieldType: 'number',
|
||||
printable: false,
|
||||
},
|
||||
currencyCode: {
|
||||
name: 'invoice.field.currency',
|
||||
fieldType: 'text',
|
||||
printable: false,
|
||||
},
|
||||
invoiceMessage: {
|
||||
name: 'invoice.field.invoice_message',
|
||||
fieldType: 'text',
|
||||
printable: false,
|
||||
},
|
||||
termsConditions: {
|
||||
name: 'invoice.field.terms_conditions',
|
||||
fieldType: 'text',
|
||||
printable: false,
|
||||
},
|
||||
entries: {
|
||||
name: 'invoice.field.entries',
|
||||
fieldType: 'collection',
|
||||
collectionOf: 'object',
|
||||
collectionMinLength: 1,
|
||||
required: true,
|
||||
fields: {
|
||||
itemId: {
|
||||
name: 'invoice.field.item_name',
|
||||
fieldType: 'relation',
|
||||
relationModel: 'Item',
|
||||
relationImportMatch: ['name', 'code'],
|
||||
required: true,
|
||||
importHint: 'Matches the item name or code.',
|
||||
},
|
||||
rate: {
|
||||
name: 'invoice.field.rate',
|
||||
fieldType: 'number',
|
||||
required: true,
|
||||
},
|
||||
quantity: {
|
||||
name: 'invoice.field.quantity',
|
||||
fieldType: 'number',
|
||||
required: true,
|
||||
},
|
||||
description: {
|
||||
name: 'invoice.field.description',
|
||||
fieldType: 'text',
|
||||
},
|
||||
},
|
||||
},
|
||||
delivered: {
|
||||
name: 'invoice.field.delivered',
|
||||
fieldType: 'boolean',
|
||||
printable: false,
|
||||
},
|
||||
branchId: {
|
||||
name: 'Branch',
|
||||
fieldType: 'relation',
|
||||
relationModel: 'Branch',
|
||||
relationImportMatch: ['name', 'code'],
|
||||
features: [Features.BRANCHES],
|
||||
required: true,
|
||||
},
|
||||
warehouseId: {
|
||||
name: 'Warehouse',
|
||||
fieldType: 'relation',
|
||||
relationModel: 'Warehouse',
|
||||
relationImportMatch: ['name', 'code'],
|
||||
features: [Features.WAREHOUSES],
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Status field filter custom query.
|
||||
*/
|
||||
function StatusFieldFilterQuery(query, role) {
|
||||
query.modify('statusFilter', role.value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Status field sort custom query.
|
||||
*/
|
||||
function StatusFieldSortQuery(query, role) {
|
||||
query.modify('sortByStatus', role.order);
|
||||
}
|
||||
@@ -11,13 +11,15 @@ import { DiscountType } from '@/common/types/Discount';
|
||||
import { Account } from '@/modules/Accounts/models/Account.model';
|
||||
import { ISearchRole } from '@/modules/DynamicListing/DynamicFilter/DynamicFilter.types';
|
||||
import { TenantBaseModel } from '@/modules/System/models/TenantBaseModel';
|
||||
import { PaymentIntegrationTransactionLink } from '../SaleInvoice.types';
|
||||
import { TransactionPaymentServiceEntry } from '@/modules/PaymentServices/models/TransactionPaymentServiceEntry.model';
|
||||
import { InjectAttachable } from '@/modules/Attachments/decorators/InjectAttachable.decorator';
|
||||
import { ExportableModel } from '@/modules/Export/decorators/ExportableModel.decorator';
|
||||
import { InjectModelMeta } from '@/modules/Tenancy/TenancyModels/decorators/InjectModelMeta.decorator';
|
||||
import { SaleInvoiceMeta } from './SaleInvoice.meta';
|
||||
|
||||
@InjectAttachable()
|
||||
@ExportableModel()
|
||||
@InjectModelMeta(SaleInvoiceMeta)
|
||||
export class SaleInvoice extends TenantBaseModel{
|
||||
public taxAmountWithheld: number;
|
||||
public balance: number;
|
||||
|
||||
@@ -82,6 +82,7 @@ const models = [
|
||||
TenantUser,
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* Decorator factory that registers a model with the tenancy system.
|
||||
* @param model The model class to register
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
|
||||
/**
|
||||
* Decorator function that adds metadata to the model class.
|
||||
* @param value - The metadata value to be added to the model.
|
||||
* @returns A class decorator function.
|
||||
*/
|
||||
export function InjectModelMeta(value: any) {
|
||||
return function(target: any) {
|
||||
// Define a static getter for 'meta' on the target class
|
||||
Object.defineProperty(target, 'meta', {
|
||||
get: function() {
|
||||
return value;
|
||||
},
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
};
|
||||
}
|
||||
407
packages/server/src/modules/Vendors/models/Vendor.meta.ts
Normal file
407
packages/server/src/modules/Vendors/models/Vendor.meta.ts
Normal file
@@ -0,0 +1,407 @@
|
||||
export const VendorMeta = {
|
||||
defaultFilterField: 'displayName',
|
||||
defaultSort: {
|
||||
sortOrder: 'DESC',
|
||||
sortField: 'created_at',
|
||||
},
|
||||
importable: true,
|
||||
exportable: true,
|
||||
fields: {
|
||||
first_name: {
|
||||
name: 'vendor.field.first_name',
|
||||
column: 'first_name',
|
||||
fieldType: 'text',
|
||||
},
|
||||
last_name: {
|
||||
name: 'vendor.field.last_name',
|
||||
column: 'last_name',
|
||||
fieldType: 'text',
|
||||
},
|
||||
display_name: {
|
||||
name: 'vendor.field.display_name',
|
||||
column: 'display_name',
|
||||
fieldType: 'text',
|
||||
},
|
||||
email: {
|
||||
name: 'vendor.field.email',
|
||||
column: 'email',
|
||||
fieldType: 'text',
|
||||
},
|
||||
work_phone: {
|
||||
name: 'vendor.field.work_phone',
|
||||
column: 'work_phone',
|
||||
fieldType: 'text',
|
||||
},
|
||||
personal_phone: {
|
||||
name: 'vendor.field.personal_phone',
|
||||
column: 'personal_phone',
|
||||
fieldType: 'text',
|
||||
},
|
||||
company_name: {
|
||||
name: 'vendor.field.company_name',
|
||||
column: 'company_name',
|
||||
fieldType: 'text',
|
||||
},
|
||||
website: {
|
||||
name: 'vendor.field.website',
|
||||
column: 'website',
|
||||
fieldType: 'text',
|
||||
},
|
||||
created_at: {
|
||||
name: 'vendor.field.created_at',
|
||||
column: 'created_at',
|
||||
fieldType: 'date',
|
||||
},
|
||||
balance: {
|
||||
name: 'vendor.field.balance',
|
||||
column: 'balance',
|
||||
fieldType: 'number',
|
||||
},
|
||||
opening_balance: {
|
||||
name: 'vendor.field.opening_balance',
|
||||
column: 'opening_balance',
|
||||
fieldType: 'number',
|
||||
},
|
||||
opening_balance_at: {
|
||||
name: 'vendor.field.opening_balance_at',
|
||||
column: 'opening_balance_at',
|
||||
fieldType: 'date',
|
||||
},
|
||||
currency_code: {
|
||||
name: 'vendor.field.currency',
|
||||
column: 'currency_code',
|
||||
fieldType: 'text',
|
||||
},
|
||||
status: {
|
||||
name: 'vendor.field.status',
|
||||
type: 'enumeration',
|
||||
options: [
|
||||
{ key: 'overdue', label: 'vendor.field.status.overdue' },
|
||||
{ key: 'unpaid', label: 'vendor.field.status.unpaid' },
|
||||
],
|
||||
filterCustomQuery: (query, role) => {
|
||||
switch (role.value) {
|
||||
case 'overdue':
|
||||
query.modify('overdue');
|
||||
break;
|
||||
case 'unpaid':
|
||||
query.modify('unpaid');
|
||||
break;
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
columns: {
|
||||
firstName: {
|
||||
name: 'vendor.field.first_name',
|
||||
type: 'text',
|
||||
},
|
||||
lastName: {
|
||||
name: 'vendor.field.last_name',
|
||||
type: 'text',
|
||||
},
|
||||
displayName: {
|
||||
name: 'vendor.field.display_name',
|
||||
type: 'text',
|
||||
},
|
||||
email: {
|
||||
name: 'vendor.field.email',
|
||||
type: 'text',
|
||||
},
|
||||
workPhone: {
|
||||
name: 'vendor.field.work_phone',
|
||||
type: 'text',
|
||||
},
|
||||
personalPhone: {
|
||||
name: 'vendor.field.personal_phone',
|
||||
type: 'text',
|
||||
},
|
||||
companyName: {
|
||||
name: 'vendor.field.company_name',
|
||||
type: 'text',
|
||||
},
|
||||
website: {
|
||||
name: 'vendor.field.website',
|
||||
type: 'text',
|
||||
},
|
||||
balance: {
|
||||
name: 'vendor.field.balance',
|
||||
type: 'number',
|
||||
},
|
||||
openingBalance: {
|
||||
name: 'vendor.field.opening_balance',
|
||||
type: 'number',
|
||||
printable: false
|
||||
},
|
||||
openingBalanceAt: {
|
||||
name: 'vendor.field.opening_balance_at',
|
||||
type: 'date',
|
||||
printable: false
|
||||
},
|
||||
currencyCode: {
|
||||
name: 'vendor.field.currency',
|
||||
type: 'text',
|
||||
printable: false
|
||||
},
|
||||
status: {
|
||||
name: 'vendor.field.status',
|
||||
printable: false
|
||||
},
|
||||
note: {
|
||||
name: 'vendor.field.note',
|
||||
type: 'text',
|
||||
printable: false
|
||||
},
|
||||
// Billing Address
|
||||
billingAddress1: {
|
||||
name: 'Billing Address 1',
|
||||
column: 'billing_address1',
|
||||
type: 'text',
|
||||
exportable: true,
|
||||
printable: false
|
||||
},
|
||||
billingAddress2: {
|
||||
name: 'Billing Address 2',
|
||||
column: 'billing_address2',
|
||||
type: 'text',
|
||||
exportable: true,
|
||||
printable: false
|
||||
},
|
||||
billingAddressCity: {
|
||||
name: 'Billing Address City',
|
||||
column: 'billing_address_city',
|
||||
type: 'text',
|
||||
exportable: true,
|
||||
printable: false
|
||||
},
|
||||
billingAddressCountry: {
|
||||
name: 'Billing Address Country',
|
||||
column: 'billing_address_country',
|
||||
type: 'text',
|
||||
exportable: true,
|
||||
printable: false
|
||||
},
|
||||
billingAddressPostcode: {
|
||||
name: 'Billing Address Postcode',
|
||||
column: 'billing_address_postcode',
|
||||
type: 'text',
|
||||
exportable: true,
|
||||
printable: false
|
||||
},
|
||||
billingAddressState: {
|
||||
name: 'Billing Address State',
|
||||
column: 'billing_address_state',
|
||||
type: 'text',
|
||||
exportable: true,
|
||||
printable: false
|
||||
},
|
||||
billingAddressPhone: {
|
||||
name: 'Billing Address Phone',
|
||||
column: 'billing_address_phone',
|
||||
type: 'text',
|
||||
exportable: true,
|
||||
printable: false
|
||||
},
|
||||
// Shipping Address
|
||||
shippingAddress1: {
|
||||
name: 'Shipping Address 1',
|
||||
column: 'shipping_address1',
|
||||
type: 'text',
|
||||
exportable: true,
|
||||
printable: false
|
||||
},
|
||||
shippingAddress2: {
|
||||
name: 'Shipping Address 2',
|
||||
column: 'shipping_address2',
|
||||
type: 'text',
|
||||
exportable: true,
|
||||
printable: false
|
||||
},
|
||||
shippingAddressCity: {
|
||||
name: 'Shipping Address City',
|
||||
column: 'shipping_address_city',
|
||||
type: 'text',
|
||||
exportable: true,
|
||||
printable: false
|
||||
},
|
||||
shippingAddressCountry: {
|
||||
name: 'Shipping Address Country',
|
||||
column: 'shipping_address_country',
|
||||
type: 'text',
|
||||
exportable: true,
|
||||
printable: false
|
||||
},
|
||||
shippingAddressPostcode: {
|
||||
name: 'Shipping Address Postcode',
|
||||
column: 'shipping_address_postcode',
|
||||
type: 'text',
|
||||
exportable: true,
|
||||
printable: false
|
||||
},
|
||||
shippingAddressState: {
|
||||
name: 'Shipping Address State',
|
||||
column: 'shipping_address_state',
|
||||
type: 'text',
|
||||
exportable: true,
|
||||
printable: false
|
||||
},
|
||||
shippingAddressPhone: {
|
||||
name: 'Shipping Address Phone',
|
||||
column: 'shipping_address_phone',
|
||||
type: 'text',
|
||||
exportable: true,
|
||||
printable: false
|
||||
},
|
||||
createdAt: {
|
||||
name: 'vendor.field.created_at',
|
||||
type: 'date',
|
||||
exportable: true,
|
||||
printable: false
|
||||
},
|
||||
},
|
||||
fields2: {
|
||||
firstName: {
|
||||
name: 'vendor.field.first_name',
|
||||
column: 'first_name',
|
||||
fieldType: 'text',
|
||||
},
|
||||
lastName: {
|
||||
name: 'vendor.field.last_name',
|
||||
column: 'last_name',
|
||||
fieldType: 'text',
|
||||
},
|
||||
displayName: {
|
||||
name: 'vendor.field.display_name',
|
||||
column: 'display_name',
|
||||
fieldType: 'text',
|
||||
required: true,
|
||||
},
|
||||
email: {
|
||||
name: 'vendor.field.email',
|
||||
column: 'email',
|
||||
fieldType: 'text',
|
||||
},
|
||||
workPhone: {
|
||||
name: 'vendor.field.work_phone',
|
||||
column: 'work_phone',
|
||||
fieldType: 'text',
|
||||
},
|
||||
personalPhone: {
|
||||
name: 'vendor.field.personal_phone',
|
||||
column: 'personal_phone',
|
||||
fieldType: 'text',
|
||||
},
|
||||
companyName: {
|
||||
name: 'vendor.field.company_name',
|
||||
column: 'company_name',
|
||||
fieldType: 'text',
|
||||
},
|
||||
website: {
|
||||
name: 'vendor.field.website',
|
||||
column: 'website',
|
||||
fieldType: 'text',
|
||||
},
|
||||
openingBalance: {
|
||||
name: 'vendor.field.opening_balance',
|
||||
column: 'opening_balance',
|
||||
fieldType: 'number',
|
||||
},
|
||||
openingBalanceAt: {
|
||||
name: 'vendor.field.opening_balance_at',
|
||||
column: 'opening_balance_at',
|
||||
fieldType: 'date',
|
||||
},
|
||||
openingBalanceExchangeRate: {
|
||||
name: 'Opening Balance Ex. Rate',
|
||||
column: 'opening_balance_exchange_rate',
|
||||
fieldType: 'number',
|
||||
},
|
||||
currencyCode: {
|
||||
name: 'vendor.field.currency',
|
||||
column: 'currency_code',
|
||||
fieldType: 'text',
|
||||
},
|
||||
note: {
|
||||
name: 'Note',
|
||||
column: 'note',
|
||||
fieldType: 'text',
|
||||
},
|
||||
active: {
|
||||
name: 'Active',
|
||||
column: 'active',
|
||||
fieldType: 'boolean',
|
||||
},
|
||||
// Billing Address
|
||||
billingAddress1: {
|
||||
name: 'Billing Address 1',
|
||||
column: 'billing_address1',
|
||||
fieldType: 'text',
|
||||
},
|
||||
billingAddress2: {
|
||||
name: 'Billing Address 2',
|
||||
column: 'billing_address2',
|
||||
fieldType: 'text',
|
||||
},
|
||||
billingAddressCity: {
|
||||
name: 'Billing Address City',
|
||||
column: 'billing_address_city',
|
||||
fieldType: 'text',
|
||||
},
|
||||
billingAddressCountry: {
|
||||
name: 'Billing Address Country',
|
||||
column: 'billing_address_country',
|
||||
fieldType: 'text',
|
||||
},
|
||||
billingAddressPostcode: {
|
||||
name: 'Billing Address Postcode',
|
||||
column: 'billing_address_postcode',
|
||||
fieldType: 'text',
|
||||
},
|
||||
billingAddressState: {
|
||||
name: 'Billing Address State',
|
||||
column: 'billing_address_state',
|
||||
fieldType: 'text',
|
||||
},
|
||||
billingAddressPhone: {
|
||||
name: 'Billing Address Phone',
|
||||
column: 'billing_address_phone',
|
||||
fieldType: 'text',
|
||||
},
|
||||
// Shipping Address
|
||||
shippingAddress1: {
|
||||
name: 'Shipping Address 1',
|
||||
column: 'shipping_address1',
|
||||
fieldType: 'text',
|
||||
},
|
||||
shippingAddress2: {
|
||||
name: 'Shipping Address 2',
|
||||
column: 'shipping_address2',
|
||||
fieldType: 'text',
|
||||
},
|
||||
shippingAddressCity: {
|
||||
name: 'Shipping Address City',
|
||||
column: 'shipping_address_city',
|
||||
fieldType: 'text',
|
||||
},
|
||||
shippingAddressCountry: {
|
||||
name: 'Shipping Address Country',
|
||||
column: 'shipping_address_country',
|
||||
fieldType: 'text',
|
||||
},
|
||||
shippingAddressPostcode: {
|
||||
name: 'Shipping Address Postcode',
|
||||
column: 'shipping_address_postcode',
|
||||
fieldType: 'text',
|
||||
},
|
||||
shippingAddressState: {
|
||||
name: 'Shipping Address State',
|
||||
column: 'shipping_address_state',
|
||||
fieldType: 'text',
|
||||
},
|
||||
shippingAddressPhone: {
|
||||
name: 'Shipping Address Phone',
|
||||
column: 'shipping_address_phone',
|
||||
fieldType: 'text',
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -9,6 +9,8 @@ import { Model, mixin } from 'objection';
|
||||
import { BaseModel } from '@/models/Model';
|
||||
import { TenantBaseModel } from '@/modules/System/models/TenantBaseModel';
|
||||
import { ExportableModel } from '@/modules/Export/decorators/ExportableModel.decorator';
|
||||
import { InjectModelMeta } from '@/modules/Tenancy/TenancyModels/decorators/InjectModelMeta.decorator';
|
||||
import { VendorMeta } from './Vendor.meta';
|
||||
|
||||
// class VendorQueryBuilder extends PaginationQueryBuilder {
|
||||
// constructor(...args) {
|
||||
@@ -23,6 +25,7 @@ import { ExportableModel } from '@/modules/Export/decorators/ExportableModel.dec
|
||||
// }
|
||||
|
||||
@ExportableModel()
|
||||
@InjectModelMeta(VendorMeta)
|
||||
export class Vendor extends TenantBaseModel {
|
||||
contactService: string;
|
||||
contactType: string;
|
||||
|
||||
@@ -90,6 +90,6 @@ const models = [RegisterTenancyModel(Warehouse)];
|
||||
InventoryTransactionsWarehouses,
|
||||
ValidateWarehouseExistance
|
||||
],
|
||||
exports: [WarehouseTransactionDTOTransform, ...models],
|
||||
exports: [WarehousesSettings, WarehouseTransactionDTOTransform, ...models],
|
||||
})
|
||||
export class WarehousesModule {}
|
||||
|
||||
Reference in New Issue
Block a user