mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-15 12:20:31 +00:00
feat(nestjs): migrate to NestJS
This commit is contained in:
6
packages/server/src/common/config/gotenberg.ts
Normal file
6
packages/server/src/common/config/gotenberg.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import { registerAs } from '@nestjs/config';
|
||||
|
||||
export default registerAs('gotenberg', () => ({
|
||||
url: process.env.GOTENBERG_URL,
|
||||
docsUrl: process.env.GOTENBERG_DOCS_URL,
|
||||
}));
|
||||
33
packages/server/src/common/config/index.ts
Normal file
33
packages/server/src/common/config/index.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import systemDatabase from './system-database';
|
||||
import tenantDatabase from './tenant-database';
|
||||
import signup from './signup';
|
||||
import gotenberg from './gotenberg';
|
||||
import plaid from './plaid';
|
||||
import lemonsqueezy from './lemonsqueezy';
|
||||
import s3 from './s3';
|
||||
import openExchange from './open-exchange';
|
||||
import posthog from './posthog';
|
||||
import stripePayment from './stripe-payment';
|
||||
import signupConfirmation from './signup-confirmation';
|
||||
import signupRestrictions from './signup-restrictions';
|
||||
import jwt from './jwt';
|
||||
import mail from './mail';
|
||||
import loops from './loops';
|
||||
|
||||
export const config = [
|
||||
systemDatabase,
|
||||
tenantDatabase,
|
||||
signup,
|
||||
gotenberg,
|
||||
plaid,
|
||||
lemonsqueezy,
|
||||
s3,
|
||||
openExchange,
|
||||
posthog,
|
||||
stripePayment,
|
||||
signupConfirmation,
|
||||
signupRestrictions,
|
||||
jwt,
|
||||
mail,
|
||||
loops
|
||||
];
|
||||
5
packages/server/src/common/config/inventory.ts
Normal file
5
packages/server/src/common/config/inventory.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import { registerAs } from "@nestjs/config";
|
||||
|
||||
export default registerAs('inventory', () => ({
|
||||
scheduleComputeItemCost: process.env.INVENTORY_SCHEDULE_COMPUTE_ITEM_COST,
|
||||
}));
|
||||
5
packages/server/src/common/config/jwt.ts
Normal file
5
packages/server/src/common/config/jwt.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import { registerAs } from '@nestjs/config';
|
||||
|
||||
export default registerAs('jwt', () => ({
|
||||
secret: process.env.APP_JWT_SECRET || '123123',
|
||||
}));
|
||||
7
packages/server/src/common/config/lemonsqueezy.ts
Normal file
7
packages/server/src/common/config/lemonsqueezy.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { registerAs } from '@nestjs/config';
|
||||
|
||||
export default registerAs('lemonsqueezy', () => ({
|
||||
apiKey: process.env.LEMONSQUEEZY_API_KEY,
|
||||
storeId: process.env.LEMONSQUEEZY_STORE_ID,
|
||||
webhookSecret: process.env.LEMONSQUEEZY_WEBHOOK_SECRET,
|
||||
}));
|
||||
6
packages/server/src/common/config/loops.ts
Normal file
6
packages/server/src/common/config/loops.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
|
||||
import { registerAs } from '@nestjs/config';
|
||||
|
||||
export default registerAs('loops', () => ({
|
||||
apiKey: process.env.LOOPS_API_KEY,
|
||||
}));
|
||||
13
packages/server/src/common/config/mail.ts
Normal file
13
packages/server/src/common/config/mail.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { registerAs } from '@nestjs/config';
|
||||
|
||||
export default registerAs('mail', () => ({
|
||||
host: process.env.MAIL_HOST,
|
||||
username: process.env.MAIL_USERNAME,
|
||||
password: process.env.MAIL_PASSWORD,
|
||||
port: parseInt(process.env.MAIL_PORT, 10),
|
||||
secure: process.env.MAIL_SECURE === 'true',
|
||||
from: {
|
||||
name: process.env.MAIL_FROM_NAME,
|
||||
address: process.env.MAIL_FROM_ADDRESS,
|
||||
},
|
||||
}));
|
||||
5
packages/server/src/common/config/open-exchange.ts
Normal file
5
packages/server/src/common/config/open-exchange.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import { registerAs } from '@nestjs/config';
|
||||
|
||||
export default registerAs('openExchange', () => ({
|
||||
appId: process.env.OPEN_EXCHANGE_RATE_APP_ID,
|
||||
}));
|
||||
8
packages/server/src/common/config/plaid.ts
Normal file
8
packages/server/src/common/config/plaid.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { registerAs } from '@nestjs/config';
|
||||
|
||||
export default registerAs('plaid', () => ({
|
||||
env: process.env.PLAID_ENV || 'sandbox',
|
||||
clientId: process.env.PLAID_CLIENT_ID,
|
||||
secret: process.env.PLAID_SECRET,
|
||||
linkWebhook: process.env.PLAID_LINK_WEBHOOK,
|
||||
}));
|
||||
6
packages/server/src/common/config/posthog.ts
Normal file
6
packages/server/src/common/config/posthog.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import { registerAs } from '@nestjs/config';
|
||||
|
||||
export default registerAs('posthog', () => ({
|
||||
apiKey: process.env.POSTHOG_API_KEY,
|
||||
host: process.env.POSTHOG_HOST || 'https://us.i.posthog.com',
|
||||
}));
|
||||
8
packages/server/src/common/config/redis.ts
Normal file
8
packages/server/src/common/config/redis.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { registerAs } from '@nestjs/config';
|
||||
|
||||
export default registerAs('redis', () => ({
|
||||
host: process.env.REDIS_HOST || 'localhost',
|
||||
port: parseInt(process.env.REDIS_PORT, 10) || 6379,
|
||||
password: process.env.REDIS_PASSWORD || undefined,
|
||||
db: parseInt(process.env.REDIS_DB, 10) || 0,
|
||||
}));
|
||||
9
packages/server/src/common/config/s3.ts
Normal file
9
packages/server/src/common/config/s3.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { registerAs } from '@nestjs/config';
|
||||
|
||||
export default registerAs('s3', () => ({
|
||||
region: process.env.S3_REGION || 'US',
|
||||
accessKeyId: process.env.S3_ACCESS_KEY_ID,
|
||||
secretAccessKey: process.env.S3_SECRET_ACCESS_KEY,
|
||||
endpoint: process.env.S3_ENDPOINT,
|
||||
bucket: process.env.S3_BUCKET,
|
||||
}));
|
||||
6
packages/server/src/common/config/signup-confirmation.ts
Normal file
6
packages/server/src/common/config/signup-confirmation.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import { parseBoolean } from '@/utils/parse-boolean';
|
||||
import { registerAs } from '@nestjs/config';
|
||||
|
||||
export default registerAs('signupConfirmation', () => ({
|
||||
enabled: parseBoolean<boolean>(process.env.SIGNUP_EMAIL_CONFIRMATION, false),
|
||||
}));
|
||||
11
packages/server/src/common/config/signup-restrictions.ts
Normal file
11
packages/server/src/common/config/signup-restrictions.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { castCommaListEnvVarToArray } from '@/utils/cast-comma-list-envvar-Array';
|
||||
import { parseBoolean } from '@/utils/parse-boolean';
|
||||
import { registerAs } from '@nestjs/config';
|
||||
|
||||
export default registerAs('signupRestrictions', () => ({
|
||||
disabled: parseBoolean<boolean>(process.env.SIGNUP_DISABLED, false),
|
||||
allowedDomains: castCommaListEnvVarToArray(
|
||||
process.env.SIGNUP_ALLOWED_DOMAINS,
|
||||
),
|
||||
allowedEmails: castCommaListEnvVarToArray(process.env.SIGNUP_ALLOWED_EMAILS),
|
||||
}));
|
||||
12
packages/server/src/common/config/signup.ts
Normal file
12
packages/server/src/common/config/signup.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { registerAs } from '@nestjs/config';
|
||||
|
||||
export default registerAs('signup', () => ({
|
||||
disabled: process.env.SIGNUP_DISABLED === 'true',
|
||||
allowedDomains: process.env.SIGNUP_ALLOWED_DOMAINS
|
||||
? process.env.SIGNUP_ALLOWED_DOMAINS.split(',')
|
||||
: [],
|
||||
allowedEmails: process.env.SIGNUP_ALLOWED_EMAILS
|
||||
? process.env.SIGNUP_ALLOWED_EMAILS.split(',')
|
||||
: [],
|
||||
emailConfirmation: process.env.SIGNUP_EMAIL_CONFIRMATION === 'true',
|
||||
}));
|
||||
9
packages/server/src/common/config/stripe-payment.ts
Normal file
9
packages/server/src/common/config/stripe-payment.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { registerAs } from '@nestjs/config';
|
||||
|
||||
export default registerAs('stripePayment', () => ({
|
||||
secretKey: process.env.STRIPE_PAYMENT_SECRET_KEY,
|
||||
publishableKey: process.env.STRIPE_PAYMENT_PUBLISHABLE_KEY,
|
||||
clientId: process.env.STRIPE_PAYMENT_CLIENT_ID,
|
||||
webhooksSecret: process.env.STRIPE_PAYMENT_WEBHOOKS_SECRET,
|
||||
redirectUrl: process.env.STRIPE_PAYMENT_REDIRECT_URL,
|
||||
}));
|
||||
10
packages/server/src/common/config/system-database.ts
Normal file
10
packages/server/src/common/config/system-database.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { registerAs } from '@nestjs/config';
|
||||
|
||||
export default registerAs('systemDatabase', () => ({
|
||||
client: 'mysql',
|
||||
host: process.env.SYSTEM_DB_HOST || process.env.DB_HOST,
|
||||
port: process.env.SYSTEM_DB_PORT || process.env.DB_PORT || 5432,
|
||||
user: process.env.SYSTEM_DB_USER || process.env.DB_USER,
|
||||
password: process.env.SYSTEM_DB_PASSWORD || process.env.DB_PASSWORD,
|
||||
databaseName: process.env.SYSTEM_DB_NAME || process.env.DB_NAME,
|
||||
}));
|
||||
13
packages/server/src/common/config/tenant-database.ts
Normal file
13
packages/server/src/common/config/tenant-database.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import * as path from 'path';
|
||||
import { registerAs } from '@nestjs/config';
|
||||
|
||||
export default registerAs('tenantDatabase', () => ({
|
||||
client: 'mysql',
|
||||
host: process.env.TENANT_DB_HOST || process.env.DB_HOST,
|
||||
port: process.env.TENANT_DB_PORT || process.env.DB_PORT || 5432,
|
||||
user: process.env.TENANT_DB_USER || process.env.DB_USER,
|
||||
password: process.env.TENANT_DB_PASSWORD || process.env.DB_PASSWORD,
|
||||
dbNamePrefix: process.env.TENANT_DB_NAME_PERFIX || 'bigcapital_tenant_',
|
||||
migrationsDir: path.join(__dirname, '../../database/migrations'),
|
||||
seedsDir: path.join(__dirname, '../../database/seeds/core'),
|
||||
}));
|
||||
1
packages/server/src/common/constants/files.constants.ts
Normal file
1
packages/server/src/common/constants/files.constants.ts
Normal file
@@ -0,0 +1 @@
|
||||
export const MULTER_MODULE_OPTIONS = 'MULTER_MODULE_OPTIONS';
|
||||
24
packages/server/src/common/constants/multer.constants.ts
Normal file
24
packages/server/src/common/constants/multer.constants.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import type { Multer } from 'multer';
|
||||
import * as multerS3 from 'multer-s3';
|
||||
|
||||
export const multerExceptions = {
|
||||
// from https://github.com/expressjs/multer/blob/master/lib/multer-error.js
|
||||
LIMIT_PART_COUNT: 'Too many parts',
|
||||
LIMIT_FILE_SIZE: 'File too large',
|
||||
LIMIT_FILE_COUNT: 'Too many files',
|
||||
LIMIT_FIELD_KEY: 'Field name too long',
|
||||
LIMIT_FIELD_VALUE: 'Field value too long',
|
||||
LIMIT_FIELD_COUNT: 'Too many fields',
|
||||
LIMIT_UNEXPECTED_FILE: 'Unexpected field',
|
||||
MISSING_FIELD_NAME: 'Field name missing',
|
||||
};
|
||||
|
||||
export const busboyExceptions = {
|
||||
// from https://github.com/mscdex/busboy/blob/master/lib/types/multipart.js
|
||||
MULTIPART_BOUNDARY_NOT_FOUND: 'Multipart: Boundary not found',
|
||||
MULTIPART_MALFORMED_PART_HEADER: 'Malformed part header',
|
||||
MULTIPART_UNEXPECTED_END_OF_FORM: 'Unexpected end of form',
|
||||
MULTIPART_UNEXPECTED_END_OF_FILE: 'Unexpected end of file',
|
||||
};
|
||||
|
||||
|
||||
38
packages/server/src/common/constants/multer.utils.ts
Normal file
38
packages/server/src/common/constants/multer.utils.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
import {
|
||||
BadRequestException,
|
||||
HttpException,
|
||||
PayloadTooLargeException,
|
||||
} from '@nestjs/common';
|
||||
import { multerExceptions, busboyExceptions } from './multer.constants';
|
||||
|
||||
// Multer may add in a 'field' property to the error
|
||||
// https://github.com/expressjs/multer/blob/aa42bea6ac7d0cb8fcb279b15a7278cda805dc63/lib/multer-error.js#L19
|
||||
export function transformException(
|
||||
error: (Error & { field?: string }) | undefined,
|
||||
) {
|
||||
if (!error || error instanceof HttpException) {
|
||||
return error;
|
||||
}
|
||||
switch (error.message) {
|
||||
case multerExceptions.LIMIT_FILE_SIZE:
|
||||
return new PayloadTooLargeException(error.message);
|
||||
case multerExceptions.LIMIT_FILE_COUNT:
|
||||
case multerExceptions.LIMIT_FIELD_KEY:
|
||||
case multerExceptions.LIMIT_FIELD_VALUE:
|
||||
case multerExceptions.LIMIT_FIELD_COUNT:
|
||||
case multerExceptions.LIMIT_UNEXPECTED_FILE:
|
||||
case multerExceptions.LIMIT_PART_COUNT:
|
||||
case multerExceptions.MISSING_FIELD_NAME:
|
||||
if (error.field) {
|
||||
return new BadRequestException(`${error.message} - ${error.field}`);
|
||||
}
|
||||
return new BadRequestException(error.message);
|
||||
case busboyExceptions.MULTIPART_BOUNDARY_NOT_FOUND:
|
||||
return new BadRequestException(error.message);
|
||||
case busboyExceptions.MULTIPART_MALFORMED_PART_HEADER:
|
||||
case busboyExceptions.MULTIPART_UNEXPECTED_END_OF_FORM:
|
||||
case busboyExceptions.MULTIPART_UNEXPECTED_END_OF_FILE:
|
||||
return new BadRequestException(`Multipart: ${error.message}`);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
775
packages/server/src/common/events/events.ts
Normal file
775
packages/server/src/common/events/events.ts
Normal file
@@ -0,0 +1,775 @@
|
||||
export const events = {
|
||||
/**
|
||||
* Authentication service.
|
||||
*/
|
||||
auth: {
|
||||
signIn: 'onSignIn',
|
||||
signingIn: 'onSigningIn',
|
||||
|
||||
signUp: 'onSignUp',
|
||||
signingUp: 'onSigningUp',
|
||||
|
||||
signUpConfirming: 'signUpConfirming',
|
||||
signUpConfirmed: 'signUpConfirmed',
|
||||
|
||||
sendingResetPassword: 'onSendingResetPassword',
|
||||
sendResetPassword: 'onSendResetPassword',
|
||||
|
||||
resetPassword: 'onResetPassword',
|
||||
resetingPassword: 'onResetingPassword',
|
||||
},
|
||||
|
||||
/**
|
||||
* Invite users service.
|
||||
*/
|
||||
inviteUser: {
|
||||
acceptInvite: 'onUserAcceptInvite',
|
||||
sendInvite: 'onUserSendInvite',
|
||||
resendInvite: 'onUserInviteResend',
|
||||
checkInvite: 'onUserCheckInvite',
|
||||
sendInviteTenantSynced: 'onUserSendInviteTenantSynced',
|
||||
},
|
||||
|
||||
/**
|
||||
* Organization managment service.
|
||||
*/
|
||||
organization: {
|
||||
build: 'onOrganizationBuild',
|
||||
built: 'onOrganizationBuilt',
|
||||
|
||||
seeded: 'onOrganizationSeeded',
|
||||
|
||||
baseCurrencyUpdated: 'onOrganizationBaseCurrencyUpdated',
|
||||
},
|
||||
|
||||
/**
|
||||
* Organization subscription.
|
||||
*/
|
||||
subscription: {
|
||||
onSubscriptionCancel: 'onSubscriptionCancel',
|
||||
onSubscriptionCancelled: 'onSubscriptionCancelled',
|
||||
|
||||
onSubscriptionResume: 'onSubscriptionResume',
|
||||
onSubscriptionResumed: 'onSubscriptionResumed',
|
||||
|
||||
onSubscriptionPlanChange: 'onSubscriptionPlanChange',
|
||||
onSubscriptionPlanChanged: 'onSubscriptionPlanChanged',
|
||||
|
||||
onSubscriptionSubscribed: 'onSubscriptionSubscribed',
|
||||
|
||||
onSubscriptionPaymentSucceed: 'onSubscriptionPaymentSucceed',
|
||||
onSubscriptionPaymentFailed: 'onSubscriptionPaymentFailed',
|
||||
},
|
||||
|
||||
/**
|
||||
* Tenants managment service.
|
||||
*/
|
||||
tenantManager: {
|
||||
databaseCreated: 'onDatabaseCreated',
|
||||
tenantMigrated: 'onTenantMigrated',
|
||||
tenantSeeded: 'onTenantSeeded',
|
||||
},
|
||||
|
||||
/**
|
||||
* Accounts service.
|
||||
*/
|
||||
accounts: {
|
||||
onViewed: 'onAccountViewed',
|
||||
onListViewed: 'onAccountsListViewed',
|
||||
|
||||
onCreating: 'onAccountCreating',
|
||||
onCreated: 'onAccountCreated',
|
||||
|
||||
onEditing: 'onAccountEditing',
|
||||
onEdited: 'onAccountEdited',
|
||||
|
||||
onDelete: 'onAccountDelete',
|
||||
onDeleted: 'onAccountDeleted',
|
||||
|
||||
onBulkDeleted: 'onBulkDeleted',
|
||||
onBulkActivated: 'onAccountBulkActivated',
|
||||
|
||||
onActivated: 'onAccountActivated',
|
||||
},
|
||||
|
||||
/**
|
||||
* Manual journals service.
|
||||
*/
|
||||
manualJournals: {
|
||||
onCreating: 'onManualJournalCreating',
|
||||
onCreated: 'onManualJournalCreated',
|
||||
|
||||
onEditing: 'onManualJournalEditing',
|
||||
onEdited: 'onManualJournalEdited',
|
||||
|
||||
onDeleting: 'onManualJournalDeleting',
|
||||
onDeleted: 'onManualJournalDeleted',
|
||||
|
||||
onPublished: 'onManualJournalPublished',
|
||||
onPublishing: 'onManualJournalPublishing',
|
||||
},
|
||||
|
||||
/**
|
||||
* Expenses service.
|
||||
*/
|
||||
expenses: {
|
||||
onCreating: 'onExpenseCreating',
|
||||
onCreated: 'onExpenseCreated',
|
||||
|
||||
onEditing: 'onExpenseEditing',
|
||||
onEdited: 'onExpenseEdited',
|
||||
|
||||
onDeleting: 'onExpenseDeleting',
|
||||
onDeleted: 'onExpenseDeleted',
|
||||
|
||||
onPublishing: 'onExpensePublishing',
|
||||
onPublished: 'onExpensePublished',
|
||||
},
|
||||
|
||||
/**
|
||||
* Sales invoices service.
|
||||
*/
|
||||
saleInvoice: {
|
||||
onViewed: 'onSaleInvoiceItemViewed',
|
||||
onListViewed: 'onSaleInvoiceListViewed',
|
||||
|
||||
onPdfViewed: 'onSaleInvoicePdfViewed',
|
||||
|
||||
onCreate: 'onSaleInvoiceCreate',
|
||||
onCreating: 'onSaleInvoiceCreating',
|
||||
onCreated: 'onSaleInvoiceCreated',
|
||||
|
||||
onEdit: 'onSaleInvoiceEdit',
|
||||
onEditing: 'onSaleInvoiceEditing',
|
||||
onEdited: 'onSaleInvoiceEdited',
|
||||
|
||||
onDelete: 'onSaleInvoiceDelete',
|
||||
onDeleting: 'onSaleInvoiceDeleting',
|
||||
onDeleted: 'onSaleInvoiceDeleted',
|
||||
|
||||
onDelivering: 'onSaleInvoiceDelivering',
|
||||
onDeliver: 'onSaleInvoiceDeliver',
|
||||
onDelivered: 'onSaleInvoiceDelivered',
|
||||
|
||||
onPublish: 'onSaleInvoicePublish',
|
||||
onPublished: 'onSaleInvoicePublished',
|
||||
|
||||
onWriteoff: 'onSaleInvoiceWriteoff',
|
||||
onWrittenoff: 'onSaleInvoiceWrittenoff',
|
||||
onWrittenoffCancel: 'onSaleInvoiceWrittenoffCancel',
|
||||
onWrittenoffCanceled: 'onSaleInvoiceWrittenoffCanceled',
|
||||
|
||||
onNotifySms: 'onSaleInvoiceNotifySms',
|
||||
onNotifiedSms: 'onSaleInvoiceNotifiedSms',
|
||||
|
||||
onNotifyMail: 'onSaleInvoiceNotifyMail',
|
||||
onNotifyReminderMail: 'onSaleInvoiceNotifyReminderMail',
|
||||
|
||||
onPreMailSend: 'onSaleInvoicePreMailSend',
|
||||
onMailSend: 'onSaleInvoiceMailSend',
|
||||
onMailSent: 'onSaleInvoiceMailSent',
|
||||
|
||||
onMailReminderSend: 'onSaleInvoiceMailReminderSend',
|
||||
onMailReminderSent: 'onSaleInvoiceMailReminderSent',
|
||||
|
||||
onPublicLinkGenerating: 'onPublicSharableLinkGenerating',
|
||||
onPublicLinkGenerated: 'onPublicSharableLinkGenerated',
|
||||
},
|
||||
|
||||
/**
|
||||
* Sales estimates service.
|
||||
*/
|
||||
saleEstimate: {
|
||||
onViewed: 'onSaleEstimateViewed',
|
||||
onPdfViewed: 'onSaleEstimatePdfViewed',
|
||||
|
||||
onCreating: 'onSaleEstimateCreating',
|
||||
onCreated: 'onSaleEstimateCreated',
|
||||
|
||||
onEditing: 'onSaleEstimateEditing',
|
||||
onEdited: 'onSaleEstimateEdited',
|
||||
|
||||
onDeleting: 'onSaleEstimatedDeleting',
|
||||
onDeleted: 'onSaleEstimatedDeleted',
|
||||
|
||||
onPublishing: 'onSaleEstimatedPublishing',
|
||||
onPublished: 'onSaleEstimatedPublished',
|
||||
|
||||
onNotifySms: 'onSaleEstimateNotifySms',
|
||||
onNotifiedSms: 'onSaleEstimateNotifiedSms',
|
||||
|
||||
onDelivering: 'onSaleEstimateDelivering',
|
||||
onDelivered: 'onSaleEstimateDelivered',
|
||||
|
||||
onConvertedToInvoice: 'onSaleEstimateConvertedToInvoice',
|
||||
|
||||
onApproving: 'onSaleEstimateApproving',
|
||||
onApproved: 'onSaleEstimateApproved',
|
||||
|
||||
onRejecting: 'onSaleEstimateRejecting',
|
||||
onRejected: 'onSaleEstimateRejected',
|
||||
|
||||
onNotifyMail: 'onSaleEstimateNotifyMail',
|
||||
|
||||
onPreMailSend: 'onSaleEstimatePreMailSend',
|
||||
onMailSend: 'onSaleEstimateMailSend',
|
||||
onMailSent: 'onSaleEstimateMailSent',
|
||||
},
|
||||
|
||||
/**
|
||||
* Sales receipts service.
|
||||
*/
|
||||
saleReceipt: {
|
||||
onPdfViewed: 'onSaleReceiptPdfViewed',
|
||||
|
||||
onCreating: 'onSaleReceiptsCreating',
|
||||
onCreated: 'onSaleReceiptsCreated',
|
||||
|
||||
onEditing: 'onSaleReceiptsEditing',
|
||||
onEdited: 'onSaleReceiptsEdited',
|
||||
|
||||
onDeleting: 'onSaleReceiptsDeleting',
|
||||
onDeleted: 'onSaleReceiptsDeleted',
|
||||
|
||||
onPublishing: 'onSaleReceiptPublishing',
|
||||
onPublished: 'onSaleReceiptPublished',
|
||||
|
||||
onClosed: 'onSaleReceiptClosed',
|
||||
onClosing: 'onSaleReceiptClosing',
|
||||
|
||||
onNotifySms: 'onSaleReceiptNotifySms',
|
||||
onNotifiedSms: 'onSaleReceiptNotifiedSms',
|
||||
|
||||
onPreMailSend: 'onSaleReceiptPreMailSend',
|
||||
onMailSend: 'onSaleReceiptMailSend',
|
||||
onMailSent: 'onSaleReceiptMailSent',
|
||||
},
|
||||
|
||||
/**
|
||||
* Payment receipts service.
|
||||
*/
|
||||
paymentReceive: {
|
||||
onPdfViewed: 'onPaymentReceivedPdfViewed',
|
||||
|
||||
onCreated: 'onPaymentReceiveCreated',
|
||||
onCreating: 'onPaymentReceiveCreating',
|
||||
|
||||
onEditing: 'onPaymentReceiveEditing',
|
||||
onEdited: 'onPaymentReceiveEdited',
|
||||
|
||||
onDeleting: 'onPaymentReceiveDeleting',
|
||||
onDeleted: 'onPaymentReceiveDeleted',
|
||||
|
||||
onPublishing: 'onPaymentReceivePublishing',
|
||||
onPublished: 'onPaymentReceivePublished',
|
||||
|
||||
onNotifySms: 'onPaymentReceiveNotifySms',
|
||||
onNotifiedSms: 'onPaymentReceiveNotifiedSms',
|
||||
|
||||
onPreMailSend: 'onPaymentReceivePreMailSend',
|
||||
onMailSend: 'onPaymentReceiveMailSend',
|
||||
onMailSent: 'onPaymentReceiveMailSent',
|
||||
},
|
||||
|
||||
/**
|
||||
* Bills service.
|
||||
*/
|
||||
bill: {
|
||||
onCreating: 'onBillCreating',
|
||||
onCreated: 'onBillCreated',
|
||||
|
||||
onEditing: 'onBillEditing',
|
||||
onEdited: 'onBillEdited',
|
||||
|
||||
onDeleting: 'onBillDeleting',
|
||||
onDeleted: 'onBillDeleted',
|
||||
|
||||
onPublishing: 'onBillPublishing',
|
||||
onPublished: 'onBillPublished',
|
||||
|
||||
onOpening: 'onBillOpening',
|
||||
onOpened: 'onBillOpened',
|
||||
},
|
||||
|
||||
/**
|
||||
* Bill payments service.
|
||||
*/
|
||||
billPayment: {
|
||||
onCreating: 'onBillPaymentCreating',
|
||||
onCreated: 'onBillPaymentCreated',
|
||||
|
||||
onEditing: 'onBillPaymentEditing',
|
||||
onEdited: 'onBillPaymentEdited',
|
||||
|
||||
onDeleted: 'onBillPaymentDeleted',
|
||||
onDeleting: 'onBillPaymentDeleting',
|
||||
|
||||
onPublishing: 'onBillPaymentPublishing',
|
||||
onPublished: 'onBillPaymentPublished',
|
||||
},
|
||||
|
||||
/**
|
||||
* Customers services.
|
||||
*/
|
||||
customers: {
|
||||
onCreating: 'onCustomerCreating',
|
||||
onCreated: 'onCustomerCreated',
|
||||
|
||||
onEdited: 'onCustomerEdited',
|
||||
onEditing: 'onCustomerEditing',
|
||||
|
||||
onDeleted: 'onCustomerDeleted',
|
||||
onDeleting: 'onCustomerDeleting',
|
||||
onBulkDeleted: 'onBulkDeleted',
|
||||
|
||||
onOpeningBalanceChanging: 'onCustomerOpeningBalanceChanging',
|
||||
onOpeningBalanceChanged: 'onCustomerOpeingBalanceChanged',
|
||||
|
||||
onActivating: 'onCustomerActivating',
|
||||
onActivated: 'onCustomerActivated',
|
||||
},
|
||||
|
||||
/**
|
||||
* Vendors services.
|
||||
*/
|
||||
vendors: {
|
||||
onCreated: 'onVendorCreated',
|
||||
onCreating: 'onVendorCreating',
|
||||
|
||||
onEdited: 'onVendorEdited',
|
||||
onEditing: 'onVendorEditing',
|
||||
|
||||
onDeleted: 'onVendorDeleted',
|
||||
onDeleting: 'onVendorDeleting',
|
||||
|
||||
onOpeningBalanceChanging: 'onVendorOpeingBalanceChanging',
|
||||
onOpeningBalanceChanged: 'onVendorOpeingBalanceChanged',
|
||||
|
||||
onActivating: 'onVendorActivating',
|
||||
onActivated: 'onVendorActivated',
|
||||
},
|
||||
|
||||
/**
|
||||
* Items service.
|
||||
*/
|
||||
item: {
|
||||
onViewed: 'onItemViewed',
|
||||
|
||||
onCreated: 'onItemCreated',
|
||||
onCreating: 'onItemCreating',
|
||||
|
||||
onEditing: 'onItemEditing',
|
||||
onEdited: 'onItemEdited',
|
||||
|
||||
onDeleted: 'onItemDeleted',
|
||||
onDeleting: 'onItemDeleting',
|
||||
|
||||
onActivating: 'onItemActivating',
|
||||
onActivated: 'onItemActivated',
|
||||
|
||||
onInactivating: 'onInactivating',
|
||||
onInactivated: 'onItemInactivated',
|
||||
},
|
||||
|
||||
/**
|
||||
* Item category service.
|
||||
*/
|
||||
itemCategory: {
|
||||
onCreated: 'onItemCategoryCreated',
|
||||
onEdited: 'onItemCategoryEdited',
|
||||
onDeleted: 'onItemCategoryDeleted',
|
||||
onBulkDeleted: 'onItemCategoryBulkDeleted',
|
||||
},
|
||||
|
||||
/**
|
||||
* Inventory service.
|
||||
*/
|
||||
inventory: {
|
||||
onInventoryTransactionsCreated: 'onInventoryTransactionsCreated',
|
||||
onInventoryTransactionsDeleted: 'onInventoryTransactionsDeleted',
|
||||
|
||||
onComputeItemCostJobScheduled: 'onComputeItemCostJobScheduled',
|
||||
onComputeItemCostJobStarted: 'onComputeItemCostJobStarted',
|
||||
onComputeItemCostJobCompleted: 'onComputeItemCostJobCompleted',
|
||||
|
||||
onInventoryCostEntriesWritten: 'onInventoryCostEntriesWritten',
|
||||
|
||||
onCostLotsGLEntriesBeforeWrite: 'onInventoryCostLotsGLEntriesBeforeWrite',
|
||||
onCostLotsGLEntriesWrite: 'onInventoryCostLotsGLEntriesWrite',
|
||||
},
|
||||
|
||||
/**
|
||||
* Inventory adjustment service.
|
||||
*/
|
||||
inventoryAdjustment: {
|
||||
onQuickCreating: 'onInventoryAdjustmentCreating',
|
||||
onQuickCreated: 'onInventoryAdjustmentQuickCreated',
|
||||
|
||||
onCreated: 'onInventoryAdjustmentCreated',
|
||||
|
||||
onDeleting: 'onInventoryAdjustmentDeleting',
|
||||
onDeleted: 'onInventoryAdjustmentDeleted',
|
||||
|
||||
onPublishing: 'onInventoryAdjustmentPublishing',
|
||||
onPublished: 'onInventoryAdjustmentPublished',
|
||||
},
|
||||
|
||||
/**
|
||||
* Bill landed cost.
|
||||
*/
|
||||
billLandedCost: {
|
||||
onCreate: 'onBillLandedCostCreate',
|
||||
onCreated: 'onBillLandedCostCreated',
|
||||
onDelete: 'onBillLandedCostDelete',
|
||||
onDeleted: 'onBillLandedCostDeleted',
|
||||
},
|
||||
|
||||
cashflow: {
|
||||
onOwnerContributionCreate: 'onCashflowOwnerContributionCreate',
|
||||
onOwnerContributionCreated: 'onCashflowOwnerContributionCreated',
|
||||
|
||||
onOtherIncomeCreate: 'onCashflowOtherIncomeCreate',
|
||||
onOtherIncomeCreated: 'onCashflowOtherIncomeCreated',
|
||||
|
||||
onTransactionCreating: 'onCashflowTransactionCreating',
|
||||
onTransactionCreated: 'onCashflowTransactionCreated',
|
||||
|
||||
onTransactionDeleting: 'onCashflowTransactionDeleting',
|
||||
onTransactionDeleted: 'onCashflowTransactionDeleted',
|
||||
|
||||
onTransactionCategorizing: 'onTransactionCategorizing',
|
||||
onTransactionCategorized: 'onCashflowTransactionCategorized',
|
||||
|
||||
onTransactionUncategorizedCreating: 'onTransactionUncategorizedCreating',
|
||||
onTransactionUncategorizedCreated: 'onTransactionUncategorizedCreated',
|
||||
|
||||
onTransactionUncategorizing: 'onTransactionUncategorizing',
|
||||
onTransactionUncategorized: 'onTransactionUncategorized',
|
||||
|
||||
onTransactionCategorizingAsExpense: 'onTransactionCategorizingAsExpense',
|
||||
onTransactionCategorizedAsExpense: 'onTransactionCategorizedAsExpense',
|
||||
},
|
||||
|
||||
/**
|
||||
* Roles service events.
|
||||
*/
|
||||
roles: {
|
||||
onCreate: 'onRoleCreate',
|
||||
onCreated: 'onRoleCreated',
|
||||
onEdit: 'onRoleEdit',
|
||||
onEdited: 'onRoleEdited',
|
||||
onDelete: 'onRoleDelete',
|
||||
onDeleted: 'onRoleDeleted',
|
||||
},
|
||||
|
||||
tenantUser: {
|
||||
onEdited: 'onTenantUserEdited',
|
||||
onDeleted: 'onTenantUserDeleted',
|
||||
onActivated: 'onTenantUserActivated',
|
||||
onInactivated: 'onTenantUserInactivated',
|
||||
},
|
||||
|
||||
/**
|
||||
* Credit note service.
|
||||
*/
|
||||
creditNote: {
|
||||
onPdfViewed: 'onCreditNotePdfViewed',
|
||||
|
||||
onCreate: 'onCreditNoteCreate',
|
||||
onCreating: 'onCreditNoteCreating',
|
||||
onCreated: 'onCreditNoteCreated',
|
||||
|
||||
onEditing: 'onCreditNoteEditing',
|
||||
onEdit: 'onCreditNoteEdit',
|
||||
onEdited: 'onCreditNoteEdited',
|
||||
|
||||
onDelete: 'onCreditNoteDelete',
|
||||
onDeleting: 'onCreditNoteDeleting',
|
||||
onDeleted: 'onCreditNoteDeleted',
|
||||
|
||||
onOpen: 'onCreditNoteOpen',
|
||||
onOpening: 'onCreditNoteOpening',
|
||||
onOpened: 'onCreditNoteOpened',
|
||||
|
||||
onRefundCreate: 'onCreditNoteRefundCreate',
|
||||
onRefundCreating: 'onCreditNoteRefundCreating',
|
||||
onRefundCreated: 'onCreditNoteRefundCreated',
|
||||
|
||||
onRefundDelete: 'onCreditNoteRefundDelete',
|
||||
onRefundDeleting: 'onCreditNoteRefundDeleting',
|
||||
onRefundDeleted: 'onCreditNoteRefundDeleted',
|
||||
|
||||
onApplyToInvoicesCreated: 'onCreditNoteApplyToInvoiceCreated',
|
||||
onApplyToInvoicesCreate: 'onCreditNoteApplyToInvoiceCreate',
|
||||
onApplyToInvoicesDeleted: 'onCreditNoteApplyToInvoiceDeleted',
|
||||
},
|
||||
|
||||
/**
|
||||
* Vendor credit service.
|
||||
*/
|
||||
vendorCredit: {
|
||||
onCreate: 'onVendorCreditCreate',
|
||||
onCreating: 'onVendorCreditCreating',
|
||||
onCreated: 'onVendorCreditCreated',
|
||||
|
||||
onEdit: 'onVendorCreditEdit',
|
||||
onEditing: 'onVendorCreditEditing',
|
||||
onEdited: 'onVendorCreditEdited',
|
||||
|
||||
onDelete: 'onVendorCreditDelete',
|
||||
onDeleting: 'onVendorCreditDeleting',
|
||||
onDeleted: 'onVendorCreditDeleted',
|
||||
|
||||
onOpen: 'onVendorCreditOpen',
|
||||
onOpened: 'onVendorCreditOpened',
|
||||
|
||||
onRefundCreating: 'onVendorCreditRefundCreating',
|
||||
onRefundCreate: 'onVendorCreditRefundCreate',
|
||||
onRefundCreated: 'onVendorCreditRefundCreated',
|
||||
|
||||
onRefundDelete: 'onVendorCreditRefundDelete',
|
||||
onRefundDeleting: 'onVendorCreditRefundDeleting',
|
||||
onRefundDeleted: 'onVendorCreditRefundDeleted',
|
||||
|
||||
onApplyToInvoicesCreated: 'onVendorCreditApplyToInvoiceCreated',
|
||||
onApplyToInvoicesCreate: 'onVendorCreditApplyToInvoiceCreate',
|
||||
onApplyToInvoicesDeleted: 'onVendorCreditApplyToInvoiceDeleted',
|
||||
},
|
||||
|
||||
transactionsLocking: {
|
||||
locked: 'onTransactionLockingLocked',
|
||||
lockCanceled: 'onTransactionLockingLockCanceled',
|
||||
partialUnlocked: 'onTransactionLockingPartialUnlocked',
|
||||
partialUnlockCanceled: 'onTransactionLockingPartialUnlockCanceled',
|
||||
},
|
||||
|
||||
warehouse: {
|
||||
onCreate: 'onWarehouseCreate',
|
||||
onCreated: 'onWarehouseCreated',
|
||||
|
||||
onEdit: 'onWarehouseEdit',
|
||||
onEdited: 'onWarehouseEdited',
|
||||
|
||||
onDelete: 'onWarehouseDelete',
|
||||
onDeleted: 'onWarehouseDeleted',
|
||||
|
||||
onActivate: 'onWarehouseActivate',
|
||||
onActivated: 'onWarehouseActivated',
|
||||
|
||||
onMarkPrimary: 'onWarehouseMarkPrimary',
|
||||
onMarkedPrimary: 'onWarehouseMarkedPrimary',
|
||||
},
|
||||
|
||||
warehouseTransfer: {
|
||||
onCreate: 'onWarehouseTransferCreate',
|
||||
onCreated: 'onWarehouseTransferCreated',
|
||||
|
||||
onEdit: 'onWarehouseTransferEdit',
|
||||
onEdited: 'onWarehouseTransferEdited',
|
||||
|
||||
onDelete: 'onWarehouseTransferDelete',
|
||||
onDeleted: 'onWarehouseTransferDeleted',
|
||||
|
||||
onInitiate: 'onWarehouseTransferInitiate',
|
||||
onInitiated: 'onWarehouseTransferInitated',
|
||||
|
||||
onTransfer: 'onWarehouseTransferInitiate',
|
||||
onTransferred: 'onWarehouseTransferTransferred',
|
||||
},
|
||||
|
||||
/**
|
||||
* Branches.
|
||||
*/
|
||||
branch: {
|
||||
onActivate: 'onBranchActivate',
|
||||
onActivated: 'onBranchActivated',
|
||||
|
||||
onMarkPrimary: 'onBranchMarkPrimary',
|
||||
onMarkedPrimary: 'onBranchMarkedPrimary',
|
||||
},
|
||||
|
||||
/**
|
||||
* Projects.
|
||||
*/
|
||||
project: {
|
||||
onCreate: 'onProjectCreate',
|
||||
onCreating: 'onProjectCreating',
|
||||
onCreated: 'onProjectCreated',
|
||||
|
||||
onEdit: 'onEditProject',
|
||||
onEditing: 'onEditingProject',
|
||||
onEdited: 'onEditedProject',
|
||||
|
||||
onEditStatus: 'onEditStatusProject',
|
||||
onEditingStatus: 'onEditingStatusProject',
|
||||
onEditedStatus: 'onEditedStatusProject',
|
||||
|
||||
onDelete: 'onDeleteProject',
|
||||
onDeleting: 'onDeletingProject',
|
||||
onDeleted: 'onDeletedProject',
|
||||
},
|
||||
|
||||
/**
|
||||
* Project Tasks.
|
||||
*/
|
||||
projectTask: {
|
||||
onCreate: 'onProjectTaskCreate',
|
||||
onCreating: 'onProjectTaskCreating',
|
||||
onCreated: 'onProjectTaskCreated',
|
||||
|
||||
onEdit: 'onProjectTaskEdit',
|
||||
onEditing: 'onProjectTaskEditing',
|
||||
onEdited: 'onProjectTaskEdited',
|
||||
|
||||
onDelete: 'onProjectTaskDelete',
|
||||
onDeleting: 'onProjectTaskDeleting',
|
||||
onDeleted: 'onProjectTaskDeleted',
|
||||
},
|
||||
|
||||
/**
|
||||
* Project Times.
|
||||
*/
|
||||
projectTime: {
|
||||
onCreate: 'onProjectTimeCreate',
|
||||
onCreating: 'onProjectTimeCreating',
|
||||
onCreated: 'onProjectTimeCreated',
|
||||
|
||||
onEdit: 'onProjectTimeEdit',
|
||||
onEditing: 'onProjectTimeEditing',
|
||||
onEdited: 'onProjectTimeEdited',
|
||||
|
||||
onDelete: 'onProjectTimeDelete',
|
||||
onDeleting: 'onProjectTimeDeleting',
|
||||
onDeleted: 'onProjectTimeDeleted',
|
||||
},
|
||||
|
||||
taxRates: {
|
||||
onCreating: 'onTaxRateCreating',
|
||||
onCreated: 'onTaxRateCreated',
|
||||
|
||||
onEditing: 'onTaxRateEditing',
|
||||
onEdited: 'onTaxRateEdited',
|
||||
|
||||
onDeleting: 'onTaxRateDeleting',
|
||||
onDeleted: 'onTaxRateDeleted',
|
||||
|
||||
onActivating: 'onTaxRateActivating',
|
||||
onActivated: 'onTaxRateActivated',
|
||||
|
||||
onInactivating: 'onTaxRateInactivating',
|
||||
onInactivated: 'onTaxRateInactivated',
|
||||
},
|
||||
|
||||
plaid: {
|
||||
onItemCreated: 'onPlaidItemCreated',
|
||||
onTransactionsSynced: 'onPlaidTransactionsSynced',
|
||||
},
|
||||
|
||||
// Bank rules.
|
||||
bankRules: {
|
||||
onCreating: 'onBankRuleCreating',
|
||||
onCreated: 'onBankRuleCreated',
|
||||
|
||||
onEditing: 'onBankRuleEditing',
|
||||
onEdited: 'onBankRuleEdited',
|
||||
|
||||
onDeleting: 'onBankRuleDeleting',
|
||||
onDeleted: 'onBankRuleDeleted',
|
||||
},
|
||||
|
||||
// Bank matching.
|
||||
bankMatch: {
|
||||
onMatching: 'onBankTransactionMatching',
|
||||
onMatched: 'onBankTransactionMatched',
|
||||
|
||||
onUnmatching: 'onBankTransactionUnmathcing',
|
||||
onUnmatched: 'onBankTransactionUnmathced',
|
||||
},
|
||||
|
||||
bankTransactions: {
|
||||
onExcluding: 'onBankTransactionExclude',
|
||||
onExcluded: 'onBankTransactionExcluded',
|
||||
|
||||
onUnexcluding: 'onBankTransactionUnexcluding',
|
||||
onUnexcluded: 'onBankTransactionUnexcluded',
|
||||
|
||||
onPendingRemoving: 'onBankTransactionPendingRemoving',
|
||||
onPendingRemoved: 'onBankTransactionPendingRemoved',
|
||||
},
|
||||
|
||||
bankAccount: {
|
||||
onDisconnecting: 'onBankAccountDisconnecting',
|
||||
onDisconnected: 'onBankAccountDisconnected',
|
||||
},
|
||||
|
||||
// Import files.
|
||||
import: {
|
||||
onImportCommitted: 'onImportFileCommitted',
|
||||
},
|
||||
|
||||
// Branding templates
|
||||
pdfTemplate: {
|
||||
onCreating: 'onPdfTemplateCreating',
|
||||
onCreated: 'onPdfTemplateCreated',
|
||||
|
||||
onEditing: 'onPdfTemplateEditing',
|
||||
onEdited: 'onPdfTemplatedEdited',
|
||||
|
||||
onDeleting: 'onPdfTemplateDeleting',
|
||||
onDeleted: 'onPdfTemplateDeleted',
|
||||
|
||||
onAssignedDefault: 'onPdfTemplateAssignedDefault',
|
||||
onAssigningDefault: 'onPdfTemplateAssigningDefault',
|
||||
},
|
||||
|
||||
// Payment method.
|
||||
paymentMethod: {
|
||||
onEditing: 'onPaymentMethodEditing',
|
||||
onEdited: 'onPaymentMethodEdited',
|
||||
|
||||
onDeleted: 'onPaymentMethodDeleted',
|
||||
},
|
||||
|
||||
// Payment methods integrations
|
||||
paymentIntegrationLink: {
|
||||
onPaymentIntegrationLink: 'onPaymentIntegrationLink',
|
||||
onPaymentIntegrationDeleteLink: 'onPaymentIntegrationDeleteLink',
|
||||
},
|
||||
|
||||
// Stripe Payment Integration
|
||||
stripeIntegration: {
|
||||
onAccountCreated: 'onStripeIntegrationAccountCreated',
|
||||
onAccountDeleted: 'onStripeIntegrationAccountDeleted',
|
||||
|
||||
onPaymentLinkCreated: 'onStripePaymentLinkCreated',
|
||||
onPaymentLinkInactivated: 'onStripePaymentLinkInactivated',
|
||||
|
||||
onOAuthCodeGranted: 'onStripeOAuthCodeGranted',
|
||||
},
|
||||
|
||||
// Stripe Payment Webhooks
|
||||
stripeWebhooks: {
|
||||
onCheckoutSessionCompleted: 'onStripeCheckoutSessionCompleted',
|
||||
onAccountUpdated: 'onStripeAccountUpdated',
|
||||
},
|
||||
|
||||
// Reports
|
||||
reports: {
|
||||
onBalanceSheetViewed: 'onBalanceSheetViewed',
|
||||
onTrialBalanceSheetView: 'onTrialBalanceSheetViewed',
|
||||
onProfitLossSheetViewed: 'onProfitLossSheetViewed',
|
||||
onCashflowStatementViewed: 'onCashflowStatementViewed',
|
||||
onGeneralLedgerViewed: 'onGeneralLedgerViewed',
|
||||
onJournalViewed: 'onJounralViewed',
|
||||
onReceivableAgingViewed: 'onReceivableAgingViewed',
|
||||
onPayableAgingViewed: 'onPayableAgingViewed',
|
||||
onCustomerBalanceSummaryViewed: 'onInventoryValuationViewed',
|
||||
onVendorBalanceSummaryViewed: 'onVendorBalanceSummaryViewed',
|
||||
onInventoryValuationViewed: 'onCustomerBalanceSummaryViewed',
|
||||
onCustomerTransactionsViewed: 'onCustomerTransactionsViewed',
|
||||
onVendorTransactionsViewed: 'onVendorTransactionsViewed',
|
||||
onSalesByItemViewed: 'onSalesByItemViewed',
|
||||
onPurchasesByItemViewed: 'onPurchasesByItemViewed',
|
||||
},
|
||||
|
||||
};
|
||||
@@ -0,0 +1,6 @@
|
||||
export class ModelEntityNotFound extends Error {
|
||||
constructor(entityId, message?) {
|
||||
message = message || `Entity with id ${entityId} does not exist`;
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
24
packages/server/src/common/filters/service-error.filter.ts
Normal file
24
packages/server/src/common/filters/service-error.filter.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import {
|
||||
ExceptionFilter,
|
||||
Catch,
|
||||
ArgumentsHost,
|
||||
HttpStatus,
|
||||
} from '@nestjs/common';
|
||||
import { Response } from 'express';
|
||||
import { ServiceError } from '@/modules/Items/ServiceError';
|
||||
|
||||
@Catch(ServiceError)
|
||||
export class ServiceErrorFilter implements ExceptionFilter {
|
||||
catch(exception: ServiceError, host: ArgumentsHost) {
|
||||
const ctx = host.switchToHttp();
|
||||
const response = ctx.getResponse<Response>();
|
||||
const status = exception.getStatus();
|
||||
|
||||
response.status(status).json({
|
||||
statusCode: status,
|
||||
errorType: exception.errorType,
|
||||
message: exception.message,
|
||||
payload: exception.payload,
|
||||
});
|
||||
}
|
||||
}
|
||||
70
packages/server/src/common/interceptors/file.interceptor.ts
Normal file
70
packages/server/src/common/interceptors/file.interceptor.ts
Normal file
@@ -0,0 +1,70 @@
|
||||
import {
|
||||
CallHandler,
|
||||
ExecutionContext,
|
||||
Inject,
|
||||
mixin,
|
||||
NestInterceptor,
|
||||
Optional,
|
||||
Type,
|
||||
} from '@nestjs/common';
|
||||
import * as multer from 'multer';
|
||||
import { Observable } from 'rxjs';
|
||||
import { MULTER_MODULE_OPTIONS } from '../constants/files.constants';
|
||||
import { transformException } from '../constants/multer.utils';
|
||||
import { MulterModuleOptions } from '@nestjs/platform-express';
|
||||
import { MulterOptions } from '@nestjs/platform-express/multer/interfaces/multer-options.interface';
|
||||
|
||||
type MulterInstance = any;
|
||||
/**
|
||||
* @param {string} fieldName
|
||||
* @param {Function|MulterOptions} localOptions - Function that receives controller instance or MulterOptions object
|
||||
*/
|
||||
export function FileInterceptor(
|
||||
fieldName: string,
|
||||
localOptions?: ((instance: any) => MulterOptions) | MulterOptions,
|
||||
): Type<NestInterceptor> {
|
||||
class MixinInterceptor implements NestInterceptor {
|
||||
protected multer: MulterInstance;
|
||||
|
||||
constructor(
|
||||
@Optional()
|
||||
@Inject(MULTER_MODULE_OPTIONS)
|
||||
options: (() => MulterModuleOptions | MulterModuleOptions) = () => ({}),
|
||||
) {
|
||||
const resolvedOptions = typeof localOptions === 'function'
|
||||
? localOptions(this)
|
||||
: localOptions;
|
||||
|
||||
this.multer = (multer as any)({
|
||||
...(typeof options === 'function' ? options() : options),
|
||||
...resolvedOptions,
|
||||
});
|
||||
}
|
||||
|
||||
async intercept(
|
||||
context: ExecutionContext,
|
||||
next: CallHandler,
|
||||
): Promise<Observable<any>> {
|
||||
const ctx = context.switchToHttp();
|
||||
|
||||
await new Promise<void>((resolve, reject) =>
|
||||
this.multer.single(fieldName)(
|
||||
ctx.getRequest(),
|
||||
ctx.getResponse(),
|
||||
(err: any) => {
|
||||
if (err) {
|
||||
const error = transformException(err);
|
||||
return reject(error);
|
||||
}
|
||||
resolve();
|
||||
},
|
||||
),
|
||||
);
|
||||
return next.handle();
|
||||
}
|
||||
}
|
||||
|
||||
const Interceptor = mixin(MixinInterceptor);
|
||||
|
||||
return Interceptor;
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
import {
|
||||
type ExecutionContext,
|
||||
Injectable,
|
||||
type NestInterceptor,
|
||||
type CallHandler,
|
||||
Optional,
|
||||
} from '@nestjs/common';
|
||||
import { type Observable } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
|
||||
export function camelToSnake<T = any>(value: T) {
|
||||
if (value === null || value === undefined) {
|
||||
return value;
|
||||
}
|
||||
if (Array.isArray(value)) {
|
||||
return value.map(camelToSnake);
|
||||
}
|
||||
if (typeof value === 'object' && !(value instanceof Date)) {
|
||||
return Object.fromEntries(
|
||||
Object.entries(value).map(([key, value]) => [
|
||||
key
|
||||
.split(/(?=[A-Z])/)
|
||||
.join('_')
|
||||
.toLowerCase(),
|
||||
camelToSnake(value),
|
||||
]),
|
||||
);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
export function snakeToCamel<T = any>(value: T) {
|
||||
if (value === null || value === undefined) {
|
||||
return value;
|
||||
}
|
||||
|
||||
if (Array.isArray(value)) {
|
||||
return value.map(snakeToCamel);
|
||||
}
|
||||
|
||||
const impl = (str: string) => {
|
||||
const converted = str.replace(/([-_]\w)/g, (group) =>
|
||||
group[1].toUpperCase(),
|
||||
);
|
||||
return converted[0].toLowerCase() + converted.slice(1);
|
||||
};
|
||||
|
||||
if (typeof value === 'object' && !(value instanceof Date)) {
|
||||
return Object.fromEntries(
|
||||
Object.entries(value).map(([key, value]) => [
|
||||
impl(key),
|
||||
snakeToCamel(value),
|
||||
]),
|
||||
);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
export const DEFAULT_STRATEGY = {
|
||||
in: snakeToCamel,
|
||||
out: camelToSnake,
|
||||
};
|
||||
|
||||
@Injectable()
|
||||
export class SerializeInterceptor implements NestInterceptor<any, any> {
|
||||
constructor(@Optional() readonly strategy = DEFAULT_STRATEGY) {}
|
||||
|
||||
intercept(
|
||||
context: ExecutionContext,
|
||||
next: CallHandler<any>,
|
||||
): Observable<any> {
|
||||
const request = context.switchToHttp().getRequest();
|
||||
request.body = this.strategy.in(request.body);
|
||||
|
||||
// handle returns stream..
|
||||
return next.handle().pipe(map(this.strategy.out));
|
||||
}
|
||||
}
|
||||
29
packages/server/src/common/pipes/ClassValidation.pipe.ts
Normal file
29
packages/server/src/common/pipes/ClassValidation.pipe.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import {
|
||||
PipeTransform,
|
||||
Injectable,
|
||||
ArgumentMetadata,
|
||||
BadRequestException,
|
||||
} from '@nestjs/common';
|
||||
import { validate } from 'class-validator';
|
||||
import { plainToInstance } from 'class-transformer';
|
||||
|
||||
@Injectable()
|
||||
export class ValidationPipe implements PipeTransform<any> {
|
||||
async transform(value: any, { metatype }: ArgumentMetadata) {
|
||||
if (!metatype || !this.toValidate(metatype)) {
|
||||
return value;
|
||||
}
|
||||
const object = plainToInstance(metatype, value);
|
||||
const errors = await validate(object);
|
||||
|
||||
if (errors.length > 0) {
|
||||
throw new BadRequestException(errors);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private toValidate(metatype: Function): boolean {
|
||||
const types: Function[] = [String, Boolean, Number, Array, Object];
|
||||
return !types.includes(metatype);
|
||||
}
|
||||
}
|
||||
20
packages/server/src/common/pipes/ZodValidation.pipe.ts
Normal file
20
packages/server/src/common/pipes/ZodValidation.pipe.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import {
|
||||
PipeTransform,
|
||||
ArgumentMetadata,
|
||||
BadRequestException,
|
||||
} from '@nestjs/common';
|
||||
import { ZodSchema } from 'zod';
|
||||
|
||||
export class ZodValidationPipe implements PipeTransform {
|
||||
constructor(private schema: ZodSchema) {}
|
||||
|
||||
transform(value: unknown, metadata: ArgumentMetadata) {
|
||||
try {
|
||||
const parsedValue = this.schema.parse(value);
|
||||
return parsedValue;
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
throw new BadRequestException(error.errors);
|
||||
}
|
||||
}
|
||||
}
|
||||
260
packages/server/src/common/repository/CachableRepository.ts
Normal file
260
packages/server/src/common/repository/CachableRepository.ts
Normal file
@@ -0,0 +1,260 @@
|
||||
// import hashObject from 'object-hash';
|
||||
// import { EntityRepository } from './EntityRepository';
|
||||
|
||||
// export class CachableRepository extends EntityRepository {
|
||||
// repositoryName: string;
|
||||
// cache: any;
|
||||
// i18n: any;
|
||||
|
||||
// /**
|
||||
// * Constructor method.
|
||||
// * @param {Knex} knex
|
||||
// * @param {Cache} cache
|
||||
// */
|
||||
// constructor(knex, cache, i18n) {
|
||||
// super(knex);
|
||||
|
||||
// this.cache = cache;
|
||||
// this.i18n = i18n;
|
||||
// this.repositoryName = this.constructor.name;
|
||||
// }
|
||||
|
||||
// getByCache(key, callback) {
|
||||
// return callback();
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Retrieve the cache key of the method name and arguments.
|
||||
// * @param {string} method
|
||||
// * @param {...any} args
|
||||
// * @return {string}
|
||||
// */
|
||||
// getCacheKey(method, ...args) {
|
||||
// const hashArgs = hashObject({ ...args });
|
||||
// const repositoryName = this.repositoryName;
|
||||
|
||||
// return `${repositoryName}-${method}-${hashArgs}`;
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Retrieve all entries with specified relations.
|
||||
// * @param withRelations
|
||||
// */
|
||||
// all(withRelations?, trx?) {
|
||||
// const cacheKey = this.getCacheKey('all', withRelations);
|
||||
|
||||
// return this.getByCache(cacheKey, () => {
|
||||
// return super.all(withRelations, trx);
|
||||
// });
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Finds list of entities with specified attributes
|
||||
// * @param {Object} attributeValues - values to filter retrieved entities by
|
||||
// * @param {string || string[]} [withRelations] - name of relation(s) to eagerly retrieve.
|
||||
// * @returns {Promise<Object[]>} - query builder. You can chain additional methods to it or call "await" or then() on it to execute
|
||||
// */
|
||||
// find(attributeValues = {}, withRelations?) {
|
||||
// const cacheKey = this.getCacheKey('find', attributeValues, withRelations);
|
||||
|
||||
// return this.getByCache(cacheKey, () => {
|
||||
// return super.find(attributeValues, withRelations);
|
||||
// });
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Finds list of entities with attribute values that are different from specified ones
|
||||
// * @param {Object} attributeValues - values to filter retrieved entities by
|
||||
// * @param {string || string[]} [withRelations] - name of relation(s) to eagerly retrieve, as defined in model relationMappings()
|
||||
// * @returns {Promise<Object[]>} - query builder. You can chain additional methods to it or call "await" or then() on it to execute
|
||||
// */
|
||||
// findWhereNot(attributeValues = {}, withRelations?) {
|
||||
// const cacheKey = this.getCacheKey(
|
||||
// 'findWhereNot',
|
||||
// attributeValues,
|
||||
// withRelations
|
||||
// );
|
||||
|
||||
// return this.getByCache(cacheKey, () => {
|
||||
// return super.findWhereNot(attributeValues, withRelations);
|
||||
// });
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Finds list of entities with specified attributes (any of multiple specified values)
|
||||
// * Supports both ('attrName', ['value1', 'value2]) and ({attrName: ['value1', 'value2']} formats)
|
||||
// *
|
||||
// * @param {string|Object} searchParam - attribute name or search criteria object
|
||||
// * @param {*[]} [attributeValues] - attribute values to filter retrieved entities by
|
||||
// * @param {string || string[]} [withRelations] - name of relation(s) to eagerly retrieve, as defined in model relationMappings()
|
||||
// * @returns {PromiseLike<Object[]>} - query builder. You can chain additional methods to it or call "await" or then() on it to execute
|
||||
// */
|
||||
// findWhereIn(searchParam, attributeValues, withRelations?) {
|
||||
// const cacheKey = this.getCacheKey(
|
||||
// 'findWhereIn',
|
||||
// attributeValues,
|
||||
// withRelations
|
||||
// );
|
||||
|
||||
// return this.getByCache(cacheKey, () => {
|
||||
// return super.findWhereIn(searchParam, attributeValues, withRelations);
|
||||
// });
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Finds first entity by given parameters
|
||||
// *
|
||||
// * @param {Object} attributeValues - values to filter retrieved entities by
|
||||
// * @param {string || string[]} [withRelations] - name of relation(s) to eagerly retrieve, as defined in model relationMappings()
|
||||
// * @returns {Promise<Object>}
|
||||
// */
|
||||
// findOne(attributeValues = {}, withRelations?) {
|
||||
// const cacheKey = this.getCacheKey(
|
||||
// 'findOne',
|
||||
// attributeValues,
|
||||
// withRelations
|
||||
// );
|
||||
// return this.getByCache(cacheKey, () => {
|
||||
// return super.findOne(attributeValues, withRelations);
|
||||
// });
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Finds first entity by given parameters
|
||||
// *
|
||||
// * @param {string || number} id - value of id column of the entity
|
||||
// * @param {string || string[]} [withRelations] - name of relation(s) to eagerly retrieve, as defined in model relationMappings()
|
||||
// * @returns {Promise<Object>}
|
||||
// */
|
||||
// findOneById(id, withRelations?) {
|
||||
// const cacheKey = this.getCacheKey('findOneById', id, withRelations);
|
||||
|
||||
// return this.getByCache(cacheKey, () => {
|
||||
// return super.findOneById(id, withRelations);
|
||||
// });
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Persists new entity or an array of entities.
|
||||
// * This method does not recursively persist related entities, use createRecursively (to be implemented) for that.
|
||||
// * Batch insert only works on PostgreSQL
|
||||
// * @param {Object} entity - model instance or parameters for a new entity
|
||||
// * @returns {Promise<Object>} - query builder. You can chain additional methods to it or call "await" or then() on it to execute
|
||||
// */
|
||||
// async create(entity, trx?) {
|
||||
// const result = await super.create(entity, trx);
|
||||
|
||||
// // Flushes the repository cache after insert operation.
|
||||
// this.flushCache();
|
||||
|
||||
// return result;
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Persists updated entity. If previously set fields are not present, performs an incremental update (does not remove fields unless explicitly set to null)
|
||||
// *
|
||||
// * @param {Object} entity - single entity instance
|
||||
// * @param {Object} [trx] - knex transaction instance. If not specified, new implicit transaction will be used.
|
||||
// * @returns {Promise<integer>} number of affected rows
|
||||
// */
|
||||
// async update(entity, whereAttributes?, trx?) {
|
||||
// const result = await super.update(entity, whereAttributes, trx);
|
||||
|
||||
// // Flushes the repository cache after update operation.
|
||||
// this.flushCache();
|
||||
|
||||
// return result;
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * @param {Object} attributeValues - values to filter deleted entities by
|
||||
// * @param {Object} [trx]
|
||||
// * @returns {Promise<integer>} Query builder. After promise is resolved, returns count of deleted rows
|
||||
// */
|
||||
// async deleteBy(attributeValues, trx?) {
|
||||
// const result = await super.deleteBy(attributeValues, trx);
|
||||
// this.flushCache();
|
||||
|
||||
// return result;
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * @param {string || number} id - value of id column of the entity
|
||||
// * @returns {Promise<integer>} Query builder. After promise is resolved, returns count of deleted rows
|
||||
// */
|
||||
// deleteById(id: number | string, trx?) {
|
||||
// const result = super.deleteById(id, trx);
|
||||
|
||||
// // Flushes the repository cache after insert operation.
|
||||
// this.flushCache();
|
||||
|
||||
// return result;
|
||||
// }
|
||||
|
||||
// /**
|
||||
// *
|
||||
// * @param {string|number[]} values -
|
||||
// */
|
||||
// async deleteWhereIn(field: string, values: string | number[]) {
|
||||
// const result = await super.deleteWhereIn(field, values);
|
||||
|
||||
// // Flushes the repository cache after delete operation.
|
||||
// this.flushCache();
|
||||
|
||||
// return result;
|
||||
// }
|
||||
|
||||
// /**
|
||||
// *
|
||||
// * @param {string|number[]} values
|
||||
// */
|
||||
// async deleteWhereIdIn(values: string | number[], trx?) {
|
||||
// const result = await super.deleteWhereIdIn(values, trx);
|
||||
|
||||
// // Flushes the repository cache after delete operation.
|
||||
// this.flushCache();
|
||||
|
||||
// return result;
|
||||
// }
|
||||
|
||||
// /**
|
||||
// *
|
||||
// * @param graph
|
||||
// * @param options
|
||||
// */
|
||||
// async upsertGraph(graph, options) {
|
||||
// const result = await super.upsertGraph(graph, options);
|
||||
|
||||
// // Flushes the repository cache after insert operation.
|
||||
// this.flushCache();
|
||||
|
||||
// return result;
|
||||
// }
|
||||
|
||||
// /**
|
||||
// *
|
||||
// * @param {} whereAttributes
|
||||
// * @param {string} field
|
||||
// * @param {number} amount
|
||||
// */
|
||||
// async changeNumber(whereAttributes, field: string, amount: number, trx?) {
|
||||
// const result = await super.changeNumber(
|
||||
// whereAttributes,
|
||||
// field,
|
||||
// amount,
|
||||
// trx
|
||||
// );
|
||||
|
||||
// // Flushes the repository cache after update operation.
|
||||
// this.flushCache();
|
||||
|
||||
// return result;
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Flush repository cache.
|
||||
// */
|
||||
// flushCache(): void {
|
||||
// this.cache.delStartWith(this.repositoryName);
|
||||
// }
|
||||
// }
|
||||
232
packages/server/src/common/repository/EntityRepository.ts
Normal file
232
packages/server/src/common/repository/EntityRepository.ts
Normal file
@@ -0,0 +1,232 @@
|
||||
import { cloneDeep, forOwn, isString } from 'lodash';
|
||||
import { ModelEntityNotFound } from '../exceptions/ModelEntityNotFound';
|
||||
import { Model } from 'objection';
|
||||
|
||||
function applyGraphFetched(withRelations, builder) {
|
||||
const relations = Array.isArray(withRelations)
|
||||
? withRelations
|
||||
: typeof withRelations === 'string'
|
||||
? withRelations.split(',').map((relation) => relation.trim())
|
||||
: [];
|
||||
|
||||
relations.forEach((relation) => {
|
||||
builder.withGraphFetched(relation);
|
||||
});
|
||||
}
|
||||
|
||||
export class EntityRepository {
|
||||
idColumn: string = 'id';
|
||||
knex: any;
|
||||
|
||||
/**
|
||||
* Retrieve the repository model binded it to knex instance.
|
||||
*/
|
||||
get model(): typeof Model {
|
||||
throw new Error("The repository's model is not defined.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve all entries with specified relations.
|
||||
* @param withRelations
|
||||
*/
|
||||
all(withRelations?, trx?) {
|
||||
const builder = this.model.query(trx);
|
||||
applyGraphFetched(withRelations, builder);
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds list of entities with specified attributes
|
||||
*
|
||||
* @param {Object} attributeValues - values to filter retrieved entities by
|
||||
* @param {string || string[]} [withRelations] - name of relation(s) to eagerly retrieve.
|
||||
* @returns {Promise<Object[]>} - query builder. You can chain additional methods to it or call "await" or then() on it to execute
|
||||
*/
|
||||
find(attributeValues = {}, withRelations?) {
|
||||
const builder = this.model.query().where(attributeValues);
|
||||
|
||||
applyGraphFetched(withRelations, builder);
|
||||
return builder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds list of entities with attribute values that are different from specified ones
|
||||
*
|
||||
* @param {Object} attributeValues - values to filter retrieved entities by
|
||||
* @param {string || string[]} [withRelations] - name of relation(s) to eagerly retrieve, as defined in model relationMappings()
|
||||
* @returns {PromiseLike<Object[]>} - query builder. You can chain additional methods to it or call "await" or then() on it to execute
|
||||
*/
|
||||
findWhereNot(attributeValues = {}, withRelations?) {
|
||||
const builder = this.model.query().whereNot(attributeValues);
|
||||
|
||||
applyGraphFetched(withRelations, builder);
|
||||
return builder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds list of entities with specified attributes (any of multiple specified values)
|
||||
* Supports both ('attrName', ['value1', 'value2]) and ({attrName: ['value1', 'value2']} formats)
|
||||
*
|
||||
* @param {string|Object} searchParam - attribute name or search criteria object
|
||||
* @param {*[]} [attributeValues] - attribute values to filter retrieved entities by
|
||||
* @param {string || string[]} [withRelations] - name of relation(s) to eagerly retrieve, as defined in model relationMappings()
|
||||
* @returns {PromiseLike<Object[]>} - query builder. You can chain additional methods to it or call "await" or then() on it to execute
|
||||
*/
|
||||
findWhereIn(searchParam, attributeValues, withRelations?) {
|
||||
const commonBuilder = (builder) => {
|
||||
applyGraphFetched(withRelations, builder);
|
||||
};
|
||||
if (isString(searchParam)) {
|
||||
return this.model
|
||||
.query()
|
||||
.whereIn(searchParam, attributeValues)
|
||||
.onBuild(commonBuilder);
|
||||
} else {
|
||||
const builder = this.model.query(this.knex).onBuild(commonBuilder);
|
||||
|
||||
forOwn(searchParam, (value, key) => {
|
||||
if (Array.isArray(value)) {
|
||||
builder.whereIn(key, value);
|
||||
} else {
|
||||
builder.where(key, value);
|
||||
}
|
||||
});
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds first entity by given parameters
|
||||
*
|
||||
* @param {Object} attributeValues - values to filter retrieved entities by
|
||||
* @param {string || string[]} [withRelations] - name of relation(s) to eagerly retrieve, as defined in model relationMappings()
|
||||
* @returns {Promise<Object>}
|
||||
*/
|
||||
async findOne(attributeValues = {}, withRelations?) {
|
||||
const results = await this.find(attributeValues, withRelations);
|
||||
return results[0] || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds first entity by given parameters
|
||||
*
|
||||
* @param {string || number} id - value of id column of the entity
|
||||
* @param {string || string[]} [withRelations] - name of relation(s) to eagerly retrieve, as defined in model relationMappings()
|
||||
* @returns {Promise<Object>}
|
||||
*/
|
||||
findOneById(id, withRelations?) {
|
||||
return this.findOne({ [this.idColumn]: id }, withRelations);
|
||||
}
|
||||
|
||||
/**
|
||||
* Persists new entity or an array of entities.
|
||||
* This method does not recursively persist related entities, use createRecursively (to be implemented) for that.
|
||||
* Batch insert only works on PostgreSQL
|
||||
*
|
||||
* @param {Object} entity - model instance or parameters for a new entity
|
||||
* @returns {Promise<Object>} - query builder. You can chain additional methods to it or call "await" or then() on it to execute
|
||||
*/
|
||||
create(entity, trx?) {
|
||||
// Keep the input parameter immutable
|
||||
const instanceDTO = cloneDeep(entity);
|
||||
|
||||
return this.model.query(trx).insert(instanceDTO);
|
||||
}
|
||||
|
||||
/**
|
||||
* Persists updated entity. If previously set fields are not present, performs an incremental update (does not remove fields unless explicitly set to null)
|
||||
*
|
||||
* @param {Object} entity - single entity instance
|
||||
* @returns {Promise<integer>} number of affected rows
|
||||
*/
|
||||
async update(entity, whereAttributes?, trx?) {
|
||||
const entityDto = cloneDeep(entity);
|
||||
const identityClause = {};
|
||||
|
||||
if (Array.isArray(this.idColumn)) {
|
||||
this.idColumn.forEach(
|
||||
(idColumn) => (identityClause[idColumn] = entityDto[idColumn]),
|
||||
);
|
||||
} else {
|
||||
identityClause[this.idColumn] = entityDto[this.idColumn];
|
||||
}
|
||||
const whereConditions = whereAttributes || identityClause;
|
||||
const modifiedEntitiesCount = await this.model
|
||||
.query(trx)
|
||||
.where(whereConditions)
|
||||
.update(entityDto);
|
||||
|
||||
if (modifiedEntitiesCount === 0) {
|
||||
throw new ModelEntityNotFound(entityDto[this.idColumn]);
|
||||
}
|
||||
return modifiedEntitiesCount;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {Object} attributeValues - values to filter deleted entities by
|
||||
* @param {Object} [trx]
|
||||
* @returns {Promise<integer>} Query builder. After promise is resolved, returns count of deleted rows
|
||||
*/
|
||||
deleteBy(attributeValues, trx?) {
|
||||
return this.model.query(trx).delete().where(attributeValues);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string || number} id - value of id column of the entity
|
||||
* @returns {Promise<integer>} Query builder. After promise is resolved, returns count of deleted rows
|
||||
*/
|
||||
deleteById(id: number | string, trx?) {
|
||||
return this.deleteBy(
|
||||
{
|
||||
[this.idColumn]: id,
|
||||
},
|
||||
trx,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the given entries in the array on the specific field.
|
||||
* @param {string} field -
|
||||
* @param {number|string} values -
|
||||
*/
|
||||
deleteWhereIn(field: string, values: (string | number)[], trx) {
|
||||
return this.model.query(trx).whereIn(field, values).delete();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string|number[]} values
|
||||
*/
|
||||
deleteWhereIdIn(values: (string | number)[], trx?) {
|
||||
return this.deleteWhereIn(this.idColumn, values, trx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Arbitrary relation graphs can be upserted (insert + update + delete)
|
||||
* using the upsertGraph method.
|
||||
* @param graph
|
||||
* @param options
|
||||
*/
|
||||
upsertGraph(graph, options) {
|
||||
// Keep the input grpah immutable
|
||||
const graphCloned = cloneDeep(graph);
|
||||
return this.model.query().upsertGraph(graphCloned, options);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {object} whereAttributes
|
||||
* @param {string} field
|
||||
* @param amount
|
||||
*/
|
||||
changeNumber(whereAttributes, field: string, amount: number, trx) {
|
||||
const changeMethod = amount > 0 ? 'increment' : 'decrement';
|
||||
|
||||
return this.model
|
||||
.query(trx)
|
||||
.where(whereAttributes)
|
||||
[changeMethod](field, Math.abs(amount));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
// import { CachableRepository } from './CachableRepository';
|
||||
import { EntityRepository } from './EntityRepository';
|
||||
|
||||
export class TenantRepository extends EntityRepository {
|
||||
|
||||
}
|
||||
2
packages/server/src/common/types/Constructor.ts
Normal file
2
packages/server/src/common/types/Constructor.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export type Constructor = new (...args: any[]) => {};
|
||||
export type GConstructor<T> = new (...args: any[]) => T;
|
||||
3
packages/server/src/common/types/Date.ts
Normal file
3
packages/server/src/common/types/Date.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import * as moment from 'moment';
|
||||
|
||||
export type DateInput = moment.MomentInput;
|
||||
4
packages/server/src/common/types/Discount.ts
Normal file
4
packages/server/src/common/types/Discount.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export enum DiscountType {
|
||||
Percentage = 'percentage',
|
||||
Amount = 'amount',
|
||||
}
|
||||
16
packages/server/src/common/types/Features.ts
Normal file
16
packages/server/src/common/types/Features.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
export enum Features {
|
||||
WAREHOUSES = 'warehouses',
|
||||
BRANCHES = 'branches',
|
||||
BankSyncing = 'BankSyncing',
|
||||
}
|
||||
|
||||
export interface IFeatureAllItem {
|
||||
name: string;
|
||||
isAccessible: boolean;
|
||||
defaultAccessible: boolean;
|
||||
}
|
||||
|
||||
export interface IFeatureConfiugration {
|
||||
name: string;
|
||||
defaultValue?: boolean;
|
||||
}
|
||||
Reference in New Issue
Block a user