This commit is contained in:
elforjani3
2021-01-03 19:44:43 +02:00
13 changed files with 715 additions and 361 deletions

View File

@@ -3,14 +3,13 @@ import { check, param, query } from 'express-validator';
import BaseController from 'api/controllers/BaseController';
import asyncMiddleware from 'api/middleware/asyncMiddleware';
import ManualJournalsService from 'services/ManualJournals/ManualJournalsService';
import { Inject, Service } from "typedi";
import { Inject, Service } from 'typedi';
import { ServiceError } from 'exceptions';
import DynamicListingService from 'services/DynamicListing/DynamicListService';
import { DATATYPES_LENGTH } from 'data/DataTypes';
@Service()
export default class ManualJournalsController extends BaseController {
@Inject()
manualJournalsService: ManualJournalsService;
@@ -24,67 +23,59 @@ export default class ManualJournalsController extends BaseController {
const router = Router();
router.get(
'/', [
...this.manualJournalsListSchema,
],
'/',
[...this.manualJournalsListSchema],
this.validationResult,
asyncMiddleware(this.getManualJournalsList.bind(this)),
this.dynamicListService.handlerErrorsToResponse,
this.catchServiceErrors.bind(this),
this.catchServiceErrors.bind(this)
);
router.get(
'/:id',
asyncMiddleware(this.getManualJournal.bind(this)),
this.catchServiceErrors.bind(this),
this.catchServiceErrors.bind(this)
);
router.post(
'/publish', [
...this.manualJournalIdsSchema,
],
'/publish',
[...this.manualJournalIdsSchema],
this.validationResult,
asyncMiddleware(this.publishManualJournals.bind(this)),
this.catchServiceErrors.bind(this),
this.catchServiceErrors.bind(this)
);
router.post(
'/:id/publish', [
...this.manualJournalParamSchema,
],
'/:id/publish',
[...this.manualJournalParamSchema],
this.validationResult,
asyncMiddleware(this.publishManualJournal.bind(this)),
this.catchServiceErrors.bind(this),
this.catchServiceErrors.bind(this)
);
router.post(
'/:id', [
...this.manualJournalValidationSchema,
...this.manualJournalParamSchema,
],
'/:id',
[...this.manualJournalValidationSchema, ...this.manualJournalParamSchema],
this.validationResult,
asyncMiddleware(this.editManualJournal.bind(this)),
this.catchServiceErrors.bind(this),
this.catchServiceErrors.bind(this)
);
router.delete(
'/:id', [
...this.manualJournalParamSchema,
],
'/:id',
[...this.manualJournalParamSchema],
this.validationResult,
asyncMiddleware(this.deleteManualJournal.bind(this)),
this.catchServiceErrors.bind(this),
this.catchServiceErrors.bind(this)
);
router.delete(
'/', [
...this.manualJournalIdsSchema,
],
'/',
[...this.manualJournalIdsSchema],
this.validationResult,
asyncMiddleware(this.deleteBulkManualJournals.bind(this)),
this.catchServiceErrors.bind(this),
this.catchServiceErrors.bind(this)
);
router.post(
'/', [
...this.manualJournalValidationSchema,
],
'/',
[...this.manualJournalValidationSchema],
this.validationResult,
asyncMiddleware(this.makeJournalEntries.bind(this)),
this.catchServiceErrors.bind(this),
this.catchServiceErrors.bind(this)
);
return router;
}
@@ -93,9 +84,7 @@ export default class ManualJournalsController extends BaseController {
* Specific manual journal id param validation schema.
*/
get manualJournalParamSchema() {
return [
param('id').exists().isNumeric().toInt()
];
return [param('id').exists().isNumeric().toInt()];
}
/**
@@ -105,7 +94,7 @@ export default class ManualJournalsController extends BaseController {
return [
query('ids').isArray({ min: 1 }),
query('ids.*').isNumeric().toInt(),
]
];
}
/**
@@ -138,11 +127,12 @@ export default class ManualJournalsController extends BaseController {
.trim()
.escape()
.isLength({ max: DATATYPES_LENGTH.TEXT }),
check('status').optional().isBoolean().toBoolean(),
check('publish').optional().isBoolean().toBoolean(),
check('entries').isArray({ min: 2 }),
check('entries.*.index')
.exists()
.isInt({ max: DATATYPES_LENGTH.INT_10 }).toInt(),
.isInt({ max: DATATYPES_LENGTH.INT_10 })
.toInt(),
check('entries.*.credit')
.optional({ nullable: true })
.isFloat({ min: 0, max: DATATYPES_LENGTH.DECIMAL_13_3 })
@@ -151,7 +141,9 @@ export default class ManualJournalsController extends BaseController {
.optional({ nullable: true })
.isFloat({ min: 0, max: DATATYPES_LENGTH.DECIMAL_13_3 })
.toFloat(),
check('entries.*.account_id').isInt({ max: DATATYPES_LENGTH.INT_10 }).toInt(),
check('entries.*.account_id')
.isInt({ max: DATATYPES_LENGTH.INT_10 })
.toInt(),
check('entries.*.note')
.optional({ nullable: true })
.isString()
@@ -161,7 +153,7 @@ export default class ManualJournalsController extends BaseController {
.isInt({ max: DATATYPES_LENGTH.INT_10 })
.toInt(),
check('entries.*.contact_type').optional().isIn(['vendor', 'customer']),
]
];
}
/**
@@ -180,119 +172,24 @@ export default class ManualJournalsController extends BaseController {
];
}
async getManualJournal(req: Request, res: Response, next: NextFunction) {
const { tenantId } = req;
const { id: manualJournalId } = req.params;
try {
const manualJournal = await this.manualJournalsService.getManualJournal(tenantId, manualJournalId);
return res.status(200).send({ manualJournal });
} catch (error) {
next(error);
};
}
/**
* Publish the given manual journal.
* @param {Request} req
* @param {Response} res
* @param {NextFunction} next
*/
async publishManualJournal(req: Request, res: Response, next: NextFunction) {
const { tenantId } = req;
const { id: manualJournalId } = req.params;
try {
await this.manualJournalsService.publishManualJournal(tenantId, manualJournalId);
return res.status(200).send({
id: manualJournalId,
message: 'The manual journal has been published successfully.',
});
} catch (error) {
next(error);
}
}
/**
* Publish the given manual journals in bulk.
* @param {Request} req
* @param {Response} res
* @param {NextFunction} next
*/
async publishManualJournals(req: Request, res: Response, next: NextFunction) {
const { tenantId } = req;
const { ids: manualJournalsIds } = req.query;
try {
await this.manualJournalsService.publishManualJournals(tenantId, manualJournalsIds);
return res.status(200).send({
ids: manualJournalsIds,
message: 'The manual journals have been published successfully.',
});
} catch (error) {
next(error);
}
}
/**
* Delete the given manual journal.
* @param {Request} req
* @param {Response} res
* @param {NextFunction} next
*/
async deleteManualJournal(req: Request, res: Response, next: NextFunction) {
const { tenantId, user } = req;
const { id: manualJournalId } = req.params;
try {
await this.manualJournalsService.deleteManualJournal(tenantId, manualJournalId);
return res.status(200).send({
id: manualJournalId,
message: 'Manual journal has been deleted successfully.',
});
} catch (error) {
next(error);
}
}
/**
* Deletes manual journals in bulk.
* @param {Request} req
* @param {Response} res
* @param {NextFunction} next
*/
async deleteBulkManualJournals(req: Request, res: Response, next: NextFunction) {
const { tenantId } = req;
const { ids: manualJournalsIds } = req.query;
try {
await this.manualJournalsService.deleteManualJournals(tenantId, manualJournalsIds);
return res.status(200).send({
ids: manualJournalsIds,
message: 'Manual journal have been delete successfully.',
});
} catch (error) {
next(error);
}
}
/**
* Make manual journal.
* @param {Request} req
* @param {Response} res
* @param {NextFunction} next
* @param {Request} req
* @param {Response} res
* @param {NextFunction} next
*/
async makeJournalEntries(req: Request, res: Response, next: NextFunction) {
const { tenantId, user } = req;
const manualJournalDTO = this.matchedBodyData(req);
try {
const { manualJournal } = await this.manualJournalsService
.makeJournalEntries(tenantId, manualJournalDTO, user);
const {
manualJournal,
} = await this.manualJournalsService.makeJournalEntries(
tenantId,
manualJournalDTO,
user
);
return res.status(200).send({
id: manualJournal.id,
@@ -305,9 +202,9 @@ export default class ManualJournalsController extends BaseController {
/**
* Edit the given manual journal.
* @param {Request} req
* @param {Response} res
* @param {NextFunction} next
* @param {Request} req
* @param {Response} res
* @param {NextFunction} next
*/
async editManualJournal(req: Request, res: Response, next: NextFunction) {
const { tenantId, user } = req;
@@ -315,11 +212,13 @@ export default class ManualJournalsController extends BaseController {
const manualJournalDTO = this.matchedBodyData(req);
try {
const { manualJournal } = await this.manualJournalsService.editJournalEntries(
const {
manualJournal,
} = await this.manualJournalsService.editJournalEntries(
tenantId,
manualJournalId,
manualJournalDTO,
user,
user
);
return res.status(200).send({
id: manualJournal.id,
@@ -330,11 +229,139 @@ export default class ManualJournalsController extends BaseController {
}
}
/**
* Retrieve the given manual journal details.
* @param {Request} req
* @param {Response} res
* @param {NextFunction} next
*/
async getManualJournal(req: Request, res: Response, next: NextFunction) {
const { tenantId } = req;
const { id: manualJournalId } = req.params;
try {
const manualJournal = await this.manualJournalsService.getManualJournal(
tenantId,
manualJournalId
);
return res.status(200).send({ manualJournal });
} catch (error) {
next(error);
}
}
/**
* Publish the given manual journal.
* @param {Request} req
* @param {Response} res
* @param {NextFunction} next
*/
async publishManualJournal(req: Request, res: Response, next: NextFunction) {
const { tenantId } = req;
const { id: manualJournalId } = req.params;
try {
await this.manualJournalsService.publishManualJournal(
tenantId,
manualJournalId
);
return res.status(200).send({
id: manualJournalId,
message: 'The manual journal has been published successfully.',
});
} catch (error) {
next(error);
}
}
/**
* Publish the given manual journals in bulk.
* @param {Request} req
* @param {Response} res
* @param {NextFunction} next
*/
async publishManualJournals(req: Request, res: Response, next: NextFunction) {
const { tenantId } = req;
const { ids: manualJournalsIds } = req.query;
try {
const {
meta: { alreadyPublished, published, total },
} = await this.manualJournalsService.publishManualJournals(
tenantId,
manualJournalsIds
);
return res.status(200).send({
ids: manualJournalsIds,
message: 'The manual journals have been published successfully.',
meta: { alreadyPublished, published, total },
});
} catch (error) {
next(error);
}
}
/**
* Delete the given manual journal.
* @param {Request} req
* @param {Response} res
* @param {NextFunction} next
*/
async deleteManualJournal(req: Request, res: Response, next: NextFunction) {
const { tenantId, user } = req;
const { id: manualJournalId } = req.params;
try {
await this.manualJournalsService.deleteManualJournal(
tenantId,
manualJournalId
);
return res.status(200).send({
id: manualJournalId,
message: 'Manual journal has been deleted successfully.',
});
} catch (error) {
next(error);
}
}
/**
* Deletes manual journals in bulk.
* @param {Request} req
* @param {Response} res
* @param {NextFunction} next
*/
async deleteBulkManualJournals(
req: Request,
res: Response,
next: NextFunction
) {
const { tenantId } = req;
const { ids: manualJournalsIds } = req.query;
try {
await this.manualJournalsService.deleteManualJournals(
tenantId,
manualJournalsIds
);
return res.status(200).send({
ids: manualJournalsIds,
message: 'Manual journal have been delete successfully.',
});
} catch (error) {
next(error);
}
}
/**
* Retrieve manual journals list.
* @param {Request} req
* @param {Response} res
* @param {NextFunction} next
* @param {Request} req
* @param {Response} res
* @param {NextFunction} next
*/
async getManualJournalsList(req: Request, res: Response, next: NextFunction) {
const { tenantId } = req;
@@ -345,7 +372,7 @@ export default class ManualJournalsController extends BaseController {
page: 1,
pageSize: 12,
...this.matchedQueryData(req),
}
};
if (filter.stringifiedFilterRoles) {
filter.filterRoles = JSON.parse(filter.stringifiedFilterRoles);
}
@@ -353,13 +380,13 @@ export default class ManualJournalsController extends BaseController {
const {
manualJournals,
pagination,
filterMeta
filterMeta,
} = await this.manualJournalsService.getManualJournals(tenantId, filter);
return res.status(200).send({
manual_journals: manualJournals,
pagination: this.transfromToResponse(pagination),
filter_meta: this.transfromToResponse(filterMeta),
filter_meta: this.transfromToResponse(filterMeta),
});
} catch (error) {
next(error);
@@ -368,64 +395,69 @@ export default class ManualJournalsController extends BaseController {
/**
* Catches all service errors.
* @param error
* @param {Request} req
* @param {Response} res
* @param {NextFunction} next
* @param error
* @param {Request} req
* @param {Response} res
* @param {NextFunction} next
*/
catchServiceErrors(error, req: Request, res: Response, next: NextFunction) {
if (error instanceof ServiceError) {
if (error.errorType === 'manual_journal_not_found') {
res.boom.badRequest(
'Manual journal not found.',
{ errors: [{ type: 'MANUAL.JOURNAL.NOT.FOUND', code: 100 }], }
)
res.boom.badRequest('Manual journal not found.', {
errors: [{ type: 'MANUAL.JOURNAL.NOT.FOUND', code: 100 }],
});
}
if (error.errorType === 'credit_debit_not_equal_zero') {
return res.boom.badRequest(
'Credit and debit should not be equal zero.',
{ errors: [{ type: 'CREDIT.DEBIT.SUMATION.SHOULD.NOT.EQUAL.ZERO', code: 200, }] }
)
{
errors: [
{
type: 'CREDIT.DEBIT.SUMATION.SHOULD.NOT.EQUAL.ZERO',
code: 200,
},
],
}
);
}
if (error.errorType === 'credit_debit_not_equal') {
return res.boom.badRequest(
'Credit and debit should be equal.',
{ errors: [{ type: 'CREDIT.DEBIT.NOT.EQUALS', code: 300 }] }
)
return res.boom.badRequest('Credit and debit should be equal.', {
errors: [{ type: 'CREDIT.DEBIT.NOT.EQUALS', code: 300 }],
});
}
if (error.errorType === 'acccounts_ids_not_found') {
return res.boom.badRequest(
'Journal entries some of accounts ids not exists.',
{ errors: [{ type: 'ACCOUNTS.IDS.NOT.FOUND', code: 400 }] }
)
);
}
if (error.errorType === 'journal_number_exists') {
return res.boom.badRequest(
'Journal number should be unique.',
{ errors: [{ type: 'JOURNAL.NUMBER.ALREADY.EXISTS', code: 500 }] },
);
return res.boom.badRequest('Journal number should be unique.', {
errors: [{ type: 'JOURNAL.NUMBER.ALREADY.EXISTS', code: 500 }],
});
}
if (error.errorType === 'ENTRIES_SHOULD_ASSIGN_WITH_CONTACT') {
return res.boom.badRequest(
'',
{
errors: [
{
type: 'ENTRIES_SHOULD_ASSIGN_WITH_CONTACT',
code: 600,
meta: this.transfromToResponse(error.payload),
}
]
},
);
return res.boom.badRequest('', {
errors: [
{
type: 'ENTRIES_SHOULD_ASSIGN_WITH_CONTACT',
code: 600,
meta: this.transfromToResponse(error.payload),
},
],
});
}
if (error.errorType === 'contacts_not_found') {
return res.boom.badRequest(
'',
{ errors: [{ type: 'CONTACTS_NOT_FOUND', code: 700 }] },
);
return res.boom.badRequest('', {
errors: [{ type: 'CONTACTS_NOT_FOUND', code: 700 }],
});
}
if (error.errorType === 'MANUAL_JOURNAL_ALREADY_PUBLISHED') {
return res.boom.badRequest('', {
errors: [{ type: 'MANUAL_JOURNAL_ALREADY_PUBLISHED', code: 800 }],
});
}
}
next(error);
}
}
}

View File

@@ -7,8 +7,8 @@ exports.up = function(knex) {
table.string('journal_type').index();
table.decimal('amount', 13, 3);
table.date('date').index();
table.boolean('status').defaultTo(false).index();
table.string('description');
table.date('published_at').index();
table.string('attachment_file');
table.integer('user_id').unsigned().index();
table.timestamps();

View File

@@ -0,0 +1,18 @@
exports.up = function(knex) {
return knex.schema.createTable('manual_journals_entries', (table) => {
table.increments();
table.decimal('credit', 13, 3);
table.decimal('debit', 13, 3);
table.integer('index').unsigned();
table.integer('account_id').unsigned().index().references('id').inTable('accounts');
table.string('contact_type').nullable().index();
table.integer('contact_id').unsigned().nullable().index();
table.string('note');
table.integer('manual_journal_id').unsigned().index().references('id').inTable('manual_journals');
}).raw('ALTER TABLE `MANUAL_JOURNALS_ENTRIES` AUTO_INCREMENT = 1000');
};
exports.down = function(knex) {
return knex.schema.dropTableIfExists('manual_journals_entries');
};

View File

@@ -1,53 +1,98 @@
import { IDynamicListFilterDTO } from "./DynamicFilter";
import { IJournalEntry } from "./Journal";
import { ISystemUser } from "./User";
import { IDynamicListFilterDTO } from './DynamicFilter';
import { IJournalEntry } from './Journal';
import { ISystemUser } from './User';
export interface IManualJournal {
id: number,
date: Date|string,
journalNumber: number,
journalType: string,
amount: number,
status: boolean,
description: string,
userId: number,
entries: IJournalEntry[],
id: number;
date: Date | string;
journalNumber: number;
journalType: string;
amount: number;
publishedAt: Date | null;
description: string;
userId: number;
entries: IManualJournalEntry[];
}
export interface IManualJournalEntry {
index: number;
credit: number;
debit: number;
accountId: number;
note: string;
contactId?: number;
contactType?: string;
}
export interface IManualJournalEntryDTO {
index: number,
credit: number,
debit: number,
accountId: number,
note?: string,
contactId?: number,
contactType?: string,
index: number;
credit: number;
debit: number;
accountId: number;
note: string;
contactId?: number;
contactType?: string;
}
export interface IManualJournalDTO {
date: Date,
journalNumber: number,
journalType: string,
reference?: string,
description?: string,
status?: string,
entries: IManualJournalEntryDTO[],
mediaIds: number[],
date: Date;
journalNumber: number;
journalType: string;
reference?: string;
description?: string;
publish?: boolean;
entries: IManualJournalEntryDTO[];
}
export interface IManualJournalsFilter extends IDynamicListFilterDTO {
stringifiedFilterRoles?: string,
page: number,
pageSize: number,
stringifiedFilterRoles?: string;
page: number;
pageSize: number;
}
export interface IManualJournalsService {
makeJournalEntries(tenantId: number, manualJournalDTO: IManualJournalDTO, authorizedUser: ISystemUser): Promise<{ manualJournal: IManualJournal }>;
editJournalEntries(tenantId: number, manualJournalId: number, manualJournalDTO: IManualJournalDTO, authorizedUser): Promise<{ manualJournal: IManualJournal }>;
deleteManualJournal(tenantId: number, manualJournalId: number): Promise<void>;
deleteManualJournals(tenantId: number, manualJournalsIds: number[]): Promise<void>;
publishManualJournals(tenantId: number, manualJournalsIds: number[]): Promise<void>;
publishManualJournal(tenantId: number, manualJournalId: number): Promise<void>;
makeJournalEntries(
tenantId: number,
manualJournalDTO: IManualJournalDTO,
authorizedUser: ISystemUser
): Promise<{ manualJournal: IManualJournal }>;
getManualJournals(tenantId: number, filter: IManualJournalsFilter): Promise<{ manualJournals: IManualJournal, pagination: IPaginationMeta, filterMeta: IFilterMeta }>;
}
editJournalEntries(
tenantId: number,
manualJournalId: number,
manualJournalDTO: IManualJournalDTO,
authorizedUser
): Promise<{ manualJournal: IManualJournal }>;
deleteManualJournal(tenantId: number, manualJournalId: number): Promise<void>;
deleteManualJournals(
tenantId: number,
manualJournalsIds: number[]
): Promise<void>;
publishManualJournals(
tenantId: number,
manualJournalsIds: number[]
): Promise<{
meta: {
alreadyPublished: number;
published: number;
total: number;
};
}>;
publishManualJournal(
tenantId: number,
manualJournalId: number
): Promise<void>;
getManualJournals(
tenantId: number,
filter: IManualJournalsFilter
): Promise<{
manualJournals: IManualJournal;
pagination: IPaginationMeta;
filterMeta: IFilterMeta;
}>;
}

View File

@@ -32,6 +32,7 @@ import Option from 'models/Option';
import InventoryCostLotTracker from 'models/InventoryCostLotTracker';
import InventoryTransaction from 'models/InventoryTransaction';
import ManualJournal from 'models/ManualJournal';
import ManualJournalEntry from 'models/ManualJournalEntry';
import Media from 'models/Media';
import MediaLink from 'models/MediaLink';
@@ -45,6 +46,7 @@ export default (knex) => {
ItemCategory,
ItemEntry,
ManualJournal,
ManualJournalEntry,
Bill,
BillPayment,
BillPaymentEntry,

View File

@@ -1,6 +1,5 @@
import { Model } from 'objection';
import TenantModel from 'models/TenantModel';
import { AccountTransaction } from 'models';
export default class ManualJournal extends TenantModel {
/**
@@ -27,9 +26,18 @@ export default class ManualJournal extends TenantModel {
static get relationMappings() {
const Media = require('models/Media');
const AccountTransaction = require('models/AccountTransaction');
const ManualJournalEntry = require('models/ManualJournalEntry');
return {
entries: {
relation: Model.HasManyRelation,
modelClass: ManualJournalEntry.default,
join: {
from: 'manual_journals.id',
to: 'manual_journals_entries.manualJournalId',
},
},
transactions: {
relation: Model.HasManyRelation,
modelClass: AccountTransaction.default,
join: {

View File

@@ -0,0 +1,18 @@
import { Model } from 'objection';
import TenantModel from 'models/TenantModel';
export default class ManualJournalEntry extends TenantModel {
/**
* Table name.
*/
static get tableName() {
return 'manual_journals_entries';
}
/**
* Model timestamps.
*/
get timestamps() {
return [];
}
}

View File

@@ -1,6 +1,6 @@
import { sumBy, chain } from 'lodash';
import moment from 'moment';
import { IBill, ISystemUser } from 'interfaces';
import { IBill, IManualJournalEntry, ISystemUser } from 'interfaces';
import JournalPoster from './JournalPoster';
import JournalEntry from './JournalEntry';
import { AccountTransaction } from 'models';
@@ -257,9 +257,9 @@ export default class JournalCommands {
}
/**
*
* @param {number|number[]} referenceId
* @param {string} referenceType
* Reverts the jouranl entries.
* @param {number|number[]} referenceId - Reference id.
* @param {string} referenceType - Reference type.
*/
async revertJournalEntries(
referenceId: number | number[],
@@ -286,15 +286,14 @@ export default class JournalCommands {
*/
async manualJournal(
manualJournalObj: IManualJournal,
manualJournalId: number
) {
manualJournalObj.entries.forEach((entry) => {
manualJournalObj.entries.forEach((entry: IManualJournalEntry) => {
const jouranlEntry = new JournalEntry({
debit: entry.debit,
credit: entry.credit,
account: entry.account,
account: entry.accountId,
referenceType: 'Journal',
referenceId: manualJournalId,
referenceId: manualJournalObj.id,
contactType: entry.contactType,
contactId: entry.contactId,
note: entry.note,

View File

@@ -674,7 +674,7 @@ export default class ExpensesService implements IExpensesService {
// Filters the published expenses.
const publishedExpenses = this.getPublishedExpenses(oldExpenses);
// Mappes the published expenses to get id.
// Mappes the not-published expenses to get id.
const notPublishedExpensesIds = map(notPublishedExpenses, 'id');
if (notPublishedExpensesIds.length > 0) {

View File

@@ -1,4 +1,4 @@
import { difference, sumBy, omit, groupBy } from 'lodash';
import { difference, sumBy, omit, map } from 'lodash';
import { Service, Inject } from 'typedi';
import moment from 'moment';
import { ServiceError } from 'exceptions';
@@ -8,7 +8,6 @@ import {
IManualJournalsFilter,
ISystemUser,
IManualJournal,
IManualJournalEntryDTO,
IPaginationMeta,
} from 'interfaces';
import TenancyService from 'services/Tenancy/TenancyService';
@@ -20,6 +19,7 @@ import {
} from 'decorators/eventDispatcher';
import JournalPoster from 'services/Accounting/JournalPoster';
import JournalCommands from 'services/Accounting/JournalCommands';
import JournalPosterService from 'services/Sales/JournalPosterService';
const ERRORS = {
NOT_FOUND: 'manual_journal_not_found',
@@ -29,11 +29,20 @@ const ERRORS = {
JOURNAL_NUMBER_EXISTS: 'journal_number_exists',
ENTRIES_SHOULD_ASSIGN_WITH_CONTACT: 'ENTRIES_SHOULD_ASSIGN_WITH_CONTACT',
CONTACTS_NOT_FOUND: 'contacts_not_found',
MANUAL_JOURNAL_ALREADY_PUBLISHED: 'MANUAL_JOURNAL_ALREADY_PUBLISHED',
};
const CONTACTS_CONFIG = [
{ accountBySlug: 'accounts-receivable', contactService: 'customer', assignRequired: false, },
{ accountBySlug: 'accounts-payable', contactService: 'vendor', assignRequired: true },
{
accountBySlug: 'accounts-receivable',
contactService: 'customer',
assignRequired: false,
},
{
accountBySlug: 'accounts-payable',
contactService: 'vendor',
assignRequired: true,
},
];
@Service()
@@ -44,6 +53,9 @@ export default class ManualJournalsService implements IManualJournalsService {
@Inject()
dynamicListService: DynamicListingService;
@Inject()
journalService: JournalPosterService;
@Inject('logger')
logger: any;
@@ -55,7 +67,7 @@ export default class ManualJournalsService implements IManualJournalsService {
* @param {number} tenantId
* @param {number} manualJournalId
*/
private async validateManualJournalExistance(
private async getManualJournalOrThrowError(
tenantId: number,
manualJournalId: number
) {
@@ -65,7 +77,9 @@ export default class ManualJournalsService implements IManualJournalsService {
tenantId,
manualJournalId,
});
const manualJournal = await ManualJournal.query().findById(manualJournalId);
const manualJournal = await ManualJournal.query()
.findById(manualJournalId)
.withGraphFetched('entries');
if (!manualJournal) {
this.logger.warn('[manual_journal] not exists on the storage.', {
@@ -74,24 +88,24 @@ export default class ManualJournalsService implements IManualJournalsService {
});
throw new ServiceError(ERRORS.NOT_FOUND);
}
return manualJournal;
}
/**
* Validate manual journals existance.
* @param {number} tenantId
* @param {number[]} manualJournalsIds
* @param {number} tenantId - Tenant id.
* @param {number[]} manualJournalsIds - Manual jorunal ids.
* @throws {ServiceError}
*/
private async validateManualJournalsExistance(
private async getManualJournalsOrThrowError(
tenantId: number,
manualJournalsIds: number[]
) {
const { ManualJournal } = this.tenancy.models(tenantId);
const manualJournals = await ManualJournal.query().whereIn(
'id',
manualJournalsIds
);
const manualJournals = await ManualJournal.query()
.whereIn('id', manualJournalsIds)
.withGraphFetched('entries');
const notFoundManualJournals = difference(
manualJournalsIds,
@@ -100,6 +114,7 @@ export default class ManualJournalsService implements IManualJournalsService {
if (notFoundManualJournals.length > 0) {
throw new ServiceError(ERRORS.NOT_FOUND);
}
return manualJournals;
}
/**
@@ -134,8 +149,8 @@ export default class ManualJournalsService implements IManualJournalsService {
/**
* Validate manual entries accounts existance on the storage.
* @param {number} tenantId
* @param {IManualJournalDTO} manualJournalDTO
* @param {number} tenantId -
* @param {IManualJournalDTO} manualJournalDTO -
*/
private async validateAccountsExistance(
tenantId: number,
@@ -183,7 +198,7 @@ export default class ManualJournalsService implements IManualJournalsService {
}
/**
*
*
* @param {number} tenantId
* @param {IManualJournalDTO} manualJournalDTO
* @param {string} accountBySlug
@@ -194,10 +209,12 @@ export default class ManualJournalsService implements IManualJournalsService {
manualJournalDTO: IManualJournalDTO,
accountBySlug: string,
contactType: string,
contactRequired: boolean = true,
contactRequired: boolean = true
): Promise<void> {
const { accountRepository } = this.tenancy.repositories(tenantId);
const payableAccount = await accountRepository.findOne({ slug: accountBySlug });
const payableAccount = await accountRepository.findOne({
slug: accountBySlug,
});
const entriesHasNoVendorContact = manualJournalDTO.entries.filter(
(e) =>
@@ -205,12 +222,12 @@ export default class ManualJournalsService implements IManualJournalsService {
((!e.contactId && contactRequired) || e.contactType !== contactType)
);
if (entriesHasNoVendorContact.length > 0) {
const indexes = entriesHasNoVendorContact.map(e => e.index);
const indexes = entriesHasNoVendorContact.map((e) => e.index);
throw new ServiceError(ERRORS.ENTRIES_SHOULD_ASSIGN_WITH_CONTACT, '', {
contactType,
accountBySlug,
indexes
indexes,
});
}
}
@@ -222,8 +239,8 @@ export default class ManualJournalsService implements IManualJournalsService {
*/
private async dynamicValidateAccountsWithContactType(
tenantId: number,
manualJournalDTO: IManualJournalDTO,
): Promise<any>{
manualJournalDTO: IManualJournalDTO
): Promise<any> {
return Promise.all(
CONTACTS_CONFIG.map(({ accountBySlug, contactService, assignRequired }) =>
this.validateAccountsWithContactType(
@@ -232,7 +249,7 @@ export default class ManualJournalsService implements IManualJournalsService {
accountBySlug,
contactService,
assignRequired
),
)
)
);
}
@@ -244,23 +261,28 @@ export default class ManualJournalsService implements IManualJournalsService {
*/
private async validateContactsExistance(
tenantId: number,
manualJournalDTO: IManualJournalDTO,
manualJournalDTO: IManualJournalDTO
) {
const { contactRepository } = this.tenancy.repositories(tenantId);
// Filters the entries that have contact only.
const entriesContactPairs = manualJournalDTO.entries
.filter((entry) => entry.contactId);
const entriesContactPairs = manualJournalDTO.entries.filter(
(entry) => entry.contactId
);
if (entriesContactPairs.length > 0) {
const entriesContactsIds = entriesContactPairs.map(entry => entry.contactId);
const entriesContactsIds = entriesContactPairs.map(
(entry) => entry.contactId
);
// Retrieve all stored contacts on the storage from contacts entries.
const storedContacts = await contactRepository.findByIds(
entriesContactsIds,
entriesContactsIds
);
// Converts the stored contacts to map with id as key and entry as value.
const storedContactsMap = new Map(storedContacts.map(contact => [contact.id, contact]));
const storedContactsMap = new Map(
storedContacts.map((contact) => [contact.id, contact])
);
const notFoundContactsIds = [];
entriesContactPairs.forEach((contactEntry) => {
@@ -284,35 +306,49 @@ export default class ManualJournalsService implements IManualJournalsService {
}
/**
* Transform manual journal DTO to graphed model to save it.
* @param {IManualJournalDTO} manualJournalDTO
* Transform the new manual journal DTO to upsert graph operation.
* @param {IManualJournalDTO} manualJournalDTO - Manual jorunal DTO.
* @param {ISystemUser} authorizedUser
*/
private transformDTOToModel(
private transformNewDTOToModel(
manualJournalDTO: IManualJournalDTO,
user: ISystemUser
): IManualJournal {
authorizedUser: ISystemUser
) {
const amount = sumBy(manualJournalDTO.entries, 'credit') || 0;
const date = moment(manualJournalDTO.date).format('YYYY-MM-DD');
return {
...manualJournalDTO,
...omit(manualJournalDTO, ['publish']),
...(manualJournalDTO.publish
? { publishedAt: moment().toMySqlDateTime() }
: {}),
amount,
date,
userId: user.id,
entries: this.transformDTOToEntriesModel(manualJournalDTO.entries),
userId: authorizedUser.id,
};
}
/**
* Transform DTO to model.
* @param {IManualJournalEntryDTO[]} entries
* Transform the edit manual journal DTO to upsert graph operation.
* @param {IManualJournalDTO} manualJournalDTO - Manual jorunal DTO.
* @param {IManualJournal} oldManualJournal
*/
private transformDTOToEntriesModel(entries: IManualJournalEntryDTO[]) {
return entries.map((entry: IManualJournalEntryDTO) => ({
...omit(entry, ['accountId']),
account: entry.accountId,
}));
private transformEditDTOToModel(
manualJournalDTO: IManualJournalDTO,
oldManualJournal: IManualJournal
) {
const amount = sumBy(manualJournalDTO.entries, 'credit') || 0;
const date = moment(manualJournalDTO.date).format('YYYY-MM-DD');
return {
id: oldManualJournal.id,
...omit(manualJournalDTO, ['publish']),
...(manualJournalDTO.publish && !oldManualJournal.publishedAt
? { publishedAt: moment().toMySqlDateTime() }
: {}),
amount,
date,
};
}
/**
@@ -341,23 +377,26 @@ export default class ManualJournalsService implements IManualJournalsService {
await this.validateManualJournalNoUnique(tenantId, manualJournalDTO);
// Validate accounts with contact type from the given config.
await this.dynamicValidateAccountsWithContactType(tenantId, manualJournalDTO);
await this.dynamicValidateAccountsWithContactType(
tenantId,
manualJournalDTO
);
this.logger.info(
'[manual_journal] trying to save manual journal to the storage.',
{ tenantId, manualJournalDTO }
);
const manualJournalObj = this.transformDTOToModel(
const manualJournalObj = this.transformNewDTOToModel(
manualJournalDTO,
authorizedUser
);
const manualJournal = await ManualJournal.query().insertAndFetch({
...omit(manualJournalObj, ['entries']),
const manualJournal = await ManualJournal.query().upsertGraph({
...manualJournalObj,
});
// Triggers `onManualJournalCreated` event.
this.eventDispatcher.dispatch(events.manualJournals.onCreated, {
tenantId,
manualJournal: { ...manualJournal, entries: manualJournalObj.entries },
manualJournal,
manualJournalId: manualJournal.id,
});
this.logger.info(
'[manual_journal] the manual journal inserted successfully.',
@@ -379,12 +418,17 @@ export default class ManualJournalsService implements IManualJournalsService {
manualJournalId: number,
manualJournalDTO: IManualJournalDTO,
authorizedUser: ISystemUser
): Promise<{ manualJournal: IManualJournal }> {
): Promise<{
manualJournal: IManualJournal;
oldManualJournal: IManualJournal;
}> {
const { ManualJournal } = this.tenancy.models(tenantId);
// Validates the manual journal existance on the storage.
await this.validateManualJournalExistance(tenantId, manualJournalId);
const oldManualJournal = await this.getManualJournalOrThrowError(
tenantId,
manualJournalId
);
// Validates the total credit and debit to be equals.
this.valdiateCreditDebitTotalEquals(manualJournalDTO);
@@ -401,29 +445,30 @@ export default class ManualJournalsService implements IManualJournalsService {
manualJournalId
);
// Validate accounts with contact type from the given config.
await this.dynamicValidateAccountsWithContactType(tenantId, manualJournalDTO);
const manualJournalObj = this.transformDTOToModel(
manualJournalDTO,
authorizedUser
await this.dynamicValidateAccountsWithContactType(
tenantId,
manualJournalDTO
);
const storedManualJournal = await ManualJournal.query()
.where('id', manualJournalId)
.patch({
...omit(manualJournalObj, ['entries']),
});
const manualJournal: IManualJournal = {
// Transform manual journal DTO to model.
const manualJournalObj = this.transformEditDTOToModel(
manualJournalDTO,
oldManualJournal
);
await ManualJournal.query().upsertGraph({
...manualJournalObj,
id: manualJournalId,
};
});
// Retrieve the given manual journal with associated entries after modifications.
const manualJournal = await ManualJournal.query()
.findById(manualJournalId)
.withGraphFetched('entries');
// Triggers `onManualJournalEdited` event.
this.eventDispatcher.dispatch(events.manualJournals.onEdited, {
tenantId,
manualJournal,
oldManualJournal,
});
return { manualJournal };
return { manualJournal, oldManualJournal };
}
/**
@@ -435,25 +480,40 @@ export default class ManualJournalsService implements IManualJournalsService {
public async deleteManualJournal(
tenantId: number,
manualJournalId: number
): Promise<void> {
const { ManualJournal } = this.tenancy.models(tenantId);
await this.validateManualJournalExistance(tenantId, manualJournalId);
): Promise<{
oldManualJournal: IManualJournal;
}> {
const { ManualJournal, ManualJournalEntry } = this.tenancy.models(tenantId);
// Validate the manual journal exists on the storage.
const oldManualJournal = await this.getManualJournalOrThrowError(
tenantId,
manualJournalId
);
this.logger.info('[manual_journal] trying to delete the manual journal.', {
tenantId,
manualJournalId,
});
// Deletes the manual journal entries.
await ManualJournalEntry.query()
.where('manual_journal_id', manualJournalId)
.delete();
// Deletes the manual journal transaction.
await ManualJournal.query().findById(manualJournalId).delete();
// Triggers `onManualJournalDeleted` event.
this.eventDispatcher.dispatch(events.manualJournals.onDeleted, {
tenantId,
manualJournalId,
oldManualJournal,
});
this.logger.info(
'[manual_journal] the given manual journal deleted successfully.',
{ tenantId, manualJournalId }
);
return { oldManualJournal };
}
/**
@@ -465,14 +525,26 @@ export default class ManualJournalsService implements IManualJournalsService {
public async deleteManualJournals(
tenantId: number,
manualJournalsIds: number[]
): Promise<void> {
const { ManualJournal } = this.tenancy.models(tenantId);
await this.validateManualJournalsExistance(tenantId, manualJournalsIds);
): Promise<{
oldManualJournals: IManualJournal[]
}> {
const { ManualJournal, ManualJournalEntry } = this.tenancy.models(tenantId);
// Validate the manual journals exist on the storage.
const oldManualJournals = await this.getManualJournalsOrThrowError(
tenantId,
manualJournalsIds
);
this.logger.info('[manual_journal] trying to delete the manual journals.', {
tenantId,
manualJournalsIds,
});
// Deletes the manual journal entries.
await ManualJournalEntry.query()
.whereIn('manual_journal_id', manualJournalsIds)
.delete();
// Deletes the manual journal transaction.
await ManualJournal.query().whereIn('id', manualJournalsIds).delete();
// Triggers `onManualJournalDeletedBulk` event.
@@ -484,6 +556,7 @@ export default class ManualJournalsService implements IManualJournalsService {
'[manual_journal] the given manual journals deleted successfully.',
{ tenantId, manualJournalsIds }
);
return { oldManualJournals };
}
/**
@@ -494,51 +567,130 @@ export default class ManualJournalsService implements IManualJournalsService {
public async publishManualJournals(
tenantId: number,
manualJournalsIds: number[]
): Promise<void> {
): Promise<{
meta: {
alreadyPublished: number;
published: number;
total: number;
};
}> {
const { ManualJournal } = this.tenancy.models(tenantId);
await this.validateManualJournalsExistance(tenantId, manualJournalsIds);
// Retrieve manual journals or throw service error.
const oldManualJournals = await this.getManualJournalsOrThrowError(
tenantId,
manualJournalsIds
);
// Filters the not published journals.
const notPublishedJournals = this.getNonePublishedManualJournals(
oldManualJournals
);
// Filters the published journals.
const publishedJournals = this.getPublishedManualJournals(
oldManualJournals
);
// Mappes the not-published journals to get id.
const notPublishedJournalsIds = map(notPublishedJournals, 'id');
this.logger.info('[manual_journal] trying to publish the manual journal.', {
tenantId,
manualJournalsIds,
});
await ManualJournal.query()
.whereIn('id', manualJournalsIds)
.patch({ status: 1 });
if (notPublishedJournals.length > 0) {
// Mark the given manual journals as published.
await ManualJournal.query().whereIn('id', notPublishedJournalsIds).patch({
publishedAt: moment().toMySqlDateTime(),
});
}
// Triggers `onManualJournalPublishedBulk` event.
this.eventDispatcher.dispatch(events.manualJournals.onPublishedBulk, {
tenantId,
manualJournalsIds,
oldManualJournals,
});
this.logger.info(
'[manual_journal] the given manula journal published successfully.',
{ tenantId, manualJournalId }
{ tenantId, manualJournalsIds }
);
return {
meta: {
alreadyPublished: publishedJournals.length,
published: notPublishedJournals.length,
total: oldManualJournals.length,
},
};
}
/**
* Validates expenses is not already published before.
* @param {IManualJournal} manualJournal
*/
private validateManualJournalIsNotPublished(manualJournal: IManualJournal) {
if (manualJournal.publishedAt) {
throw new ServiceError(ERRORS.MANUAL_JOURNAL_ALREADY_PUBLISHED);
}
}
/**
* Filters the not published manual jorunals.
* @param {IManualJournal[]} manualJournal - Manual journal.
* @return {IManualJournal[]}
*/
public getNonePublishedManualJournals(
manualJournals: IManualJournal[]
): IManualJournal[] {
return manualJournals.filter((manualJournal) => !manualJournal.publishedAt);
}
/**
* Filters the published manual journals.
* @param {IManualJournal[]} manualJournal - Manual journal.
* @return {IManualJournal[]}
*/
public getPublishedManualJournals(
manualJournals: IManualJournal[]
): IManualJournal[] {
return manualJournals.filter((expense) => expense.publishedAt);
}
/**
* Publish the given manual journal.
* @param {number} tenantId
* @param {number} manualJournalId
* @param {number} tenantId - Tenant id.
* @param {number} manualJournalId - Manual journal id.
*/
public async publishManualJournal(
tenantId: number,
manualJournalId: number
): Promise<void> {
const { ManualJournal } = this.tenancy.models(tenantId);
await this.validateManualJournalExistance(tenantId, manualJournalId);
const oldManualJournal = await this.getManualJournalOrThrowError(
tenantId,
manualJournalId
);
this.logger.info('[manual_journal] trying to publish the manual journal.', {
tenantId,
manualJournalId,
});
await ManualJournal.query().findById(manualJournalId).patch({ status: 1 });
this.validateManualJournalIsNotPublished(oldManualJournal);
// Mark the given manual journal as published.
await ManualJournal.query().findById(manualJournalId).patch({
publishedAt: moment().toMySqlDateTime(),
});
// Retrieve the manual journal with enrties after modification.
const manualJournal = await ManualJournal.query()
.findById(manualJournalId)
.withGraphFetched('entries');
// Triggers `onManualJournalPublishedBulk` event.
this.eventDispatcher.dispatch(events.manualJournals.onPublished, {
tenantId,
manualJournal,
manualJournalId,
oldManualJournal,
});
this.logger.info(
'[manual_journal] the given manula journal published successfully.',
@@ -592,7 +744,7 @@ export default class ManualJournalsService implements IManualJournalsService {
public async getManualJournal(tenantId: number, manualJournalId: number) {
const { ManualJournal } = this.tenancy.models(tenantId);
await this.validateManualJournalExistance(tenantId, manualJournalId);
await this.getManualJournalOrThrowError(tenantId, manualJournalId);
this.logger.info(
'[manual_journals] trying to get specific manual journal.',
@@ -601,11 +753,33 @@ export default class ManualJournalsService implements IManualJournalsService {
const manualJournal = await ManualJournal.query()
.findById(manualJournalId)
.withGraphFetched('entries')
.withGraphFetched('transactions')
.withGraphFetched('media');
return manualJournal;
}
/**
* Reverts the manual journal journal entries.
* @param {number} tenantId
* @param {number|number[]} manualJournalId
* @return {Promise<void>}
*/
public async revertJournalEntries(
tenantId: number,
manualJournalId: number | number[]
): Promise<void> {
this.logger.info('[manual_journal] trying to revert journal entries.', {
tenantId,
manualJournalId,
});
return this.journalService.revertJournalTransactions(
tenantId,
manualJournalId,
'Journal'
);
}
/**
* Write manual journal entries.
* @param {number} tenantId
@@ -615,26 +789,30 @@ export default class ManualJournalsService implements IManualJournalsService {
*/
public async writeJournalEntries(
tenantId: number,
manualJournalId: number,
manualJournalObj?: IManualJournal | null,
override?: Boolean
manualJorunal: IManualJournal | IManualJournal[],
override: Boolean = false
) {
const journal = new JournalPoster(tenantId);
const journalCommands = new JournalCommands(journal);
const manualJournals = Array.isArray(manualJorunal)
? manualJorunal
: [manualJorunal];
const manualJournalsIds = map(manualJournals, 'id');
if (override) {
this.logger.info('[manual_journal] trying to revert journal entries.', {
tenantId,
manualJournalId,
manualJorunal,
});
await journalCommands.revertJournalEntries(manualJournalId, 'Journal');
}
if (manualJournalObj) {
journalCommands.manualJournal(manualJournalObj, manualJournalId);
await journalCommands.revertJournalEntries(manualJournalsIds, 'Journal');
}
manualJournals.forEach((manualJournal) => {
journalCommands.manualJournal(manualJournal);
});
this.logger.info('[manual_journal] trying to save journal entries.', {
tenantId,
manualJournalId,
manualJorunal,
});
await Promise.all([
journal.saveBalance(),
@@ -643,7 +821,7 @@ export default class ManualJournalsService implements IManualJournalsService {
]);
this.logger.info(
'[manual_journal] the journal entries saved successfully.',
{ tenantId, manualJournalId }
{ tenantId, manualJournalId: manualJorunal.id }
);
}
}

View File

@@ -17,7 +17,7 @@ export default class JournalPosterService {
*/
async revertJournalTransactions(
tenantId: number,
referenceId: number,
referenceId: number|number[],
referenceType: string
) {
const journal = new JournalPoster(tenantId);

View File

@@ -370,7 +370,6 @@ export default class PaymentReceiveService {
tenantId,
paymentReceiveId
);
// Validate payment receive number uniquiness.
if (paymentReceiveDTO.paymentReceiveNo) {
await this.validatePaymentReceiveNoExistance(
@@ -391,21 +390,18 @@ export default class PaymentReceiveService {
paymentReceiveId,
paymentReceiveDTO.entries
);
// Validate payment receive invoices IDs existance and associated to the given customer id.
await this.validateInvoicesIDsExistance(
tenantId,
oldPaymentReceive.customerId,
paymentReceiveDTO.entries
);
// Validate invoice payment amount.
await this.validateInvoicesPaymentsAmount(
tenantId,
paymentReceiveDTO.entries,
oldPaymentReceive.entries
);
// Update the payment receive transaction.
const paymentReceive = await PaymentReceive.query().upsertGraphAndFetch({
id: paymentReceiveId,
@@ -669,8 +665,8 @@ export default class PaymentReceiveService {
/**
* Reverts the given payment receive journal entries.
* @param {number} tenantId
* @param {number} paymentReceiveId
* @param {number} tenantId - Tenant id.
* @param {number} paymentReceiveId - Payment receive id.
*/
async revertPaymentReceiveJournalEntries(
tenantId: number,

View File

@@ -1,5 +1,5 @@
import { Inject, Container } from 'typedi';
import { On, EventSubscriber } from "event-dispatch";
import { On, EventSubscriber } from 'event-dispatch';
import events from 'subscribers/events';
import SettingsService from 'services/Settings/SettingsService';
import ManualJournalsService from 'services/ManualJournals/ManualJournalsService';
@@ -8,46 +8,104 @@ import ManualJournalsService from 'services/ManualJournals/ManualJournalsService
export class ManualJournalSubscriber {
logger: any;
settingsService: SettingsService;
manualJournalsService: ManualJournalsService;
constructor() {
this.logger = Container.get('logger');
this.settingsService = Container.get(SettingsService);
this.manualJournalsService = Container.get(ManualJournalsService);
}
/**
* Handle manual journal created event.
* @param {{ tenantId: number, manualJournal: IManualJournal }}
*/
@On(events.manualJournals.onCreated)
public async handleWriteJournalEntries({ tenantId, manualJournal }) {
const manualJournalsService = Container.get(ManualJournalsService);
await manualJournalsService
.writeJournalEntries(tenantId, manualJournal.id, manualJournal);
public async handleWriteJournalEntriesOnCreated({ tenantId, manualJournal }) {
// Ingore writing manual journal journal entries in case was not published.
if (manualJournal.publishedAt) {
await this.manualJournalsService.writeJournalEntries(
tenantId,
manualJournal
);
}
}
/**
* Handle manual journal edited event.
* @param {{ tenantId: number, manualJournal: IManualJournal }}
*/
@On(events.manualJournals.onEdited)
public async handleRewriteJournalEntries({ tenantId, manualJournal }) {
const manualJournalsService = Container.get(ManualJournalsService);
public async handleRewriteJournalEntriesOnEdited({
tenantId,
manualJournal,
oldManualJournal,
}) {
if (manualJournal.publishedAt) {
await this.manualJournalsService.writeJournalEntries(
tenantId,
manualJournal,
true
);
}
}
await manualJournalsService
.writeJournalEntries(tenantId, manualJournal.id, manualJournal, true);
/**
* Handles writing journal entries once the manula journal publish.
*/
@On(events.manualJournals.onPublished)
public async handleWriteJournalEntriesOnPublished({
tenantId,
manualJournal,
}) {
await this.manualJournalsService.writeJournalEntries(
tenantId,
manualJournal
);
}
/**
* Handle manual journal deleted event.
* @param {{ tenantId: number, manualJournalId: number }}
*/
@On(events.manualJournals.onDeleted)
public async handleRevertJournalEntries({ tenantId, manualJournalId, }) {
const manualJournalsService = Container.get(ManualJournalsService);
public async handleRevertJournalEntries({
tenantId,
manualJournalId,
oldManualJournal,
}) {
await this.manualJournalsService.revertJournalEntries(
tenantId,
manualJournalId
);
}
await manualJournalsService
.writeJournalEntries(tenantId, manualJournalId, null, true);
/**
* Handles the writing journal entries once the manual journals bulk published.
*/
@On(events.manualJournals.onPublishedBulk)
public async handleWritingJournalEntriesOnBulkPublish({
tenantId,
oldManualJournals,
}) {
const notPublishedJournals = this.manualJournalsService.getNonePublishedManualJournals(
oldManualJournals
);
await this.manualJournalsService.writeJournalEntries(
tenantId,
notPublishedJournals
);
}
/**
* Handles revert journal entries once manual journals bulk delete.
*/
@On(events.manualJournals.onDeletedBulk)
public async handleRevertJournalEntriesOnBulkDelete({
tenantId,
manualJournalsIds,
}) {
await this.manualJournalsService.revertJournalEntries(
tenantId,
manualJournalsIds
);
}
/**
@@ -61,4 +119,4 @@ export class ManualJournalSubscriber {
};
await this.settingsService.incrementNextNumber(tenantId, query);
}
}
}