feat(server): implement tracking tags for GL entries and reporting
- Add tracking tags infrastructure with 5 database tables - Create TrackingTags module with CRUD API endpoints - Associate tags with invoice/bill line items and manual journal entries - Propagate tags to GL entries (accounts_transactions) via ledger storage - Add tracking tag filtering to all 12 GL-dependent financial reports: - General Ledger, Balance Sheet, Profit & Loss - Trial Balance, Journal Sheet, Cash Flow Statement - Customer/Vendor Balance Summary - Transactions by Customer/Vendor/Reference - Sales Tax Liability Summary - Add filterByTrackingTags query modifier to AccountTransaction model - Add sdk-ts types and fetch functions for tracking tags - Add React hooks (useTrackingTags, useCreateTrackingTag, etc.) - TypeScript typecheck passes across all packages
This commit is contained in:
+67
@@ -0,0 +1,67 @@
|
|||||||
|
exports.up = function(knex) {
|
||||||
|
return knex.schema
|
||||||
|
.createTable('tracking_tags', table => {
|
||||||
|
table.increments();
|
||||||
|
table.string('name').notNullable();
|
||||||
|
table.string('description').nullable();
|
||||||
|
table.boolean('active').defaultTo(true);
|
||||||
|
table.timestamps();
|
||||||
|
table.index(['active']);
|
||||||
|
table.unique(['name']);
|
||||||
|
})
|
||||||
|
.createTable('tracking_tag_options', table => {
|
||||||
|
table.increments();
|
||||||
|
table.integer('tag_id').unsigned().notNullable();
|
||||||
|
table.string('name').notNullable();
|
||||||
|
table.boolean('active').defaultTo(true);
|
||||||
|
table.timestamps();
|
||||||
|
table.foreign('tag_id').references('tracking_tags.id').onDelete('CASCADE');
|
||||||
|
table.unique(['tag_id', 'name']);
|
||||||
|
})
|
||||||
|
.createTable('item_entry_tracking_tags', table => {
|
||||||
|
table.integer('item_entry_id').unsigned().notNullable();
|
||||||
|
table.integer('tag_id').unsigned().notNullable();
|
||||||
|
table.integer('option_id').unsigned().notNullable();
|
||||||
|
table.timestamps();
|
||||||
|
table.primary(['item_entry_id', 'tag_id']);
|
||||||
|
table.foreign('item_entry_id').references('items_entries.id').onDelete('CASCADE');
|
||||||
|
table.foreign('tag_id').references('tracking_tags.id').onDelete('CASCADE');
|
||||||
|
table.foreign('option_id').references('tracking_tag_options.id').onDelete('CASCADE');
|
||||||
|
table.index(['tag_id']);
|
||||||
|
table.index(['option_id']);
|
||||||
|
})
|
||||||
|
.createTable('manual_journal_entry_tracking_tags', table => {
|
||||||
|
table.integer('manual_journal_entry_id').unsigned().notNullable();
|
||||||
|
table.integer('tag_id').unsigned().notNullable();
|
||||||
|
table.integer('option_id').unsigned().notNullable();
|
||||||
|
table.timestamps();
|
||||||
|
table.primary(['manual_journal_entry_id', 'tag_id']);
|
||||||
|
table.foreign('manual_journal_entry_id').references('manual_journals_entries.id').onDelete('CASCADE');
|
||||||
|
table.foreign('tag_id').references('tracking_tags.id').onDelete('CASCADE');
|
||||||
|
table.foreign('option_id').references('tracking_tag_options.id').onDelete('CASCADE');
|
||||||
|
table.index(['tag_id']);
|
||||||
|
table.index(['option_id']);
|
||||||
|
})
|
||||||
|
.createTable('account_transaction_tracking_tags', table => {
|
||||||
|
table.integer('account_transaction_id').unsigned().notNullable();
|
||||||
|
table.integer('tag_id').unsigned().notNullable();
|
||||||
|
table.integer('option_id').unsigned().notNullable();
|
||||||
|
table.timestamps();
|
||||||
|
table.primary(['account_transaction_id', 'tag_id']);
|
||||||
|
table.foreign('account_transaction_id').references('accounts_transactions.id').onDelete('CASCADE');
|
||||||
|
table.foreign('tag_id').references('tracking_tags.id').onDelete('CASCADE');
|
||||||
|
table.foreign('option_id').references('tracking_tag_options.id').onDelete('CASCADE');
|
||||||
|
table.index(['tag_id']);
|
||||||
|
table.index(['option_id']);
|
||||||
|
table.index(['account_transaction_id']);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.down = function(knex) {
|
||||||
|
return knex.schema
|
||||||
|
.dropTableIfExists('account_transaction_tracking_tags')
|
||||||
|
.dropTableIfExists('manual_journal_entry_tracking_tags')
|
||||||
|
.dropTableIfExists('item_entry_tracking_tags')
|
||||||
|
.dropTableIfExists('tracking_tag_options')
|
||||||
|
.dropTableIfExists('tracking_tags');
|
||||||
|
};
|
||||||
@@ -230,6 +230,23 @@ export class AccountTransaction extends BaseModel {
|
|||||||
query.where('reference_id', referenceId);
|
query.where('reference_id', referenceId);
|
||||||
query.where('reference_type', referenceType);
|
query.where('reference_type', referenceType);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
filterByTrackingTags(query, trackingTags: Array<{ tagId: number; optionId?: number }>) {
|
||||||
|
if (isEmpty(trackingTags)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const tagIds = trackingTags.map((t) => t.tagId);
|
||||||
|
query.whereExists(
|
||||||
|
query
|
||||||
|
.knex()
|
||||||
|
.select(1)
|
||||||
|
.from('account_transaction_tracking_tags')
|
||||||
|
.whereRaw(
|
||||||
|
'account_transaction_tracking_tags.account_transaction_id = accounts_transactions.id',
|
||||||
|
)
|
||||||
|
.whereIn('account_transaction_tracking_tags.tag_id', tagIds),
|
||||||
|
);
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -99,6 +99,7 @@ import { UsersModule } from '../UsersModule/Users.module';
|
|||||||
import { ContactsModule } from '../Contacts/Contacts.module';
|
import { ContactsModule } from '../Contacts/Contacts.module';
|
||||||
import { BankingPlaidModule } from '../BankingPlaid/BankingPlaid.module';
|
import { BankingPlaidModule } from '../BankingPlaid/BankingPlaid.module';
|
||||||
import { CustomFieldsModule } from '../CustomFields/CustomFields.module';
|
import { CustomFieldsModule } from '../CustomFields/CustomFields.module';
|
||||||
|
import { TrackingTagsModule } from '../TrackingTags/TrackingTags.module';
|
||||||
import { BankingCategorizeModule } from '../BankingCategorize/BankingCategorize.module';
|
import { BankingCategorizeModule } from '../BankingCategorize/BankingCategorize.module';
|
||||||
import { ExchangeRatesModule } from '../ExchangeRates/ExchangeRates.module';
|
import { ExchangeRatesModule } from '../ExchangeRates/ExchangeRates.module';
|
||||||
import { TenantModelsInitializeModule } from '../Tenancy/TenantModelsInitialize.module';
|
import { TenantModelsInitializeModule } from '../Tenancy/TenantModelsInitialize.module';
|
||||||
@@ -258,6 +259,7 @@ import { AppThrottleModule } from './AppThrottle.module';
|
|||||||
UsersModule,
|
UsersModule,
|
||||||
ContactsModule,
|
ContactsModule,
|
||||||
CustomFieldsModule,
|
CustomFieldsModule,
|
||||||
|
TrackingTagsModule,
|
||||||
SocketModule,
|
SocketModule,
|
||||||
ExchangeRatesModule,
|
ExchangeRatesModule,
|
||||||
],
|
],
|
||||||
|
|||||||
+9
@@ -11,6 +11,7 @@ import {
|
|||||||
} from 'class-validator';
|
} from 'class-validator';
|
||||||
import { FinancialSheetBranchesQueryDto } from '../../dtos/FinancialSheetBranchesQuery.dto';
|
import { FinancialSheetBranchesQueryDto } from '../../dtos/FinancialSheetBranchesQuery.dto';
|
||||||
import { ApiProperty } from '@nestjs/swagger';
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { TrackingTagAssignmentDto } from '@/modules/TrackingTags/dtos/AssignTrackingTags.dto';
|
||||||
|
|
||||||
export class BalanceSheetQueryDto extends FinancialSheetBranchesQueryDto {
|
export class BalanceSheetQueryDto extends FinancialSheetBranchesQueryDto {
|
||||||
@ApiProperty({
|
@ApiProperty({
|
||||||
@@ -173,4 +174,12 @@ export class BalanceSheetQueryDto extends FinancialSheetBranchesQueryDto {
|
|||||||
@Transform(({ value }) => parseBoolean(value, false))
|
@Transform(({ value }) => parseBoolean(value, false))
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
previousYearPercentageChange: boolean;
|
previousYearPercentageChange: boolean;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'Tracking tags to filter the report',
|
||||||
|
type: [TrackingTagAssignmentDto],
|
||||||
|
required: false,
|
||||||
|
})
|
||||||
|
@IsOptional()
|
||||||
|
trackingTags?: TrackingTagAssignmentDto[];
|
||||||
}
|
}
|
||||||
|
|||||||
+3
@@ -5,6 +5,7 @@ import {
|
|||||||
INumberFormatQuery,
|
INumberFormatQuery,
|
||||||
} from '../../types/Report.types';
|
} from '../../types/Report.types';
|
||||||
import { IFinancialTable } from '../../types/Table.types';
|
import { IFinancialTable } from '../../types/Table.types';
|
||||||
|
import { ITrackingTagFilter } from '../../types/TrackingTagFilter.types';
|
||||||
|
|
||||||
// Balance sheet schema nodes types.
|
// Balance sheet schema nodes types.
|
||||||
export enum BALANCE_SHEET_SCHEMA_NODE_TYPE {
|
export enum BALANCE_SHEET_SCHEMA_NODE_TYPE {
|
||||||
@@ -63,6 +64,8 @@ export interface IBalanceSheetQuery extends IFinancialSheetBranchesQuery {
|
|||||||
previousYear: boolean;
|
previousYear: boolean;
|
||||||
previousYearAmountChange: boolean;
|
previousYearAmountChange: boolean;
|
||||||
previousYearPercentageChange: boolean;
|
previousYearPercentageChange: boolean;
|
||||||
|
|
||||||
|
trackingTags?: ITrackingTagFilter[];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Balance sheet meta.
|
// Balance sheet meta.
|
||||||
|
|||||||
+3
@@ -401,5 +401,8 @@ export class BalanceSheetRepository extends R.compose(
|
|||||||
if (!isEmpty(this.query.branchesIds)) {
|
if (!isEmpty(this.query.branchesIds)) {
|
||||||
query.modify('filterByBranches', this.query.branchesIds);
|
query.modify('filterByBranches', this.query.branchesIds);
|
||||||
}
|
}
|
||||||
|
if (!isEmpty(this.query.trackingTags)) {
|
||||||
|
query.modify('filterByTrackingTags', this.query.trackingTags);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
+3
@@ -173,5 +173,8 @@ export class CashFlowRepository {
|
|||||||
if (!isEmpty(query.branchesIds)) {
|
if (!isEmpty(query.branchesIds)) {
|
||||||
knexQuery.modify('filterByBranches', query.branchesIds);
|
knexQuery.modify('filterByBranches', query.branchesIds);
|
||||||
}
|
}
|
||||||
|
if (!isEmpty(query.trackingTags)) {
|
||||||
|
knexQuery.modify('filterByTrackingTags', query.trackingTags);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
+9
@@ -11,6 +11,7 @@ import { NumberFormatQueryDto } from '@/modules/BankingTransactions/dtos/NumberF
|
|||||||
import { Transform, Type } from 'class-transformer';
|
import { Transform, Type } from 'class-transformer';
|
||||||
import { parseBoolean } from '@/utils/parse-boolean';
|
import { parseBoolean } from '@/utils/parse-boolean';
|
||||||
import { ApiProperty } from '@nestjs/swagger';
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { TrackingTagAssignmentDto } from '@/modules/TrackingTags/dtos/AssignTrackingTags.dto';
|
||||||
|
|
||||||
export class CashFlowStatementQueryDto extends FinancialSheetBranchesQueryDto {
|
export class CashFlowStatementQueryDto extends FinancialSheetBranchesQueryDto {
|
||||||
@ApiProperty({
|
@ApiProperty({
|
||||||
@@ -92,4 +93,12 @@ export class CashFlowStatementQueryDto extends FinancialSheetBranchesQueryDto {
|
|||||||
@IsString()
|
@IsString()
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
basis: string;
|
basis: string;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'Tracking tags to filter the report',
|
||||||
|
type: [TrackingTagAssignmentDto],
|
||||||
|
required: false,
|
||||||
|
})
|
||||||
|
@IsOptional()
|
||||||
|
trackingTags?: TrackingTagAssignmentDto[];
|
||||||
}
|
}
|
||||||
|
|||||||
+1
@@ -16,6 +16,7 @@ export interface ICashFlowStatementQuery {
|
|||||||
basis: string;
|
basis: string;
|
||||||
|
|
||||||
branchesIds?: number[];
|
branchesIds?: number[];
|
||||||
|
trackingTags?: Array<{ tagId: number; optionId?: number }>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ICashFlowStatementTotal {
|
export interface ICashFlowStatementTotal {
|
||||||
|
|||||||
+8
@@ -1,6 +1,7 @@
|
|||||||
import { IsArray, IsOptional } from 'class-validator';
|
import { IsArray, IsOptional } from 'class-validator';
|
||||||
import { ContactBalanceSummaryQueryDto } from '../ContactBalanceSummary/ContactBalanceSummaryQuery.dto';
|
import { ContactBalanceSummaryQueryDto } from '../ContactBalanceSummary/ContactBalanceSummaryQuery.dto';
|
||||||
import { ApiPropertyOptional } from '@nestjs/swagger';
|
import { ApiPropertyOptional } from '@nestjs/swagger';
|
||||||
|
import { TrackingTagAssignmentDto } from '@/modules/TrackingTags/dtos/AssignTrackingTags.dto';
|
||||||
|
|
||||||
export class CustomerBalanceSummaryQueryDto extends ContactBalanceSummaryQueryDto {
|
export class CustomerBalanceSummaryQueryDto extends ContactBalanceSummaryQueryDto {
|
||||||
@ApiPropertyOptional({
|
@ApiPropertyOptional({
|
||||||
@@ -11,4 +12,11 @@ export class CustomerBalanceSummaryQueryDto extends ContactBalanceSummaryQueryDt
|
|||||||
@IsArray()
|
@IsArray()
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
customersIds: number[];
|
customersIds: number[];
|
||||||
|
|
||||||
|
@ApiPropertyOptional({
|
||||||
|
description: 'Tracking tags to filter the report',
|
||||||
|
type: [TrackingTagAssignmentDto],
|
||||||
|
})
|
||||||
|
@IsOptional()
|
||||||
|
trackingTags?: TrackingTagAssignmentDto[];
|
||||||
}
|
}
|
||||||
|
|||||||
+4
@@ -56,6 +56,7 @@ export class CustomerBalanceSummaryRepository {
|
|||||||
*/
|
*/
|
||||||
public async getCustomersTransactions(
|
public async getCustomersTransactions(
|
||||||
asDate: any,
|
asDate: any,
|
||||||
|
trackingTags?: Array<{ tagId: number; optionId?: number }>,
|
||||||
): Promise<ModelObject<AccountTransaction>[]> {
|
): Promise<ModelObject<AccountTransaction>[]> {
|
||||||
// Retrieve the receivable accounts A/R.
|
// Retrieve the receivable accounts A/R.
|
||||||
const receivableAccounts = await this.getReceivableAccounts();
|
const receivableAccounts = await this.getReceivableAccounts();
|
||||||
@@ -67,6 +68,9 @@ export class CustomerBalanceSummaryRepository {
|
|||||||
.onBuild((query) => {
|
.onBuild((query) => {
|
||||||
query.whereIn('accountId', receivableAccountsIds);
|
query.whereIn('accountId', receivableAccountsIds);
|
||||||
query.modify('filterDateRange', null, asDate);
|
query.modify('filterDateRange', null, asDate);
|
||||||
|
if (!isEmpty(trackingTags)) {
|
||||||
|
query.modify('filterByTrackingTags', trackingTags);
|
||||||
|
}
|
||||||
query.groupBy('contactId');
|
query.groupBy('contactId');
|
||||||
query.sum('credit as credit');
|
query.sum('credit as credit');
|
||||||
query.sum('debit as debit');
|
query.sum('debit as debit');
|
||||||
|
|||||||
+14
@@ -1,5 +1,6 @@
|
|||||||
import { IFinancialSheetCommonMeta, INumberFormatQuery } from "../../types/Report.types";
|
import { IFinancialSheetCommonMeta, INumberFormatQuery } from "../../types/Report.types";
|
||||||
import { IFinancialTable } from "../../types/Table.types";
|
import { IFinancialTable } from "../../types/Table.types";
|
||||||
|
import { ITrackingTagFilter } from "../../types/TrackingTagFilter.types";
|
||||||
|
|
||||||
export interface IGeneralLedgerSheetQuery {
|
export interface IGeneralLedgerSheetQuery {
|
||||||
fromDate: Date | string;
|
fromDate: Date | string;
|
||||||
@@ -10,6 +11,19 @@ export interface IGeneralLedgerSheetQuery {
|
|||||||
noneTransactions: boolean;
|
noneTransactions: boolean;
|
||||||
accountsIds: number[];
|
accountsIds: number[];
|
||||||
branchesIds?: number[];
|
branchesIds?: number[];
|
||||||
|
trackingTags?: ITrackingTagFilter[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IGeneralLedgerSheetQuery {
|
||||||
|
fromDate: Date | string;
|
||||||
|
toDate: Date | string;
|
||||||
|
basis: string;
|
||||||
|
numberFormat: IGeneralLedgerNumberFormat;
|
||||||
|
dateFormat?: string;
|
||||||
|
noneTransactions: boolean;
|
||||||
|
accountsIds: number[];
|
||||||
|
branchesIds?: number[];
|
||||||
|
trackingTags?: ITrackingTagFilter[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IGeneralLedgerNumberFormat extends INumberFormatQuery{
|
export interface IGeneralLedgerNumberFormat extends INumberFormatQuery{
|
||||||
|
|||||||
+6
@@ -119,6 +119,9 @@ export class GeneralLedgerRepository {
|
|||||||
if (!isEmpty(this.filter.branchesIds)) {
|
if (!isEmpty(this.filter.branchesIds)) {
|
||||||
query.modify('filterByBranches', this.filter.branchesIds);
|
query.modify('filterByBranches', this.filter.branchesIds);
|
||||||
}
|
}
|
||||||
|
if (!isEmpty(this.filter.trackingTags)) {
|
||||||
|
query.modify('filterByTrackingTags', this.filter.trackingTags);
|
||||||
|
}
|
||||||
query.orderBy('date', 'ASC');
|
query.orderBy('date', 'ASC');
|
||||||
|
|
||||||
if (this.filter.accountsIds?.length > 0) {
|
if (this.filter.accountsIds?.length > 0) {
|
||||||
@@ -146,6 +149,9 @@ export class GeneralLedgerRepository {
|
|||||||
if (!isEmpty(this.filter.branchesIds)) {
|
if (!isEmpty(this.filter.branchesIds)) {
|
||||||
query.modify('filterByBranches', this.filter.branchesIds);
|
query.modify('filterByBranches', this.filter.branchesIds);
|
||||||
}
|
}
|
||||||
|
if (!isEmpty(this.filter.trackingTags)) {
|
||||||
|
query.modify('filterByTrackingTags', this.filter.trackingTags);
|
||||||
|
}
|
||||||
query.withGraphFetched('account');
|
query.withGraphFetched('account');
|
||||||
});
|
});
|
||||||
// Accounts opening transactions.
|
// Accounts opening transactions.
|
||||||
|
|||||||
+8
@@ -10,6 +10,7 @@ import {
|
|||||||
import { Type } from 'class-transformer';
|
import { Type } from 'class-transformer';
|
||||||
import { FinancialSheetBranchesQueryDto } from '../../dtos/FinancialSheetBranchesQuery.dto';
|
import { FinancialSheetBranchesQueryDto } from '../../dtos/FinancialSheetBranchesQuery.dto';
|
||||||
import { ApiPropertyOptional } from '@nestjs/swagger';
|
import { ApiPropertyOptional } from '@nestjs/swagger';
|
||||||
|
import { TrackingTagAssignmentDto } from '@/modules/TrackingTags/dtos/AssignTrackingTags.dto';
|
||||||
|
|
||||||
class JournalSheetNumberFormatQueryDto {
|
class JournalSheetNumberFormatQueryDto {
|
||||||
@ApiPropertyOptional({
|
@ApiPropertyOptional({
|
||||||
@@ -93,4 +94,11 @@ export class JournalSheetQueryDto extends FinancialSheetBranchesQueryDto {
|
|||||||
@IsNumber()
|
@IsNumber()
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
toRange: number;
|
toRange: number;
|
||||||
|
|
||||||
|
@ApiPropertyOptional({
|
||||||
|
description: 'Tracking tags to filter the report',
|
||||||
|
type: [TrackingTagAssignmentDto],
|
||||||
|
})
|
||||||
|
@IsOptional()
|
||||||
|
trackingTags?: TrackingTagAssignmentDto[];
|
||||||
}
|
}
|
||||||
|
|||||||
+4
@@ -6,6 +6,7 @@ import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
|||||||
import { TenancyContext } from '@/modules/Tenancy/TenancyContext.service';
|
import { TenancyContext } from '@/modules/Tenancy/TenancyContext.service';
|
||||||
import { transformToMap } from '@/utils/transform-to-key';
|
import { transformToMap } from '@/utils/transform-to-key';
|
||||||
import { Inject } from '@nestjs/common';
|
import { Inject } from '@nestjs/common';
|
||||||
|
import { isEmpty } from 'lodash';
|
||||||
import { ModelObject } from 'objection';
|
import { ModelObject } from 'objection';
|
||||||
|
|
||||||
export class JournalSheetRepository {
|
export class JournalSheetRepository {
|
||||||
@@ -112,6 +113,9 @@ export class JournalSheetRepository {
|
|||||||
if (this.filter.transactionType && this.filter.transactionId) {
|
if (this.filter.transactionType && this.filter.transactionId) {
|
||||||
query.where('reference_id', this.filter.transactionId);
|
query.where('reference_id', this.filter.transactionId);
|
||||||
}
|
}
|
||||||
|
if (!isEmpty(this.filter.trackingTags)) {
|
||||||
|
query.modify('filterByTrackingTags', this.filter.trackingTags);
|
||||||
|
}
|
||||||
query.withGraphFetched('account');
|
query.withGraphFetched('account');
|
||||||
});
|
});
|
||||||
this.accountTransactions = transactions;
|
this.accountTransactions = transactions;
|
||||||
|
|||||||
+3
@@ -5,6 +5,7 @@ import {
|
|||||||
INumberFormatQuery,
|
INumberFormatQuery,
|
||||||
} from '../../types/Report.types';
|
} from '../../types/Report.types';
|
||||||
import { IFinancialTable } from '../../types/Table.types';
|
import { IFinancialTable } from '../../types/Table.types';
|
||||||
|
import { ITrackingTagFilter } from '../../types/TrackingTagFilter.types';
|
||||||
|
|
||||||
export enum ProfitLossAggregateNodeId {
|
export enum ProfitLossAggregateNodeId {
|
||||||
INCOME = 'INCOME',
|
INCOME = 'INCOME',
|
||||||
@@ -86,6 +87,8 @@ export interface IProfitLossSheetQuery extends IFinancialSheetBranchesQuery {
|
|||||||
previousYear: boolean;
|
previousYear: boolean;
|
||||||
previousYearAmountChange: boolean;
|
previousYearAmountChange: boolean;
|
||||||
previousYearPercentageChange: boolean;
|
previousYearPercentageChange: boolean;
|
||||||
|
|
||||||
|
trackingTags?: ITrackingTagFilter[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IProfitLossSheetTotal {
|
export interface IProfitLossSheetTotal {
|
||||||
|
|||||||
+8
@@ -14,6 +14,7 @@ import { Transform, Type } from 'class-transformer';
|
|||||||
import { ToNumber } from '@/common/decorators/Validators';
|
import { ToNumber } from '@/common/decorators/Validators';
|
||||||
import { parseBoolean } from '@/utils/parse-boolean';
|
import { parseBoolean } from '@/utils/parse-boolean';
|
||||||
import { NumberFormatQueryDto } from '@/modules/BankingTransactions/dtos/NumberFormatQuery.dto';
|
import { NumberFormatQueryDto } from '@/modules/BankingTransactions/dtos/NumberFormatQuery.dto';
|
||||||
|
import { TrackingTagAssignmentDto } from '@/modules/TrackingTags/dtos/AssignTrackingTags.dto';
|
||||||
|
|
||||||
export class ProfitLossSheetQueryDto extends FinancialSheetBranchesQueryDto {
|
export class ProfitLossSheetQueryDto extends FinancialSheetBranchesQueryDto {
|
||||||
@IsString()
|
@IsString()
|
||||||
@@ -136,4 +137,11 @@ export class ProfitLossSheetQueryDto extends FinancialSheetBranchesQueryDto {
|
|||||||
description: 'Whether to show previous year percentage change',
|
description: 'Whether to show previous year percentage change',
|
||||||
})
|
})
|
||||||
previousYearPercentageChange: boolean;
|
previousYearPercentageChange: boolean;
|
||||||
|
|
||||||
|
@ApiPropertyOptional({
|
||||||
|
description: 'Tracking tags to filter the report',
|
||||||
|
type: [TrackingTagAssignmentDto],
|
||||||
|
})
|
||||||
|
@IsOptional()
|
||||||
|
trackingTags?: TrackingTagAssignmentDto[];
|
||||||
}
|
}
|
||||||
|
|||||||
+3
@@ -363,6 +363,9 @@ export class ProfitLossSheetRepository extends R.compose(FinancialDatePeriods)(
|
|||||||
if (!isEmpty(this.query.query.branchesIds)) {
|
if (!isEmpty(this.query.query.branchesIds)) {
|
||||||
query.modify('filterByBranches', this.query.query.branchesIds);
|
query.modify('filterByBranches', this.query.query.branchesIds);
|
||||||
}
|
}
|
||||||
|
if (!isEmpty(this.query.query.trackingTags)) {
|
||||||
|
query.modify('filterByTrackingTags', this.query.query.trackingTags);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+1
@@ -31,4 +31,5 @@ export interface ITransactionsByContactsFilter {
|
|||||||
numberFormat: INumberFormatQuery;
|
numberFormat: INumberFormatQuery;
|
||||||
noneTransactions: boolean;
|
noneTransactions: boolean;
|
||||||
noneZero: boolean;
|
noneZero: boolean;
|
||||||
|
trackingTags?: Array<{ tagId: number; optionId?: number }>;
|
||||||
}
|
}
|
||||||
|
|||||||
+9
@@ -1,8 +1,17 @@
|
|||||||
import { IsArray, IsOptional } from 'class-validator';
|
import { IsArray, IsOptional } from 'class-validator';
|
||||||
import { TransactionsByContactQueryDto } from '../TransactionsByContact/TransactionsByContactQuery.dto';
|
import { TransactionsByContactQueryDto } from '../TransactionsByContact/TransactionsByContactQuery.dto';
|
||||||
|
import { ApiPropertyOptional } from '@nestjs/swagger';
|
||||||
|
import { TrackingTagAssignmentDto } from '@/modules/TrackingTags/dtos/AssignTrackingTags.dto';
|
||||||
|
|
||||||
export class TransactionsByCustomerQueryDto extends TransactionsByContactQueryDto {
|
export class TransactionsByCustomerQueryDto extends TransactionsByContactQueryDto {
|
||||||
@IsArray()
|
@IsArray()
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
customersIds: number[];
|
customersIds: number[];
|
||||||
|
|
||||||
|
@ApiPropertyOptional({
|
||||||
|
description: 'Tracking tags to filter the report',
|
||||||
|
type: [TrackingTagAssignmentDto],
|
||||||
|
})
|
||||||
|
@IsOptional()
|
||||||
|
trackingTags?: TrackingTagAssignmentDto[];
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-1
@@ -236,7 +236,12 @@ export class TransactionsByCustomersRepository extends TransactionsByContactRepo
|
|||||||
openingDate,
|
openingDate,
|
||||||
receivableAccountsIds,
|
receivableAccountsIds,
|
||||||
customersIds,
|
customersIds,
|
||||||
);
|
)
|
||||||
|
.onBuild((query) => {
|
||||||
|
if (!isEmpty(this.filter.trackingTags)) {
|
||||||
|
query.modify('filterByTrackingTags', this.filter.trackingTags);
|
||||||
|
}
|
||||||
|
});
|
||||||
return openingTransactions;
|
return openingTransactions;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -264,6 +269,10 @@ export class TransactionsByCustomersRepository extends TransactionsByContactRepo
|
|||||||
|
|
||||||
// Filter by accounts.
|
// Filter by accounts.
|
||||||
query.whereIn('accountId', receivableAccountsIds);
|
query.whereIn('accountId', receivableAccountsIds);
|
||||||
|
|
||||||
|
if (!isEmpty(this.filter.trackingTags)) {
|
||||||
|
query.modify('filterByTrackingTags', this.filter.trackingTags);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return transactions;
|
return transactions;
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-1
@@ -1,5 +1,6 @@
|
|||||||
import { IsNotEmpty, IsString } from 'class-validator';
|
import { IsNotEmpty, IsOptional, IsString } from 'class-validator';
|
||||||
import { ApiProperty } from '@nestjs/swagger';
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { TrackingTagAssignmentDto } from '@/modules/TrackingTags/dtos/AssignTrackingTags.dto';
|
||||||
|
|
||||||
export class TransactionsByReferenceQueryDto {
|
export class TransactionsByReferenceQueryDto {
|
||||||
@IsString()
|
@IsString()
|
||||||
@@ -19,4 +20,12 @@ export class TransactionsByReferenceQueryDto {
|
|||||||
required: true,
|
required: true,
|
||||||
})
|
})
|
||||||
referenceId: number;
|
referenceId: number;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'Tracking tags to filter the report',
|
||||||
|
type: [TrackingTagAssignmentDto],
|
||||||
|
required: false,
|
||||||
|
})
|
||||||
|
@IsOptional()
|
||||||
|
trackingTags?: TrackingTagAssignmentDto[];
|
||||||
}
|
}
|
||||||
|
|||||||
+7
@@ -2,6 +2,7 @@ import { AccountTransaction } from '@/modules/Accounts/models/AccountTransaction
|
|||||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
import { ModelObject } from 'objection';
|
import { ModelObject } from 'objection';
|
||||||
|
import { isEmpty } from 'lodash';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class TransactionsByReferenceRepository {
|
export class TransactionsByReferenceRepository {
|
||||||
@@ -21,12 +22,18 @@ export class TransactionsByReferenceRepository {
|
|||||||
public async getTransactions(
|
public async getTransactions(
|
||||||
referenceId: number,
|
referenceId: number,
|
||||||
referenceType: string,
|
referenceType: string,
|
||||||
|
trackingTags?: Array<{ tagId: number; optionId?: number }>,
|
||||||
): Promise<Array<ModelObject<AccountTransaction>>> {
|
): Promise<Array<ModelObject<AccountTransaction>>> {
|
||||||
return this.accountTransactionModel()
|
return this.accountTransactionModel()
|
||||||
.query()
|
.query()
|
||||||
.skipUndefined()
|
.skipUndefined()
|
||||||
.where('reference_id', referenceId)
|
.where('reference_id', referenceId)
|
||||||
.where('reference_type', referenceType)
|
.where('reference_type', referenceType)
|
||||||
|
.onBuild((query) => {
|
||||||
|
if (!isEmpty(trackingTags)) {
|
||||||
|
query.modify('filterByTrackingTags', trackingTags);
|
||||||
|
}
|
||||||
|
})
|
||||||
.withGraphFetched('account');
|
.withGraphFetched('account');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+8
@@ -1,6 +1,7 @@
|
|||||||
import { IsArray, IsOptional } from 'class-validator';
|
import { IsArray, IsOptional } from 'class-validator';
|
||||||
import { TransactionsByContactQueryDto } from '../TransactionsByContact/TransactionsByContactQuery.dto';
|
import { TransactionsByContactQueryDto } from '../TransactionsByContact/TransactionsByContactQuery.dto';
|
||||||
import { ApiPropertyOptional } from '@nestjs/swagger';
|
import { ApiPropertyOptional } from '@nestjs/swagger';
|
||||||
|
import { TrackingTagAssignmentDto } from '@/modules/TrackingTags/dtos/AssignTrackingTags.dto';
|
||||||
|
|
||||||
export class TransactionsByVendorQueryDto extends TransactionsByContactQueryDto {
|
export class TransactionsByVendorQueryDto extends TransactionsByContactQueryDto {
|
||||||
@IsArray()
|
@IsArray()
|
||||||
@@ -10,4 +11,11 @@ export class TransactionsByVendorQueryDto extends TransactionsByContactQueryDto
|
|||||||
example: [1, 2, 3],
|
example: [1, 2, 3],
|
||||||
})
|
})
|
||||||
vendorsIds: number[];
|
vendorsIds: number[];
|
||||||
|
|
||||||
|
@ApiPropertyOptional({
|
||||||
|
description: 'Tracking tags to filter the report',
|
||||||
|
type: [TrackingTagAssignmentDto],
|
||||||
|
})
|
||||||
|
@IsOptional()
|
||||||
|
trackingTags?: TrackingTagAssignmentDto[];
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-1
@@ -242,7 +242,12 @@ export class TransactionsByVendorRepository extends TransactionsByContactReposit
|
|||||||
openingDate,
|
openingDate,
|
||||||
payableAccountsIds,
|
payableAccountsIds,
|
||||||
customersIds,
|
customersIds,
|
||||||
);
|
)
|
||||||
|
.onBuild((query) => {
|
||||||
|
if (!isEmpty(this.filter.trackingTags)) {
|
||||||
|
query.modify('filterByTrackingTags', this.filter.trackingTags);
|
||||||
|
}
|
||||||
|
});
|
||||||
return openingTransactions;
|
return openingTransactions;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -270,6 +275,10 @@ export class TransactionsByVendorRepository extends TransactionsByContactReposit
|
|||||||
|
|
||||||
// Filter by accounts.
|
// Filter by accounts.
|
||||||
query.whereIn('accountId', receivableAccountsIds);
|
query.whereIn('accountId', receivableAccountsIds);
|
||||||
|
|
||||||
|
if (!isEmpty(this.filter.trackingTags)) {
|
||||||
|
query.modify('filterByTrackingTags', this.filter.trackingTags);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return transactions;
|
return transactions;
|
||||||
}
|
}
|
||||||
|
|||||||
+2
@@ -1,5 +1,6 @@
|
|||||||
import { IFinancialSheetCommonMeta, INumberFormatQuery } from "../../types/Report.types";
|
import { IFinancialSheetCommonMeta, INumberFormatQuery } from "../../types/Report.types";
|
||||||
import { IFinancialTable } from "../../types/Table.types";
|
import { IFinancialTable } from "../../types/Table.types";
|
||||||
|
import { ITrackingTagFilter } from "../../types/TrackingTagFilter.types";
|
||||||
|
|
||||||
export interface ITrialBalanceSheetQuery {
|
export interface ITrialBalanceSheetQuery {
|
||||||
fromDate: Date | string;
|
fromDate: Date | string;
|
||||||
@@ -11,6 +12,7 @@ export interface ITrialBalanceSheetQuery {
|
|||||||
onlyActive: boolean;
|
onlyActive: boolean;
|
||||||
accountIds: number[];
|
accountIds: number[];
|
||||||
branchesIds?: number[];
|
branchesIds?: number[];
|
||||||
|
trackingTags?: ITrackingTagFilter[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ITrialBalanceTotal {
|
export interface ITrialBalanceTotal {
|
||||||
|
|||||||
+9
@@ -12,6 +12,7 @@ import {
|
|||||||
import { Transform, Type } from 'class-transformer';
|
import { Transform, Type } from 'class-transformer';
|
||||||
import { parseBoolean } from '@/utils/parse-boolean';
|
import { parseBoolean } from '@/utils/parse-boolean';
|
||||||
import { ApiProperty } from '@nestjs/swagger';
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { TrackingTagAssignmentDto } from '@/modules/TrackingTags/dtos/AssignTrackingTags.dto';
|
||||||
|
|
||||||
export class TrialBalanceSheetQueryDto extends FinancialSheetBranchesQueryDto {
|
export class TrialBalanceSheetQueryDto extends FinancialSheetBranchesQueryDto {
|
||||||
@ApiProperty({
|
@ApiProperty({
|
||||||
@@ -92,4 +93,12 @@ export class TrialBalanceSheetQueryDto extends FinancialSheetBranchesQueryDto {
|
|||||||
@IsArray()
|
@IsArray()
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
accountIds: number[];
|
accountIds: number[];
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'Tracking tags to filter the report',
|
||||||
|
type: [TrackingTagAssignmentDto],
|
||||||
|
required: false,
|
||||||
|
})
|
||||||
|
@IsOptional()
|
||||||
|
trackingTags?: TrackingTagAssignmentDto[];
|
||||||
}
|
}
|
||||||
|
|||||||
+4
@@ -111,5 +111,9 @@ export class TrialBalanceSheetRepository {
|
|||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
query.modify('filterByBranches', this.query.branchesIds);
|
query.modify('filterByBranches', this.query.branchesIds);
|
||||||
}
|
}
|
||||||
|
if (!isEmpty(this.query.trackingTags)) {
|
||||||
|
// @ts-ignore
|
||||||
|
query.modify('filterByTrackingTags', this.query.trackingTags);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
+1
@@ -11,6 +11,7 @@ export interface IVendorBalanceSummaryQuery {
|
|||||||
percentageColumn: boolean;
|
percentageColumn: boolean;
|
||||||
noneTransactions: boolean;
|
noneTransactions: boolean;
|
||||||
noneZero: boolean;
|
noneZero: boolean;
|
||||||
|
trackingTags?: Array<{ tagId: number; optionId?: number }>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IVendorBalanceSummaryAmount {
|
export interface IVendorBalanceSummaryAmount {
|
||||||
|
|||||||
+8
@@ -1,6 +1,7 @@
|
|||||||
import { IsArray, IsOptional } from 'class-validator';
|
import { IsArray, IsOptional } from 'class-validator';
|
||||||
import { ContactBalanceSummaryQueryDto } from '../ContactBalanceSummary/ContactBalanceSummaryQuery.dto';
|
import { ContactBalanceSummaryQueryDto } from '../ContactBalanceSummary/ContactBalanceSummaryQuery.dto';
|
||||||
import { ApiPropertyOptional } from '@nestjs/swagger';
|
import { ApiPropertyOptional } from '@nestjs/swagger';
|
||||||
|
import { TrackingTagAssignmentDto } from '@/modules/TrackingTags/dtos/AssignTrackingTags.dto';
|
||||||
|
|
||||||
export class VendorBalanceSummaryQueryDto extends ContactBalanceSummaryQueryDto {
|
export class VendorBalanceSummaryQueryDto extends ContactBalanceSummaryQueryDto {
|
||||||
@IsArray()
|
@IsArray()
|
||||||
@@ -11,4 +12,11 @@ export class VendorBalanceSummaryQueryDto extends ContactBalanceSummaryQueryDto
|
|||||||
example: [1, 2, 3],
|
example: [1, 2, 3],
|
||||||
})
|
})
|
||||||
vendorsIds: number[];
|
vendorsIds: number[];
|
||||||
|
|
||||||
|
@ApiPropertyOptional({
|
||||||
|
description: 'Tracking tags to filter the report',
|
||||||
|
type: [TrackingTagAssignmentDto],
|
||||||
|
})
|
||||||
|
@IsOptional()
|
||||||
|
trackingTags?: TrackingTagAssignmentDto[];
|
||||||
}
|
}
|
||||||
|
|||||||
+3
@@ -138,6 +138,9 @@ export class VendorBalanceSummaryRepository {
|
|||||||
.onBuild((query) => {
|
.onBuild((query) => {
|
||||||
query.whereIn('accountId', payableAccountsIds);
|
query.whereIn('accountId', payableAccountsIds);
|
||||||
query.modify('filterDateRange', null, asDate);
|
query.modify('filterDateRange', null, asDate);
|
||||||
|
if (!isEmpty(this.filter.trackingTags)) {
|
||||||
|
query.modify('filterByTrackingTags', this.filter.trackingTags);
|
||||||
|
}
|
||||||
query.groupBy('contactId');
|
query.groupBy('contactId');
|
||||||
query.sum('credit as credit');
|
query.sum('credit as credit');
|
||||||
query.sum('debit as debit');
|
query.sum('debit as debit');
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
export interface ITrackingTagFilter {
|
||||||
|
tagId: number;
|
||||||
|
optionId?: number;
|
||||||
|
}
|
||||||
@@ -8,6 +8,7 @@ import {
|
|||||||
} from './types/Ledger.types';
|
} from './types/Ledger.types';
|
||||||
import { ILedger } from './types/Ledger.types';
|
import { ILedger } from './types/Ledger.types';
|
||||||
import { AccountTransaction } from '../Accounts/models/AccountTransaction.model';
|
import { AccountTransaction } from '../Accounts/models/AccountTransaction.model';
|
||||||
|
import { AccountTransactionTrackingTag } from '../TrackingTags/models/AccountTransactionTrackingTag';
|
||||||
import { TenantModelProxy } from '../System/models/TenantBaseModel';
|
import { TenantModelProxy } from '../System/models/TenantBaseModel';
|
||||||
|
|
||||||
// Filter the blank entries.
|
// Filter the blank entries.
|
||||||
@@ -24,6 +25,11 @@ export class LedgerEntriesStorageService {
|
|||||||
private readonly accountTransactionModel: TenantModelProxy<
|
private readonly accountTransactionModel: TenantModelProxy<
|
||||||
typeof AccountTransaction
|
typeof AccountTransaction
|
||||||
>,
|
>,
|
||||||
|
|
||||||
|
@Inject(AccountTransactionTrackingTag.name)
|
||||||
|
private readonly accountTransactionTrackingTagModel: TenantModelProxy<
|
||||||
|
typeof AccountTransactionTrackingTag
|
||||||
|
>,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -71,7 +77,22 @@ export class LedgerEntriesStorageService {
|
|||||||
): Promise<void> => {
|
): Promise<void> => {
|
||||||
const transaction = transformLedgerEntryToTransaction(entry);
|
const transaction = transformLedgerEntryToTransaction(entry);
|
||||||
|
|
||||||
await this.accountTransactionModel().query(trx).insert(transaction);
|
const insertedTransaction = await this.accountTransactionModel()
|
||||||
|
.query(trx)
|
||||||
|
.insert(transaction);
|
||||||
|
|
||||||
|
// Save tracking tag associations if present.
|
||||||
|
if (entry.trackingTags?.length > 0) {
|
||||||
|
const tagAssociations = entry.trackingTags.map((tag) => ({
|
||||||
|
accountTransactionId: insertedTransaction.id,
|
||||||
|
tagId: tag.tagId,
|
||||||
|
optionId: tag.optionId,
|
||||||
|
}));
|
||||||
|
|
||||||
|
await this.accountTransactionTrackingTagModel()
|
||||||
|
.query(trx)
|
||||||
|
.insert(tagAssociations);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -69,6 +69,8 @@ export interface ILedgerEntry {
|
|||||||
createdAt?: Date | string;
|
createdAt?: Date | string;
|
||||||
|
|
||||||
costable?: boolean;
|
costable?: boolean;
|
||||||
|
|
||||||
|
trackingTags?: Array<{ tagId: number; optionId: number }>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ISaveLedgerEntryQueuePayload {
|
export interface ISaveLedgerEntryQueuePayload {
|
||||||
|
|||||||
@@ -56,6 +56,18 @@ export class CreateManualJournalService {
|
|||||||
const authorizedUser = await this.tenancyContext.getSystemUser();
|
const authorizedUser = await this.tenancyContext.getSystemUser();
|
||||||
|
|
||||||
const entries = R.compose(
|
const entries = R.compose(
|
||||||
|
// Map trackingTags to trackingTagAssociations for upsertGraph.
|
||||||
|
R.map((entry: any) => ({
|
||||||
|
...entry,
|
||||||
|
...(entry.trackingTags
|
||||||
|
? {
|
||||||
|
trackingTagAssociations: entry.trackingTags.map((tag) => ({
|
||||||
|
tagId: tag.tagId,
|
||||||
|
optionId: tag.optionId,
|
||||||
|
})),
|
||||||
|
}
|
||||||
|
: {}),
|
||||||
|
})),
|
||||||
// Associate the default index to each item entry.
|
// Associate the default index to each item entry.
|
||||||
assocItemEntriesDefaultIndex,
|
assocItemEntriesDefaultIndex,
|
||||||
)(manualJournalDTO.entries);
|
)(manualJournalDTO.entries);
|
||||||
|
|||||||
@@ -68,6 +68,18 @@ export class EditManualJournal {
|
|||||||
const amount = sumBy(manualJournalDTO.entries, 'credit') || 0;
|
const amount = sumBy(manualJournalDTO.entries, 'credit') || 0;
|
||||||
const date = moment(manualJournalDTO.date).format('YYYY-MM-DD');
|
const date = moment(manualJournalDTO.date).format('YYYY-MM-DD');
|
||||||
|
|
||||||
|
const entries = manualJournalDTO.entries.map((entry: any) => ({
|
||||||
|
...entry,
|
||||||
|
...(entry.trackingTags
|
||||||
|
? {
|
||||||
|
trackingTagAssociations: entry.trackingTags.map((tag) => ({
|
||||||
|
tagId: tag.tagId,
|
||||||
|
optionId: tag.optionId,
|
||||||
|
})),
|
||||||
|
}
|
||||||
|
: {}),
|
||||||
|
}));
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: oldManualJournal.id,
|
id: oldManualJournal.id,
|
||||||
...omit(manualJournalDTO, ['publish', 'attachments']),
|
...omit(manualJournalDTO, ['publish', 'attachments']),
|
||||||
@@ -76,6 +88,7 @@ export class EditManualJournal {
|
|||||||
: {}),
|
: {}),
|
||||||
amount,
|
amount,
|
||||||
date,
|
date,
|
||||||
|
entries,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -52,6 +52,11 @@ export class ManualJournalGL {
|
|||||||
public getManualJournalEntry(entry: ManualJournalEntry): ILedgerEntry {
|
public getManualJournalEntry(entry: ManualJournalEntry): ILedgerEntry {
|
||||||
const commonEntry = this.manualJournalCommonEntry;
|
const commonEntry = this.manualJournalCommonEntry;
|
||||||
|
|
||||||
|
const trackingTags = entry.trackingTagAssociations?.map((assoc) => ({
|
||||||
|
tagId: assoc.tagId,
|
||||||
|
optionId: assoc.optionId,
|
||||||
|
}));
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...commonEntry,
|
...commonEntry,
|
||||||
debit: entry.debit,
|
debit: entry.debit,
|
||||||
@@ -66,6 +71,7 @@ export class ManualJournalGL {
|
|||||||
|
|
||||||
branchId: entry.branchId,
|
branchId: entry.branchId,
|
||||||
projectId: entry.projectId,
|
projectId: entry.projectId,
|
||||||
|
trackingTags,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import {
|
|||||||
Min,
|
Min,
|
||||||
ValidateNested,
|
ValidateNested,
|
||||||
} from 'class-validator';
|
} from 'class-validator';
|
||||||
|
import { TrackingTagAssignmentDto } from '@/modules/TrackingTags/dtos/AssignTrackingTags.dto';
|
||||||
|
|
||||||
export class ManualJournalEntryDto {
|
export class ManualJournalEntryDto {
|
||||||
@ApiProperty({ description: 'Entry index' })
|
@ApiProperty({ description: 'Entry index' })
|
||||||
@@ -63,6 +64,17 @@ export class ManualJournalEntryDto {
|
|||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsInt()
|
@IsInt()
|
||||||
projectId?: number;
|
projectId?: number;
|
||||||
|
|
||||||
|
@IsOptional()
|
||||||
|
@IsArray()
|
||||||
|
@ValidateNested({ each: true })
|
||||||
|
@Type(() => TrackingTagAssignmentDto)
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'The tracking tags of the manual journal entry',
|
||||||
|
type: [TrackingTagAssignmentDto],
|
||||||
|
required: false,
|
||||||
|
})
|
||||||
|
trackingTags?: TrackingTagAssignmentDto[];
|
||||||
}
|
}
|
||||||
|
|
||||||
class AttachmentDto {
|
class AttachmentDto {
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ export class ManualJournalEntry extends BaseModel {
|
|||||||
contact?: Contact;
|
contact?: Contact;
|
||||||
account?: Account;
|
account?: Account;
|
||||||
branch?: Branch;
|
branch?: Branch;
|
||||||
|
trackingTagAssociations?: any[];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Table name.
|
* Table name.
|
||||||
@@ -40,6 +41,7 @@ export class ManualJournalEntry extends BaseModel {
|
|||||||
const { Account } = require('../../Accounts/models/Account.model');
|
const { Account } = require('../../Accounts/models/Account.model');
|
||||||
const { Contact } = require('../../Contacts/models/Contact');
|
const { Contact } = require('../../Contacts/models/Contact');
|
||||||
const { Branch } = require('../../Branches/models/Branch.model');
|
const { Branch } = require('../../Branches/models/Branch.model');
|
||||||
|
const { ManualJournalEntryTrackingTag } = require('../../TrackingTags/models/ManualJournalEntryTrackingTag');
|
||||||
|
|
||||||
return {
|
return {
|
||||||
account: {
|
account: {
|
||||||
@@ -66,6 +68,15 @@ export class ManualJournalEntry extends BaseModel {
|
|||||||
to: 'branches.id',
|
to: 'branches.id',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
trackingTagAssociations: {
|
||||||
|
relation: Model.HasManyRelation,
|
||||||
|
modelClass: ManualJournalEntryTrackingTag,
|
||||||
|
join: {
|
||||||
|
from: 'manual_journals_entries.id',
|
||||||
|
to: 'manual_journal_entry_tracking_tags.manualJournalEntryId',
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ export enum AbilitySubject {
|
|||||||
Project = 'Project',
|
Project = 'Project',
|
||||||
TaxRate = 'TaxRate',
|
TaxRate = 'TaxRate',
|
||||||
CustomField = 'CustomField',
|
CustomField = 'CustomField',
|
||||||
|
TrackingTag = 'TrackingTag',
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IRoleCreatedPayload {
|
export interface IRoleCreatedPayload {
|
||||||
|
|||||||
+13
@@ -91,6 +91,19 @@ export class CommandSaleInvoiceDTOTransformer {
|
|||||||
// Remove tax code from entries.
|
// Remove tax code from entries.
|
||||||
R.map(R.omit(['taxCode'])),
|
R.map(R.omit(['taxCode'])),
|
||||||
|
|
||||||
|
// Map trackingTags to trackingTagAssociations for upsertGraph.
|
||||||
|
R.map((entry: any) => ({
|
||||||
|
...entry,
|
||||||
|
...(entry.trackingTags
|
||||||
|
? {
|
||||||
|
trackingTagAssociations: entry.trackingTags.map((tag) => ({
|
||||||
|
tagId: tag.tagId,
|
||||||
|
optionId: tag.optionId,
|
||||||
|
})),
|
||||||
|
}
|
||||||
|
: {}),
|
||||||
|
})),
|
||||||
|
|
||||||
// Associate the default index for each item entry lin.
|
// Associate the default index for each item entry lin.
|
||||||
assocItemEntriesDefaultIndex,
|
assocItemEntriesDefaultIndex,
|
||||||
)(asyncEntries);
|
)(asyncEntries);
|
||||||
|
|||||||
@@ -109,6 +109,11 @@ export class InvoiceGL {
|
|||||||
const localAmount =
|
const localAmount =
|
||||||
entry.totalExcludingTax * this.saleInvoice.exchangeRate;
|
entry.totalExcludingTax * this.saleInvoice.exchangeRate;
|
||||||
|
|
||||||
|
const trackingTags = entry.trackingTagAssociations?.map((assoc) => ({
|
||||||
|
tagId: assoc.tagId,
|
||||||
|
optionId: assoc.optionId,
|
||||||
|
}));
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...commonEntry,
|
...commonEntry,
|
||||||
credit: localAmount,
|
credit: localAmount,
|
||||||
@@ -119,6 +124,7 @@ export class InvoiceGL {
|
|||||||
accountNormal: AccountNormal.CREDIT,
|
accountNormal: AccountNormal.CREDIT,
|
||||||
taxRateId: entry.taxRateId,
|
taxRateId: entry.taxRateId,
|
||||||
taxRate: entry.taxRate,
|
taxRate: entry.taxRate,
|
||||||
|
trackingTags,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -40,6 +40,11 @@ import { PaymentReceived } from '@/modules/PaymentReceived/models/PaymentReceive
|
|||||||
import { Model } from 'objection';
|
import { Model } from 'objection';
|
||||||
import { ClsModule } from 'nestjs-cls';
|
import { ClsModule } from 'nestjs-cls';
|
||||||
import { TenantUser } from './models/TenantUser.model';
|
import { TenantUser } from './models/TenantUser.model';
|
||||||
|
import { TrackingTag } from '@/modules/TrackingTags/models/TrackingTag';
|
||||||
|
import { TrackingTagOption } from '@/modules/TrackingTags/models/TrackingTagOption';
|
||||||
|
import { ItemEntryTrackingTag } from '@/modules/TrackingTags/models/ItemEntryTrackingTag';
|
||||||
|
import { ManualJournalEntryTrackingTag } from '@/modules/TrackingTags/models/ManualJournalEntryTrackingTag';
|
||||||
|
import { AccountTransactionTrackingTag } from '@/modules/TrackingTags/models/AccountTransactionTrackingTag';
|
||||||
|
|
||||||
const models = [
|
const models = [
|
||||||
Item,
|
Item,
|
||||||
@@ -80,6 +85,11 @@ const models = [
|
|||||||
PaymentReceived,
|
PaymentReceived,
|
||||||
PaymentReceivedEntry,
|
PaymentReceivedEntry,
|
||||||
TenantUser,
|
TenantUser,
|
||||||
|
TrackingTag,
|
||||||
|
TrackingTagOption,
|
||||||
|
ItemEntryTrackingTag,
|
||||||
|
ManualJournalEntryTrackingTag,
|
||||||
|
AccountTransactionTrackingTag,
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -0,0 +1,64 @@
|
|||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { CreateTrackingTagService } from './commands/CreateTrackingTag.service';
|
||||||
|
import { EditTrackingTagService } from './commands/EditTrackingTag.service';
|
||||||
|
import { DeleteTrackingTagService } from './commands/DeleteTrackingTag.service';
|
||||||
|
import { GetTrackingTagsService } from './queries/GetTrackingTags.service';
|
||||||
|
import { GetTrackingTagService } from './queries/GetTrackingTag.service';
|
||||||
|
import { CreateTrackingTagDto, EditTrackingTagDto } from './dtos/TrackingTag.dto';
|
||||||
|
import { TrackingTag } from './models/TrackingTag';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class TrackingTagsApplication {
|
||||||
|
constructor(
|
||||||
|
private createService: CreateTrackingTagService,
|
||||||
|
private editService: EditTrackingTagService,
|
||||||
|
private deleteService: DeleteTrackingTagService,
|
||||||
|
private getTagsService: GetTrackingTagsService,
|
||||||
|
private getTagService: GetTrackingTagService,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new tracking tag.
|
||||||
|
* @param {CreateTrackingTagDto} dto
|
||||||
|
* @returns {Promise<TrackingTag>}
|
||||||
|
*/
|
||||||
|
public createTrackingTag = (dto: CreateTrackingTagDto): Promise<TrackingTag> => {
|
||||||
|
return this.createService.createTrackingTag(dto);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Edits a tracking tag.
|
||||||
|
* @param {number} tagId
|
||||||
|
* @param {EditTrackingTagDto} dto
|
||||||
|
* @returns {Promise<TrackingTag>}
|
||||||
|
*/
|
||||||
|
public editTrackingTag = (tagId: number, dto: EditTrackingTagDto): Promise<TrackingTag> => {
|
||||||
|
return this.editService.editTrackingTag(tagId, dto);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes a tracking tag.
|
||||||
|
* @param {number} tagId
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
public deleteTrackingTag = (tagId: number): Promise<void> => {
|
||||||
|
return this.deleteService.deleteTrackingTag(tagId);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves all tracking tags.
|
||||||
|
* @returns {Promise<TrackingTag[]>}
|
||||||
|
*/
|
||||||
|
public getTrackingTags = (): Promise<TrackingTag[]> => {
|
||||||
|
return this.getTagsService.getTrackingTags();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves a tracking tag by ID.
|
||||||
|
* @param {number} tagId
|
||||||
|
* @returns {Promise<TrackingTag>}
|
||||||
|
*/
|
||||||
|
public getTrackingTag = (tagId: number): Promise<TrackingTag> => {
|
||||||
|
return this.getTagService.getTrackingTag(tagId);
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
import {
|
||||||
|
Body,
|
||||||
|
Controller,
|
||||||
|
Delete,
|
||||||
|
Get,
|
||||||
|
Param,
|
||||||
|
Post,
|
||||||
|
Put,
|
||||||
|
UseGuards,
|
||||||
|
} from '@nestjs/common';
|
||||||
|
import { TrackingTagsApplication } from './TrackingTags.application';
|
||||||
|
import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
|
||||||
|
import {
|
||||||
|
CreateTrackingTagDto,
|
||||||
|
EditTrackingTagDto,
|
||||||
|
} from './dtos/TrackingTag.dto';
|
||||||
|
import { ApiCommonHeaders } from '@/common/decorators/ApiCommonHeaders';
|
||||||
|
import { RequirePermission } from '@/modules/Roles/RequirePermission.decorator';
|
||||||
|
import { PermissionGuard } from '@/modules/Roles/Permission.guard';
|
||||||
|
import { AuthorizationGuard } from '@/modules/Roles/Authorization.guard';
|
||||||
|
import { AbilitySubject } from '@/modules/Roles/Roles.types';
|
||||||
|
|
||||||
|
@Controller('tracking-tags')
|
||||||
|
@ApiTags('Tracking Tags')
|
||||||
|
@ApiCommonHeaders()
|
||||||
|
@UseGuards(AuthorizationGuard, PermissionGuard)
|
||||||
|
export class TrackingTagsController {
|
||||||
|
constructor(private readonly trackingTagsApplication: TrackingTagsApplication) {}
|
||||||
|
|
||||||
|
@Post()
|
||||||
|
@RequirePermission('Create', AbilitySubject.TrackingTag)
|
||||||
|
@ApiOperation({ summary: 'Create a new tracking tag.' })
|
||||||
|
@ApiResponse({
|
||||||
|
status: 201,
|
||||||
|
description: 'The tracking tag has been successfully created.',
|
||||||
|
})
|
||||||
|
public createTrackingTag(@Body() dto: CreateTrackingTagDto) {
|
||||||
|
return this.trackingTagsApplication.createTrackingTag(dto);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Put(':id')
|
||||||
|
@RequirePermission('Edit', AbilitySubject.TrackingTag)
|
||||||
|
@ApiOperation({ summary: 'Edit the given tracking tag.' })
|
||||||
|
@ApiResponse({
|
||||||
|
status: 200,
|
||||||
|
description: 'The tracking tag has been successfully updated.',
|
||||||
|
})
|
||||||
|
public editTrackingTag(
|
||||||
|
@Param('id') tagId: number,
|
||||||
|
@Body() dto: EditTrackingTagDto,
|
||||||
|
) {
|
||||||
|
return this.trackingTagsApplication.editTrackingTag(tagId, dto);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Delete(':id')
|
||||||
|
@RequirePermission('Delete', AbilitySubject.TrackingTag)
|
||||||
|
@ApiOperation({ summary: 'Delete the given tracking tag.' })
|
||||||
|
@ApiResponse({
|
||||||
|
status: 200,
|
||||||
|
description: 'The tracking tag has been successfully deleted.',
|
||||||
|
})
|
||||||
|
public deleteTrackingTag(@Param('id') tagId: number) {
|
||||||
|
return this.trackingTagsApplication.deleteTrackingTag(tagId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Get()
|
||||||
|
@RequirePermission('View', AbilitySubject.TrackingTag)
|
||||||
|
@ApiOperation({ summary: 'Retrieves all tracking tags.' })
|
||||||
|
@ApiResponse({
|
||||||
|
status: 200,
|
||||||
|
description: 'The tracking tags have been successfully retrieved.',
|
||||||
|
})
|
||||||
|
public getTrackingTags() {
|
||||||
|
return this.trackingTagsApplication.getTrackingTags();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Get(':id')
|
||||||
|
@RequirePermission('View', AbilitySubject.TrackingTag)
|
||||||
|
@ApiOperation({ summary: 'Retrieves the tracking tag details.' })
|
||||||
|
@ApiResponse({
|
||||||
|
status: 200,
|
||||||
|
description: 'The tracking tag details have been successfully retrieved.',
|
||||||
|
})
|
||||||
|
public getTrackingTag(@Param('id') tagId: number) {
|
||||||
|
return this.trackingTagsApplication.getTrackingTag(tagId);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
import { Module } from '@nestjs/common';
|
||||||
|
import { TrackingTagsController } from './TrackingTags.controller';
|
||||||
|
import { TrackingTagsApplication } from './TrackingTags.application';
|
||||||
|
import { CreateTrackingTagService } from './commands/CreateTrackingTag.service';
|
||||||
|
import { EditTrackingTagService } from './commands/EditTrackingTag.service';
|
||||||
|
import { DeleteTrackingTagService } from './commands/DeleteTrackingTag.service';
|
||||||
|
import { GetTrackingTagsService } from './queries/GetTrackingTags.service';
|
||||||
|
import { GetTrackingTagService } from './queries/GetTrackingTag.service';
|
||||||
|
import { RegisterTenancyModel } from '../Tenancy/TenancyModels/Tenancy.module';
|
||||||
|
import { TrackingTag } from './models/TrackingTag';
|
||||||
|
import { TrackingTagOption } from './models/TrackingTagOption';
|
||||||
|
import { ItemEntryTrackingTag } from './models/ItemEntryTrackingTag';
|
||||||
|
import { ManualJournalEntryTrackingTag } from './models/ManualJournalEntryTrackingTag';
|
||||||
|
import { AccountTransactionTrackingTag } from './models/AccountTransactionTrackingTag';
|
||||||
|
|
||||||
|
const models = [
|
||||||
|
RegisterTenancyModel(TrackingTag),
|
||||||
|
RegisterTenancyModel(TrackingTagOption),
|
||||||
|
RegisterTenancyModel(ItemEntryTrackingTag),
|
||||||
|
RegisterTenancyModel(ManualJournalEntryTrackingTag),
|
||||||
|
RegisterTenancyModel(AccountTransactionTrackingTag),
|
||||||
|
];
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
imports: [...models],
|
||||||
|
controllers: [TrackingTagsController],
|
||||||
|
providers: [
|
||||||
|
TrackingTagsApplication,
|
||||||
|
CreateTrackingTagService,
|
||||||
|
EditTrackingTagService,
|
||||||
|
DeleteTrackingTagService,
|
||||||
|
GetTrackingTagsService,
|
||||||
|
GetTrackingTagService,
|
||||||
|
],
|
||||||
|
exports: [
|
||||||
|
GetTrackingTagsService,
|
||||||
|
GetTrackingTagService,
|
||||||
|
...models,
|
||||||
|
],
|
||||||
|
})
|
||||||
|
export class TrackingTagsModule {}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { Inject } from '@nestjs/common';
|
||||||
|
import { TrackingTag } from '../models/TrackingTag';
|
||||||
|
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||||
|
import { CreateTrackingTagDto } from '../dtos/TrackingTag.dto';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class CreateTrackingTagService {
|
||||||
|
constructor(
|
||||||
|
@Inject(TrackingTag.name)
|
||||||
|
private trackingTagModel: TenantModelProxy<typeof TrackingTag>,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new tracking tag with options.
|
||||||
|
* @param {CreateTrackingTagDto} dto
|
||||||
|
* @returns {Promise<TrackingTag>}
|
||||||
|
*/
|
||||||
|
public createTrackingTag = async (dto: CreateTrackingTagDto): Promise<TrackingTag> => {
|
||||||
|
const tag = await this.trackingTagModel()
|
||||||
|
.query()
|
||||||
|
.insertGraphAndFetch({
|
||||||
|
name: dto.name,
|
||||||
|
description: dto.description,
|
||||||
|
active: dto.active,
|
||||||
|
options: dto.options.map((opt) => ({
|
||||||
|
name: opt.name,
|
||||||
|
active: opt.active,
|
||||||
|
})),
|
||||||
|
});
|
||||||
|
|
||||||
|
return tag;
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { Inject } from '@nestjs/common';
|
||||||
|
import { TrackingTag } from '../models/TrackingTag';
|
||||||
|
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class DeleteTrackingTagService {
|
||||||
|
constructor(
|
||||||
|
@Inject(TrackingTag.name)
|
||||||
|
private trackingTagModel: TenantModelProxy<typeof TrackingTag>,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes a tracking tag.
|
||||||
|
* @param {number} tagId
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
public deleteTrackingTag = async (tagId: number): Promise<void> => {
|
||||||
|
const tag = await this.trackingTagModel()
|
||||||
|
.query()
|
||||||
|
.findById(tagId)
|
||||||
|
.throwIfNotFound();
|
||||||
|
|
||||||
|
await this.trackingTagModel().query().deleteById(tagId);
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
import { Injectable, NotFoundException } from '@nestjs/common';
|
||||||
|
import { Inject } from '@nestjs/common';
|
||||||
|
import { TrackingTag } from '../models/TrackingTag';
|
||||||
|
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||||
|
import { EditTrackingTagDto } from '../dtos/TrackingTag.dto';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class EditTrackingTagService {
|
||||||
|
constructor(
|
||||||
|
@Inject(TrackingTag.name)
|
||||||
|
private trackingTagModel: TenantModelProxy<typeof TrackingTag>,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Edits a tracking tag.
|
||||||
|
* @param {number} tagId
|
||||||
|
* @param {EditTrackingTagDto} dto
|
||||||
|
* @returns {Promise<TrackingTag>}
|
||||||
|
*/
|
||||||
|
public editTrackingTag = async (
|
||||||
|
tagId: number,
|
||||||
|
dto: EditTrackingTagDto,
|
||||||
|
): Promise<TrackingTag> => {
|
||||||
|
const tag = await this.trackingTagModel()
|
||||||
|
.query()
|
||||||
|
.findById(tagId)
|
||||||
|
.throwIfNotFound();
|
||||||
|
|
||||||
|
const updatePayload: any = {};
|
||||||
|
|
||||||
|
if (dto.name !== undefined) updatePayload.name = dto.name;
|
||||||
|
if (dto.description !== undefined) updatePayload.description = dto.description;
|
||||||
|
if (dto.active !== undefined) updatePayload.active = dto.active;
|
||||||
|
|
||||||
|
if (dto.options) {
|
||||||
|
updatePayload.options = dto.options.map((opt) => ({
|
||||||
|
...(opt.id ? { id: opt.id } : {}),
|
||||||
|
name: opt.name,
|
||||||
|
active: opt.active,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.trackingTagModel()
|
||||||
|
.query()
|
||||||
|
.upsertGraphAndFetch({
|
||||||
|
id: tagId,
|
||||||
|
...updatePayload,
|
||||||
|
});
|
||||||
|
|
||||||
|
const updatedTag = await this.trackingTagModel()
|
||||||
|
.query()
|
||||||
|
.findById(tagId)
|
||||||
|
.withGraphFetched('options')
|
||||||
|
.throwIfNotFound();
|
||||||
|
|
||||||
|
return updatedTag;
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { IsInt, IsNotEmpty, IsOptional, ValidateNested } from 'class-validator';
|
||||||
|
import { Type } from 'class-transformer';
|
||||||
|
|
||||||
|
export class TrackingTagAssignmentDto {
|
||||||
|
@IsInt()
|
||||||
|
@IsNotEmpty()
|
||||||
|
@ApiProperty({ description: 'Tag ID', example: 1 })
|
||||||
|
tagId: number;
|
||||||
|
|
||||||
|
@IsInt()
|
||||||
|
@IsOptional()
|
||||||
|
@ApiProperty({ description: 'Option ID', example: 5 })
|
||||||
|
optionId?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class AssignTrackingTagsDto {
|
||||||
|
@ValidateNested({ each: true })
|
||||||
|
@Type(() => TrackingTagAssignmentDto)
|
||||||
|
@ApiProperty({ description: 'Tracking tag assignments', type: [TrackingTagAssignmentDto] })
|
||||||
|
assignments: TrackingTagAssignmentDto[];
|
||||||
|
}
|
||||||
@@ -0,0 +1,99 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import {
|
||||||
|
IsArray,
|
||||||
|
IsBoolean,
|
||||||
|
IsInt,
|
||||||
|
IsNotEmpty,
|
||||||
|
IsOptional,
|
||||||
|
IsString,
|
||||||
|
ValidateNested,
|
||||||
|
} from 'class-validator';
|
||||||
|
import { Type } from 'class-transformer';
|
||||||
|
|
||||||
|
export class TrackingTagOptionDto {
|
||||||
|
@IsInt()
|
||||||
|
@IsOptional()
|
||||||
|
@ApiProperty({ description: 'Option ID (for updates)', required: false })
|
||||||
|
id?: number;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
@ApiProperty({ description: 'Option name', example: 'New York' })
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
@IsBoolean()
|
||||||
|
@IsOptional()
|
||||||
|
@ApiProperty({ description: 'Whether the option is active', required: false, example: true })
|
||||||
|
active?: boolean = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class CreateTrackingTagDto {
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
@ApiProperty({ description: 'Tag name', example: 'Location' })
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@IsOptional()
|
||||||
|
@ApiProperty({ description: 'Tag description', required: false, example: 'Business location tracking' })
|
||||||
|
description?: string;
|
||||||
|
|
||||||
|
@IsBoolean()
|
||||||
|
@IsOptional()
|
||||||
|
@ApiProperty({ description: 'Whether the tag is active', required: false, example: true })
|
||||||
|
active?: boolean = true;
|
||||||
|
|
||||||
|
@IsArray()
|
||||||
|
@ValidateNested({ each: true })
|
||||||
|
@Type(() => TrackingTagOptionDto)
|
||||||
|
@ApiProperty({ description: 'Tag options', type: [TrackingTagOptionDto] })
|
||||||
|
options: TrackingTagOptionDto[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export class EditTrackingTagDto {
|
||||||
|
@IsString()
|
||||||
|
@IsOptional()
|
||||||
|
@ApiProperty({ description: 'Tag name', required: false, example: 'Location' })
|
||||||
|
name?: string;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@IsOptional()
|
||||||
|
@ApiProperty({ description: 'Tag description', required: false, example: 'Business location tracking' })
|
||||||
|
description?: string;
|
||||||
|
|
||||||
|
@IsBoolean()
|
||||||
|
@IsOptional()
|
||||||
|
@ApiProperty({ description: 'Whether the tag is active', required: false, example: true })
|
||||||
|
active?: boolean;
|
||||||
|
|
||||||
|
@IsArray()
|
||||||
|
@ValidateNested({ each: true })
|
||||||
|
@Type(() => TrackingTagOptionDto)
|
||||||
|
@IsOptional()
|
||||||
|
@ApiProperty({ description: 'Tag options', type: [TrackingTagOptionDto], required: false })
|
||||||
|
options?: TrackingTagOptionDto[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export class CreateTrackingTagOptionDto {
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
@ApiProperty({ description: 'Option name', example: 'New York' })
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
@IsBoolean()
|
||||||
|
@IsOptional()
|
||||||
|
@ApiProperty({ description: 'Whether the option is active', required: false, example: true })
|
||||||
|
active?: boolean = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class EditTrackingTagOptionDto {
|
||||||
|
@IsString()
|
||||||
|
@IsOptional()
|
||||||
|
@ApiProperty({ description: 'Option name', required: false, example: 'New York' })
|
||||||
|
name?: string;
|
||||||
|
|
||||||
|
@IsBoolean()
|
||||||
|
@IsOptional()
|
||||||
|
@ApiProperty({ description: 'Whether the option is active', required: false, example: true })
|
||||||
|
active?: boolean;
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
import { Model } from 'objection';
|
||||||
|
import { BaseModel } from '@/models/Model';
|
||||||
|
import { TrackingTag } from './TrackingTag';
|
||||||
|
import { TrackingTagOption } from './TrackingTagOption';
|
||||||
|
import { AccountTransaction } from '@/modules/Accounts/models/AccountTransaction.model';
|
||||||
|
|
||||||
|
export class AccountTransactionTrackingTag extends BaseModel {
|
||||||
|
public accountTransactionId!: number;
|
||||||
|
public tagId!: number;
|
||||||
|
public optionId!: number;
|
||||||
|
|
||||||
|
public tag!: TrackingTag;
|
||||||
|
public option!: TrackingTagOption;
|
||||||
|
public accountTransaction!: AccountTransaction;
|
||||||
|
|
||||||
|
static get tableName() {
|
||||||
|
return 'account_transaction_tracking_tags';
|
||||||
|
}
|
||||||
|
|
||||||
|
static get idColumn() {
|
||||||
|
return ['accountTransactionId', 'tagId'];
|
||||||
|
}
|
||||||
|
|
||||||
|
static get timestamps() {
|
||||||
|
return ['createdAt', 'updatedAt'];
|
||||||
|
}
|
||||||
|
|
||||||
|
static get relationMappings() {
|
||||||
|
const { TrackingTag } = require('./TrackingTag');
|
||||||
|
const { TrackingTagOption } = require('./TrackingTagOption');
|
||||||
|
const { AccountTransaction } = require('../../Accounts/models/AccountTransaction.model');
|
||||||
|
|
||||||
|
return {
|
||||||
|
tag: {
|
||||||
|
relation: Model.BelongsToOneRelation,
|
||||||
|
modelClass: TrackingTag,
|
||||||
|
join: {
|
||||||
|
from: 'account_transaction_tracking_tags.tagId',
|
||||||
|
to: 'tracking_tags.id',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
option: {
|
||||||
|
relation: Model.BelongsToOneRelation,
|
||||||
|
modelClass: TrackingTagOption,
|
||||||
|
join: {
|
||||||
|
from: 'account_transaction_tracking_tags.optionId',
|
||||||
|
to: 'tracking_tag_options.id',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
accountTransaction: {
|
||||||
|
relation: Model.BelongsToOneRelation,
|
||||||
|
modelClass: AccountTransaction,
|
||||||
|
join: {
|
||||||
|
from: 'account_transaction_tracking_tags.accountTransactionId',
|
||||||
|
to: 'accounts_transactions.id',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
import { Model } from 'objection';
|
||||||
|
import { BaseModel } from '@/models/Model';
|
||||||
|
import { TrackingTag } from './TrackingTag';
|
||||||
|
import { TrackingTagOption } from './TrackingTagOption';
|
||||||
|
import { ItemEntry } from '@/modules/TransactionItemEntry/models/ItemEntry';
|
||||||
|
|
||||||
|
export class ItemEntryTrackingTag extends BaseModel {
|
||||||
|
public itemEntryId!: number;
|
||||||
|
public tagId!: number;
|
||||||
|
public optionId!: number;
|
||||||
|
|
||||||
|
public tag!: TrackingTag;
|
||||||
|
public option!: TrackingTagOption;
|
||||||
|
public itemEntry!: ItemEntry;
|
||||||
|
|
||||||
|
static get tableName() {
|
||||||
|
return 'item_entry_tracking_tags';
|
||||||
|
}
|
||||||
|
|
||||||
|
static get idColumn() {
|
||||||
|
return ['itemEntryId', 'tagId'];
|
||||||
|
}
|
||||||
|
|
||||||
|
static get timestamps() {
|
||||||
|
return ['createdAt', 'updatedAt'];
|
||||||
|
}
|
||||||
|
|
||||||
|
static get relationMappings() {
|
||||||
|
const { TrackingTag } = require('./TrackingTag');
|
||||||
|
const { TrackingTagOption } = require('./TrackingTagOption');
|
||||||
|
const { ItemEntry } = require('../../TransactionItemEntry/models/ItemEntry');
|
||||||
|
|
||||||
|
return {
|
||||||
|
tag: {
|
||||||
|
relation: Model.BelongsToOneRelation,
|
||||||
|
modelClass: TrackingTag,
|
||||||
|
join: {
|
||||||
|
from: 'item_entry_tracking_tags.tagId',
|
||||||
|
to: 'tracking_tags.id',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
option: {
|
||||||
|
relation: Model.BelongsToOneRelation,
|
||||||
|
modelClass: TrackingTagOption,
|
||||||
|
join: {
|
||||||
|
from: 'item_entry_tracking_tags.optionId',
|
||||||
|
to: 'tracking_tag_options.id',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
itemEntry: {
|
||||||
|
relation: Model.BelongsToOneRelation,
|
||||||
|
modelClass: ItemEntry,
|
||||||
|
join: {
|
||||||
|
from: 'item_entry_tracking_tags.itemEntryId',
|
||||||
|
to: 'items_entries.id',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
import { Model } from 'objection';
|
||||||
|
import { BaseModel } from '@/models/Model';
|
||||||
|
import { TrackingTag } from './TrackingTag';
|
||||||
|
import { TrackingTagOption } from './TrackingTagOption';
|
||||||
|
import { ManualJournalEntry } from '@/modules/ManualJournals/models/ManualJournalEntry';
|
||||||
|
|
||||||
|
export class ManualJournalEntryTrackingTag extends BaseModel {
|
||||||
|
public manualJournalEntryId!: number;
|
||||||
|
public tagId!: number;
|
||||||
|
public optionId!: number;
|
||||||
|
|
||||||
|
public tag!: TrackingTag;
|
||||||
|
public option!: TrackingTagOption;
|
||||||
|
public manualJournalEntry!: ManualJournalEntry;
|
||||||
|
|
||||||
|
static get tableName() {
|
||||||
|
return 'manual_journal_entry_tracking_tags';
|
||||||
|
}
|
||||||
|
|
||||||
|
static get idColumn() {
|
||||||
|
return ['manualJournalEntryId', 'tagId'];
|
||||||
|
}
|
||||||
|
|
||||||
|
static get timestamps() {
|
||||||
|
return ['createdAt', 'updatedAt'];
|
||||||
|
}
|
||||||
|
|
||||||
|
static get relationMappings() {
|
||||||
|
const { TrackingTag } = require('./TrackingTag');
|
||||||
|
const { TrackingTagOption } = require('./TrackingTagOption');
|
||||||
|
const { ManualJournalEntry } = require('../../ManualJournals/models/ManualJournalEntry');
|
||||||
|
|
||||||
|
return {
|
||||||
|
tag: {
|
||||||
|
relation: Model.BelongsToOneRelation,
|
||||||
|
modelClass: TrackingTag,
|
||||||
|
join: {
|
||||||
|
from: 'manual_journal_entry_tracking_tags.tagId',
|
||||||
|
to: 'tracking_tags.id',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
option: {
|
||||||
|
relation: Model.BelongsToOneRelation,
|
||||||
|
modelClass: TrackingTagOption,
|
||||||
|
join: {
|
||||||
|
from: 'manual_journal_entry_tracking_tags.optionId',
|
||||||
|
to: 'tracking_tag_options.id',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
manualJournalEntry: {
|
||||||
|
relation: Model.BelongsToOneRelation,
|
||||||
|
modelClass: ManualJournalEntry,
|
||||||
|
join: {
|
||||||
|
from: 'manual_journal_entry_tracking_tags.manualJournalEntryId',
|
||||||
|
to: 'manual_journals_entries.id',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
import { Model } from 'objection';
|
||||||
|
import { TenantBaseModel } from '@/modules/System/models/TenantBaseModel';
|
||||||
|
import { TrackingTagOption } from './TrackingTagOption';
|
||||||
|
|
||||||
|
export class TrackingTag extends TenantBaseModel {
|
||||||
|
public name!: string;
|
||||||
|
public description!: string | null;
|
||||||
|
public active!: boolean;
|
||||||
|
|
||||||
|
public options!: TrackingTagOption[];
|
||||||
|
|
||||||
|
static get tableName() {
|
||||||
|
return 'tracking_tags';
|
||||||
|
}
|
||||||
|
|
||||||
|
static get timestamps() {
|
||||||
|
return ['createdAt', 'updatedAt'];
|
||||||
|
}
|
||||||
|
|
||||||
|
static get relationMappings() {
|
||||||
|
const { TrackingTagOption } = require('./TrackingTagOption');
|
||||||
|
|
||||||
|
return {
|
||||||
|
options: {
|
||||||
|
relation: Model.HasManyRelation,
|
||||||
|
modelClass: TrackingTagOption,
|
||||||
|
join: {
|
||||||
|
from: 'tracking_tags.id',
|
||||||
|
to: 'tracking_tag_options.tagId',
|
||||||
|
},
|
||||||
|
filter(query) {
|
||||||
|
query.where('active', true);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
import { Model } from 'objection';
|
||||||
|
import { BaseModel } from '@/models/Model';
|
||||||
|
import { TrackingTag } from './TrackingTag';
|
||||||
|
|
||||||
|
export class TrackingTagOption extends BaseModel {
|
||||||
|
public tagId!: number;
|
||||||
|
public name!: string;
|
||||||
|
public active!: boolean;
|
||||||
|
|
||||||
|
public tag!: TrackingTag;
|
||||||
|
|
||||||
|
static get tableName() {
|
||||||
|
return 'tracking_tag_options';
|
||||||
|
}
|
||||||
|
|
||||||
|
static get timestamps() {
|
||||||
|
return ['createdAt', 'updatedAt'];
|
||||||
|
}
|
||||||
|
|
||||||
|
static get relationMappings() {
|
||||||
|
const { TrackingTag } = require('./TrackingTag');
|
||||||
|
|
||||||
|
return {
|
||||||
|
tag: {
|
||||||
|
relation: Model.BelongsToOneRelation,
|
||||||
|
modelClass: TrackingTag,
|
||||||
|
join: {
|
||||||
|
from: 'tracking_tag_options.tagId',
|
||||||
|
to: 'tracking_tags.id',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import { Injectable, NotFoundException } from '@nestjs/common';
|
||||||
|
import { Inject } from '@nestjs/common';
|
||||||
|
import { TrackingTag } from '../models/TrackingTag';
|
||||||
|
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class GetTrackingTagService {
|
||||||
|
constructor(
|
||||||
|
@Inject(TrackingTag.name)
|
||||||
|
private trackingTagModel: TenantModelProxy<typeof TrackingTag>,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves a tracking tag by ID with its options.
|
||||||
|
* @param {number} tagId
|
||||||
|
* @returns {Promise<TrackingTag>}
|
||||||
|
*/
|
||||||
|
public getTrackingTag = async (tagId: number): Promise<TrackingTag> => {
|
||||||
|
const tag = await this.trackingTagModel()
|
||||||
|
.query()
|
||||||
|
.findById(tagId)
|
||||||
|
.withGraphFetched('options');
|
||||||
|
|
||||||
|
if (!tag) {
|
||||||
|
throw new NotFoundException('Tracking tag not found.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return tag;
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { Inject } from '@nestjs/common';
|
||||||
|
import { TrackingTag } from '../models/TrackingTag';
|
||||||
|
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class GetTrackingTagsService {
|
||||||
|
constructor(
|
||||||
|
@Inject(TrackingTag.name)
|
||||||
|
private trackingTagModel: TenantModelProxy<typeof TrackingTag>,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves all tracking tags with their options.
|
||||||
|
* @returns {Promise<TrackingTag[]>}
|
||||||
|
*/
|
||||||
|
public getTrackingTags = async (): Promise<TrackingTag[]> => {
|
||||||
|
return this.trackingTagModel()
|
||||||
|
.query()
|
||||||
|
.withGraphFetched('options');
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@ import { ToNumber } from '@/common/decorators/Validators';
|
|||||||
import { DiscountType } from '@/common/types/Discount';
|
import { DiscountType } from '@/common/types/Discount';
|
||||||
import { ApiProperty } from '@nestjs/swagger';
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
import {
|
import {
|
||||||
|
IsArray,
|
||||||
IsEnum,
|
IsEnum,
|
||||||
IsIn,
|
IsIn,
|
||||||
IsInt,
|
IsInt,
|
||||||
@@ -9,7 +10,10 @@ import {
|
|||||||
IsNumber,
|
IsNumber,
|
||||||
IsOptional,
|
IsOptional,
|
||||||
IsString,
|
IsString,
|
||||||
|
ValidateNested,
|
||||||
} from 'class-validator';
|
} from 'class-validator';
|
||||||
|
import { Type } from 'class-transformer';
|
||||||
|
import { TrackingTagAssignmentDto } from '@/modules/TrackingTags/dtos/AssignTrackingTags.dto';
|
||||||
|
|
||||||
export class ItemEntryDto {
|
export class ItemEntryDto {
|
||||||
@IsInt()
|
@IsInt()
|
||||||
@@ -153,4 +157,15 @@ export class ItemEntryDto {
|
|||||||
example: 1021,
|
example: 1021,
|
||||||
})
|
})
|
||||||
costAccountId?: number;
|
costAccountId?: number;
|
||||||
|
|
||||||
|
@IsOptional()
|
||||||
|
@IsArray()
|
||||||
|
@ValidateNested({ each: true })
|
||||||
|
@Type(() => TrackingTagAssignmentDto)
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'The tracking tags of the item entry',
|
||||||
|
type: [TrackingTagAssignmentDto],
|
||||||
|
required: false,
|
||||||
|
})
|
||||||
|
trackingTags?: TrackingTagAssignmentDto[];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ export class ItemEntry extends BaseModel {
|
|||||||
|
|
||||||
item: Item;
|
item: Item;
|
||||||
allocatedCostEntries: BillLandedCostEntry[];
|
allocatedCostEntries: BillLandedCostEntry[];
|
||||||
|
trackingTagAssociations: any[];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Table name.
|
* Table name.
|
||||||
@@ -190,6 +191,7 @@ export class ItemEntry extends BaseModel {
|
|||||||
const { SaleReceipt } = require('../../SaleReceipts/models/SaleReceipt');
|
const { SaleReceipt } = require('../../SaleReceipts/models/SaleReceipt');
|
||||||
const { SaleEstimate } = require('../../SaleEstimates/models/SaleEstimate');
|
const { SaleEstimate } = require('../../SaleEstimates/models/SaleEstimate');
|
||||||
const { TaxRateModel } = require('../../TaxRates/models/TaxRate.model');
|
const { TaxRateModel } = require('../../TaxRates/models/TaxRate.model');
|
||||||
|
const { ItemEntryTrackingTag } = require('../../TrackingTags/models/ItemEntryTrackingTag');
|
||||||
// const { Expense } = require('../../Expenses/models/Expense.model');
|
// const { Expense } = require('../../Expenses/models/Expense.model');
|
||||||
// const ProjectTask = require('models/Task');
|
// const ProjectTask = require('models/Task');
|
||||||
|
|
||||||
@@ -297,6 +299,18 @@ export class ItemEntry extends BaseModel {
|
|||||||
to: 'tax_rates.id',
|
to: 'tax_rates.id',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tracking tag associations.
|
||||||
|
*/
|
||||||
|
trackingTagAssociations: {
|
||||||
|
relation: Model.HasManyRelation,
|
||||||
|
modelClass: ItemEntryTrackingTag,
|
||||||
|
join: {
|
||||||
|
from: 'items_entries.id',
|
||||||
|
to: 'item_entry_tracking_tags.itemEntryId',
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,95 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
import { useMutation, useQueryClient } from 'react-query';
|
||||||
|
import { useRequestQuery } from '../useQueryRequest';
|
||||||
|
import QUERY_TYPES from './types';
|
||||||
|
import useApiRequest from '../useRequest';
|
||||||
|
|
||||||
|
// Common invalidate queries.
|
||||||
|
const commonInvalidateQueries = (queryClient) => {
|
||||||
|
queryClient.invalidateQueries(QUERY_TYPES.TRACKING_TAGS);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves tracking tags.
|
||||||
|
*/
|
||||||
|
export function useTrackingTags(props) {
|
||||||
|
return useRequestQuery(
|
||||||
|
[QUERY_TYPES.TRACKING_TAGS],
|
||||||
|
{
|
||||||
|
method: 'get',
|
||||||
|
url: `tracking-tags`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
select: (res) => res.data,
|
||||||
|
defaultData: [],
|
||||||
|
...props,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves tracking tag.
|
||||||
|
* @param {number} tagId - Tracking tag id.
|
||||||
|
*/
|
||||||
|
export function useTrackingTag(tagId: string, props) {
|
||||||
|
return useRequestQuery(
|
||||||
|
[QUERY_TYPES.TRACKING_TAGS, tagId],
|
||||||
|
{
|
||||||
|
method: 'get',
|
||||||
|
url: `tracking-tags/${tagId}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
select: (res) => res.data,
|
||||||
|
...props,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new tracking tag.
|
||||||
|
*/
|
||||||
|
export function useCreateTrackingTag(props) {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
const apiRequest = useApiRequest();
|
||||||
|
|
||||||
|
return useMutation((values) => apiRequest.post('tracking-tags', values), {
|
||||||
|
onSuccess: () => {
|
||||||
|
commonInvalidateQueries(queryClient);
|
||||||
|
},
|
||||||
|
...props,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Edit the given tracking tag.
|
||||||
|
*/
|
||||||
|
export function useEditTrackingTag(props) {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
const apiRequest = useApiRequest();
|
||||||
|
|
||||||
|
return useMutation(
|
||||||
|
([id, values]) => apiRequest.put(`tracking-tags/${id}`, values),
|
||||||
|
{
|
||||||
|
onSuccess: (res, id) => {
|
||||||
|
commonInvalidateQueries(queryClient);
|
||||||
|
queryClient.invalidateQueries([QUERY_TYPES.TRACKING_TAGS, id]);
|
||||||
|
},
|
||||||
|
...props,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete the given tracking tag.
|
||||||
|
*/
|
||||||
|
export function useDeleteTrackingTag(props) {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
const apiRequest = useApiRequest();
|
||||||
|
|
||||||
|
return useMutation((id) => apiRequest.delete(`tracking-tags/${id}`), {
|
||||||
|
onSuccess: () => {
|
||||||
|
commonInvalidateQueries(queryClient);
|
||||||
|
},
|
||||||
|
...props,
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -250,6 +250,11 @@ const CUSTOM_FIELDS = {
|
|||||||
CUSTOM_FIELD: 'CUSTOM_FIELD',
|
CUSTOM_FIELD: 'CUSTOM_FIELD',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const TRACKING_TAGS = {
|
||||||
|
TRACKING_TAGS: 'TRACKING_TAGS',
|
||||||
|
TRACKING_TAG: 'TRACKING_TAG',
|
||||||
|
};
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
...Authentication,
|
...Authentication,
|
||||||
...ACCOUNTS,
|
...ACCOUNTS,
|
||||||
@@ -287,4 +292,5 @@ export default {
|
|||||||
...EXCHANGE_RATE,
|
...EXCHANGE_RATE,
|
||||||
...API_KEYS,
|
...API_KEYS,
|
||||||
...CUSTOM_FIELDS,
|
...CUSTOM_FIELDS,
|
||||||
|
...TRACKING_TAGS,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -15341,6 +15341,26 @@
|
|||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"description": "Tag ID",
|
||||||
|
"name": "tagId",
|
||||||
|
"in": "query",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"example": 1,
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Option ID",
|
||||||
|
"name": "optionId",
|
||||||
|
"in": "query",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"example": 5,
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "accept",
|
"name": "accept",
|
||||||
"required": true,
|
"required": true,
|
||||||
@@ -17016,6 +17036,26 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"description": "Tag ID",
|
||||||
|
"name": "tagId",
|
||||||
|
"in": "query",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"example": 1,
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Option ID",
|
||||||
|
"name": "optionId",
|
||||||
|
"in": "query",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"example": 5,
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "accept",
|
"name": "accept",
|
||||||
"required": true,
|
"required": true,
|
||||||
@@ -17190,6 +17230,26 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"description": "Tag ID",
|
||||||
|
"name": "tagId",
|
||||||
|
"in": "query",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"example": 1,
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Option ID",
|
||||||
|
"name": "optionId",
|
||||||
|
"in": "query",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"example": 5,
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "accept",
|
"name": "accept",
|
||||||
"required": true,
|
"required": true,
|
||||||
@@ -18870,6 +18930,26 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"description": "Tag ID",
|
||||||
|
"name": "tagId",
|
||||||
|
"in": "query",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"example": 1,
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Option ID",
|
||||||
|
"name": "optionId",
|
||||||
|
"in": "query",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"example": 5,
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "accept",
|
"name": "accept",
|
||||||
"required": true,
|
"required": true,
|
||||||
@@ -19605,6 +19685,26 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"description": "Tag ID",
|
||||||
|
"name": "tagId",
|
||||||
|
"in": "query",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"example": 1,
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Option ID",
|
||||||
|
"name": "optionId",
|
||||||
|
"in": "query",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"example": 5,
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "accept",
|
"name": "accept",
|
||||||
"required": true,
|
"required": true,
|
||||||
@@ -19741,6 +19841,26 @@
|
|||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"description": "Tag ID",
|
||||||
|
"name": "tagId",
|
||||||
|
"in": "query",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"example": 1,
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Option ID",
|
||||||
|
"name": "optionId",
|
||||||
|
"in": "query",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"example": 5,
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "accept",
|
"name": "accept",
|
||||||
"required": true,
|
"required": true,
|
||||||
@@ -19796,6 +19916,26 @@
|
|||||||
"example": "1",
|
"example": "1",
|
||||||
"type": "number"
|
"type": "number"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Tag ID",
|
||||||
|
"name": "tagId",
|
||||||
|
"in": "query",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"example": 1,
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Option ID",
|
||||||
|
"name": "optionId",
|
||||||
|
"in": "query",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"example": 5,
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"responses": {
|
"responses": {
|
||||||
@@ -21099,6 +21239,26 @@
|
|||||||
"type": "number"
|
"type": "number"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"description": "Tag ID",
|
||||||
|
"name": "tagId",
|
||||||
|
"in": "query",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"example": 1,
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Option ID",
|
||||||
|
"name": "optionId",
|
||||||
|
"in": "query",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"example": 5,
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "accept",
|
"name": "accept",
|
||||||
"required": true,
|
"required": true,
|
||||||
@@ -21644,6 +21804,26 @@
|
|||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"description": "Tag ID",
|
||||||
|
"name": "tagId",
|
||||||
|
"in": "query",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"example": 1,
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Option ID",
|
||||||
|
"name": "optionId",
|
||||||
|
"in": "query",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"example": 5,
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "accept",
|
"name": "accept",
|
||||||
"required": true,
|
"required": true,
|
||||||
@@ -22077,6 +22257,26 @@
|
|||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"description": "Tag ID",
|
||||||
|
"name": "tagId",
|
||||||
|
"in": "query",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"example": 1,
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Option ID",
|
||||||
|
"name": "optionId",
|
||||||
|
"in": "query",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"example": 5,
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "accept",
|
"name": "accept",
|
||||||
"required": true,
|
"required": true,
|
||||||
@@ -24127,6 +24327,219 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/api/tracking-tags": {
|
||||||
|
"post": {
|
||||||
|
"operationId": "TrackingTagsController_createTrackingTag",
|
||||||
|
"summary": "Create a new tracking tag.",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "Authorization",
|
||||||
|
"in": "header",
|
||||||
|
"description": "Value must be 'Bearer <token>' where <token> is an API key prefixed with 'bc_' or a JWT token.",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "Bearer bc_1234567890abcdef"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "organization-id",
|
||||||
|
"in": "header",
|
||||||
|
"description": "Required if Authorization is a JWT token. The organization ID to operate within.",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"requestBody": {
|
||||||
|
"required": true,
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/CreateTrackingTagDto"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"responses": {
|
||||||
|
"201": {
|
||||||
|
"description": "The tracking tag has been successfully created."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tags": [
|
||||||
|
"Tracking Tags"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"get": {
|
||||||
|
"operationId": "TrackingTagsController_getTrackingTags",
|
||||||
|
"summary": "Retrieves all tracking tags.",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "Authorization",
|
||||||
|
"in": "header",
|
||||||
|
"description": "Value must be 'Bearer <token>' where <token> is an API key prefixed with 'bc_' or a JWT token.",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "Bearer bc_1234567890abcdef"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "organization-id",
|
||||||
|
"in": "header",
|
||||||
|
"description": "Required if Authorization is a JWT token. The organization ID to operate within.",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "The tracking tags have been successfully retrieved."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tags": [
|
||||||
|
"Tracking Tags"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/api/tracking-tags/{id}": {
|
||||||
|
"put": {
|
||||||
|
"operationId": "TrackingTagsController_editTrackingTag",
|
||||||
|
"summary": "Edit the given tracking tag.",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "Authorization",
|
||||||
|
"in": "header",
|
||||||
|
"description": "Value must be 'Bearer <token>' where <token> is an API key prefixed with 'bc_' or a JWT token.",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "Bearer bc_1234567890abcdef"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "organization-id",
|
||||||
|
"in": "header",
|
||||||
|
"description": "Required if Authorization is a JWT token. The organization ID to operate within.",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "id",
|
||||||
|
"required": true,
|
||||||
|
"in": "path",
|
||||||
|
"schema": {
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"requestBody": {
|
||||||
|
"required": true,
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/EditTrackingTagDto"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "The tracking tag has been successfully updated."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tags": [
|
||||||
|
"Tracking Tags"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"delete": {
|
||||||
|
"operationId": "TrackingTagsController_deleteTrackingTag",
|
||||||
|
"summary": "Delete the given tracking tag.",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "Authorization",
|
||||||
|
"in": "header",
|
||||||
|
"description": "Value must be 'Bearer <token>' where <token> is an API key prefixed with 'bc_' or a JWT token.",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "Bearer bc_1234567890abcdef"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "organization-id",
|
||||||
|
"in": "header",
|
||||||
|
"description": "Required if Authorization is a JWT token. The organization ID to operate within.",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "id",
|
||||||
|
"required": true,
|
||||||
|
"in": "path",
|
||||||
|
"schema": {
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "The tracking tag has been successfully deleted."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tags": [
|
||||||
|
"Tracking Tags"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"get": {
|
||||||
|
"operationId": "TrackingTagsController_getTrackingTag",
|
||||||
|
"summary": "Retrieves the tracking tag details.",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "Authorization",
|
||||||
|
"in": "header",
|
||||||
|
"description": "Value must be 'Bearer <token>' where <token> is an API key prefixed with 'bc_' or a JWT token.",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "Bearer bc_1234567890abcdef"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "organization-id",
|
||||||
|
"in": "header",
|
||||||
|
"description": "Required if Authorization is a JWT token. The organization ID to operate within.",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "id",
|
||||||
|
"required": true,
|
||||||
|
"in": "path",
|
||||||
|
"schema": {
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "The tracking tag details have been successfully retrieved."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tags": [
|
||||||
|
"Tracking Tags"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
"/api/exchange-rates/latest": {
|
"/api/exchange-rates/latest": {
|
||||||
"get": {
|
"get": {
|
||||||
"operationId": "ExchangeRatesController_getLatestExchangeRate",
|
"operationId": "ExchangeRatesController_getLatestExchangeRate",
|
||||||
@@ -26480,6 +26893,25 @@
|
|||||||
"defaultTemplateId"
|
"defaultTemplateId"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"TrackingTagAssignmentDto": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"tagId": {
|
||||||
|
"type": "number",
|
||||||
|
"description": "Tag ID",
|
||||||
|
"example": 1
|
||||||
|
},
|
||||||
|
"optionId": {
|
||||||
|
"type": "number",
|
||||||
|
"description": "Option ID",
|
||||||
|
"example": 5
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"tagId",
|
||||||
|
"optionId"
|
||||||
|
]
|
||||||
|
},
|
||||||
"ItemEntryDto": {
|
"ItemEntryDto": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
@@ -26562,6 +26994,13 @@
|
|||||||
"type": "number",
|
"type": "number",
|
||||||
"description": "The cost account id of the item entry",
|
"description": "The cost account id of the item entry",
|
||||||
"example": 1021
|
"example": 1021
|
||||||
|
},
|
||||||
|
"trackingTags": {
|
||||||
|
"description": "The tracking tags of the item entry",
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/components/schemas/TrackingTagAssignmentDto"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": [
|
||||||
@@ -31659,6 +32098,13 @@
|
|||||||
"description": "The cost account id of the item entry",
|
"description": "The cost account id of the item entry",
|
||||||
"example": 1021
|
"example": 1021
|
||||||
},
|
},
|
||||||
|
"trackingTags": {
|
||||||
|
"description": "The tracking tags of the item entry",
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/components/schemas/TrackingTagAssignmentDto"
|
||||||
|
}
|
||||||
|
},
|
||||||
"landedCost": {
|
"landedCost": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"description": "Flag indicating whether the entry contributes to landed cost",
|
"description": "Flag indicating whether the entry contributes to landed cost",
|
||||||
@@ -32131,6 +32577,13 @@
|
|||||||
"projectId": {
|
"projectId": {
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"description": "Project ID"
|
"description": "Project ID"
|
||||||
|
},
|
||||||
|
"trackingTags": {
|
||||||
|
"description": "The tracking tags of the manual journal entry",
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/components/schemas/TrackingTagAssignmentDto"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": [
|
||||||
@@ -40639,6 +41092,86 @@
|
|||||||
"password"
|
"password"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"TrackingTagOptionDto": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "number",
|
||||||
|
"description": "Option ID (for updates)"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Option name",
|
||||||
|
"example": "New York"
|
||||||
|
},
|
||||||
|
"active": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Whether the option is active",
|
||||||
|
"example": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"name"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"CreateTrackingTagDto": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Tag name",
|
||||||
|
"example": "Location"
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Tag description",
|
||||||
|
"example": "Business location tracking"
|
||||||
|
},
|
||||||
|
"active": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Whether the tag is active",
|
||||||
|
"example": true
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"description": "Tag options",
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/components/schemas/TrackingTagOptionDto"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"name",
|
||||||
|
"options"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"EditTrackingTagDto": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Tag name",
|
||||||
|
"example": "Location"
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Tag description",
|
||||||
|
"example": "Business location tracking"
|
||||||
|
},
|
||||||
|
"active": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Whether the tag is active",
|
||||||
|
"example": true
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"description": "Tag options",
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/components/schemas/TrackingTagOptionDto"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"ExchangeRateLatestResponseDto": {
|
"ExchangeRateLatestResponseDto": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ export * from './import';
|
|||||||
export * from './manual-journals';
|
export * from './manual-journals';
|
||||||
export * from './roles';
|
export * from './roles';
|
||||||
export * from './custom-fields';
|
export * from './custom-fields';
|
||||||
|
export * from './tracking-tags';
|
||||||
export * from './users';
|
export * from './users';
|
||||||
export * from './dashboard';
|
export * from './dashboard';
|
||||||
export * from './settings';
|
export * from './settings';
|
||||||
|
|||||||
+283
-7
@@ -4714,6 +4714,43 @@ export interface paths {
|
|||||||
patch: operations["ContactsController_inactivateContact"];
|
patch: operations["ContactsController_inactivateContact"];
|
||||||
trace?: never;
|
trace?: never;
|
||||||
};
|
};
|
||||||
|
"/api/tracking-tags": {
|
||||||
|
parameters: {
|
||||||
|
query?: never;
|
||||||
|
header?: never;
|
||||||
|
path?: never;
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
/** Retrieves all tracking tags. */
|
||||||
|
get: operations["TrackingTagsController_getTrackingTags"];
|
||||||
|
put?: never;
|
||||||
|
/** Create a new tracking tag. */
|
||||||
|
post: operations["TrackingTagsController_createTrackingTag"];
|
||||||
|
delete?: never;
|
||||||
|
options?: never;
|
||||||
|
head?: never;
|
||||||
|
patch?: never;
|
||||||
|
trace?: never;
|
||||||
|
};
|
||||||
|
"/api/tracking-tags/{id}": {
|
||||||
|
parameters: {
|
||||||
|
query?: never;
|
||||||
|
header?: never;
|
||||||
|
path?: never;
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
/** Retrieves the tracking tag details. */
|
||||||
|
get: operations["TrackingTagsController_getTrackingTag"];
|
||||||
|
/** Edit the given tracking tag. */
|
||||||
|
put: operations["TrackingTagsController_editTrackingTag"];
|
||||||
|
post?: never;
|
||||||
|
/** Delete the given tracking tag. */
|
||||||
|
delete: operations["TrackingTagsController_deleteTrackingTag"];
|
||||||
|
options?: never;
|
||||||
|
head?: never;
|
||||||
|
patch?: never;
|
||||||
|
trace?: never;
|
||||||
|
};
|
||||||
"/api/exchange-rates/latest": {
|
"/api/exchange-rates/latest": {
|
||||||
parameters: {
|
parameters: {
|
||||||
query?: never;
|
query?: never;
|
||||||
@@ -6349,6 +6386,18 @@ export interface components {
|
|||||||
*/
|
*/
|
||||||
defaultTemplateId: number | null;
|
defaultTemplateId: number | null;
|
||||||
};
|
};
|
||||||
|
TrackingTagAssignmentDto: {
|
||||||
|
/**
|
||||||
|
* @description Tag ID
|
||||||
|
* @example 1
|
||||||
|
*/
|
||||||
|
tagId: number;
|
||||||
|
/**
|
||||||
|
* @description Option ID
|
||||||
|
* @example 5
|
||||||
|
*/
|
||||||
|
optionId: number;
|
||||||
|
};
|
||||||
ItemEntryDto: {
|
ItemEntryDto: {
|
||||||
/**
|
/**
|
||||||
* @description The index of the item entry
|
* @description The index of the item entry
|
||||||
@@ -6430,6 +6479,8 @@ export interface components {
|
|||||||
* @example 1021
|
* @example 1021
|
||||||
*/
|
*/
|
||||||
costAccountId: number;
|
costAccountId: number;
|
||||||
|
/** @description The tracking tags of the item entry */
|
||||||
|
trackingTags?: components["schemas"]["TrackingTagAssignmentDto"][];
|
||||||
};
|
};
|
||||||
AttachmentLinkDto: Record<string, never>;
|
AttachmentLinkDto: Record<string, never>;
|
||||||
PaymentMethodDto: {
|
PaymentMethodDto: {
|
||||||
@@ -10050,6 +10101,8 @@ export interface components {
|
|||||||
* @example 1021
|
* @example 1021
|
||||||
*/
|
*/
|
||||||
costAccountId: number;
|
costAccountId: number;
|
||||||
|
/** @description The tracking tags of the item entry */
|
||||||
|
trackingTags?: components["schemas"]["TrackingTagAssignmentDto"][];
|
||||||
/**
|
/**
|
||||||
* @description Flag indicating whether the entry contributes to landed cost
|
* @description Flag indicating whether the entry contributes to landed cost
|
||||||
* @example true
|
* @example true
|
||||||
@@ -10397,6 +10450,8 @@ export interface components {
|
|||||||
branchId?: number;
|
branchId?: number;
|
||||||
/** @description Project ID */
|
/** @description Project ID */
|
||||||
projectId?: number;
|
projectId?: number;
|
||||||
|
/** @description The tracking tags of the manual journal entry */
|
||||||
|
trackingTags?: components["schemas"]["TrackingTagAssignmentDto"][];
|
||||||
};
|
};
|
||||||
CreateManualJournalDto: {
|
CreateManualJournalDto: {
|
||||||
/**
|
/**
|
||||||
@@ -14601,6 +14656,58 @@ export interface components {
|
|||||||
*/
|
*/
|
||||||
password: string;
|
password: string;
|
||||||
};
|
};
|
||||||
|
TrackingTagOptionDto: {
|
||||||
|
/** @description Option ID (for updates) */
|
||||||
|
id?: number;
|
||||||
|
/**
|
||||||
|
* @description Option name
|
||||||
|
* @example New York
|
||||||
|
*/
|
||||||
|
name: string;
|
||||||
|
/**
|
||||||
|
* @description Whether the option is active
|
||||||
|
* @example true
|
||||||
|
*/
|
||||||
|
active?: boolean;
|
||||||
|
};
|
||||||
|
CreateTrackingTagDto: {
|
||||||
|
/**
|
||||||
|
* @description Tag name
|
||||||
|
* @example Location
|
||||||
|
*/
|
||||||
|
name: string;
|
||||||
|
/**
|
||||||
|
* @description Tag description
|
||||||
|
* @example Business location tracking
|
||||||
|
*/
|
||||||
|
description?: string;
|
||||||
|
/**
|
||||||
|
* @description Whether the tag is active
|
||||||
|
* @example true
|
||||||
|
*/
|
||||||
|
active?: boolean;
|
||||||
|
/** @description Tag options */
|
||||||
|
options: components["schemas"]["TrackingTagOptionDto"][];
|
||||||
|
};
|
||||||
|
EditTrackingTagDto: {
|
||||||
|
/**
|
||||||
|
* @description Tag name
|
||||||
|
* @example Location
|
||||||
|
*/
|
||||||
|
name?: string;
|
||||||
|
/**
|
||||||
|
* @description Tag description
|
||||||
|
* @example Business location tracking
|
||||||
|
*/
|
||||||
|
description?: string;
|
||||||
|
/**
|
||||||
|
* @description Whether the tag is active
|
||||||
|
* @example true
|
||||||
|
*/
|
||||||
|
active?: boolean;
|
||||||
|
/** @description Tag options */
|
||||||
|
options?: components["schemas"]["TrackingTagOptionDto"][];
|
||||||
|
};
|
||||||
ExchangeRateLatestResponseDto: {
|
ExchangeRateLatestResponseDto: {
|
||||||
/**
|
/**
|
||||||
* @description The base currency code
|
* @description The base currency code
|
||||||
@@ -23238,6 +23345,10 @@ export interface operations {
|
|||||||
previousYearAmountChange?: boolean;
|
previousYearAmountChange?: boolean;
|
||||||
/** @description Whether to show percentage change from previous year */
|
/** @description Whether to show percentage change from previous year */
|
||||||
previousYearPercentageChange?: boolean;
|
previousYearPercentageChange?: boolean;
|
||||||
|
/** @description Tag ID */
|
||||||
|
tagId: number;
|
||||||
|
/** @description Option ID */
|
||||||
|
optionId: number;
|
||||||
};
|
};
|
||||||
header: {
|
header: {
|
||||||
/** @description Value must be 'Bearer <token>' where <token> is an API key prefixed with 'bc_' or a JWT token. */
|
/** @description Value must be 'Bearer <token>' where <token> is an API key prefixed with 'bc_' or a JWT token. */
|
||||||
@@ -24645,7 +24756,7 @@ export interface operations {
|
|||||||
};
|
};
|
||||||
CustomerBalanceSummaryController_customerBalanceSummary: {
|
CustomerBalanceSummaryController_customerBalanceSummary: {
|
||||||
parameters: {
|
parameters: {
|
||||||
query?: {
|
query: {
|
||||||
/** @description The date as of which the balance summary is calculated */
|
/** @description The date as of which the balance summary is calculated */
|
||||||
asDate?: string;
|
asDate?: string;
|
||||||
/** @description Number of decimal places to display */
|
/** @description Number of decimal places to display */
|
||||||
@@ -24666,6 +24777,10 @@ export interface operations {
|
|||||||
noneZero?: boolean;
|
noneZero?: boolean;
|
||||||
/** @description Array of customer IDs to filter the summary */
|
/** @description Array of customer IDs to filter the summary */
|
||||||
customersIds?: number[];
|
customersIds?: number[];
|
||||||
|
/** @description Tag ID */
|
||||||
|
tagId: number;
|
||||||
|
/** @description Option ID */
|
||||||
|
optionId: number;
|
||||||
};
|
};
|
||||||
header: {
|
header: {
|
||||||
/** @description Value must be 'Bearer <token>' where <token> is an API key prefixed with 'bc_' or a JWT token. */
|
/** @description Value must be 'Bearer <token>' where <token> is an API key prefixed with 'bc_' or a JWT token. */
|
||||||
@@ -24693,7 +24808,7 @@ export interface operations {
|
|||||||
};
|
};
|
||||||
VendorBalanceSummaryController_vendorBalanceSummary: {
|
VendorBalanceSummaryController_vendorBalanceSummary: {
|
||||||
parameters: {
|
parameters: {
|
||||||
query?: {
|
query: {
|
||||||
/** @description The date as of which the balance summary is calculated */
|
/** @description The date as of which the balance summary is calculated */
|
||||||
asDate?: string;
|
asDate?: string;
|
||||||
/** @description Number of decimal places to display */
|
/** @description Number of decimal places to display */
|
||||||
@@ -24714,6 +24829,10 @@ export interface operations {
|
|||||||
noneZero?: boolean;
|
noneZero?: boolean;
|
||||||
/** @description Array of vendor IDs to filter the summary */
|
/** @description Array of vendor IDs to filter the summary */
|
||||||
vendorsIds?: number[];
|
vendorsIds?: number[];
|
||||||
|
/** @description Tag ID */
|
||||||
|
tagId: number;
|
||||||
|
/** @description Option ID */
|
||||||
|
optionId: number;
|
||||||
};
|
};
|
||||||
header: {
|
header: {
|
||||||
/** @description Value must be 'Bearer <token>' where <token> is an API key prefixed with 'bc_' or a JWT token. */
|
/** @description Value must be 'Bearer <token>' where <token> is an API key prefixed with 'bc_' or a JWT token. */
|
||||||
@@ -26000,7 +26119,7 @@ export interface operations {
|
|||||||
};
|
};
|
||||||
TrialBalanceSheetController_getTrialBalanceSheet: {
|
TrialBalanceSheetController_getTrialBalanceSheet: {
|
||||||
parameters: {
|
parameters: {
|
||||||
query?: {
|
query: {
|
||||||
/** @description Start date for the trial balance sheet */
|
/** @description Start date for the trial balance sheet */
|
||||||
fromDate?: string;
|
fromDate?: string;
|
||||||
/** @description End date for the trial balance sheet */
|
/** @description End date for the trial balance sheet */
|
||||||
@@ -26025,6 +26144,10 @@ export interface operations {
|
|||||||
onlyActive?: boolean;
|
onlyActive?: boolean;
|
||||||
/** @description Filter by specific account IDs */
|
/** @description Filter by specific account IDs */
|
||||||
accountIds?: number[];
|
accountIds?: number[];
|
||||||
|
/** @description Tag ID */
|
||||||
|
tagId: number;
|
||||||
|
/** @description Option ID */
|
||||||
|
optionId: number;
|
||||||
};
|
};
|
||||||
header: {
|
header: {
|
||||||
/** @description Value must be 'Bearer <token>' where <token> is an API key prefixed with 'bc_' or a JWT token. */
|
/** @description Value must be 'Bearer <token>' where <token> is an API key prefixed with 'bc_' or a JWT token. */
|
||||||
@@ -26641,7 +26764,7 @@ export interface operations {
|
|||||||
};
|
};
|
||||||
TransactionsByVendorController_transactionsByVendor: {
|
TransactionsByVendorController_transactionsByVendor: {
|
||||||
parameters: {
|
parameters: {
|
||||||
query?: {
|
query: {
|
||||||
/** @description Number of decimal places to display */
|
/** @description Number of decimal places to display */
|
||||||
precision?: number;
|
precision?: number;
|
||||||
/** @description Whether to divide the number by 1000 */
|
/** @description Whether to divide the number by 1000 */
|
||||||
@@ -26658,6 +26781,10 @@ export interface operations {
|
|||||||
noneZero?: boolean;
|
noneZero?: boolean;
|
||||||
/** @description Array of vendor IDs to include */
|
/** @description Array of vendor IDs to include */
|
||||||
vendorsIds?: string[];
|
vendorsIds?: string[];
|
||||||
|
/** @description Tag ID */
|
||||||
|
tagId: number;
|
||||||
|
/** @description Option ID */
|
||||||
|
optionId: number;
|
||||||
};
|
};
|
||||||
header: {
|
header: {
|
||||||
/** @description Value must be 'Bearer <token>' where <token> is an API key prefixed with 'bc_' or a JWT token. */
|
/** @description Value must be 'Bearer <token>' where <token> is an API key prefixed with 'bc_' or a JWT token. */
|
||||||
@@ -26685,7 +26812,7 @@ export interface operations {
|
|||||||
};
|
};
|
||||||
TransactionsByCustomerController_transactionsByCustomer: {
|
TransactionsByCustomerController_transactionsByCustomer: {
|
||||||
parameters: {
|
parameters: {
|
||||||
query?: {
|
query: {
|
||||||
/** @description Number of decimal places to display */
|
/** @description Number of decimal places to display */
|
||||||
precision?: number;
|
precision?: number;
|
||||||
/** @description Whether to divide the number by 1000 */
|
/** @description Whether to divide the number by 1000 */
|
||||||
@@ -26700,6 +26827,10 @@ export interface operations {
|
|||||||
noneTransactions?: boolean;
|
noneTransactions?: boolean;
|
||||||
/** @description Whether to exclude zero values */
|
/** @description Whether to exclude zero values */
|
||||||
noneZero?: boolean;
|
noneZero?: boolean;
|
||||||
|
/** @description Tag ID */
|
||||||
|
tagId: number;
|
||||||
|
/** @description Option ID */
|
||||||
|
optionId: number;
|
||||||
};
|
};
|
||||||
header: {
|
header: {
|
||||||
/** @description Value must be 'Bearer <token>' where <token> is an API key prefixed with 'bc_' or a JWT token. */
|
/** @description Value must be 'Bearer <token>' where <token> is an API key prefixed with 'bc_' or a JWT token. */
|
||||||
@@ -26732,6 +26863,10 @@ export interface operations {
|
|||||||
referenceType: string;
|
referenceType: string;
|
||||||
/** @description The ID of the reference */
|
/** @description The ID of the reference */
|
||||||
referenceId: number;
|
referenceId: number;
|
||||||
|
/** @description Tag ID */
|
||||||
|
tagId: number;
|
||||||
|
/** @description Option ID */
|
||||||
|
optionId: number;
|
||||||
};
|
};
|
||||||
header?: never;
|
header?: never;
|
||||||
path?: never;
|
path?: never;
|
||||||
@@ -27420,7 +27555,7 @@ export interface operations {
|
|||||||
};
|
};
|
||||||
JournalSheetController_journalSheet: {
|
JournalSheetController_journalSheet: {
|
||||||
parameters: {
|
parameters: {
|
||||||
query?: {
|
query: {
|
||||||
/** @description Whether to hide cents in the number format */
|
/** @description Whether to hide cents in the number format */
|
||||||
noCents?: boolean;
|
noCents?: boolean;
|
||||||
/** @description Whether to divide numbers by 1000 */
|
/** @description Whether to divide numbers by 1000 */
|
||||||
@@ -27433,6 +27568,10 @@ export interface operations {
|
|||||||
fromRange?: number;
|
fromRange?: number;
|
||||||
/** @description End range for filtering */
|
/** @description End range for filtering */
|
||||||
toRange?: number;
|
toRange?: number;
|
||||||
|
/** @description Tag ID */
|
||||||
|
tagId: number;
|
||||||
|
/** @description Option ID */
|
||||||
|
optionId: number;
|
||||||
};
|
};
|
||||||
header: {
|
header: {
|
||||||
/** @description Value must be 'Bearer <token>' where <token> is an API key prefixed with 'bc_' or a JWT token. */
|
/** @description Value must be 'Bearer <token>' where <token> is an API key prefixed with 'bc_' or a JWT token. */
|
||||||
@@ -27785,6 +27924,10 @@ export interface operations {
|
|||||||
previousYearAmountChange?: boolean;
|
previousYearAmountChange?: boolean;
|
||||||
/** @description Whether to show previous year percentage change */
|
/** @description Whether to show previous year percentage change */
|
||||||
previousYearPercentageChange?: boolean;
|
previousYearPercentageChange?: boolean;
|
||||||
|
/** @description Tag ID */
|
||||||
|
tagId: number;
|
||||||
|
/** @description Option ID */
|
||||||
|
optionId: number;
|
||||||
};
|
};
|
||||||
header: {
|
header: {
|
||||||
/** @description Value must be 'Bearer <token>' where <token> is an API key prefixed with 'bc_' or a JWT token. */
|
/** @description Value must be 'Bearer <token>' where <token> is an API key prefixed with 'bc_' or a JWT token. */
|
||||||
@@ -28054,7 +28197,7 @@ export interface operations {
|
|||||||
};
|
};
|
||||||
CashflowController_getCashflow: {
|
CashflowController_getCashflow: {
|
||||||
parameters: {
|
parameters: {
|
||||||
query?: {
|
query: {
|
||||||
/** @description Start date for the cash flow statement period */
|
/** @description Start date for the cash flow statement period */
|
||||||
fromDate?: string;
|
fromDate?: string;
|
||||||
/** @description End date for the cash flow statement period */
|
/** @description End date for the cash flow statement period */
|
||||||
@@ -28079,6 +28222,10 @@ export interface operations {
|
|||||||
negativeFormat?: "parentheses" | "mines";
|
negativeFormat?: "parentheses" | "mines";
|
||||||
/** @description Basis for the cash flow statement */
|
/** @description Basis for the cash flow statement */
|
||||||
basis?: string;
|
basis?: string;
|
||||||
|
/** @description Tag ID */
|
||||||
|
tagId: number;
|
||||||
|
/** @description Option ID */
|
||||||
|
optionId: number;
|
||||||
};
|
};
|
||||||
header: {
|
header: {
|
||||||
/** @description Value must be 'Bearer <token>' where <token> is an API key prefixed with 'bc_' or a JWT token. */
|
/** @description Value must be 'Bearer <token>' where <token> is an API key prefixed with 'bc_' or a JWT token. */
|
||||||
@@ -29617,6 +29764,135 @@ export interface operations {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
TrackingTagsController_getTrackingTags: {
|
||||||
|
parameters: {
|
||||||
|
query?: never;
|
||||||
|
header: {
|
||||||
|
/** @description Value must be 'Bearer <token>' where <token> is an API key prefixed with 'bc_' or a JWT token. */
|
||||||
|
Authorization: string;
|
||||||
|
/** @description Required if Authorization is a JWT token. The organization ID to operate within. */
|
||||||
|
"organization-id": string;
|
||||||
|
};
|
||||||
|
path?: never;
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
requestBody?: never;
|
||||||
|
responses: {
|
||||||
|
/** @description The tracking tags have been successfully retrieved. */
|
||||||
|
200: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown;
|
||||||
|
};
|
||||||
|
content?: never;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
TrackingTagsController_createTrackingTag: {
|
||||||
|
parameters: {
|
||||||
|
query?: never;
|
||||||
|
header: {
|
||||||
|
/** @description Value must be 'Bearer <token>' where <token> is an API key prefixed with 'bc_' or a JWT token. */
|
||||||
|
Authorization: string;
|
||||||
|
/** @description Required if Authorization is a JWT token. The organization ID to operate within. */
|
||||||
|
"organization-id": string;
|
||||||
|
};
|
||||||
|
path?: never;
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
requestBody: {
|
||||||
|
content: {
|
||||||
|
"application/json": components["schemas"]["CreateTrackingTagDto"];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
responses: {
|
||||||
|
/** @description The tracking tag has been successfully created. */
|
||||||
|
201: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown;
|
||||||
|
};
|
||||||
|
content?: never;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
TrackingTagsController_getTrackingTag: {
|
||||||
|
parameters: {
|
||||||
|
query?: never;
|
||||||
|
header: {
|
||||||
|
/** @description Value must be 'Bearer <token>' where <token> is an API key prefixed with 'bc_' or a JWT token. */
|
||||||
|
Authorization: string;
|
||||||
|
/** @description Required if Authorization is a JWT token. The organization ID to operate within. */
|
||||||
|
"organization-id": string;
|
||||||
|
};
|
||||||
|
path: {
|
||||||
|
id: number;
|
||||||
|
};
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
requestBody?: never;
|
||||||
|
responses: {
|
||||||
|
/** @description The tracking tag details have been successfully retrieved. */
|
||||||
|
200: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown;
|
||||||
|
};
|
||||||
|
content?: never;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
TrackingTagsController_editTrackingTag: {
|
||||||
|
parameters: {
|
||||||
|
query?: never;
|
||||||
|
header: {
|
||||||
|
/** @description Value must be 'Bearer <token>' where <token> is an API key prefixed with 'bc_' or a JWT token. */
|
||||||
|
Authorization: string;
|
||||||
|
/** @description Required if Authorization is a JWT token. The organization ID to operate within. */
|
||||||
|
"organization-id": string;
|
||||||
|
};
|
||||||
|
path: {
|
||||||
|
id: number;
|
||||||
|
};
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
requestBody: {
|
||||||
|
content: {
|
||||||
|
"application/json": components["schemas"]["EditTrackingTagDto"];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
responses: {
|
||||||
|
/** @description The tracking tag has been successfully updated. */
|
||||||
|
200: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown;
|
||||||
|
};
|
||||||
|
content?: never;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
TrackingTagsController_deleteTrackingTag: {
|
||||||
|
parameters: {
|
||||||
|
query?: never;
|
||||||
|
header: {
|
||||||
|
/** @description Value must be 'Bearer <token>' where <token> is an API key prefixed with 'bc_' or a JWT token. */
|
||||||
|
Authorization: string;
|
||||||
|
/** @description Required if Authorization is a JWT token. The organization ID to operate within. */
|
||||||
|
"organization-id": string;
|
||||||
|
};
|
||||||
|
path: {
|
||||||
|
id: number;
|
||||||
|
};
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
requestBody?: never;
|
||||||
|
responses: {
|
||||||
|
/** @description The tracking tag has been successfully deleted. */
|
||||||
|
200: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown;
|
||||||
|
};
|
||||||
|
content?: never;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
ExchangeRatesController_getLatestExchangeRate: {
|
ExchangeRatesController_getLatestExchangeRate: {
|
||||||
parameters: {
|
parameters: {
|
||||||
query?: {
|
query?: {
|
||||||
|
|||||||
@@ -0,0 +1,57 @@
|
|||||||
|
import type { ApiFetcher } from './fetch-utils';
|
||||||
|
import { paths } from './schema';
|
||||||
|
import { OpForPath, OpQueryParams, OpRequestBody, OpResponseBody } from './utils';
|
||||||
|
|
||||||
|
export const TRACKING_TAGS_ROUTES = {
|
||||||
|
LIST: '/api/tracking-tags',
|
||||||
|
BY_ID: '/api/tracking-tags/{id}',
|
||||||
|
} as const satisfies Record<string, keyof paths>;
|
||||||
|
|
||||||
|
export type TrackingTagsList = OpResponseBody<OpForPath<typeof TRACKING_TAGS_ROUTES.LIST, 'get'>>;
|
||||||
|
export type TrackingTag = OpResponseBody<OpForPath<typeof TRACKING_TAGS_ROUTES.BY_ID, 'get'>>;
|
||||||
|
export type CreateTrackingTagBody = OpRequestBody<OpForPath<typeof TRACKING_TAGS_ROUTES.LIST, 'post'>>;
|
||||||
|
export type EditTrackingTagBody = OpRequestBody<OpForPath<typeof TRACKING_TAGS_ROUTES.BY_ID, 'put'>>;
|
||||||
|
|
||||||
|
export async function fetchTrackingTags(
|
||||||
|
fetcher: ApiFetcher,
|
||||||
|
): Promise<TrackingTagsList> {
|
||||||
|
const get = fetcher.path(TRACKING_TAGS_ROUTES.LIST).method('get').create();
|
||||||
|
const { data } = await get({});
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function fetchTrackingTag(
|
||||||
|
fetcher: ApiFetcher,
|
||||||
|
id: number,
|
||||||
|
): Promise<TrackingTag> {
|
||||||
|
const get = fetcher.path(TRACKING_TAGS_ROUTES.BY_ID).method('get').create();
|
||||||
|
const { data } = await get({ id });
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function createTrackingTag(
|
||||||
|
fetcher: ApiFetcher,
|
||||||
|
values: CreateTrackingTagBody,
|
||||||
|
): Promise<TrackingTag> {
|
||||||
|
const post = fetcher.path(TRACKING_TAGS_ROUTES.LIST).method('post').create();
|
||||||
|
const { data } = await post(values);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function editTrackingTag(
|
||||||
|
fetcher: ApiFetcher,
|
||||||
|
id: number,
|
||||||
|
values: EditTrackingTagBody,
|
||||||
|
): Promise<TrackingTag> {
|
||||||
|
const put = fetcher.path(TRACKING_TAGS_ROUTES.BY_ID).method('put').create();
|
||||||
|
const { data } = await put({ id, ...values });
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function deleteTrackingTag(
|
||||||
|
fetcher: ApiFetcher,
|
||||||
|
id: number,
|
||||||
|
): Promise<void> {
|
||||||
|
const del = fetcher.path(TRACKING_TAGS_ROUTES.BY_ID).method('delete').create();
|
||||||
|
await del({ id });
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user