mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-18 13:50:31 +00:00
Compare commits
14 Commits
fix-gettin
...
v0.19.14
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2cfa9123b8 | ||
|
|
bb9614aafb | ||
|
|
302564a56e | ||
|
|
dcfc231d4d | ||
|
|
64080ed678 | ||
|
|
263935d91e | ||
|
|
7f5ffb8da1 | ||
|
|
f07d25edbe | ||
|
|
7c07d6b5ff | ||
|
|
e433f4ad68 | ||
|
|
a79b9caff6 | ||
|
|
2227cead66 | ||
|
|
410c4ea3e2 | ||
|
|
ee2d8d3065 |
@@ -89,3 +89,7 @@ S3_ACCESS_KEY_ID=
|
|||||||
S3_SECRET_ACCESS_KEY=
|
S3_SECRET_ACCESS_KEY=
|
||||||
S3_ENDPOINT=
|
S3_ENDPOINT=
|
||||||
S3_BUCKET=
|
S3_BUCKET=
|
||||||
|
|
||||||
|
# PostHog
|
||||||
|
POSTHOG_API_KEY=
|
||||||
|
POSTHOG_HOST=
|
||||||
@@ -99,6 +99,7 @@
|
|||||||
"objection-unique": "^1.2.2",
|
"objection-unique": "^1.2.2",
|
||||||
"plaid": "^10.3.0",
|
"plaid": "^10.3.0",
|
||||||
"pluralize": "^8.0.0",
|
"pluralize": "^8.0.0",
|
||||||
|
"posthog-node": "^4.2.0",
|
||||||
"pug": "^3.0.2",
|
"pug": "^3.0.2",
|
||||||
"puppeteer": "^10.2.0",
|
"puppeteer": "^10.2.0",
|
||||||
"qim": "0.0.52",
|
"qim": "0.0.52",
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import { Container } from 'typedi';
|
import { Container } from 'typedi';
|
||||||
import { Request, Response, NextFunction } from 'express';
|
import { Request, Response, NextFunction } from 'express';
|
||||||
|
|
||||||
|
const SupportedMethods = ['POST', 'PUT'];
|
||||||
|
|
||||||
export default (subscriptionSlug = 'main') =>
|
export default (subscriptionSlug = 'main') =>
|
||||||
async (req: Request, res: Response, next: NextFunction) => {
|
async (req: Request, res: Response, next: NextFunction) => {
|
||||||
const { tenant, tenantId } = req;
|
const { tenant, tenantId } = req;
|
||||||
@@ -19,8 +21,10 @@ export default (subscriptionSlug = 'main') =>
|
|||||||
errors: [{ type: 'TENANT.HAS.NO.SUBSCRIPTION' }],
|
errors: [{ type: 'TENANT.HAS.NO.SUBSCRIPTION' }],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// Validate in case the subscription is inactive.
|
const isMethodSupported = SupportedMethods.includes(req.method);
|
||||||
else if (subscription.inactive()) {
|
const isSubscriptionInactive = subscription.inactive();
|
||||||
|
|
||||||
|
if (isMethodSupported && isSubscriptionInactive) {
|
||||||
return res.boom.badRequest(null, {
|
return res.boom.badRequest(null, {
|
||||||
errors: [{ type: 'ORGANIZATION.SUBSCRIPTION.INACTIVE' }],
|
errors: [{ type: 'ORGANIZATION.SUBSCRIPTION.INACTIVE' }],
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -253,4 +253,12 @@ module.exports = {
|
|||||||
enable: parseBoolean(process.env.ONE_CLICK_DEMO_ACCOUNTS, false),
|
enable: parseBoolean(process.env.ONE_CLICK_DEMO_ACCOUNTS, false),
|
||||||
demoUrl: process.env.ONE_CLICK_DEMO_ACCOUNTS_URL || '',
|
demoUrl: process.env.ONE_CLICK_DEMO_ACCOUNTS_URL || '',
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PostHog
|
||||||
|
*/
|
||||||
|
posthog: {
|
||||||
|
apiKey: process.env.POSTHOG_API_KEY,
|
||||||
|
host: process.env.POSTHOG_HOST
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
43
packages/server/src/constants/event-tracker.ts
Normal file
43
packages/server/src/constants/event-tracker.ts
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
export const SALE_INVOICE_CREATED = 'Sale invoice created';
|
||||||
|
export const SALE_INVOICE_EDITED = 'Sale invoice d';
|
||||||
|
export const SALE_INVOICE_DELETED = 'Sale invoice deleted';
|
||||||
|
export const SALE_INVOICE_MAIL_DELIVERED = 'Sale invoice mail delivered';
|
||||||
|
|
||||||
|
export const SALE_ESTIMATE_CREATED = 'Sale estimate created';
|
||||||
|
export const SALE_ESTIMATE_EDITED = 'Sale estimate edited';
|
||||||
|
export const SALE_ESTIMATE_DELETED = 'Sale estimate deleted';
|
||||||
|
|
||||||
|
export const PAYMENT_RECEIVED_CREATED = 'Payment received created';
|
||||||
|
export const PAYMENT_RECEIVED_EDITED = 'payment received edited';
|
||||||
|
export const PAYMENT_RECEIVED_DELETED = 'Payment received deleted';
|
||||||
|
|
||||||
|
export const BILL_CREATED = 'Bill created';
|
||||||
|
export const BILL_EDITED = 'Bill edited';
|
||||||
|
export const BILL_DELETED = 'Bill deleted';
|
||||||
|
|
||||||
|
export const PAYMENT_MADE_CREATED = 'Payment made created';
|
||||||
|
export const PAYMENT_MADE_EDITED = 'Payment made edited';
|
||||||
|
export const PAYMENT_MADE_DELETED = 'Payment made deleted';
|
||||||
|
|
||||||
|
export const EXPENSE_CREATED = 'Expense created';
|
||||||
|
export const EXPENSE_EDITED = 'Expense edited';
|
||||||
|
export const EXPENSE_DELETED = 'Expense deleted';
|
||||||
|
|
||||||
|
export const ACCOUNT_CREATED = 'Account created';
|
||||||
|
export const ACCOUNT_EDITED = 'Account Edited';
|
||||||
|
export const ACCOUNT_DELETED = 'Account deleted';
|
||||||
|
|
||||||
|
export const ITEM_EVENT_CREATED = 'Item created';
|
||||||
|
export const ITEM_EVENT_EDITED = 'Item edited';
|
||||||
|
export const ITEM_EVENT_DELETED = 'Item deleted';
|
||||||
|
|
||||||
|
export const AUTH_SIGNED_UP = 'Auth Signed-up';
|
||||||
|
export const AUTH_RESET_PASSWORD = 'Auth reset password';
|
||||||
|
|
||||||
|
export const ACCOUNT_GROUP = 'Account';
|
||||||
|
export const ITEM_GROUP = 'Item';
|
||||||
|
export const AUTH_GROUP = 'Auth';
|
||||||
|
export const SALE_GROUP = 'Sale';
|
||||||
|
export const PAYMENT_GROUP = 'Payment';
|
||||||
|
export const BILL_GROUP = 'Bill';
|
||||||
|
export const EXPENSE_GROUP = 'Expense';
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
import { Knex } from 'knex';
|
import { Knex } from 'knex';
|
||||||
import { IDynamicListFilter, IItemEntry, IVendorCredit } from '@/interfaces';
|
import { IDynamicListFilter, IItemEntry } from '@/interfaces';
|
||||||
import { ILedgerEntry } from './Ledger';
|
import { ILedgerEntry } from './Ledger';
|
||||||
import { AttachmentLinkDTO } from './Attachments';
|
import { AttachmentLinkDTO } from './Attachments';
|
||||||
|
|
||||||
export interface ICreditNoteEntryNewDTO {
|
export interface ICreditNoteEntryNewDTO {
|
||||||
index: number;
|
index?: number;
|
||||||
itemId: number;
|
itemId: number;
|
||||||
rate: number;
|
rate: number;
|
||||||
quantity: number;
|
quantity: number;
|
||||||
@@ -22,7 +22,7 @@ export interface ICreditNoteNewDTO {
|
|||||||
entries: ICreditNoteEntryNewDTO[];
|
entries: ICreditNoteEntryNewDTO[];
|
||||||
branchId?: number;
|
branchId?: number;
|
||||||
warehouseId?: number;
|
warehouseId?: number;
|
||||||
attachments?: AttachmentLinkDTO[]
|
attachments?: AttachmentLinkDTO[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ICreditNoteEditDTO {
|
export interface ICreditNoteEditDTO {
|
||||||
@@ -35,7 +35,7 @@ export interface ICreditNoteEditDTO {
|
|||||||
entries: ICreditNoteEntryNewDTO[];
|
entries: ICreditNoteEntryNewDTO[];
|
||||||
branchId?: number;
|
branchId?: number;
|
||||||
warehouseId?: number;
|
warehouseId?: number;
|
||||||
attachments?: AttachmentLinkDTO[]
|
attachments?: AttachmentLinkDTO[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ICreditNoteEntry extends IItemEntry {}
|
export interface ICreditNoteEntry extends IItemEntry {}
|
||||||
@@ -61,7 +61,7 @@ export interface ICreditNote {
|
|||||||
localAmount?: number;
|
localAmount?: number;
|
||||||
branchId?: number;
|
branchId?: number;
|
||||||
warehouseId: number;
|
warehouseId: number;
|
||||||
createdAt?: Date,
|
createdAt?: Date;
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum CreditNoteAction {
|
export enum CreditNoteAction {
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ export interface IItemEntry {
|
|||||||
|
|
||||||
export interface IItemEntryDTO {
|
export interface IItemEntryDTO {
|
||||||
id?: number;
|
id?: number;
|
||||||
|
index?: number;
|
||||||
itemId: number;
|
itemId: number;
|
||||||
landedCost?: boolean;
|
landedCost?: boolean;
|
||||||
warehouseId?: number;
|
warehouseId?: number;
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ export interface IPaymentReceivedEntry {
|
|||||||
|
|
||||||
export interface IPaymentReceivedEntryDTO {
|
export interface IPaymentReceivedEntryDTO {
|
||||||
id?: number;
|
id?: number;
|
||||||
index: number;
|
index?: number;
|
||||||
paymentReceiveId?: number;
|
paymentReceiveId?: number;
|
||||||
invoiceId: number;
|
invoiceId: number;
|
||||||
paymentAmount: number;
|
paymentAmount: number;
|
||||||
@@ -74,6 +74,7 @@ export interface IPaymentReceivedEntryDTO {
|
|||||||
|
|
||||||
export interface IPaymentsReceivedFilter extends IDynamicListFilterDTO {
|
export interface IPaymentsReceivedFilter extends IDynamicListFilterDTO {
|
||||||
stringifiedFilterRoles?: string;
|
stringifiedFilterRoles?: string;
|
||||||
|
filterQuery?: (trx: Knex.Transaction) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IPaymentReceivePageEntry {
|
export interface IPaymentReceivePageEntry {
|
||||||
|
|||||||
@@ -118,6 +118,7 @@ import { LoopsEventsSubscriber } from '@/services/Loops/LoopsEventsSubscriber';
|
|||||||
import { DeleteUncategorizedTransactionsOnAccountDeleting } from '@/services/Banking/BankAccounts/events/DeleteUncategorizedTransactionsOnAccountDeleting';
|
import { DeleteUncategorizedTransactionsOnAccountDeleting } from '@/services/Banking/BankAccounts/events/DeleteUncategorizedTransactionsOnAccountDeleting';
|
||||||
import { SeedInitialDemoAccountDataOnOrgBuild } from '@/services/OneClickDemo/events/SeedInitialDemoAccountData';
|
import { SeedInitialDemoAccountDataOnOrgBuild } from '@/services/OneClickDemo/events/SeedInitialDemoAccountData';
|
||||||
import { TriggerInvalidateCacheOnSubscriptionChange } from '@/services/Subscription/events/TriggerInvalidateCacheOnSubscriptionChange';
|
import { TriggerInvalidateCacheOnSubscriptionChange } from '@/services/Subscription/events/TriggerInvalidateCacheOnSubscriptionChange';
|
||||||
|
import { EventsTrackerListeners } from '@/services/EventsTracker/events/events';
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
return new EventPublisher();
|
return new EventPublisher();
|
||||||
@@ -289,5 +290,7 @@ export const susbcribers = () => {
|
|||||||
|
|
||||||
// Demo Account
|
// Demo Account
|
||||||
SeedInitialDemoAccountDataOnOrgBuild,
|
SeedInitialDemoAccountDataOnOrgBuild,
|
||||||
|
|
||||||
|
...EventsTrackerListeners
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ export default {
|
|||||||
sortField: 'bill_date',
|
sortField: 'bill_date',
|
||||||
},
|
},
|
||||||
exportable: true,
|
exportable: true,
|
||||||
|
exportFlattenOn: 'entries',
|
||||||
|
|
||||||
importable: true,
|
importable: true,
|
||||||
importAggregator: 'group',
|
importAggregator: 'group',
|
||||||
importAggregateOn: 'entries',
|
importAggregateOn: 'entries',
|
||||||
@@ -77,7 +79,7 @@ export default {
|
|||||||
paymentDate: {
|
paymentDate: {
|
||||||
name: 'bill_payment.field.payment_date',
|
name: 'bill_payment.field.payment_date',
|
||||||
type: 'date',
|
type: 'date',
|
||||||
accessor: 'formattedPaymentDate'
|
accessor: 'formattedPaymentDate',
|
||||||
},
|
},
|
||||||
paymentNumber: {
|
paymentNumber: {
|
||||||
name: 'bill_payment.field.payment_number',
|
name: 'bill_payment.field.payment_number',
|
||||||
@@ -111,6 +113,34 @@ export default {
|
|||||||
name: 'bill_payment.field.reference',
|
name: 'bill_payment.field.reference',
|
||||||
type: 'text',
|
type: 'text',
|
||||||
},
|
},
|
||||||
|
entries: {
|
||||||
|
name: 'Entries',
|
||||||
|
accessor: 'entries',
|
||||||
|
type: 'collection',
|
||||||
|
collectionOf: 'object',
|
||||||
|
columns: {
|
||||||
|
date: {
|
||||||
|
name: 'Bill date',
|
||||||
|
accessor: 'bill.formattedBillDate',
|
||||||
|
},
|
||||||
|
billNo: {
|
||||||
|
name: 'Bill No.',
|
||||||
|
accessor: 'bill.billNo',
|
||||||
|
},
|
||||||
|
billRefNo: {
|
||||||
|
name: 'Bill Reference No.',
|
||||||
|
accessor: 'bill.referenceNo',
|
||||||
|
},
|
||||||
|
billAmount: {
|
||||||
|
name: 'Bill Amount',
|
||||||
|
accessor: 'bill.totalFormatted',
|
||||||
|
},
|
||||||
|
paidAmount: {
|
||||||
|
name: 'Paid Amount',
|
||||||
|
accessor: 'paymentAmountFormatted',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
fields2: {
|
fields2: {
|
||||||
vendorId: {
|
vendorId: {
|
||||||
|
|||||||
@@ -41,17 +41,17 @@ export default {
|
|||||||
fieldType: 'boolean',
|
fieldType: 'boolean',
|
||||||
},
|
},
|
||||||
sell_price: {
|
sell_price: {
|
||||||
name: 'item.field.cost_price',
|
name: 'item.field.sell_price',
|
||||||
column: 'sell_price',
|
column: 'sell_price',
|
||||||
fieldType: 'number',
|
fieldType: 'number',
|
||||||
},
|
},
|
||||||
cost_price: {
|
cost_price: {
|
||||||
name: 'item.field.cost_account',
|
name: 'item.field.cost_price',
|
||||||
column: 'cost_price',
|
column: 'cost_price',
|
||||||
fieldType: 'number',
|
fieldType: 'number',
|
||||||
},
|
},
|
||||||
cost_account: {
|
cost_account: {
|
||||||
name: 'item.field.sell_account',
|
name: 'item.field.cost_account',
|
||||||
column: 'cost_account_id',
|
column: 'cost_account_id',
|
||||||
fieldType: 'relation',
|
fieldType: 'relation',
|
||||||
|
|
||||||
@@ -62,7 +62,7 @@ export default {
|
|||||||
relationEntityKey: 'slug',
|
relationEntityKey: 'slug',
|
||||||
},
|
},
|
||||||
sell_account: {
|
sell_account: {
|
||||||
name: 'item.field.sell_description',
|
name: 'item.field.sell_account',
|
||||||
column: 'sell_account_id',
|
column: 'sell_account_id',
|
||||||
fieldType: 'relation',
|
fieldType: 'relation',
|
||||||
|
|
||||||
@@ -155,24 +155,24 @@ export default {
|
|||||||
printable: false,
|
printable: false,
|
||||||
},
|
},
|
||||||
sellPrice: {
|
sellPrice: {
|
||||||
name: 'item.field.cost_price',
|
name: 'item.field.sell_price',
|
||||||
type: 'number',
|
type: 'number',
|
||||||
exportable: true,
|
exportable: true,
|
||||||
},
|
},
|
||||||
costPrice: {
|
costPrice: {
|
||||||
name: 'item.field.cost_account',
|
name: 'item.field.cost_price',
|
||||||
type: 'number',
|
type: 'number',
|
||||||
exportable: true,
|
exportable: true,
|
||||||
},
|
},
|
||||||
costAccount: {
|
costAccount: {
|
||||||
name: 'item.field.sell_account',
|
name: 'item.field.cost_account',
|
||||||
type: 'text',
|
type: 'text',
|
||||||
accessor: 'costAccount.name',
|
accessor: 'costAccount.name',
|
||||||
exportable: true,
|
exportable: true,
|
||||||
printable: false,
|
printable: false,
|
||||||
},
|
},
|
||||||
sellAccount: {
|
sellAccount: {
|
||||||
name: 'item.field.sell_description',
|
name: 'item.field.sell_account',
|
||||||
type: 'text',
|
type: 'text',
|
||||||
accessor: 'sellAccount.name',
|
accessor: 'sellAccount.name',
|
||||||
exportable: true,
|
exportable: true,
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
export default {
|
export default {
|
||||||
importable: true,
|
importable: true,
|
||||||
|
|
||||||
exportable: true,
|
exportable: true,
|
||||||
|
exportFlattenOn: 'entries',
|
||||||
|
|
||||||
importAggregator: 'group',
|
importAggregator: 'group',
|
||||||
importAggregateOn: 'entries',
|
importAggregateOn: 'entries',
|
||||||
importAggregateBy: 'paymentReceiveNo',
|
importAggregateBy: 'paymentReceiveNo',
|
||||||
@@ -72,7 +75,7 @@ export default {
|
|||||||
amount: {
|
amount: {
|
||||||
name: 'payment_receive.field.amount',
|
name: 'payment_receive.field.amount',
|
||||||
type: 'number',
|
type: 'number',
|
||||||
accessor: 'formattedAmount'
|
accessor: 'formattedAmount',
|
||||||
},
|
},
|
||||||
referenceNo: {
|
referenceNo: {
|
||||||
name: 'payment_receive.field.reference_no',
|
name: 'payment_receive.field.reference_no',
|
||||||
@@ -92,6 +95,34 @@ export default {
|
|||||||
type: 'text',
|
type: 'text',
|
||||||
printable: false,
|
printable: false,
|
||||||
},
|
},
|
||||||
|
entries: {
|
||||||
|
name: 'Entries',
|
||||||
|
accessor: 'entries',
|
||||||
|
type: 'collection',
|
||||||
|
collectionOf: 'object',
|
||||||
|
columns: {
|
||||||
|
date: {
|
||||||
|
name: 'Invoice date',
|
||||||
|
accessor: 'invoice.invoiceDateFormatted',
|
||||||
|
},
|
||||||
|
invoiceNo: {
|
||||||
|
name: 'Invoice No.',
|
||||||
|
accessor: 'invoice.invoiceNo',
|
||||||
|
},
|
||||||
|
invoiceRefNo: {
|
||||||
|
name: 'Invoice Reference No.',
|
||||||
|
accessor: 'invoice.referenceNo',
|
||||||
|
},
|
||||||
|
invoiceAmount: {
|
||||||
|
name: 'Invoice Amount',
|
||||||
|
accessor: 'invoice.totalFormatted',
|
||||||
|
},
|
||||||
|
paidAmount: {
|
||||||
|
name: 'Paid Amount',
|
||||||
|
accessor: 'paymentAmountFormatted',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
created_at: {
|
created_at: {
|
||||||
name: 'payment_receive.field.created_at',
|
name: 'payment_receive.field.created_at',
|
||||||
type: 'date',
|
type: 'date',
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ export default {
|
|||||||
importAggregateBy: 'estimateNumber',
|
importAggregateBy: 'estimateNumber',
|
||||||
|
|
||||||
print: {
|
print: {
|
||||||
pageTitle: 'Sale Estimates'
|
pageTitle: 'Sale Estimates',
|
||||||
},
|
},
|
||||||
|
|
||||||
fields: {
|
fields: {
|
||||||
@@ -142,6 +142,7 @@ export default {
|
|||||||
delivered: {
|
delivered: {
|
||||||
name: 'Delivered',
|
name: 'Delivered',
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
|
accessor: 'isDelivered',
|
||||||
exportable: true,
|
exportable: true,
|
||||||
printable: false,
|
printable: false,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -155,6 +155,7 @@ export default {
|
|||||||
name: 'invoice.field.delivered',
|
name: 'invoice.field.delivered',
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
printable: false,
|
printable: false,
|
||||||
|
accessor: 'isDelivered',
|
||||||
},
|
},
|
||||||
entries: {
|
entries: {
|
||||||
name: 'Entries',
|
name: 'Entries',
|
||||||
|
|||||||
@@ -5,11 +5,17 @@ import * as R from 'ramda';
|
|||||||
import { ServiceError } from '@/exceptions';
|
import { ServiceError } from '@/exceptions';
|
||||||
import HasTenancyService from '@/services/Tenancy/TenancyService';
|
import HasTenancyService from '@/services/Tenancy/TenancyService';
|
||||||
import { ERRORS } from './constants';
|
import { ERRORS } from './constants';
|
||||||
import { ICreditNote, ICreditNoteEditDTO, ICreditNoteNewDTO } from '@/interfaces';
|
import {
|
||||||
|
ICreditNote,
|
||||||
|
ICreditNoteEditDTO,
|
||||||
|
ICreditNoteEntryNewDTO,
|
||||||
|
ICreditNoteNewDTO,
|
||||||
|
} from '@/interfaces';
|
||||||
import ItemsEntriesService from '@/services/Items/ItemsEntriesService';
|
import ItemsEntriesService from '@/services/Items/ItemsEntriesService';
|
||||||
import AutoIncrementOrdersService from '@/services/Sales/AutoIncrementOrdersService';
|
import AutoIncrementOrdersService from '@/services/Sales/AutoIncrementOrdersService';
|
||||||
import { WarehouseTransactionDTOTransform } from '@/services/Warehouses/Integrations/WarehouseTransactionDTOTransform';
|
import { WarehouseTransactionDTOTransform } from '@/services/Warehouses/Integrations/WarehouseTransactionDTOTransform';
|
||||||
import { BranchTransactionDTOTransform } from '@/services/Branches/Integrations/BranchTransactionDTOTransform';
|
import { BranchTransactionDTOTransform } from '@/services/Branches/Integrations/BranchTransactionDTOTransform';
|
||||||
|
import { assocItemEntriesDefaultIndex } from '../Items/utils';
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export default class BaseCreditNotes {
|
export default class BaseCreditNotes {
|
||||||
@@ -43,10 +49,17 @@ export default class BaseCreditNotes {
|
|||||||
const amount = this.itemsEntriesService.getTotalItemsEntries(
|
const amount = this.itemsEntriesService.getTotalItemsEntries(
|
||||||
creditNoteDTO.entries
|
creditNoteDTO.entries
|
||||||
);
|
);
|
||||||
const entries = creditNoteDTO.entries.map((entry) => ({
|
const entries = R.compose(
|
||||||
...entry,
|
// Associate the default index to each item entry.
|
||||||
referenceType: 'CreditNote',
|
assocItemEntriesDefaultIndex,
|
||||||
}));
|
|
||||||
|
// Associate the reference type to credit note entries.
|
||||||
|
R.map((entry: ICreditNoteEntryNewDTO) => ({
|
||||||
|
...entry,
|
||||||
|
referenceType: 'CreditNote',
|
||||||
|
}))
|
||||||
|
)(creditNoteDTO.entries);
|
||||||
|
|
||||||
// Retreive the next credit note number.
|
// Retreive the next credit note number.
|
||||||
const autoNextNumber = this.getNextCreditNumber(tenantId);
|
const autoNextNumber = this.getNextCreditNumber(tenantId);
|
||||||
|
|
||||||
|
|||||||
24
packages/server/src/services/EventsTracker/PostHog.ts
Normal file
24
packages/server/src/services/EventsTracker/PostHog.ts
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import { PostHog } from 'posthog-node';
|
||||||
|
import { Service } from 'typedi';
|
||||||
|
import { EventMessage } from 'posthog-node/src/types';
|
||||||
|
import config from '@/config';
|
||||||
|
|
||||||
|
@Service()
|
||||||
|
export class PosthogService {
|
||||||
|
public posthog: PostHog;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
if (config.posthog.apiKey && config.posthog.host) {
|
||||||
|
this.posthog = new PostHog(config.posthog.apiKey, {
|
||||||
|
host: config.posthog.host,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public trackEvent(event: EventMessage) {
|
||||||
|
// Cannot continue if the Posthog not configured.
|
||||||
|
if (!this.posthog) return;
|
||||||
|
|
||||||
|
this.posthog.capture(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
import { Inject, Service } from 'typedi';
|
||||||
|
import { EventSubscriber } from '@/lib/EventPublisher/EventPublisher';
|
||||||
|
import {
|
||||||
|
IAccountEventCreatedPayload,
|
||||||
|
IAccountEventEditedPayload,
|
||||||
|
IAccountEventDeletedPayload,
|
||||||
|
} from '@/interfaces';
|
||||||
|
import { PosthogService } from '../PostHog';
|
||||||
|
import events from '@/subscribers/events';
|
||||||
|
import {
|
||||||
|
ACCOUNT_CREATED,
|
||||||
|
ACCOUNT_EDITED,
|
||||||
|
ACCOUNT_DELETED,
|
||||||
|
} from '@/constants/event-tracker';
|
||||||
|
|
||||||
|
@Service()
|
||||||
|
export class AccountEventsTracker extends EventSubscriber {
|
||||||
|
@Inject()
|
||||||
|
private posthog: PosthogService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor method.
|
||||||
|
*/
|
||||||
|
public attach(bus) {
|
||||||
|
bus.subscribe(
|
||||||
|
events.accounts.onCreated,
|
||||||
|
this.handleTrackAccountCreatedEvent
|
||||||
|
);
|
||||||
|
bus.subscribe(events.accounts.onEdited, this.handleTrackEditedAccountEvent);
|
||||||
|
bus.subscribe(
|
||||||
|
events.accounts.onDeleted,
|
||||||
|
this.handleTrackDeletedAccountEvent
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleTrackAccountCreatedEvent = ({
|
||||||
|
tenantId,
|
||||||
|
}: IAccountEventCreatedPayload) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: `tenant-${tenantId}`,
|
||||||
|
event: ACCOUNT_CREATED,
|
||||||
|
properties: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
private handleTrackEditedAccountEvent = ({
|
||||||
|
tenantId,
|
||||||
|
}: IAccountEventEditedPayload) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: `tenant-${tenantId}`,
|
||||||
|
event: ACCOUNT_EDITED,
|
||||||
|
properties: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
private handleTrackDeletedAccountEvent = ({
|
||||||
|
tenantId,
|
||||||
|
}: IAccountEventDeletedPayload) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: `tenant-${tenantId}`,
|
||||||
|
event: ACCOUNT_DELETED,
|
||||||
|
properties: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
import { Inject, Service } from 'typedi';
|
||||||
|
import { EventSubscriber } from '@/lib/EventPublisher/EventPublisher';
|
||||||
|
import { IAuthSignedUpEventPayload } from '@/interfaces';
|
||||||
|
import { PosthogService } from '../PostHog';
|
||||||
|
import { AUTH_SIGNED_UP } from '@/constants/event-tracker';
|
||||||
|
import events from '@/subscribers/events';
|
||||||
|
|
||||||
|
@Service()
|
||||||
|
export class AuthenticationEventsTracker extends EventSubscriber {
|
||||||
|
@Inject()
|
||||||
|
private posthog: PosthogService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor method.
|
||||||
|
*/
|
||||||
|
public attach(bus) {
|
||||||
|
bus.subscribe(events.auth.signUp, this.handleTrackSignUpEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleTrackSignUpEvent = ({
|
||||||
|
signupDTO,
|
||||||
|
user,
|
||||||
|
tenant,
|
||||||
|
}: IAuthSignedUpEventPayload) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: user.email,
|
||||||
|
event: AUTH_SIGNED_UP,
|
||||||
|
properties: {
|
||||||
|
firstName: user.firstName,
|
||||||
|
lastName: user.lastName,
|
||||||
|
email: user.email,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
import { Inject, Service } from 'typedi';
|
||||||
|
import { EventSubscriber } from '@/lib/EventPublisher/EventPublisher';
|
||||||
|
import {
|
||||||
|
IBillPaymentEventCreatedPayload,
|
||||||
|
IBillPaymentEventEditedPayload,
|
||||||
|
IBillPaymentEventDeletedPayload,
|
||||||
|
} from '@/interfaces';
|
||||||
|
import { PosthogService } from '../PostHog';
|
||||||
|
import events from '@/subscribers/events';
|
||||||
|
import {
|
||||||
|
BILL_CREATED,
|
||||||
|
BILL_EDITED,
|
||||||
|
BILL_DELETED,
|
||||||
|
} from '@/constants/event-tracker';
|
||||||
|
|
||||||
|
@Service()
|
||||||
|
export class BillEventsTracker extends EventSubscriber {
|
||||||
|
@Inject()
|
||||||
|
private posthog: PosthogService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor method.
|
||||||
|
*/
|
||||||
|
public attach(bus) {
|
||||||
|
bus.subscribe(events.bill.onCreated, this.handleTrackBillCreatedEvent);
|
||||||
|
bus.subscribe(events.bill.onEdited, this.handleTrackEditedBillEvent);
|
||||||
|
bus.subscribe(events.bill.onDeleted, this.handleTrackDeletedBillEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleTrackBillCreatedEvent = ({
|
||||||
|
tenantId,
|
||||||
|
}: IBillPaymentEventCreatedPayload) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: `tenant-${tenantId}`,
|
||||||
|
event: BILL_CREATED,
|
||||||
|
properties: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
private handleTrackEditedBillEvent = ({
|
||||||
|
tenantId,
|
||||||
|
}: IBillPaymentEventEditedPayload) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: `tenant-${tenantId}`,
|
||||||
|
event: BILL_EDITED,
|
||||||
|
properties: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
private handleTrackDeletedBillEvent = ({
|
||||||
|
tenantId,
|
||||||
|
}: IBillPaymentEventDeletedPayload) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: `tenant-${tenantId}`,
|
||||||
|
event: BILL_DELETED,
|
||||||
|
properties: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
import { Inject, Service } from 'typedi';
|
||||||
|
import { EventSubscriber } from '@/lib/EventPublisher/EventPublisher';
|
||||||
|
import {
|
||||||
|
IExpenseCreatedPayload,
|
||||||
|
IExpenseEventEditPayload,
|
||||||
|
IExpenseEventDeletePayload,
|
||||||
|
} from '@/interfaces';
|
||||||
|
import { PosthogService } from '../PostHog';
|
||||||
|
import events from '@/subscribers/events';
|
||||||
|
import {
|
||||||
|
EXPENSE_CREATED,
|
||||||
|
EXPENSE_EDITED,
|
||||||
|
EXPENSE_DELETED,
|
||||||
|
} from '@/constants/event-tracker';
|
||||||
|
|
||||||
|
@Service()
|
||||||
|
export class ExpenseEventsTracker extends EventSubscriber {
|
||||||
|
@Inject()
|
||||||
|
private posthog: PosthogService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor method.
|
||||||
|
*/
|
||||||
|
public attach(bus) {
|
||||||
|
bus.subscribe(
|
||||||
|
events.expenses.onCreated,
|
||||||
|
this.handleTrackExpenseCreatedEvent
|
||||||
|
);
|
||||||
|
bus.subscribe(events.expenses.onEdited, this.handleTrackEditedExpenseEvent);
|
||||||
|
bus.subscribe(
|
||||||
|
events.expenses.onDeleted,
|
||||||
|
this.handleTrackDeletedExpenseEvent
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleTrackExpenseCreatedEvent = ({
|
||||||
|
tenantId,
|
||||||
|
}: IExpenseCreatedPayload) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: `tenant-${tenantId}`,
|
||||||
|
event: EXPENSE_CREATED,
|
||||||
|
properties: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
private handleTrackEditedExpenseEvent = ({
|
||||||
|
tenantId,
|
||||||
|
}: IExpenseEventEditPayload) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: `tenant-${tenantId}`,
|
||||||
|
event: EXPENSE_EDITED,
|
||||||
|
properties: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
private handleTrackDeletedExpenseEvent = ({
|
||||||
|
tenantId,
|
||||||
|
}: IExpenseEventDeletePayload) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: `tenant-${tenantId}`,
|
||||||
|
event: EXPENSE_DELETED,
|
||||||
|
properties: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
import { Inject, Service } from 'typedi';
|
||||||
|
import { EventSubscriber } from '@/lib/EventPublisher/EventPublisher';
|
||||||
|
import {
|
||||||
|
IItemEventCreatedPayload,
|
||||||
|
IItemEventEditedPayload,
|
||||||
|
IItemEventDeletedPayload,
|
||||||
|
} from '@/interfaces';
|
||||||
|
import { PosthogService } from '../PostHog';
|
||||||
|
import events from '@/subscribers/events';
|
||||||
|
import {
|
||||||
|
ITEM_EVENT_CREATED,
|
||||||
|
ITEM_EVENT_EDITED,
|
||||||
|
ITEM_EVENT_DELETED,
|
||||||
|
} from '@/constants/event-tracker';
|
||||||
|
|
||||||
|
@Service()
|
||||||
|
export class ItemEventsTracker extends EventSubscriber {
|
||||||
|
@Inject()
|
||||||
|
private posthog: PosthogService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor method.
|
||||||
|
*/
|
||||||
|
public attach(bus) {
|
||||||
|
bus.subscribe(events.item.onCreated, this.handleTrackItemCreatedEvent);
|
||||||
|
bus.subscribe(events.item.onEdited, this.handleTrackEditedItemEvent);
|
||||||
|
bus.subscribe(events.item.onDeleted, this.handleTrackDeletedItemEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleTrackItemCreatedEvent = ({
|
||||||
|
tenantId,
|
||||||
|
}: IItemEventCreatedPayload) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: `tenant-${tenantId}`,
|
||||||
|
event: ITEM_EVENT_CREATED,
|
||||||
|
properties: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
private handleTrackEditedItemEvent = ({
|
||||||
|
tenantId,
|
||||||
|
}: IItemEventEditedPayload) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: `tenant-${tenantId}`,
|
||||||
|
event: ITEM_EVENT_EDITED,
|
||||||
|
properties: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
private handleTrackDeletedItemEvent = ({
|
||||||
|
tenantId,
|
||||||
|
}: IItemEventDeletedPayload) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: `tenant-${tenantId}`,
|
||||||
|
event: ITEM_EVENT_DELETED,
|
||||||
|
properties: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
import { Inject, Service } from 'typedi';
|
||||||
|
import { EventSubscriber } from '@/lib/EventPublisher/EventPublisher';
|
||||||
|
import {
|
||||||
|
IBillPaymentEventCreatedPayload,
|
||||||
|
IBillPaymentEditingPayload,
|
||||||
|
IBillPaymentEventDeletedPayload,
|
||||||
|
} from '@/interfaces';
|
||||||
|
import { PosthogService } from '../PostHog';
|
||||||
|
import events from '@/subscribers/events';
|
||||||
|
import {
|
||||||
|
PAYMENT_MADE_CREATED,
|
||||||
|
PAYMENT_MADE_EDITED,
|
||||||
|
PAYMENT_MADE_DELETED,
|
||||||
|
} from '@/constants/event-tracker';
|
||||||
|
|
||||||
|
@Service()
|
||||||
|
export class PaymentMadeEventsTracker extends EventSubscriber {
|
||||||
|
@Inject()
|
||||||
|
private posthog: PosthogService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor method.
|
||||||
|
*/
|
||||||
|
public attach(bus) {
|
||||||
|
bus.subscribe(
|
||||||
|
events.billPayment.onCreated,
|
||||||
|
this.handleTrackPaymentMadeCreatedEvent
|
||||||
|
);
|
||||||
|
bus.subscribe(
|
||||||
|
events.billPayment.onEdited,
|
||||||
|
this.handleTrackEditedPaymentMadeEvent
|
||||||
|
);
|
||||||
|
bus.subscribe(
|
||||||
|
events.billPayment.onDeleted,
|
||||||
|
this.handleTrackDeletedPaymentMadeEvent
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleTrackPaymentMadeCreatedEvent = ({
|
||||||
|
tenantId,
|
||||||
|
}: IBillPaymentEventCreatedPayload) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: `tenant-${tenantId}`,
|
||||||
|
event: PAYMENT_MADE_CREATED,
|
||||||
|
properties: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
private handleTrackEditedPaymentMadeEvent = ({
|
||||||
|
tenantId,
|
||||||
|
}: IBillPaymentEditingPayload) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: `tenant-${tenantId}`,
|
||||||
|
event: PAYMENT_MADE_EDITED,
|
||||||
|
properties: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
private handleTrackDeletedPaymentMadeEvent = ({
|
||||||
|
tenantId,
|
||||||
|
}: IBillPaymentEventDeletedPayload) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: `tenant-${tenantId}`,
|
||||||
|
event: PAYMENT_MADE_DELETED,
|
||||||
|
properties: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
import { Inject, Service } from 'typedi';
|
||||||
|
import { EventSubscriber } from '@/lib/EventPublisher/EventPublisher';
|
||||||
|
import {
|
||||||
|
IPaymentReceivedCreatedPayload,
|
||||||
|
IPaymentReceivedEditedPayload,
|
||||||
|
IPaymentReceivedDeletedPayload,
|
||||||
|
} from '@/interfaces';
|
||||||
|
import { PosthogService } from '../PostHog';
|
||||||
|
import events from '@/subscribers/events';
|
||||||
|
import {
|
||||||
|
PAYMENT_RECEIVED_CREATED,
|
||||||
|
PAYMENT_RECEIVED_EDITED,
|
||||||
|
PAYMENT_RECEIVED_DELETED,
|
||||||
|
} from '@/constants/event-tracker';
|
||||||
|
|
||||||
|
@Service()
|
||||||
|
export class PaymentReceivedEventsTracker extends EventSubscriber {
|
||||||
|
@Inject()
|
||||||
|
private posthog: PosthogService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor method.
|
||||||
|
*/
|
||||||
|
public attach(bus) {
|
||||||
|
bus.subscribe(
|
||||||
|
events.paymentReceive.onCreated,
|
||||||
|
this.handleTrackPaymentReceivedCreatedEvent
|
||||||
|
);
|
||||||
|
bus.subscribe(
|
||||||
|
events.paymentReceive.onEdited,
|
||||||
|
this.handleTrackEditedPaymentReceivedEvent
|
||||||
|
);
|
||||||
|
bus.subscribe(
|
||||||
|
events.paymentReceive.onDeleted,
|
||||||
|
this.handleTrackDeletedPaymentReceivedEvent
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleTrackPaymentReceivedCreatedEvent = ({
|
||||||
|
tenantId,
|
||||||
|
}: IPaymentReceivedCreatedPayload) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: `tenant-${tenantId}`,
|
||||||
|
event: PAYMENT_RECEIVED_CREATED,
|
||||||
|
properties: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
private handleTrackEditedPaymentReceivedEvent = ({
|
||||||
|
tenantId,
|
||||||
|
}: IPaymentReceivedEditedPayload) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: `tenant-${tenantId}`,
|
||||||
|
event: PAYMENT_RECEIVED_EDITED,
|
||||||
|
properties: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
private handleTrackDeletedPaymentReceivedEvent = ({
|
||||||
|
tenantId,
|
||||||
|
}: IPaymentReceivedDeletedPayload) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: `tenant-${tenantId}`,
|
||||||
|
event: PAYMENT_RECEIVED_DELETED,
|
||||||
|
properties: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
import { Inject, Service } from 'typedi';
|
||||||
|
import { EventSubscriber } from '@/lib/EventPublisher/EventPublisher';
|
||||||
|
import {
|
||||||
|
ISaleEstimateCreatedPayload,
|
||||||
|
ISaleEstimateEditedPayload,
|
||||||
|
ISaleEstimateDeletedPayload,
|
||||||
|
} from '@/interfaces';
|
||||||
|
import { PosthogService } from '../PostHog';
|
||||||
|
import events from '@/subscribers/events';
|
||||||
|
import {
|
||||||
|
SALE_ESTIMATE_CREATED,
|
||||||
|
SALE_ESTIMATE_EDITED,
|
||||||
|
SALE_ESTIMATE_DELETED,
|
||||||
|
} from '@/constants/event-tracker';
|
||||||
|
|
||||||
|
@Service()
|
||||||
|
export class SaleEstimateEventsTracker extends EventSubscriber {
|
||||||
|
@Inject()
|
||||||
|
private posthog: PosthogService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor method.
|
||||||
|
*/
|
||||||
|
public attach(bus) {
|
||||||
|
bus.subscribe(
|
||||||
|
events.saleEstimate.onCreated,
|
||||||
|
this.handleTrackEstimateCreatedEvent
|
||||||
|
);
|
||||||
|
bus.subscribe(
|
||||||
|
events.saleEstimate.onEdited,
|
||||||
|
this.handleTrackEditedEstimateEvent
|
||||||
|
);
|
||||||
|
bus.subscribe(
|
||||||
|
events.saleEstimate.onDeleted,
|
||||||
|
this.handleTrackDeletedEstimateEvent
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleTrackEstimateCreatedEvent = ({
|
||||||
|
tenantId,
|
||||||
|
}: ISaleEstimateCreatedPayload) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: `tenant-${tenantId}`,
|
||||||
|
event: SALE_ESTIMATE_CREATED,
|
||||||
|
properties: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
private handleTrackEditedEstimateEvent = ({
|
||||||
|
tenantId,
|
||||||
|
}: ISaleEstimateEditedPayload) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: `tenant-${tenantId}`,
|
||||||
|
event: SALE_ESTIMATE_EDITED,
|
||||||
|
properties: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
private handleTrackDeletedEstimateEvent = ({
|
||||||
|
tenantId,
|
||||||
|
}: ISaleEstimateDeletedPayload) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: `tenant-${tenantId}`,
|
||||||
|
event: SALE_ESTIMATE_DELETED,
|
||||||
|
properties: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
import { Inject, Service } from 'typedi';
|
||||||
|
import { EventSubscriber } from '@/lib/EventPublisher/EventPublisher';
|
||||||
|
import {
|
||||||
|
ISaleInvoiceCreatedPayload,
|
||||||
|
ISaleInvoiceEditedPayload,
|
||||||
|
} from '@/interfaces';
|
||||||
|
import { PosthogService } from '../PostHog';
|
||||||
|
import events from '@/subscribers/events';
|
||||||
|
import {
|
||||||
|
SALE_INVOICE_CREATED,
|
||||||
|
SALE_INVOICE_DELETED,
|
||||||
|
SALE_INVOICE_EDITED,
|
||||||
|
} from '@/constants/event-tracker';
|
||||||
|
|
||||||
|
@Service()
|
||||||
|
export class SaleInvoiceEventsTracker extends EventSubscriber {
|
||||||
|
@Inject()
|
||||||
|
private posthog: PosthogService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor method.
|
||||||
|
*/
|
||||||
|
public attach(bus) {
|
||||||
|
bus.subscribe(
|
||||||
|
events.saleInvoice.onCreated,
|
||||||
|
this.handleTrackInvoiceCreatedEvent
|
||||||
|
);
|
||||||
|
bus.subscribe(
|
||||||
|
events.saleInvoice.onEdited,
|
||||||
|
this.handleTrackEditedInvoiceEvent
|
||||||
|
);
|
||||||
|
bus.subscribe(
|
||||||
|
events.saleInvoice.onDeleted,
|
||||||
|
this.handleTrackDeletedInvoiceEvent
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleTrackInvoiceCreatedEvent = ({
|
||||||
|
tenantId,
|
||||||
|
}: ISaleInvoiceCreatedPayload) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: `tenant-${tenantId}`,
|
||||||
|
event: SALE_INVOICE_CREATED,
|
||||||
|
properties: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
private handleTrackEditedInvoiceEvent = ({
|
||||||
|
tenantId,
|
||||||
|
}: ISaleInvoiceEditedPayload) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: `tenant-${tenantId}`,
|
||||||
|
event: SALE_INVOICE_EDITED,
|
||||||
|
properties: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
private handleTrackDeletedInvoiceEvent = ({
|
||||||
|
tenantId,
|
||||||
|
}: ISaleInvoiceEditedPayload) => {
|
||||||
|
this.posthog.trackEvent({
|
||||||
|
distinctId: `tenant-${tenantId}`,
|
||||||
|
event: SALE_INVOICE_DELETED,
|
||||||
|
properties: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
21
packages/server/src/services/EventsTracker/events/events.ts
Normal file
21
packages/server/src/services/EventsTracker/events/events.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import { SaleInvoiceEventsTracker } from './SaleInvoicesEventsTracker';
|
||||||
|
import { SaleEstimateEventsTracker } from './SaleEstimateEventsTracker';
|
||||||
|
import { PaymentMadeEventsTracker } from './PaymentMadeEventsTracker';
|
||||||
|
import { PaymentReceivedEventsTracker } from './PaymentReceivedEventsTracker';
|
||||||
|
import { BillEventsTracker } from './BillEventsTracker';
|
||||||
|
import { ExpenseEventsTracker } from './ExpenseEventsTracker';
|
||||||
|
import { AccountEventsTracker } from './AccountEventsTracker';
|
||||||
|
import { AuthenticationEventsTracker } from './AuthenticationEventsTracker';
|
||||||
|
import { ItemEventsTracker } from './ItemEventsTracker';
|
||||||
|
|
||||||
|
export const EventsTrackerListeners = [
|
||||||
|
SaleInvoiceEventsTracker,
|
||||||
|
SaleEstimateEventsTracker,
|
||||||
|
PaymentMadeEventsTracker,
|
||||||
|
PaymentReceivedEventsTracker,
|
||||||
|
BillEventsTracker,
|
||||||
|
AccountEventsTracker,
|
||||||
|
ExpenseEventsTracker,
|
||||||
|
AuthenticationEventsTracker,
|
||||||
|
ItemEventsTracker
|
||||||
|
];
|
||||||
@@ -11,6 +11,7 @@ import {
|
|||||||
} from '@/interfaces';
|
} from '@/interfaces';
|
||||||
import { BranchTransactionDTOTransform } from '@/services/Branches/Integrations/BranchTransactionDTOTransform';
|
import { BranchTransactionDTOTransform } from '@/services/Branches/Integrations/BranchTransactionDTOTransform';
|
||||||
import { TenantMetadata } from '@/system/models';
|
import { TenantMetadata } from '@/system/models';
|
||||||
|
import { assocItemEntriesDefaultIndex } from '@/services/Items/utils';
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export class ExpenseDTOTransformer {
|
export class ExpenseDTOTransformer {
|
||||||
@@ -40,8 +41,8 @@ export class ExpenseDTOTransformer {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Mapping expense DTO to model.
|
* Mapping expense DTO to model.
|
||||||
* @param {IExpenseDTO} expenseDTO
|
* @param {IExpenseDTO} expenseDTO
|
||||||
* @param {ISystemUser} authorizedUser
|
* @param {ISystemUser} authorizedUser
|
||||||
* @return {IExpense}
|
* @return {IExpense}
|
||||||
*/
|
*/
|
||||||
private expenseDTOToModel(
|
private expenseDTOToModel(
|
||||||
@@ -52,9 +53,14 @@ export class ExpenseDTOTransformer {
|
|||||||
const landedCostAmount = this.getExpenseLandedCostAmount(expenseDTO);
|
const landedCostAmount = this.getExpenseLandedCostAmount(expenseDTO);
|
||||||
const totalAmount = this.getExpenseCategoriesTotal(expenseDTO.categories);
|
const totalAmount = this.getExpenseCategoriesTotal(expenseDTO.categories);
|
||||||
|
|
||||||
|
const categories = R.compose(
|
||||||
|
// Associate the default index to categories lines.
|
||||||
|
assocItemEntriesDefaultIndex
|
||||||
|
)(expenseDTO.categories || []);
|
||||||
|
|
||||||
const initialDTO = {
|
const initialDTO = {
|
||||||
categories: [],
|
|
||||||
...omit(expenseDTO, ['publish', 'attachments']),
|
...omit(expenseDTO, ['publish', 'attachments']),
|
||||||
|
categories,
|
||||||
totalAmount,
|
totalAmount,
|
||||||
landedCostAmount,
|
landedCostAmount,
|
||||||
paymentDate: moment(expenseDTO.paymentDate).toMySqlDateTime(),
|
paymentDate: moment(expenseDTO.paymentDate).toMySqlDateTime(),
|
||||||
|
|||||||
16
packages/server/src/services/Items/utils.ts
Normal file
16
packages/server/src/services/Items/utils.ts
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import { IItemEntry } from '@/interfaces';
|
||||||
|
import { isNull, isUndefined } from 'lodash';
|
||||||
|
|
||||||
|
export function assocItemEntriesDefaultIndex<T>(
|
||||||
|
entries: Array<T & { index?: number }>
|
||||||
|
): Array<T & { index: number }> {
|
||||||
|
return entries.map((entry, index) => {
|
||||||
|
return {
|
||||||
|
index:
|
||||||
|
isUndefined(entry.index) || isNull(entry.index)
|
||||||
|
? index + 1
|
||||||
|
: entry.index,
|
||||||
|
...entry,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -18,6 +18,8 @@ import { EventPublisher } from '@/lib/EventPublisher/EventPublisher';
|
|||||||
import { CommandManualJournalValidators } from './CommandManualJournalValidators';
|
import { CommandManualJournalValidators } from './CommandManualJournalValidators';
|
||||||
import { AutoIncrementManualJournal } from './AutoIncrementManualJournal';
|
import { AutoIncrementManualJournal } from './AutoIncrementManualJournal';
|
||||||
import { ManualJournalBranchesDTOTransformer } from '@/services/Branches/Integrations/ManualJournals/ManualJournalDTOTransformer';
|
import { ManualJournalBranchesDTOTransformer } from '@/services/Branches/Integrations/ManualJournals/ManualJournalDTOTransformer';
|
||||||
|
import { assocItemEntriesDefaultIndex } from '../Items/utils';
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export class CreateManualJournalService {
|
export class CreateManualJournalService {
|
||||||
@Inject()
|
@Inject()
|
||||||
@@ -58,16 +60,22 @@ export class CreateManualJournalService {
|
|||||||
// The manual or auto-increment journal number.
|
// The manual or auto-increment journal number.
|
||||||
const journalNumber = manualJournalDTO.journalNumber || autoNextNumber;
|
const journalNumber = manualJournalDTO.journalNumber || autoNextNumber;
|
||||||
|
|
||||||
|
const entries = R.compose(
|
||||||
|
// Associate the default index to each item entry.
|
||||||
|
assocItemEntriesDefaultIndex
|
||||||
|
)(manualJournalDTO.entries);
|
||||||
|
|
||||||
const initialDTO = {
|
const initialDTO = {
|
||||||
...omit(manualJournalDTO, ['publish', 'attachments']),
|
...omit(manualJournalDTO, ['publish', 'attachments']),
|
||||||
...(manualJournalDTO.publish
|
...(manualJournalDTO.publish
|
||||||
? { publishedAt: moment().toMySqlDateTime() }
|
? { publishedAt: moment().toMySqlDateTime() }
|
||||||
: {}),
|
: {}),
|
||||||
amount,
|
amount,
|
||||||
|
date,
|
||||||
currencyCode: manualJournalDTO.currencyCode || baseCurrency,
|
currencyCode: manualJournalDTO.currencyCode || baseCurrency,
|
||||||
exchangeRate: manualJournalDTO.exchangeRate || 1,
|
exchangeRate: manualJournalDTO.exchangeRate || 1,
|
||||||
date,
|
|
||||||
journalNumber,
|
journalNumber,
|
||||||
|
entries,
|
||||||
userId: authorizedUser.id,
|
userId: authorizedUser.id,
|
||||||
};
|
};
|
||||||
return R.compose(
|
return R.compose(
|
||||||
|
|||||||
@@ -14,12 +14,16 @@ export class BillPaymentExportable extends Exportable {
|
|||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
public exportable(tenantId: number, query: any) {
|
public exportable(tenantId: number, query: any) {
|
||||||
|
const filterQuery = (builder) => {
|
||||||
|
builder.withGraphFetched('entries.bill');
|
||||||
|
};
|
||||||
const parsedQuery = {
|
const parsedQuery = {
|
||||||
sortOrder: 'desc',
|
sortOrder: 'desc',
|
||||||
columnSortBy: 'created_at',
|
columnSortBy: 'created_at',
|
||||||
...query,
|
...query,
|
||||||
page: 1,
|
page: 1,
|
||||||
pageSize: EXPORT_SIZE_LIMIT,
|
pageSize: EXPORT_SIZE_LIMIT,
|
||||||
|
filterQuery
|
||||||
} as any;
|
} as any;
|
||||||
|
|
||||||
return this.billPaymentsApplication
|
return this.billPaymentsApplication
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ import * as R from 'ramda';
|
|||||||
import { omit, sumBy } from 'lodash';
|
import { omit, sumBy } from 'lodash';
|
||||||
import { IBillPayment, IBillPaymentDTO, IVendor } from '@/interfaces';
|
import { IBillPayment, IBillPaymentDTO, IVendor } from '@/interfaces';
|
||||||
import { BranchTransactionDTOTransform } from '@/services/Branches/Integrations/BranchTransactionDTOTransform';
|
import { BranchTransactionDTOTransform } from '@/services/Branches/Integrations/BranchTransactionDTOTransform';
|
||||||
|
import { assocItemEntriesDefaultIndex } from '@/services/Items/utils';
|
||||||
import { formatDateFields } from '@/utils';
|
import { formatDateFields } from '@/utils';
|
||||||
import HasTenancyService from '@/services/Tenancy/TenancyService';
|
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export class CommandBillPaymentDTOTransformer {
|
export class CommandBillPaymentDTOTransformer {
|
||||||
@@ -27,6 +27,12 @@ export class CommandBillPaymentDTOTransformer {
|
|||||||
const amount =
|
const amount =
|
||||||
billPaymentDTO.amount ?? sumBy(billPaymentDTO.entries, 'paymentAmount');
|
billPaymentDTO.amount ?? sumBy(billPaymentDTO.entries, 'paymentAmount');
|
||||||
|
|
||||||
|
// Associate the default index to each item entry.
|
||||||
|
const entries = R.compose(
|
||||||
|
// Associate the default index to payment entries.
|
||||||
|
assocItemEntriesDefaultIndex
|
||||||
|
)(billPaymentDTO.entries);
|
||||||
|
|
||||||
const initialDTO = {
|
const initialDTO = {
|
||||||
...formatDateFields(omit(billPaymentDTO, ['attachments']), [
|
...formatDateFields(omit(billPaymentDTO, ['attachments']), [
|
||||||
'paymentDate',
|
'paymentDate',
|
||||||
@@ -34,7 +40,7 @@ export class CommandBillPaymentDTOTransformer {
|
|||||||
amount,
|
amount,
|
||||||
currencyCode: vendor.currencyCode,
|
currencyCode: vendor.currencyCode,
|
||||||
exchangeRate: billPaymentDTO.exchangeRate || 1,
|
exchangeRate: billPaymentDTO.exchangeRate || 1,
|
||||||
entries: billPaymentDTO.entries,
|
entries,
|
||||||
};
|
};
|
||||||
return R.compose(
|
return R.compose(
|
||||||
this.branchDTOTransform.transformDTO<IBillPayment>(tenantId)
|
this.branchDTOTransform.transformDTO<IBillPayment>(tenantId)
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ export class GetBillPayments {
|
|||||||
builder.withGraphFetched('paymentAccount');
|
builder.withGraphFetched('paymentAccount');
|
||||||
|
|
||||||
dynamicList.buildQuery()(builder);
|
dynamicList.buildQuery()(builder);
|
||||||
|
filter?.filterQuery && filter?.filterQuery(builder);
|
||||||
})
|
})
|
||||||
.pagination(filter.page - 1, filter.pageSize);
|
.pagination(filter.page - 1, filter.pageSize);
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import moment from 'moment';
|
|||||||
import { Inject, Service } from 'typedi';
|
import { Inject, Service } from 'typedi';
|
||||||
import * as R from 'ramda';
|
import * as R from 'ramda';
|
||||||
import composeAsync from 'async/compose';
|
import composeAsync from 'async/compose';
|
||||||
import { formatDateFields } from 'utils';
|
import { assocDepthLevelToObjectTree, formatDateFields } from 'utils';
|
||||||
import {
|
import {
|
||||||
IBillDTO,
|
IBillDTO,
|
||||||
IBill,
|
IBill,
|
||||||
@@ -15,6 +15,7 @@ import { BranchTransactionDTOTransform } from '@/services/Branches/Integrations/
|
|||||||
import { WarehouseTransactionDTOTransform } from '@/services/Warehouses/Integrations/WarehouseTransactionDTOTransform';
|
import { WarehouseTransactionDTOTransform } from '@/services/Warehouses/Integrations/WarehouseTransactionDTOTransform';
|
||||||
import HasTenancyService from '@/services/Tenancy/TenancyService';
|
import HasTenancyService from '@/services/Tenancy/TenancyService';
|
||||||
import { ItemEntriesTaxTransactions } from '@/services/TaxRates/ItemEntriesTaxTransactions';
|
import { ItemEntriesTaxTransactions } from '@/services/TaxRates/ItemEntriesTaxTransactions';
|
||||||
|
import { assocItemEntriesDefaultIndex } from '@/services/Items/utils';
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export class BillDTOTransformer {
|
export class BillDTOTransformer {
|
||||||
@@ -54,9 +55,9 @@ export class BillDTOTransformer {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts create bill DTO to model.
|
* Converts create bill DTO to model.
|
||||||
* @param {number} tenantId
|
* @param {number} tenantId
|
||||||
* @param {IBillDTO} billDTO
|
* @param {IBillDTO} billDTO
|
||||||
* @param {IBill} oldBill
|
* @param {IBill} oldBill
|
||||||
* @returns {IBill}
|
* @returns {IBill}
|
||||||
*/
|
*/
|
||||||
public async billDTOToModel(
|
public async billDTOToModel(
|
||||||
@@ -92,7 +93,9 @@ export class BillDTOTransformer {
|
|||||||
|
|
||||||
const entries = R.compose(
|
const entries = R.compose(
|
||||||
// Remove tax code from entries.
|
// Remove tax code from entries.
|
||||||
R.map(R.omit(['taxCode']))
|
R.map(R.omit(['taxCode'])),
|
||||||
|
// Associate the default index to each item entry line.
|
||||||
|
assocItemEntriesDefaultIndex
|
||||||
)(asyncEntries);
|
)(asyncEntries);
|
||||||
|
|
||||||
const initialDTO = {
|
const initialDTO = {
|
||||||
|
|||||||
@@ -9,11 +9,13 @@ import {
|
|||||||
IVendorCredit,
|
IVendorCredit,
|
||||||
IVendorCreditCreateDTO,
|
IVendorCreditCreateDTO,
|
||||||
IVendorCreditEditDTO,
|
IVendorCreditEditDTO,
|
||||||
|
IVendorCreditEntryDTO,
|
||||||
} from '@/interfaces';
|
} from '@/interfaces';
|
||||||
import ItemsEntriesService from '@/services/Items/ItemsEntriesService';
|
import ItemsEntriesService from '@/services/Items/ItemsEntriesService';
|
||||||
import AutoIncrementOrdersService from '@/services/Sales/AutoIncrementOrdersService';
|
import AutoIncrementOrdersService from '@/services/Sales/AutoIncrementOrdersService';
|
||||||
import { BranchTransactionDTOTransform } from '@/services/Branches/Integrations/BranchTransactionDTOTransform';
|
import { BranchTransactionDTOTransform } from '@/services/Branches/Integrations/BranchTransactionDTOTransform';
|
||||||
import { WarehouseTransactionDTOTransform } from '@/services/Warehouses/Integrations/WarehouseTransactionDTOTransform';
|
import { WarehouseTransactionDTOTransform } from '@/services/Warehouses/Integrations/WarehouseTransactionDTOTransform';
|
||||||
|
import { assocItemEntriesDefaultIndex } from '@/services/Items/utils';
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export default class BaseVendorCredit {
|
export default class BaseVendorCredit {
|
||||||
@@ -50,10 +52,18 @@ export default class BaseVendorCredit {
|
|||||||
const amount = this.itemsEntriesService.getTotalItemsEntries(
|
const amount = this.itemsEntriesService.getTotalItemsEntries(
|
||||||
vendorCreditDTO.entries
|
vendorCreditDTO.entries
|
||||||
);
|
);
|
||||||
const entries = vendorCreditDTO.entries.map((entry) => ({
|
|
||||||
...entry,
|
const entries = R.compose(
|
||||||
referenceType: 'VendorCredit',
|
// Associate the default index to each item entry.
|
||||||
}));
|
assocItemEntriesDefaultIndex,
|
||||||
|
|
||||||
|
// Associate the reference type to item entries.
|
||||||
|
R.map((entry: IVendorCreditEntryDTO) => ({
|
||||||
|
referenceType: 'VendorCredit',
|
||||||
|
...entry,
|
||||||
|
}))
|
||||||
|
)(vendorCreditDTO.entries);
|
||||||
|
|
||||||
// Retreive the next vendor credit number.
|
// Retreive the next vendor credit number.
|
||||||
const autoNextNumber = this.getNextCreditNumber(tenantId);
|
const autoNextNumber = this.getNextCreditNumber(tenantId);
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import { WarehouseTransactionDTOTransform } from '@/services/Warehouses/Integrat
|
|||||||
import { formatDateFields } from '@/utils';
|
import { formatDateFields } from '@/utils';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import { SaleEstimateIncrement } from './SaleEstimateIncrement';
|
import { SaleEstimateIncrement } from './SaleEstimateIncrement';
|
||||||
|
import { assocItemEntriesDefaultIndex } from '@/services/Items/utils';
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export class SaleEstimateDTOTransformer {
|
export class SaleEstimateDTOTransformer {
|
||||||
@@ -56,6 +57,14 @@ export class SaleEstimateDTOTransformer {
|
|||||||
// Validate the sale estimate number require.
|
// Validate the sale estimate number require.
|
||||||
this.validators.validateEstimateNoRequire(estimateNumber);
|
this.validators.validateEstimateNoRequire(estimateNumber);
|
||||||
|
|
||||||
|
const entries = R.compose(
|
||||||
|
// Associate the reference type to item entries.
|
||||||
|
R.map((entry) => R.assoc('reference_type', 'SaleEstimate', entry)),
|
||||||
|
|
||||||
|
// Associate default index to item entries.
|
||||||
|
assocItemEntriesDefaultIndex
|
||||||
|
)(estimateDTO.entries);
|
||||||
|
|
||||||
const initialDTO = {
|
const initialDTO = {
|
||||||
amount,
|
amount,
|
||||||
...formatDateFields(
|
...formatDateFields(
|
||||||
@@ -65,10 +74,7 @@ export class SaleEstimateDTOTransformer {
|
|||||||
currencyCode: paymentCustomer.currencyCode,
|
currencyCode: paymentCustomer.currencyCode,
|
||||||
exchangeRate: estimateDTO.exchangeRate || 1,
|
exchangeRate: estimateDTO.exchangeRate || 1,
|
||||||
...(estimateNumber ? { estimateNumber } : {}),
|
...(estimateNumber ? { estimateNumber } : {}),
|
||||||
entries: estimateDTO.entries.map((entry) => ({
|
entries,
|
||||||
reference_type: 'SaleEstimate',
|
|
||||||
...entry,
|
|
||||||
})),
|
|
||||||
// Avoid rewrite the deliver date in edit mode when already published.
|
// Avoid rewrite the deliver date in edit mode when already published.
|
||||||
...(estimateDTO.delivered &&
|
...(estimateDTO.delivered &&
|
||||||
!oldSaleEstimate?.deliveredAt && {
|
!oldSaleEstimate?.deliveredAt && {
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import { CommandSaleInvoiceValidators } from './CommandSaleInvoiceValidators';
|
|||||||
import { SaleInvoiceIncrement } from './SaleInvoiceIncrement';
|
import { SaleInvoiceIncrement } from './SaleInvoiceIncrement';
|
||||||
import { formatDateFields } from 'utils';
|
import { formatDateFields } from 'utils';
|
||||||
import { ItemEntriesTaxTransactions } from '@/services/TaxRates/ItemEntriesTaxTransactions';
|
import { ItemEntriesTaxTransactions } from '@/services/TaxRates/ItemEntriesTaxTransactions';
|
||||||
|
import { assocItemEntriesDefaultIndex } from '@/services/Items/utils';
|
||||||
import { ItemEntry } from '@/models';
|
import { ItemEntry } from '@/models';
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
@@ -81,7 +82,10 @@ export class CommandSaleInvoiceDTOTransformer {
|
|||||||
|
|
||||||
const entries = R.compose(
|
const entries = R.compose(
|
||||||
// Remove tax code from entries.
|
// Remove tax code from entries.
|
||||||
R.map(R.omit(['taxCode']))
|
R.map(R.omit(['taxCode'])),
|
||||||
|
|
||||||
|
// Associate the default index for each item entry lin.
|
||||||
|
assocItemEntriesDefaultIndex
|
||||||
)(asyncEntries);
|
)(asyncEntries);
|
||||||
|
|
||||||
const initialDTO = {
|
const initialDTO = {
|
||||||
|
|||||||
@@ -50,7 +50,9 @@ export class GetPaymentReceives {
|
|||||||
.onBuild((builder) => {
|
.onBuild((builder) => {
|
||||||
builder.withGraphFetched('customer');
|
builder.withGraphFetched('customer');
|
||||||
builder.withGraphFetched('depositAccount');
|
builder.withGraphFetched('depositAccount');
|
||||||
|
|
||||||
dynamicList.buildQuery()(builder);
|
dynamicList.buildQuery()(builder);
|
||||||
|
filterDTO?.filterQuery && filterDTO.filterQuery(builder);
|
||||||
})
|
})
|
||||||
.pagination(filter.page - 1, filter.pageSize);
|
.pagination(filter.page - 1, filter.pageSize);
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { PaymentReceivedValidators } from './PaymentReceivedValidators';
|
|||||||
import { PaymentReceivedIncrement } from './PaymentReceivedIncrement';
|
import { PaymentReceivedIncrement } from './PaymentReceivedIncrement';
|
||||||
import { BranchTransactionDTOTransform } from '@/services/Branches/Integrations/BranchTransactionDTOTransform';
|
import { BranchTransactionDTOTransform } from '@/services/Branches/Integrations/BranchTransactionDTOTransform';
|
||||||
import { formatDateFields } from '@/utils';
|
import { formatDateFields } from '@/utils';
|
||||||
|
import { assocItemEntriesDefaultIndex } from '@/services/Items/utils';
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export class PaymentReceiveDTOTransformer {
|
export class PaymentReceiveDTOTransformer {
|
||||||
@@ -52,6 +53,11 @@ export class PaymentReceiveDTOTransformer {
|
|||||||
|
|
||||||
this.validators.validatePaymentNoRequire(paymentReceiveNo);
|
this.validators.validatePaymentNoRequire(paymentReceiveNo);
|
||||||
|
|
||||||
|
const entries = R.compose(
|
||||||
|
// Associate the default index to each item entry line.
|
||||||
|
assocItemEntriesDefaultIndex
|
||||||
|
)(paymentReceiveDTO.entries);
|
||||||
|
|
||||||
const initialDTO = {
|
const initialDTO = {
|
||||||
...formatDateFields(omit(paymentReceiveDTO, ['entries', 'attachments']), [
|
...formatDateFields(omit(paymentReceiveDTO, ['entries', 'attachments']), [
|
||||||
'paymentDate',
|
'paymentDate',
|
||||||
@@ -60,9 +66,7 @@ export class PaymentReceiveDTOTransformer {
|
|||||||
currencyCode: customer.currencyCode,
|
currencyCode: customer.currencyCode,
|
||||||
...(paymentReceiveNo ? { paymentReceiveNo } : {}),
|
...(paymentReceiveNo ? { paymentReceiveNo } : {}),
|
||||||
exchangeRate: paymentReceiveDTO.exchangeRate || 1,
|
exchangeRate: paymentReceiveDTO.exchangeRate || 1,
|
||||||
entries: paymentReceiveDTO.entries.map((entry) => ({
|
entries,
|
||||||
...entry,
|
|
||||||
})),
|
|
||||||
};
|
};
|
||||||
return R.compose(
|
return R.compose(
|
||||||
this.branchDTOTransform.transformDTO<IPaymentReceived>(tenantId)
|
this.branchDTOTransform.transformDTO<IPaymentReceived>(tenantId)
|
||||||
|
|||||||
@@ -16,6 +16,10 @@ export class PaymentsReceivedExportable extends Exportable {
|
|||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
public exportable(tenantId: number, query: IPaymentsReceivedFilter) {
|
public exportable(tenantId: number, query: IPaymentsReceivedFilter) {
|
||||||
|
const filterQuery = (builder) => {
|
||||||
|
builder.withGraphFetched('entries.invoice');
|
||||||
|
};
|
||||||
|
|
||||||
const parsedQuery = {
|
const parsedQuery = {
|
||||||
sortOrder: 'desc',
|
sortOrder: 'desc',
|
||||||
columnSortBy: 'created_at',
|
columnSortBy: 'created_at',
|
||||||
@@ -24,6 +28,7 @@ export class PaymentsReceivedExportable extends Exportable {
|
|||||||
structure: IAccountsStructureType.Flat,
|
structure: IAccountsStructureType.Flat,
|
||||||
page: 1,
|
page: 1,
|
||||||
pageSize: EXPORT_SIZE_LIMIT,
|
pageSize: EXPORT_SIZE_LIMIT,
|
||||||
|
filterQuery,
|
||||||
} as IPaymentsReceivedFilter;
|
} as IPaymentsReceivedFilter;
|
||||||
|
|
||||||
return this.paymentReceivedApp
|
return this.paymentReceivedApp
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { ICustomer, ISaleReceipt, ISaleReceiptDTO } from '@/interfaces';
|
|||||||
import { formatDateFields } from '@/utils';
|
import { formatDateFields } from '@/utils';
|
||||||
import { SaleReceiptIncrement } from './SaleReceiptIncrement';
|
import { SaleReceiptIncrement } from './SaleReceiptIncrement';
|
||||||
import { ItemEntry } from '@/models';
|
import { ItemEntry } from '@/models';
|
||||||
|
import { assocItemEntriesDefaultIndex } from '@/services/Items/utils';
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export class SaleReceiptDTOTransformer {
|
export class SaleReceiptDTOTransformer {
|
||||||
@@ -61,11 +62,16 @@ export class SaleReceiptDTOTransformer {
|
|||||||
...entry,
|
...entry,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const entries = await composeAsync(
|
const asyncEntries = await composeAsync(
|
||||||
// Sets default cost and sell account to receipt items entries.
|
// Sets default cost and sell account to receipt items entries.
|
||||||
this.itemsEntriesService.setItemsEntriesDefaultAccounts(tenantId)
|
this.itemsEntriesService.setItemsEntriesDefaultAccounts(tenantId)
|
||||||
)(initialEntries);
|
)(initialEntries);
|
||||||
|
|
||||||
|
const entries = R.compose(
|
||||||
|
// Associate the default index for each item entry.
|
||||||
|
assocItemEntriesDefaultIndex
|
||||||
|
)(asyncEntries);
|
||||||
|
|
||||||
const initialDTO = {
|
const initialDTO = {
|
||||||
amount,
|
amount,
|
||||||
...formatDateFields(
|
...formatDateFields(
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { Model, mixin } from 'objection';
|
|||||||
import SystemModel from '@/system/models/SystemModel';
|
import SystemModel from '@/system/models/SystemModel';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import SubscriptionPeriod from '@/services/Subscription/SubscriptionPeriod';
|
import SubscriptionPeriod from '@/services/Subscription/SubscriptionPeriod';
|
||||||
|
import { SubscriptionPaymentStatus } from '@/interfaces';
|
||||||
|
|
||||||
export default class PlanSubscription extends mixin(SystemModel) {
|
export default class PlanSubscription extends mixin(SystemModel) {
|
||||||
public lemonSubscriptionId: number;
|
public lemonSubscriptionId: number;
|
||||||
@@ -13,6 +14,8 @@ export default class PlanSubscription extends mixin(SystemModel) {
|
|||||||
|
|
||||||
public trialEndsAt: Date;
|
public trialEndsAt: Date;
|
||||||
|
|
||||||
|
public paymentStatus: SubscriptionPaymentStatus;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Table name.
|
* Table name.
|
||||||
*/
|
*/
|
||||||
@@ -31,7 +34,16 @@ export default class PlanSubscription extends mixin(SystemModel) {
|
|||||||
* Defined virtual attributes.
|
* Defined virtual attributes.
|
||||||
*/
|
*/
|
||||||
static get virtualAttributes() {
|
static get virtualAttributes() {
|
||||||
return ['active', 'inactive', 'ended', 'canceled', 'onTrial', 'status'];
|
return [
|
||||||
|
'active',
|
||||||
|
'inactive',
|
||||||
|
'ended',
|
||||||
|
'canceled',
|
||||||
|
'onTrial',
|
||||||
|
'status',
|
||||||
|
'isPaymentFailed',
|
||||||
|
'isPaymentSucceed',
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -69,6 +81,22 @@ export default class PlanSubscription extends mixin(SystemModel) {
|
|||||||
|
|
||||||
builder.where('trial_ends_at', '<=', endDate);
|
builder.where('trial_ends_at', '<=', endDate);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter the failed payment.
|
||||||
|
* @param builder
|
||||||
|
*/
|
||||||
|
failedPayment(builder) {
|
||||||
|
builder.where('payment_status', SubscriptionPaymentStatus.Failed);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter the succeed payment.
|
||||||
|
* @param builder
|
||||||
|
*/
|
||||||
|
succeedPayment(builder) {
|
||||||
|
builder.where('payment_status', SubscriptionPaymentStatus.Succeed);
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,10 +136,13 @@ export default class PlanSubscription extends mixin(SystemModel) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if the subscription is active.
|
* Check if the subscription is active.
|
||||||
|
* Crtiria should be active:
|
||||||
|
* - During the trial period should NOT be canceled.
|
||||||
|
* - Out of trial period should NOT be ended.
|
||||||
* @return {Boolean}
|
* @return {Boolean}
|
||||||
*/
|
*/
|
||||||
public active() {
|
public active() {
|
||||||
return this.onTrial() || !this.ended();
|
return this.onTrial() ? !this.canceled() : !this.ended();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -200,4 +231,20 @@ export default class PlanSubscription extends mixin(SystemModel) {
|
|||||||
);
|
);
|
||||||
return this.$query().update({ startsAt, endsAt });
|
return this.$query().update({ startsAt, endsAt });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detarmines the subscription payment whether is failed.
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
public isPaymentFailed() {
|
||||||
|
return this.paymentStatus === SubscriptionPaymentStatus.Failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detarmines the subscription payment whether is succeed.
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
public isPaymentSucceed() {
|
||||||
|
return this.paymentStatus === SubscriptionPaymentStatus.Succeed;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,12 +15,8 @@ export default class SubscriptionRepository extends SystemRepository {
|
|||||||
* @param {number} tenantId
|
* @param {number} tenantId
|
||||||
*/
|
*/
|
||||||
getBySlugInTenant(slug: string, tenantId: number) {
|
getBySlugInTenant(slug: string, tenantId: number) {
|
||||||
const cacheKey = this.getCacheKey('getBySlugInTenant', slug, tenantId);
|
return PlanSubscription.query()
|
||||||
|
.findOne('slug', slug)
|
||||||
return this.cache.get(cacheKey, () => {
|
.where('tenant_id', tenantId);
|
||||||
return PlanSubscription.query()
|
|
||||||
.findOne('slug', slug)
|
|
||||||
.where('tenant_id', tenantId);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,9 +9,11 @@ import {
|
|||||||
compose,
|
compose,
|
||||||
updateTableCell,
|
updateTableCell,
|
||||||
updateAutoAddNewLine,
|
updateAutoAddNewLine,
|
||||||
|
updateMinEntriesLines,
|
||||||
orderingLinesIndexes,
|
orderingLinesIndexes,
|
||||||
updateTableRow,
|
updateTableRow,
|
||||||
formattedAmount,
|
formattedAmount,
|
||||||
|
updateRemoveLineByIndex,
|
||||||
} from '@/utils';
|
} from '@/utils';
|
||||||
import { useItemEntriesTableContext } from './ItemEntriesTableProvider';
|
import { useItemEntriesTableContext } from './ItemEntriesTableProvider';
|
||||||
|
|
||||||
|
|||||||
@@ -77,6 +77,15 @@ function GlobalErrors({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (globalErrors.subscriptionInactive) {
|
||||||
|
AppToaster.show({
|
||||||
|
message: `You can't add new data to Bigcapital because your subscription is inactive. Make sure your billing information is up-to-date from Preferences > Billing page.`,
|
||||||
|
intent: Intent.DANGER,
|
||||||
|
onDismiss: () => {
|
||||||
|
globalErrorsSet({ subscriptionInactive: false });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
if (globalErrors.userInactive) {
|
if (globalErrors.userInactive) {
|
||||||
AppToaster.show({
|
AppToaster.show({
|
||||||
message: intl.get('global_error.authorized_user_inactive'),
|
message: intl.get('global_error.authorized_user_inactive'),
|
||||||
|
|||||||
@@ -64,12 +64,20 @@ export default function useApiRequest() {
|
|||||||
setGlobalErrors({ too_many_requests: true });
|
setGlobalErrors({ too_many_requests: true });
|
||||||
}
|
}
|
||||||
if (status === 400) {
|
if (status === 400) {
|
||||||
const lockedError = data.errors.find(
|
if (
|
||||||
(error) => error.type === 'TRANSACTIONS_DATE_LOCKED',
|
data.errors.find(
|
||||||
);
|
(error) => error.type === 'TRANSACTIONS_DATE_LOCKED',
|
||||||
if (lockedError) {
|
)
|
||||||
|
) {
|
||||||
setGlobalErrors({ transactionsLocked: { ...lockedError.data } });
|
setGlobalErrors({ transactionsLocked: { ...lockedError.data } });
|
||||||
}
|
}
|
||||||
|
if (
|
||||||
|
data.errors.find(
|
||||||
|
(e) => e.type === 'ORGANIZATION.SUBSCRIPTION.INACTIVE',
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
setGlobalErrors({ subscriptionInactive: true });
|
||||||
|
}
|
||||||
if (data.errors.find((e) => e.type === 'USER_INACTIVE')) {
|
if (data.errors.find((e) => e.type === 'USER_INACTIVE')) {
|
||||||
setGlobalErrors({ userInactive: true });
|
setGlobalErrors({ userInactive: true });
|
||||||
setLogout();
|
setLogout();
|
||||||
|
|||||||
27
pnpm-lock.yaml
generated
27
pnpm-lock.yaml
generated
@@ -272,6 +272,9 @@ importers:
|
|||||||
pluralize:
|
pluralize:
|
||||||
specifier: ^8.0.0
|
specifier: ^8.0.0
|
||||||
version: 8.0.0
|
version: 8.0.0
|
||||||
|
posthog-node:
|
||||||
|
specifier: ^4.2.0
|
||||||
|
version: 4.2.0
|
||||||
pug:
|
pug:
|
||||||
specifier: ^3.0.2
|
specifier: ^3.0.2
|
||||||
version: 3.0.2
|
version: 3.0.2
|
||||||
@@ -8099,6 +8102,16 @@ packages:
|
|||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- debug
|
- debug
|
||||||
|
|
||||||
|
/axios@1.7.7:
|
||||||
|
resolution: {integrity: sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==}
|
||||||
|
dependencies:
|
||||||
|
follow-redirects: 1.15.6
|
||||||
|
form-data: 4.0.0
|
||||||
|
proxy-from-env: 1.1.0
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- debug
|
||||||
|
dev: false
|
||||||
|
|
||||||
/axobject-query@3.2.1:
|
/axobject-query@3.2.1:
|
||||||
resolution: {integrity: sha512-jsyHu61e6N4Vbz/v18DHwWYKK0bSWLqn47eeDSKPB7m8tqMHF9YJ+mhIk2lVteyZrY8tnSj/jHOv4YiTCuCJgg==}
|
resolution: {integrity: sha512-jsyHu61e6N4Vbz/v18DHwWYKK0bSWLqn47eeDSKPB7m8tqMHF9YJ+mhIk2lVteyZrY8tnSj/jHOv4YiTCuCJgg==}
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -20477,6 +20490,16 @@ packages:
|
|||||||
picocolors: 1.0.1
|
picocolors: 1.0.1
|
||||||
source-map-js: 1.2.0
|
source-map-js: 1.2.0
|
||||||
|
|
||||||
|
/posthog-node@4.2.0:
|
||||||
|
resolution: {integrity: sha512-hgyCYMyzMvuF3qWMw6JvS8gT55v7Mtp5wKWcnDrw+nu39D0Tk9BXD7I0LOBp0lGlHEPaXCEVYUtviNKrhMALGA==}
|
||||||
|
engines: {node: '>=15.0.0'}
|
||||||
|
dependencies:
|
||||||
|
axios: 1.7.7
|
||||||
|
rusha: 0.8.14
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- debug
|
||||||
|
dev: false
|
||||||
|
|
||||||
/prebuildify@6.0.1:
|
/prebuildify@6.0.1:
|
||||||
resolution: {integrity: sha512-8Y2oOOateom/s8dNBsGIcnm6AxPmLH4/nanQzL5lQMU+sC0CMhzARZHizwr36pUPLdvBnOkCNQzxg4djuFSgIw==}
|
resolution: {integrity: sha512-8Y2oOOateom/s8dNBsGIcnm6AxPmLH4/nanQzL5lQMU+sC0CMhzARZHizwr36pUPLdvBnOkCNQzxg4djuFSgIw==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
@@ -22731,6 +22754,10 @@ packages:
|
|||||||
engines: {node: '>=14'}
|
engines: {node: '>=14'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/rusha@0.8.14:
|
||||||
|
resolution: {integrity: sha512-cLgakCUf6PedEu15t8kbsjnwIFFR2D4RfL+W3iWFJ4iac7z4B0ZI8fxy4R3J956kAI68HclCFGL8MPoUVC3qVA==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/rxjs@7.8.1:
|
/rxjs@7.8.1:
|
||||||
resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==}
|
resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|||||||
Reference in New Issue
Block a user