mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-19 22:30:31 +00:00
Merge branch 'master' of https://github.com/abouolia/Bigcapital
This commit is contained in:
@@ -22,12 +22,14 @@ export default class CustomersController extends ContactsController {
|
|||||||
router() {
|
router() {
|
||||||
const router = Router();
|
const router = Router();
|
||||||
|
|
||||||
router.post('/', [
|
router.post(
|
||||||
...this.contactDTOSchema,
|
'/',
|
||||||
...this.contactNewDTOSchema,
|
[
|
||||||
...this.customerDTOSchema,
|
...this.contactDTOSchema,
|
||||||
...this.createCustomerDTOSchema,
|
...this.contactNewDTOSchema,
|
||||||
],
|
...this.customerDTOSchema,
|
||||||
|
...this.createCustomerDTOSchema,
|
||||||
|
],
|
||||||
this.validationResult,
|
this.validationResult,
|
||||||
asyncMiddleware(this.newCustomer.bind(this)),
|
asyncMiddleware(this.newCustomer.bind(this)),
|
||||||
this.handlerServiceErrors
|
this.handlerServiceErrors
|
||||||
@@ -41,41 +43,43 @@ export default class CustomersController extends ContactsController {
|
|||||||
],
|
],
|
||||||
this.validationResult,
|
this.validationResult,
|
||||||
asyncMiddleware(this.editOpeningBalanceCustomer.bind(this)),
|
asyncMiddleware(this.editOpeningBalanceCustomer.bind(this)),
|
||||||
this.handlerServiceErrors,
|
this.handlerServiceErrors
|
||||||
);
|
);
|
||||||
router.post('/:id', [
|
router.post(
|
||||||
...this.contactDTOSchema,
|
'/:id',
|
||||||
...this.contactEditDTOSchema,
|
[
|
||||||
...this.customerDTOSchema,
|
...this.contactDTOSchema,
|
||||||
],
|
...this.contactEditDTOSchema,
|
||||||
|
...this.customerDTOSchema,
|
||||||
|
],
|
||||||
this.validationResult,
|
this.validationResult,
|
||||||
asyncMiddleware(this.editCustomer.bind(this)),
|
asyncMiddleware(this.editCustomer.bind(this)),
|
||||||
this.handlerServiceErrors,
|
this.handlerServiceErrors
|
||||||
);
|
);
|
||||||
router.delete('/:id', [
|
router.delete(
|
||||||
...this.specificContactSchema,
|
'/:id',
|
||||||
],
|
[...this.specificContactSchema],
|
||||||
this.validationResult,
|
this.validationResult,
|
||||||
asyncMiddleware(this.deleteCustomer.bind(this)),
|
asyncMiddleware(this.deleteCustomer.bind(this)),
|
||||||
this.handlerServiceErrors,
|
this.handlerServiceErrors
|
||||||
);
|
);
|
||||||
router.delete('/', [
|
router.delete(
|
||||||
...this.bulkContactsSchema,
|
'/',
|
||||||
],
|
[...this.bulkContactsSchema],
|
||||||
this.validationResult,
|
this.validationResult,
|
||||||
asyncMiddleware(this.deleteBulkCustomers.bind(this)),
|
asyncMiddleware(this.deleteBulkCustomers.bind(this)),
|
||||||
this.handlerServiceErrors,
|
this.handlerServiceErrors
|
||||||
);
|
);
|
||||||
router.get('/', [
|
router.get(
|
||||||
...this.validateListQuerySchema,
|
'/',
|
||||||
],
|
[...this.validateListQuerySchema],
|
||||||
this.validationResult,
|
this.validationResult,
|
||||||
asyncMiddleware(this.getCustomersList.bind(this)),
|
asyncMiddleware(this.getCustomersList.bind(this)),
|
||||||
this.dynamicListService.handlerErrorsToResponse,
|
this.dynamicListService.handlerErrorsToResponse
|
||||||
);
|
);
|
||||||
router.get('/:id', [
|
router.get(
|
||||||
...this.specificContactSchema,
|
'/:id',
|
||||||
],
|
[...this.specificContactSchema],
|
||||||
this.validationResult,
|
this.validationResult,
|
||||||
asyncMiddleware(this.getCustomer.bind(this)),
|
asyncMiddleware(this.getCustomer.bind(this)),
|
||||||
this.handlerServiceErrors
|
this.handlerServiceErrors
|
||||||
@@ -128,16 +132,20 @@ export default class CustomersController extends ContactsController {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new customer.
|
* Creates a new customer.
|
||||||
* @param {Request} req
|
* @param {Request} req
|
||||||
* @param {Response} res
|
* @param {Response} res
|
||||||
* @param {NextFunction} next
|
* @param {NextFunction} next
|
||||||
*/
|
*/
|
||||||
async newCustomer(req: Request, res: Response, next: NextFunction) {
|
async newCustomer(req: Request, res: Response, next: NextFunction) {
|
||||||
const contactDTO: ICustomerNewDTO = this.matchedBodyData(req);
|
const contactDTO: ICustomerNewDTO = this.matchedBodyData(req);
|
||||||
const { tenantId } = req;
|
const { tenantId, user } = req;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const contact = await this.customersService.newCustomer(tenantId, contactDTO);
|
const contact = await this.customersService.newCustomer(
|
||||||
|
tenantId,
|
||||||
|
contactDTO,
|
||||||
|
user
|
||||||
|
);
|
||||||
|
|
||||||
return res.status(200).send({
|
return res.status(200).send({
|
||||||
id: contact.id,
|
id: contact.id,
|
||||||
@@ -150,17 +158,22 @@ export default class CustomersController extends ContactsController {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Edits the given customer details.
|
* Edits the given customer details.
|
||||||
* @param {Request} req
|
* @param {Request} req
|
||||||
* @param {Response} res
|
* @param {Response} res
|
||||||
* @param {NextFunction} next
|
* @param {NextFunction} next
|
||||||
*/
|
*/
|
||||||
async editCustomer(req: Request, res: Response, next: NextFunction) {
|
async editCustomer(req: Request, res: Response, next: NextFunction) {
|
||||||
const contactDTO: ICustomerEditDTO = this.matchedBodyData(req);
|
const contactDTO: ICustomerEditDTO = this.matchedBodyData(req);
|
||||||
const { tenantId } = req;
|
const { tenantId, user } = req;
|
||||||
const { id: contactId } = req.params;
|
const { id: contactId } = req.params;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await this.customersService.editCustomer(tenantId, contactId, contactDTO);
|
await this.customersService.editCustomer(
|
||||||
|
tenantId,
|
||||||
|
contactId,
|
||||||
|
contactDTO,
|
||||||
|
user
|
||||||
|
);
|
||||||
|
|
||||||
return res.status(200).send({
|
return res.status(200).send({
|
||||||
id: contactId,
|
id: contactId,
|
||||||
@@ -177,24 +190,26 @@ export default class CustomersController extends ContactsController {
|
|||||||
* @param {Response} res -
|
* @param {Response} res -
|
||||||
* @param {NextFunction} next -
|
* @param {NextFunction} next -
|
||||||
*/
|
*/
|
||||||
async editOpeningBalanceCustomer(req: Request, res: Response, next: NextFunction) {
|
async editOpeningBalanceCustomer(
|
||||||
const { tenantId } = req;
|
req: Request,
|
||||||
|
res: Response,
|
||||||
|
next: NextFunction
|
||||||
|
) {
|
||||||
|
const { tenantId, user } = req;
|
||||||
const { id: customerId } = req.params;
|
const { id: customerId } = req.params;
|
||||||
const {
|
const { openingBalance, openingBalanceAt } = this.matchedBodyData(req);
|
||||||
openingBalance,
|
|
||||||
openingBalanceAt,
|
|
||||||
} = this.matchedBodyData(req);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await this.customersService.changeOpeningBalance(
|
await this.customersService.changeOpeningBalance(
|
||||||
tenantId,
|
tenantId,
|
||||||
customerId,
|
customerId,
|
||||||
openingBalance,
|
openingBalance,
|
||||||
openingBalanceAt,
|
openingBalanceAt
|
||||||
);
|
);
|
||||||
return res.status(200).send({
|
return res.status(200).send({
|
||||||
id: customerId,
|
id: customerId,
|
||||||
message: 'The opening balance of the given customer has been changed successfully.',
|
message:
|
||||||
|
'The opening balance of the given customer has been changed successfully.',
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
next(error);
|
next(error);
|
||||||
@@ -203,16 +218,20 @@ export default class CustomersController extends ContactsController {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve details of the given customer id.
|
* Retrieve details of the given customer id.
|
||||||
* @param {Request} req
|
* @param {Request} req
|
||||||
* @param {Response} res
|
* @param {Response} res
|
||||||
* @param {NextFunction} next
|
* @param {NextFunction} next
|
||||||
*/
|
*/
|
||||||
async getCustomer(req: Request, res: Response, next: NextFunction) {
|
async getCustomer(req: Request, res: Response, next: NextFunction) {
|
||||||
const { tenantId } = req;
|
const { tenantId, user } = req;
|
||||||
const { id: contactId } = req.params;
|
const { id: contactId } = req.params;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const customer = await this.customersService.getCustomer(tenantId, contactId);
|
const customer = await this.customersService.getCustomer(
|
||||||
|
tenantId,
|
||||||
|
contactId,
|
||||||
|
user
|
||||||
|
);
|
||||||
|
|
||||||
return res.status(200).send({
|
return res.status(200).send({
|
||||||
customer: this.transfromToResponse(customer),
|
customer: this.transfromToResponse(customer),
|
||||||
@@ -224,16 +243,16 @@ export default class CustomersController extends ContactsController {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes the given customer from the storage.
|
* Deletes the given customer from the storage.
|
||||||
* @param {Request} req
|
* @param {Request} req
|
||||||
* @param {Response} res
|
* @param {Response} res
|
||||||
* @param {NextFunction} next
|
* @param {NextFunction} next
|
||||||
*/
|
*/
|
||||||
async deleteCustomer(req: Request, res: Response, next: NextFunction) {
|
async deleteCustomer(req: Request, res: Response, next: NextFunction) {
|
||||||
const { tenantId } = req;
|
const { tenantId, user } = req;
|
||||||
const { id: contactId } = req.params;
|
const { id: contactId } = req.params;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await this.customersService.deleteCustomer(tenantId, contactId);
|
await this.customersService.deleteCustomer(tenantId, contactId, user);
|
||||||
|
|
||||||
return res.status(200).send({
|
return res.status(200).send({
|
||||||
id: contactId,
|
id: contactId,
|
||||||
@@ -246,16 +265,20 @@ export default class CustomersController extends ContactsController {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes customers in bulk.
|
* Deletes customers in bulk.
|
||||||
* @param {Request} req
|
* @param {Request} req
|
||||||
* @param {Response} res
|
* @param {Response} res
|
||||||
* @param {NextFunction} next
|
* @param {NextFunction} next
|
||||||
*/
|
*/
|
||||||
async deleteBulkCustomers(req: Request, res: Response, next: NextFunction) {
|
async deleteBulkCustomers(req: Request, res: Response, next: NextFunction) {
|
||||||
const { ids: contactsIds } = req.query;
|
const { ids: contactsIds } = req.query;
|
||||||
const { tenantId } = req;
|
const { tenantId, user } = req;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await this.customersService.deleteBulkCustomers(tenantId, contactsIds)
|
await this.customersService.deleteBulkCustomers(
|
||||||
|
tenantId,
|
||||||
|
contactsIds,
|
||||||
|
user
|
||||||
|
);
|
||||||
|
|
||||||
return res.status(200).send({
|
return res.status(200).send({
|
||||||
ids: contactsIds,
|
ids: contactsIds,
|
||||||
@@ -268,9 +291,9 @@ export default class CustomersController extends ContactsController {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve customers paginated and filterable list.
|
* Retrieve customers paginated and filterable list.
|
||||||
* @param {Request} req
|
* @param {Request} req
|
||||||
* @param {Response} res
|
* @param {Response} res
|
||||||
* @param {NextFunction} next
|
* @param {NextFunction} next
|
||||||
*/
|
*/
|
||||||
async getCustomersList(req: Request, res: Response, next: NextFunction) {
|
async getCustomersList(req: Request, res: Response, next: NextFunction) {
|
||||||
const { tenantId } = req;
|
const { tenantId } = req;
|
||||||
@@ -305,12 +328,17 @@ export default class CustomersController extends ContactsController {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles service errors.
|
* Handles service errors.
|
||||||
* @param {Error} error
|
* @param {Error} error
|
||||||
* @param {Request} req
|
* @param {Request} req
|
||||||
* @param {Response} res
|
* @param {Response} res
|
||||||
* @param {NextFunction} next
|
* @param {NextFunction} next
|
||||||
*/
|
*/
|
||||||
handlerServiceErrors(error: Error, req: Request, res: Response, next: NextFunction) {
|
handlerServiceErrors(
|
||||||
|
error: Error,
|
||||||
|
req: Request,
|
||||||
|
res: Response,
|
||||||
|
next: NextFunction
|
||||||
|
) {
|
||||||
if (error instanceof ServiceError) {
|
if (error instanceof ServiceError) {
|
||||||
if (error.errorType === 'contact_not_found') {
|
if (error.errorType === 'contact_not_found') {
|
||||||
return res.boom.badRequest(null, {
|
return res.boom.badRequest(null, {
|
||||||
@@ -340,4 +368,4 @@ export default class CustomersController extends ContactsController {
|
|||||||
}
|
}
|
||||||
next(error);
|
next(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -118,10 +118,10 @@ export default class VendorsController extends ContactsController {
|
|||||||
*/
|
*/
|
||||||
async newVendor(req: Request, res: Response, next: NextFunction) {
|
async newVendor(req: Request, res: Response, next: NextFunction) {
|
||||||
const contactDTO: IVendorNewDTO = this.matchedBodyData(req);
|
const contactDTO: IVendorNewDTO = this.matchedBodyData(req);
|
||||||
const { tenantId } = req;
|
const { tenantId, user } = req;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const vendor = await this.vendorsService.newVendor(tenantId, contactDTO);
|
const vendor = await this.vendorsService.newVendor(tenantId, contactDTO, user);
|
||||||
|
|
||||||
return res.status(200).send({
|
return res.status(200).send({
|
||||||
id: vendor.id,
|
id: vendor.id,
|
||||||
@@ -140,11 +140,11 @@ export default class VendorsController extends ContactsController {
|
|||||||
*/
|
*/
|
||||||
async editVendor(req: Request, res: Response, next: NextFunction) {
|
async editVendor(req: Request, res: Response, next: NextFunction) {
|
||||||
const contactDTO: IVendorEditDTO = this.matchedBodyData(req);
|
const contactDTO: IVendorEditDTO = this.matchedBodyData(req);
|
||||||
const { tenantId } = req;
|
const { tenantId, user } = req;
|
||||||
const { id: contactId } = req.params;
|
const { id: contactId } = req.params;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await this.vendorsService.editVendor(tenantId, contactId, contactDTO);
|
await this.vendorsService.editVendor(tenantId, contactId, contactDTO, user);
|
||||||
|
|
||||||
return res.status(200).send({
|
return res.status(200).send({
|
||||||
id: contactId,
|
id: contactId,
|
||||||
@@ -162,7 +162,7 @@ export default class VendorsController extends ContactsController {
|
|||||||
* @param {NextFunction} next -
|
* @param {NextFunction} next -
|
||||||
*/
|
*/
|
||||||
async editOpeningBalanceVendor(req: Request, res: Response, next: NextFunction) {
|
async editOpeningBalanceVendor(req: Request, res: Response, next: NextFunction) {
|
||||||
const { tenantId } = req;
|
const { tenantId, user } = req;
|
||||||
const { id: vendorId } = req.params;
|
const { id: vendorId } = req.params;
|
||||||
const {
|
const {
|
||||||
openingBalance,
|
openingBalance,
|
||||||
@@ -192,11 +192,11 @@ export default class VendorsController extends ContactsController {
|
|||||||
* @param {NextFunction} next
|
* @param {NextFunction} next
|
||||||
*/
|
*/
|
||||||
async deleteVendor(req: Request, res: Response, next: NextFunction) {
|
async deleteVendor(req: Request, res: Response, next: NextFunction) {
|
||||||
const { tenantId } = req;
|
const { tenantId, user } = req;
|
||||||
const { id: contactId } = req.params;
|
const { id: contactId } = req.params;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await this.vendorsService.deleteVendor(tenantId, contactId)
|
await this.vendorsService.deleteVendor(tenantId, contactId, user)
|
||||||
|
|
||||||
return res.status(200).send({
|
return res.status(200).send({
|
||||||
id: contactId,
|
id: contactId,
|
||||||
@@ -214,11 +214,12 @@ export default class VendorsController extends ContactsController {
|
|||||||
* @param {NextFunction} next
|
* @param {NextFunction} next
|
||||||
*/
|
*/
|
||||||
async getVendor(req: Request, res: Response, next: NextFunction) {
|
async getVendor(req: Request, res: Response, next: NextFunction) {
|
||||||
const { tenantId } = req;
|
const { tenantId, user } = req;
|
||||||
const { id: vendorId } = req.params;
|
const { id: vendorId } = req.params;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const vendor = await this.vendorsService.getVendor(tenantId, vendorId)
|
const vendor = await this.vendorsService.getVendor(tenantId, vendorId, user)
|
||||||
|
|
||||||
return res.status(200).send({ vendor });
|
return res.status(200).send({ vendor });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
next(error);
|
next(error);
|
||||||
@@ -233,10 +234,10 @@ export default class VendorsController extends ContactsController {
|
|||||||
*/
|
*/
|
||||||
async deleteBulkVendors(req: Request, res: Response, next: NextFunction) {
|
async deleteBulkVendors(req: Request, res: Response, next: NextFunction) {
|
||||||
const { ids: contactsIds } = req.query;
|
const { ids: contactsIds } = req.query;
|
||||||
const { tenantId } = req;
|
const { tenantId, user } = req;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await this.vendorsService.deleteBulkVendors(tenantId, contactsIds)
|
await this.vendorsService.deleteBulkVendors(tenantId, contactsIds, user)
|
||||||
|
|
||||||
return res.status(200).send({
|
return res.status(200).send({
|
||||||
ids: contactsIds,
|
ids: contactsIds,
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { sumBy, chain } from 'lodash';
|
import { sumBy, chain } from 'lodash';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import { IBill } from 'interfaces';
|
import { IBill, ISystemUser } from 'interfaces';
|
||||||
import JournalPoster from "./JournalPoster";
|
import JournalPoster from './JournalPoster';
|
||||||
import JournalEntry from "./JournalEntry";
|
import JournalEntry from './JournalEntry';
|
||||||
import { AccountTransaction } from 'models';
|
import { AccountTransaction } from 'models';
|
||||||
import {
|
import {
|
||||||
IInventoryTransaction,
|
IInventoryTransaction,
|
||||||
@@ -16,37 +16,37 @@ import {
|
|||||||
} from 'interfaces';
|
} from 'interfaces';
|
||||||
|
|
||||||
interface IInventoryCostEntity {
|
interface IInventoryCostEntity {
|
||||||
date: Date,
|
date: Date;
|
||||||
|
|
||||||
referenceType: string,
|
referenceType: string;
|
||||||
referenceId: number,
|
referenceId: number;
|
||||||
|
|
||||||
costAccount: number,
|
costAccount: number;
|
||||||
incomeAccount: number,
|
incomeAccount: number;
|
||||||
inventoryAccount: number,
|
inventoryAccount: number;
|
||||||
|
|
||||||
inventory: number,
|
inventory: number;
|
||||||
cost: number,
|
cost: number;
|
||||||
income: number,
|
income: number;
|
||||||
};
|
}
|
||||||
|
|
||||||
interface NonInventoryJEntries {
|
interface NonInventoryJEntries {
|
||||||
date: Date,
|
date: Date;
|
||||||
|
|
||||||
referenceType: string,
|
referenceType: string;
|
||||||
referenceId: number,
|
referenceId: number;
|
||||||
|
|
||||||
receivable: number,
|
receivable: number;
|
||||||
payable: number,
|
payable: number;
|
||||||
|
|
||||||
incomeAccountId: number,
|
incomeAccountId: number;
|
||||||
income: number,
|
income: number;
|
||||||
|
|
||||||
costAccountId: number,
|
costAccountId: number;
|
||||||
cost: number,
|
cost: number;
|
||||||
};
|
}
|
||||||
|
|
||||||
export default class JournalCommands{
|
export default class JournalCommands {
|
||||||
journal: JournalPoster;
|
journal: JournalPoster;
|
||||||
|
|
||||||
models: any;
|
models: any;
|
||||||
@@ -54,18 +54,18 @@ export default class JournalCommands{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor method.
|
* Constructor method.
|
||||||
* @param {JournalPoster} journal -
|
* @param {JournalPoster} journal -
|
||||||
*/
|
*/
|
||||||
constructor(journal: JournalPoster) {
|
constructor(journal: JournalPoster) {
|
||||||
this.journal = journal;
|
this.journal = journal;
|
||||||
|
|
||||||
this.repositories = this.journal.repositories;
|
this.repositories = this.journal.repositories;
|
||||||
this.models = this.journal.models;
|
this.models = this.journal.models;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Records the bill journal entries.
|
* Records the bill journal entries.
|
||||||
* @param {IBill} bill
|
* @param {IBill} bill
|
||||||
* @param {boolean} override - Override the old bill entries.
|
* @param {boolean} override - Override the old bill entries.
|
||||||
*/
|
*/
|
||||||
async bill(bill: IBill, override: boolean = false): Promise<void> {
|
async bill(bill: IBill, override: boolean = false): Promise<void> {
|
||||||
@@ -78,7 +78,9 @@ export default class JournalCommands{
|
|||||||
const storedItems = await Item.query().whereIn('id', entriesItemsIds);
|
const storedItems = await Item.query().whereIn('id', entriesItemsIds);
|
||||||
|
|
||||||
const storedItemsMap = new Map(storedItems.map((item) => [item.id, item]));
|
const storedItemsMap = new Map(storedItems.map((item) => [item.id, item]));
|
||||||
const payableAccount = await accountRepository.findOne({ slug: 'accounts-payable' });
|
const payableAccount = await accountRepository.findOne({
|
||||||
|
slug: 'accounts-payable',
|
||||||
|
});
|
||||||
const formattedDate = moment(bill.billDate).format('YYYY-MM-DD');
|
const formattedDate = moment(bill.billDate).format('YYYY-MM-DD');
|
||||||
|
|
||||||
const commonJournalMeta = {
|
const commonJournalMeta = {
|
||||||
@@ -127,32 +129,45 @@ export default class JournalCommands{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Customer opening balance journals.
|
* Customer opening balance journals.
|
||||||
* @param {number} customerId
|
* @param {number} customerId
|
||||||
* @param {number} openingBalance
|
* @param {number} openingBalance
|
||||||
*/
|
*/
|
||||||
async customerOpeningBalance(customerId: number, openingBalance: number) {
|
async customerOpeningBalance(
|
||||||
|
customerId: number,
|
||||||
|
openingBalance: number,
|
||||||
|
openingBalanceAt: Date | string,
|
||||||
|
userId: number
|
||||||
|
) {
|
||||||
const { accountRepository } = this.repositories;
|
const { accountRepository } = this.repositories;
|
||||||
|
|
||||||
const openingBalanceAccount = await accountRepository.findOne({ slug: 'opening-balance' });
|
const openingBalanceAccount = await accountRepository.findOne({
|
||||||
const receivableAccount = await accountRepository.findOne({ slug: 'accounts-receivable' });
|
slug: 'opening-balance',
|
||||||
|
});
|
||||||
|
const receivableAccount = await accountRepository.findOne({
|
||||||
|
slug: 'accounts-receivable',
|
||||||
|
});
|
||||||
|
|
||||||
const commonEntry = {
|
const commonEntry = {
|
||||||
referenceType: 'CustomerOpeningBalance',
|
referenceType: 'CustomerOpeningBalance',
|
||||||
referenceId: customerId,
|
referenceId: customerId,
|
||||||
contactType: 'Customer',
|
contactType: 'Customer',
|
||||||
contactId: customerId,
|
contactId: customerId,
|
||||||
|
date: openingBalanceAt,
|
||||||
|
userId,
|
||||||
};
|
};
|
||||||
const creditEntry = new JournalEntry({
|
|
||||||
...commonEntry,
|
|
||||||
credit: openingBalance,
|
|
||||||
debit: 0,
|
|
||||||
account: openingBalanceAccount.id,
|
|
||||||
});
|
|
||||||
const debitEntry = new JournalEntry({
|
const debitEntry = new JournalEntry({
|
||||||
...commonEntry,
|
...commonEntry,
|
||||||
credit: 0,
|
credit: 0,
|
||||||
debit: openingBalance,
|
debit: openingBalance,
|
||||||
account: receivableAccount.id,
|
account: receivableAccount.id,
|
||||||
|
index: 1,
|
||||||
|
});
|
||||||
|
const creditEntry = new JournalEntry({
|
||||||
|
...commonEntry,
|
||||||
|
credit: openingBalance,
|
||||||
|
debit: 0,
|
||||||
|
account: openingBalanceAccount.id,
|
||||||
|
index: 2,
|
||||||
});
|
});
|
||||||
this.journal.debit(debitEntry);
|
this.journal.debit(debitEntry);
|
||||||
this.journal.credit(creditEntry);
|
this.journal.credit(creditEntry);
|
||||||
@@ -160,32 +175,47 @@ export default class JournalCommands{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Vendor opening balance journals
|
* Vendor opening balance journals
|
||||||
* @param {number} vendorId
|
* @param {number} vendorId
|
||||||
* @param {number} openingBalance
|
* @param {number} openingBalance
|
||||||
|
* @param {Date|string} openingBalanceAt
|
||||||
|
* @param {number} authorizedUserId
|
||||||
*/
|
*/
|
||||||
async vendorOpeningBalance(vendorId: number, openingBalance: number) {
|
async vendorOpeningBalance(
|
||||||
|
vendorId: number,
|
||||||
|
openingBalance: number,
|
||||||
|
openingBalanceAt: Date|string,
|
||||||
|
authorizedUserId: ISystemUser
|
||||||
|
) {
|
||||||
const { accountRepository } = this.repositories;
|
const { accountRepository } = this.repositories;
|
||||||
|
|
||||||
const payableAccount = await accountRepository.findOne({ slug: 'accounts-payable' });
|
const payableAccount = await accountRepository.findOne({
|
||||||
const otherCost = await accountRepository.findOne({ slug: 'other-expenses' });
|
slug: 'accounts-payable',
|
||||||
|
});
|
||||||
|
const otherCost = await accountRepository.findOne({
|
||||||
|
slug: 'other-expenses',
|
||||||
|
});
|
||||||
|
|
||||||
const commonEntry = {
|
const commonEntry = {
|
||||||
referenceType: 'VendorOpeningBalance',
|
referenceType: 'VendorOpeningBalance',
|
||||||
referenceId: vendorId,
|
referenceId: vendorId,
|
||||||
contactType: 'Vendor',
|
contactType: 'Vendor',
|
||||||
contactId: vendorId,
|
contactId: vendorId,
|
||||||
|
date: openingBalanceAt,
|
||||||
|
userId: authorizedUserId,
|
||||||
};
|
};
|
||||||
const creditEntry = new JournalEntry({
|
const creditEntry = new JournalEntry({
|
||||||
...commonEntry,
|
...commonEntry,
|
||||||
account: payableAccount.id,
|
account: payableAccount.id,
|
||||||
credit: openingBalance,
|
credit: openingBalance,
|
||||||
debit: 0,
|
debit: 0,
|
||||||
|
index: 1,
|
||||||
});
|
});
|
||||||
const debitEntry = new JournalEntry({
|
const debitEntry = new JournalEntry({
|
||||||
...commonEntry,
|
...commonEntry,
|
||||||
account: otherCost.id,
|
account: otherCost.id,
|
||||||
debit: openingBalance,
|
debit: openingBalance,
|
||||||
credit: 0,
|
credit: 0,
|
||||||
|
index: 2,
|
||||||
});
|
});
|
||||||
this.journal.debit(debitEntry);
|
this.journal.debit(debitEntry);
|
||||||
this.journal.credit(creditEntry);
|
this.journal.credit(creditEntry);
|
||||||
@@ -193,7 +223,7 @@ export default class JournalCommands{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes journal entries of expense model object.
|
* Writes journal entries of expense model object.
|
||||||
* @param {IExpense} expense
|
* @param {IExpense} expense
|
||||||
*/
|
*/
|
||||||
expense(expense: IExpense) {
|
expense(expense: IExpense) {
|
||||||
const mixinEntry = {
|
const mixinEntry = {
|
||||||
@@ -224,32 +254,37 @@ export default class JournalCommands{
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {number|number[]} referenceId
|
* @param {number|number[]} referenceId
|
||||||
* @param {string} referenceType
|
* @param {string} referenceType
|
||||||
*/
|
*/
|
||||||
async revertJournalEntries(
|
async revertJournalEntries(
|
||||||
referenceId: number|number[],
|
referenceId: number | number[],
|
||||||
referenceType: string
|
referenceType: string
|
||||||
) {
|
) {
|
||||||
const { AccountTransaction } = this.models;
|
const { AccountTransaction } = this.models;
|
||||||
|
|
||||||
const transactions = await AccountTransaction.query()
|
const transactions = await AccountTransaction.query()
|
||||||
.where('reference_type', referenceType)
|
.where('reference_type', referenceType)
|
||||||
.whereIn('reference_id', Array.isArray(referenceId) ? referenceId : [referenceId])
|
.whereIn(
|
||||||
|
'reference_id',
|
||||||
|
Array.isArray(referenceId) ? referenceId : [referenceId]
|
||||||
|
)
|
||||||
.withGraphFetched('account.type');
|
.withGraphFetched('account.type');
|
||||||
|
|
||||||
this.journal.fromTransactions(transactions);
|
this.journal.fromTransactions(transactions);
|
||||||
this.journal.removeEntries();
|
this.journal.removeEntries();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes journal entries from manual journal model object.
|
* Writes journal entries from manual journal model object.
|
||||||
* @param {IManualJournal} manualJournalObj
|
* @param {IManualJournal} manualJournalObj
|
||||||
* @param {number} manualJournalId
|
* @param {number} manualJournalId
|
||||||
*/
|
*/
|
||||||
async manualJournal(manualJournalObj: IManualJournal, manualJournalId: number) {
|
async manualJournal(
|
||||||
|
manualJournalObj: IManualJournal,
|
||||||
|
manualJournalId: number
|
||||||
|
) {
|
||||||
manualJournalObj.entries.forEach((entry) => {
|
manualJournalObj.entries.forEach((entry) => {
|
||||||
const jouranlEntry = new JournalEntry({
|
const jouranlEntry = new JournalEntry({
|
||||||
debit: entry.debit,
|
debit: entry.debit,
|
||||||
@@ -276,39 +311,49 @@ export default class JournalCommands{
|
|||||||
/**
|
/**
|
||||||
* Removes and revert accounts balance journal entries that associated
|
* Removes and revert accounts balance journal entries that associated
|
||||||
* to the given inventory transactions.
|
* to the given inventory transactions.
|
||||||
* @param {IInventoryTransaction[]} inventoryTransactions
|
* @param {IInventoryTransaction[]} inventoryTransactions
|
||||||
* @param {Journal} journal
|
* @param {Journal} journal
|
||||||
*/
|
*/
|
||||||
revertEntriesFromInventoryTransactions(inventoryTransactions: IInventoryTransaction[]) {
|
revertEntriesFromInventoryTransactions(
|
||||||
|
inventoryTransactions: IInventoryTransaction[]
|
||||||
|
) {
|
||||||
const groupedInvTransactions = chain(inventoryTransactions)
|
const groupedInvTransactions = chain(inventoryTransactions)
|
||||||
.groupBy((invTransaction: IInventoryTransaction) => invTransaction.transactionType)
|
.groupBy(
|
||||||
.map((groupedTrans: IInventoryTransaction[], transType: string) => [groupedTrans, transType])
|
(invTransaction: IInventoryTransaction) =>
|
||||||
|
invTransaction.transactionType
|
||||||
|
)
|
||||||
|
.map((groupedTrans: IInventoryTransaction[], transType: string) => [
|
||||||
|
groupedTrans,
|
||||||
|
transType,
|
||||||
|
])
|
||||||
.value();
|
.value();
|
||||||
|
|
||||||
return Promise.all(
|
return Promise.all(
|
||||||
groupedInvTransactions.map(async (grouped: [IInventoryTransaction[], string]) => {
|
groupedInvTransactions.map(
|
||||||
const [invTransGroup, referenceType] = grouped;
|
async (grouped: [IInventoryTransaction[], string]) => {
|
||||||
const referencesIds = invTransGroup.map((trans: IInventoryTransaction) => trans.transactionId);
|
const [invTransGroup, referenceType] = grouped;
|
||||||
|
const referencesIds = invTransGroup.map(
|
||||||
|
(trans: IInventoryTransaction) => trans.transactionId
|
||||||
|
);
|
||||||
|
|
||||||
const _transactions = await AccountTransaction.tenant()
|
const _transactions = await AccountTransaction.tenant()
|
||||||
.query()
|
.query()
|
||||||
.where('reference_type', referenceType)
|
.where('reference_type', referenceType)
|
||||||
.whereIn('reference_id', referencesIds)
|
.whereIn('reference_id', referencesIds)
|
||||||
.withGraphFetched('account.type');
|
.withGraphFetched('account.type');
|
||||||
|
|
||||||
if (_transactions.length > 0) {
|
if (_transactions.length > 0) {
|
||||||
this.journal.loadEntries(_transactions);
|
this.journal.loadEntries(_transactions);
|
||||||
this.journal.removeEntries(_transactions.map((t: any) => t.id));
|
this.journal.removeEntries(_transactions.map((t: any) => t.id));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async nonInventoryEntries(
|
public async nonInventoryEntries(transactions: NonInventoryJEntries[]) {
|
||||||
transactions: NonInventoryJEntries[]
|
|
||||||
) {
|
|
||||||
const receivableAccount = { id: 10 };
|
const receivableAccount = { id: 10 };
|
||||||
const payableAccount = {id: 11};
|
const payableAccount = { id: 11 };
|
||||||
|
|
||||||
transactions.forEach((trans: NonInventoryJEntries) => {
|
transactions.forEach((trans: NonInventoryJEntries) => {
|
||||||
const commonEntry = {
|
const commonEntry = {
|
||||||
@@ -317,12 +362,12 @@ export default class JournalCommands{
|
|||||||
referenceType: trans.referenceType,
|
referenceType: trans.referenceType,
|
||||||
};
|
};
|
||||||
|
|
||||||
switch(trans.referenceType) {
|
switch (trans.referenceType) {
|
||||||
case 'Bill':
|
case 'Bill':
|
||||||
const payableEntry: JournalEntry = new JournalEntry({
|
const payableEntry: JournalEntry = new JournalEntry({
|
||||||
...commonEntry,
|
...commonEntry,
|
||||||
credit: trans.payable,
|
credit: trans.payable,
|
||||||
account: payableAccount.id,
|
account: payableAccount.id,
|
||||||
});
|
});
|
||||||
const costEntry: JournalEntry = new JournalEntry({
|
const costEntry: JournalEntry = new JournalEntry({
|
||||||
...commonEntry,
|
...commonEntry,
|
||||||
@@ -349,14 +394,12 @@ export default class JournalCommands{
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {string} referenceType -
|
* @param {string} referenceType -
|
||||||
* @param {number} referenceId -
|
* @param {number} referenceId -
|
||||||
* @param {ISaleInvoice[]} sales -
|
* @param {ISaleInvoice[]} sales -
|
||||||
*/
|
*/
|
||||||
public async inventoryEntries(
|
public async inventoryEntries(transactions: IInventoryCostEntity[]) {
|
||||||
transactions: IInventoryCostEntity[],
|
|
||||||
) {
|
|
||||||
const receivableAccount = { id: 10 };
|
const receivableAccount = { id: 10 };
|
||||||
const payableAccount = { id: 11 };
|
const payableAccount = { id: 11 };
|
||||||
|
|
||||||
@@ -366,12 +409,12 @@ export default class JournalCommands{
|
|||||||
referenceId: sale.referenceId,
|
referenceId: sale.referenceId,
|
||||||
referenceType: sale.referenceType,
|
referenceType: sale.referenceType,
|
||||||
};
|
};
|
||||||
switch(sale.referenceType) {
|
switch (sale.referenceType) {
|
||||||
case 'Bill':
|
case 'Bill':
|
||||||
const inventoryDebit: JournalEntry = new JournalEntry({
|
const inventoryDebit: JournalEntry = new JournalEntry({
|
||||||
...commonEntry,
|
...commonEntry,
|
||||||
debit: sale.inventory,
|
debit: sale.inventory,
|
||||||
account: sale.inventoryAccount,
|
account: sale.inventoryAccount,
|
||||||
});
|
});
|
||||||
const payableEntry: JournalEntry = new JournalEntry({
|
const payableEntry: JournalEntry = new JournalEntry({
|
||||||
...commonEntry,
|
...commonEntry,
|
||||||
@@ -401,7 +444,7 @@ export default class JournalCommands{
|
|||||||
const inventoryCredit: JournalEntry = new JournalEntry({
|
const inventoryCredit: JournalEntry = new JournalEntry({
|
||||||
...commonEntry,
|
...commonEntry,
|
||||||
credit: sale.cost,
|
credit: sale.cost,
|
||||||
account: sale.inventoryAccount,
|
account: sale.inventoryAccount,
|
||||||
});
|
});
|
||||||
this.journal.debit(receivableEntry);
|
this.journal.debit(receivableEntry);
|
||||||
this.journal.debit(costEntry);
|
this.journal.debit(costEntry);
|
||||||
@@ -418,19 +461,19 @@ export default class JournalCommands{
|
|||||||
* ----------
|
* ----------
|
||||||
* - Receivable accounts -> Debit -> XXXX
|
* - Receivable accounts -> Debit -> XXXX
|
||||||
* - Income -> Credit -> XXXX
|
* - Income -> Credit -> XXXX
|
||||||
*
|
*
|
||||||
* - Cost of goods sold -> Debit -> YYYY
|
* - Cost of goods sold -> Debit -> YYYY
|
||||||
* - Inventory assets -> YYYY
|
* - Inventory assets -> YYYY
|
||||||
*
|
*
|
||||||
* @param {ISaleInvoice} saleInvoice
|
* @param {ISaleInvoice} saleInvoice
|
||||||
* @param {JournalPoster} journal
|
* @param {JournalPoster} journal
|
||||||
*/
|
*/
|
||||||
saleInvoice(
|
saleInvoice(
|
||||||
saleInvoice: ISaleInvoice & {
|
saleInvoice: ISaleInvoice & {
|
||||||
costTransactions: IInventoryLotCost[],
|
costTransactions: IInventoryLotCost[];
|
||||||
entries: IItemEntry & { item: IItem },
|
entries: IItemEntry & { item: IItem };
|
||||||
},
|
},
|
||||||
receivableAccountsId: number,
|
receivableAccountsId: number
|
||||||
) {
|
) {
|
||||||
let inventoryTotal: number = 0;
|
let inventoryTotal: number = 0;
|
||||||
|
|
||||||
@@ -441,8 +484,9 @@ export default class JournalCommands{
|
|||||||
};
|
};
|
||||||
const costTransactions: Map<number, number> = new Map(
|
const costTransactions: Map<number, number> = new Map(
|
||||||
saleInvoice.costTransactions.map((trans: IInventoryLotCost) => [
|
saleInvoice.costTransactions.map((trans: IInventoryLotCost) => [
|
||||||
trans.entryId, trans.cost,
|
trans.entryId,
|
||||||
]),
|
trans.cost,
|
||||||
|
])
|
||||||
);
|
);
|
||||||
// XXX Debit - Receivable account.
|
// XXX Debit - Receivable account.
|
||||||
const receivableEntry = new JournalEntry({
|
const receivableEntry = new JournalEntry({
|
||||||
@@ -453,50 +497,52 @@ export default class JournalCommands{
|
|||||||
});
|
});
|
||||||
this.journal.debit(receivableEntry);
|
this.journal.debit(receivableEntry);
|
||||||
|
|
||||||
saleInvoice.entries.forEach((entry: IItemEntry & { item: IItem }, index) => {
|
saleInvoice.entries.forEach(
|
||||||
const cost: number = costTransactions.get(entry.id);
|
(entry: IItemEntry & { item: IItem }, index) => {
|
||||||
const income: number = entry.quantity * entry.rate;
|
const cost: number = costTransactions.get(entry.id);
|
||||||
|
const income: number = entry.quantity * entry.rate;
|
||||||
if (entry.item.type === 'inventory' && cost) {
|
|
||||||
// XXX Debit - Cost account.
|
|
||||||
const costEntry = new JournalEntry({
|
|
||||||
...commonEntry,
|
|
||||||
debit: cost,
|
|
||||||
account: entry.item.costAccountId,
|
|
||||||
note: entry.description,
|
|
||||||
index: index + 3,
|
|
||||||
});
|
|
||||||
this.journal.debit(costEntry);
|
|
||||||
inventoryTotal += cost;
|
|
||||||
}
|
|
||||||
// XXX Credit - Income account.
|
|
||||||
const incomeEntry = new JournalEntry({
|
|
||||||
...commonEntry,
|
|
||||||
credit: income,
|
|
||||||
account: entry.item.sellAccountId,
|
|
||||||
note: entry.description,
|
|
||||||
index: index + 2,
|
|
||||||
});
|
|
||||||
this.journal.credit(incomeEntry);
|
|
||||||
|
|
||||||
if (inventoryTotal > 0) {
|
if (entry.item.type === 'inventory' && cost) {
|
||||||
// XXX Credit - Inventory account.
|
// XXX Debit - Cost account.
|
||||||
const inventoryEntry = new JournalEntry({
|
const costEntry = new JournalEntry({
|
||||||
|
...commonEntry,
|
||||||
|
debit: cost,
|
||||||
|
account: entry.item.costAccountId,
|
||||||
|
note: entry.description,
|
||||||
|
index: index + 3,
|
||||||
|
});
|
||||||
|
this.journal.debit(costEntry);
|
||||||
|
inventoryTotal += cost;
|
||||||
|
}
|
||||||
|
// XXX Credit - Income account.
|
||||||
|
const incomeEntry = new JournalEntry({
|
||||||
...commonEntry,
|
...commonEntry,
|
||||||
credit: inventoryTotal,
|
credit: income,
|
||||||
account: entry.item.inventoryAccountId,
|
account: entry.item.sellAccountId,
|
||||||
index: index + 4,
|
note: entry.description,
|
||||||
|
index: index + 2,
|
||||||
});
|
});
|
||||||
this.journal.credit(inventoryEntry);
|
this.journal.credit(incomeEntry);
|
||||||
|
|
||||||
|
if (inventoryTotal > 0) {
|
||||||
|
// XXX Credit - Inventory account.
|
||||||
|
const inventoryEntry = new JournalEntry({
|
||||||
|
...commonEntry,
|
||||||
|
credit: inventoryTotal,
|
||||||
|
account: entry.item.inventoryAccountId,
|
||||||
|
index: index + 4,
|
||||||
|
});
|
||||||
|
this.journal.credit(inventoryEntry);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
saleInvoiceNonInventory(
|
saleInvoiceNonInventory(
|
||||||
saleInvoice: ISaleInvoice & {
|
saleInvoice: ISaleInvoice & {
|
||||||
entries: IItemEntry & { item: IItem },
|
entries: IItemEntry & { item: IItem };
|
||||||
},
|
},
|
||||||
receivableAccountsId: number,
|
receivableAccountsId: number
|
||||||
) {
|
) {
|
||||||
const commonEntry = {
|
const commonEntry = {
|
||||||
referenceType: 'SaleInvoice',
|
referenceType: 'SaleInvoice',
|
||||||
@@ -513,18 +559,20 @@ export default class JournalCommands{
|
|||||||
});
|
});
|
||||||
this.journal.debit(receivableEntry);
|
this.journal.debit(receivableEntry);
|
||||||
|
|
||||||
saleInvoice.entries.forEach((entry: IItemEntry & { item: IItem }, index: number) => {
|
saleInvoice.entries.forEach(
|
||||||
const income: number = entry.quantity * entry.rate;
|
(entry: IItemEntry & { item: IItem }, index: number) => {
|
||||||
|
const income: number = entry.quantity * entry.rate;
|
||||||
// XXX Credit - Income account.
|
|
||||||
const incomeEntry = new JournalEntry({
|
// XXX Credit - Income account.
|
||||||
...commonEntry,
|
const incomeEntry = new JournalEntry({
|
||||||
credit: income,
|
...commonEntry,
|
||||||
account: entry.item.sellAccountId,
|
credit: income,
|
||||||
note: entry.description,
|
account: entry.item.sellAccountId,
|
||||||
index: index + 2,
|
note: entry.description,
|
||||||
});
|
index: index + 2,
|
||||||
this.journal.credit(incomeEntry);
|
});
|
||||||
});
|
this.journal.credit(incomeEntry);
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ import {
|
|||||||
IContactEditDTO,
|
IContactEditDTO,
|
||||||
IContact,
|
IContact,
|
||||||
ISaleInvoice,
|
ISaleInvoice,
|
||||||
|
ISystemService,
|
||||||
|
ISystemUser,
|
||||||
} from 'interfaces';
|
} from 'interfaces';
|
||||||
import { ServiceError } from 'exceptions';
|
import { ServiceError } from 'exceptions';
|
||||||
import TenancyService from 'services/Tenancy/TenancyService';
|
import TenancyService from 'services/Tenancy/TenancyService';
|
||||||
@@ -90,20 +92,20 @@ export default class CustomersService {
|
|||||||
*/
|
*/
|
||||||
public async newCustomer(
|
public async newCustomer(
|
||||||
tenantId: number,
|
tenantId: number,
|
||||||
customerDTO: ICustomerNewDTO
|
customerDTO: ICustomerNewDTO,
|
||||||
|
authorizedUser: ISystemUser
|
||||||
): Promise<ICustomer> {
|
): Promise<ICustomer> {
|
||||||
this.logger.info('[customer] trying to create a new customer.', {
|
this.logger.info('[customer] trying to create a new customer.', {
|
||||||
tenantId,
|
tenantId,
|
||||||
customerDTO,
|
customerDTO,
|
||||||
});
|
});
|
||||||
|
|
||||||
const customerObj = this.transformNewCustomerDTO(customerDTO);
|
const customerObj = this.transformNewCustomerDTO(customerDTO);
|
||||||
|
|
||||||
const customer = await this.contactService.newContact(
|
const customer = await this.contactService.newContact(
|
||||||
tenantId,
|
tenantId,
|
||||||
customerObj,
|
customerObj,
|
||||||
'customer'
|
'customer'
|
||||||
);
|
);
|
||||||
|
|
||||||
this.logger.info('[customer] created successfully.', {
|
this.logger.info('[customer] created successfully.', {
|
||||||
tenantId,
|
tenantId,
|
||||||
customerDTO,
|
customerDTO,
|
||||||
@@ -112,6 +114,7 @@ export default class CustomersService {
|
|||||||
customer,
|
customer,
|
||||||
tenantId,
|
tenantId,
|
||||||
customerId: customer.id,
|
customerId: customer.id,
|
||||||
|
authorizedUser,
|
||||||
});
|
});
|
||||||
|
|
||||||
return customer;
|
return customer;
|
||||||
@@ -127,7 +130,8 @@ export default class CustomersService {
|
|||||||
public async editCustomer(
|
public async editCustomer(
|
||||||
tenantId: number,
|
tenantId: number,
|
||||||
customerId: number,
|
customerId: number,
|
||||||
customerDTO: ICustomerEditDTO
|
customerDTO: ICustomerEditDTO,
|
||||||
|
authorizedUser: ISystemUser
|
||||||
): Promise<ICustomer> {
|
): Promise<ICustomer> {
|
||||||
const contactDTO = this.customerToContactDTO(customerDTO);
|
const contactDTO = this.customerToContactDTO(customerDTO);
|
||||||
|
|
||||||
@@ -143,11 +147,13 @@ export default class CustomersService {
|
|||||||
'customer'
|
'customer'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Triggers `onCustomerEdited` event.
|
||||||
this.eventDispatcher.dispatch(events.customers.onEdited);
|
this.eventDispatcher.dispatch(events.customers.onEdited);
|
||||||
this.logger.info('[customer] edited successfully.', {
|
this.logger.info('[customer] edited successfully.', {
|
||||||
tenantId,
|
tenantId,
|
||||||
customerId,
|
customerId,
|
||||||
customer,
|
customer,
|
||||||
|
authorizedUser,
|
||||||
});
|
});
|
||||||
|
|
||||||
return customer;
|
return customer;
|
||||||
@@ -161,7 +167,8 @@ export default class CustomersService {
|
|||||||
*/
|
*/
|
||||||
public async deleteCustomer(
|
public async deleteCustomer(
|
||||||
tenantId: number,
|
tenantId: number,
|
||||||
customerId: number
|
customerId: number,
|
||||||
|
authorizedUser: ISystemUser
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
this.logger.info('[customer] trying to delete customer.', {
|
this.logger.info('[customer] trying to delete customer.', {
|
||||||
tenantId,
|
tenantId,
|
||||||
@@ -184,6 +191,7 @@ export default class CustomersService {
|
|||||||
this.logger.info('[customer] deleted successfully.', {
|
this.logger.info('[customer] deleted successfully.', {
|
||||||
tenantId,
|
tenantId,
|
||||||
customerId,
|
customerId,
|
||||||
|
authorizedUser,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,7 +200,11 @@ export default class CustomersService {
|
|||||||
* @param {number} tenantId
|
* @param {number} tenantId
|
||||||
* @param {number} customerId
|
* @param {number} customerId
|
||||||
*/
|
*/
|
||||||
public async getCustomer(tenantId: number, customerId: number) {
|
public async getCustomer(
|
||||||
|
tenantId: number,
|
||||||
|
customerId: number,
|
||||||
|
authorizedUser: ISystemUser
|
||||||
|
) {
|
||||||
const contact = await this.contactService.getContact(
|
const contact = await this.contactService.getContact(
|
||||||
tenantId,
|
tenantId,
|
||||||
customerId,
|
customerId,
|
||||||
@@ -245,7 +257,8 @@ export default class CustomersService {
|
|||||||
tenantId: number,
|
tenantId: number,
|
||||||
customerId: number,
|
customerId: number,
|
||||||
openingBalance: number,
|
openingBalance: number,
|
||||||
openingBalanceAt: Date | string
|
openingBalanceAt: Date | string,
|
||||||
|
authorizedUserId: number
|
||||||
) {
|
) {
|
||||||
const journal = new JournalPoster(tenantId);
|
const journal = new JournalPoster(tenantId);
|
||||||
const journalCommands = new JournalCommands(journal);
|
const journalCommands = new JournalCommands(journal);
|
||||||
@@ -253,7 +266,8 @@ export default class CustomersService {
|
|||||||
await journalCommands.customerOpeningBalance(
|
await journalCommands.customerOpeningBalance(
|
||||||
customerId,
|
customerId,
|
||||||
openingBalance,
|
openingBalance,
|
||||||
openingBalanceAt
|
openingBalanceAt,
|
||||||
|
authorizedUserId
|
||||||
);
|
);
|
||||||
await Promise.all([journal.saveBalance(), journal.saveEntries()]);
|
await Promise.all([journal.saveBalance(), journal.saveEntries()]);
|
||||||
}
|
}
|
||||||
@@ -316,7 +330,11 @@ export default class CustomersService {
|
|||||||
* @param {number[]} customersIds
|
* @param {number[]} customersIds
|
||||||
* @return {Promise<void>}
|
* @return {Promise<void>}
|
||||||
*/
|
*/
|
||||||
public async deleteBulkCustomers(tenantId: number, customersIds: number[]) {
|
public async deleteBulkCustomers(
|
||||||
|
tenantId: number,
|
||||||
|
customersIds: number[],
|
||||||
|
authorizedUser: ISystemUser,
|
||||||
|
): Promise<void> {
|
||||||
const { Contact } = this.tenancy.models(tenantId);
|
const { Contact } = this.tenancy.models(tenantId);
|
||||||
|
|
||||||
// Validate the customers existance on the storage.
|
// Validate the customers existance on the storage.
|
||||||
@@ -332,6 +350,7 @@ export default class CustomersService {
|
|||||||
await this.eventDispatcher.dispatch(events.customers.onBulkDeleted, {
|
await this.eventDispatcher.dispatch(events.customers.onBulkDeleted, {
|
||||||
tenantId,
|
tenantId,
|
||||||
customersIds,
|
customersIds,
|
||||||
|
authorizedUser,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import {
|
|||||||
IVendorsFilter,
|
IVendorsFilter,
|
||||||
IPaginationMeta,
|
IPaginationMeta,
|
||||||
IFilterMeta,
|
IFilterMeta,
|
||||||
|
ISystemUser,
|
||||||
} from 'interfaces';
|
} from 'interfaces';
|
||||||
import { ServiceError } from 'exceptions';
|
import { ServiceError } from 'exceptions';
|
||||||
import DynamicListingService from 'services/DynamicListing/DynamicListService';
|
import DynamicListingService from 'services/DynamicListing/DynamicListService';
|
||||||
@@ -55,24 +56,28 @@ export default class VendorsService {
|
|||||||
* @param {IVendorNewDTO} vendorDTO
|
* @param {IVendorNewDTO} vendorDTO
|
||||||
* @return {Promise<void>}
|
* @return {Promise<void>}
|
||||||
*/
|
*/
|
||||||
public async newVendor(tenantId: number, vendorDTO: IVendorNewDTO) {
|
public async newVendor(
|
||||||
|
tenantId: number,
|
||||||
|
vendorDTO: IVendorNewDTO,
|
||||||
|
authorizedUser: ISystemUser
|
||||||
|
) {
|
||||||
this.logger.info('[vendor] trying create a new vendor.', {
|
this.logger.info('[vendor] trying create a new vendor.', {
|
||||||
tenantId,
|
tenantId,
|
||||||
vendorDTO,
|
vendorDTO,
|
||||||
});
|
});
|
||||||
|
|
||||||
const contactDTO = this.vendorToContactDTO(vendorDTO);
|
const contactDTO = this.vendorToContactDTO(vendorDTO);
|
||||||
|
|
||||||
const vendor = await this.contactService.newContact(
|
const vendor = await this.contactService.newContact(
|
||||||
tenantId,
|
tenantId,
|
||||||
contactDTO,
|
contactDTO,
|
||||||
'vendor'
|
'vendor'
|
||||||
);
|
);
|
||||||
|
|
||||||
// Triggers `onVendorCreated` event.
|
// Triggers `onVendorCreated` event.
|
||||||
await this.eventDispatcher.dispatch(events.vendors.onCreated, {
|
await this.eventDispatcher.dispatch(events.vendors.onCreated, {
|
||||||
tenantId,
|
tenantId,
|
||||||
vendorId: vendor.id,
|
vendorId: vendor.id,
|
||||||
vendor,
|
vendor,
|
||||||
|
authorizedUser,
|
||||||
});
|
});
|
||||||
return vendor;
|
return vendor;
|
||||||
}
|
}
|
||||||
@@ -85,7 +90,8 @@ export default class VendorsService {
|
|||||||
public async editVendor(
|
public async editVendor(
|
||||||
tenantId: number,
|
tenantId: number,
|
||||||
vendorId: number,
|
vendorId: number,
|
||||||
vendorDTO: IVendorEditDTO
|
vendorDTO: IVendorEditDTO,
|
||||||
|
authorizedUser: ISystemUser
|
||||||
) {
|
) {
|
||||||
const contactDTO = this.vendorToContactDTO(vendorDTO);
|
const contactDTO = this.vendorToContactDTO(vendorDTO);
|
||||||
const vendor = await this.contactService.editContact(
|
const vendor = await this.contactService.editContact(
|
||||||
@@ -95,8 +101,13 @@ export default class VendorsService {
|
|||||||
'vendor'
|
'vendor'
|
||||||
);
|
);
|
||||||
|
|
||||||
await this.eventDispatcher.dispatch(events.vendors.onEdited);
|
// Triggers `onVendorEdited` event.
|
||||||
|
await this.eventDispatcher.dispatch(events.vendors.onEdited, {
|
||||||
|
tenantId,
|
||||||
|
vendorId,
|
||||||
|
vendor,
|
||||||
|
authorizedUser,
|
||||||
|
});
|
||||||
return vendor;
|
return vendor;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,8 +130,15 @@ export default class VendorsService {
|
|||||||
* @param {number} vendorId
|
* @param {number} vendorId
|
||||||
* @return {Promise<void>}
|
* @return {Promise<void>}
|
||||||
*/
|
*/
|
||||||
public async deleteVendor(tenantId: number, vendorId: number) {
|
public async deleteVendor(
|
||||||
|
tenantId: number,
|
||||||
|
vendorId: number,
|
||||||
|
authorizedUser: ISystemUser
|
||||||
|
) {
|
||||||
|
// Validate the vendor existance on the storage.
|
||||||
await this.getVendorByIdOrThrowError(tenantId, vendorId);
|
await this.getVendorByIdOrThrowError(tenantId, vendorId);
|
||||||
|
|
||||||
|
// Validate the vendor has no associated bills.
|
||||||
await this.vendorHasNoBillsOrThrowError(tenantId, vendorId);
|
await this.vendorHasNoBillsOrThrowError(tenantId, vendorId);
|
||||||
|
|
||||||
this.logger.info('[vendor] trying to delete vendor.', {
|
this.logger.info('[vendor] trying to delete vendor.', {
|
||||||
@@ -129,9 +147,11 @@ export default class VendorsService {
|
|||||||
});
|
});
|
||||||
await this.contactService.deleteContact(tenantId, vendorId, 'vendor');
|
await this.contactService.deleteContact(tenantId, vendorId, 'vendor');
|
||||||
|
|
||||||
|
// Triggers `onVendorDeleted` event.
|
||||||
await this.eventDispatcher.dispatch(events.vendors.onDeleted, {
|
await this.eventDispatcher.dispatch(events.vendors.onDeleted, {
|
||||||
tenantId,
|
tenantId,
|
||||||
vendorId,
|
vendorId,
|
||||||
|
authorizedUser,
|
||||||
});
|
});
|
||||||
this.logger.info('[vendor] deleted successfully.', { tenantId, vendorId });
|
this.logger.info('[vendor] deleted successfully.', { tenantId, vendorId });
|
||||||
}
|
}
|
||||||
@@ -155,7 +175,9 @@ export default class VendorsService {
|
|||||||
public async writeVendorOpeningBalanceJournal(
|
public async writeVendorOpeningBalanceJournal(
|
||||||
tenantId: number,
|
tenantId: number,
|
||||||
vendorId: number,
|
vendorId: number,
|
||||||
openingBalance: number
|
openingBalance: number,
|
||||||
|
openingBalanceAt: Date | string,
|
||||||
|
user: ISystemUser
|
||||||
) {
|
) {
|
||||||
const journal = new JournalPoster(tenantId);
|
const journal = new JournalPoster(tenantId);
|
||||||
const journalCommands = new JournalCommands(journal);
|
const journalCommands = new JournalCommands(journal);
|
||||||
@@ -164,8 +186,12 @@ export default class VendorsService {
|
|||||||
tenantId,
|
tenantId,
|
||||||
vendorId,
|
vendorId,
|
||||||
});
|
});
|
||||||
await journalCommands.vendorOpeningBalance(vendorId, openingBalance);
|
await journalCommands.vendorOpeningBalance(
|
||||||
|
vendorId,
|
||||||
|
openingBalance,
|
||||||
|
openingBalanceAt,
|
||||||
|
user
|
||||||
|
);
|
||||||
await Promise.all([journal.saveBalance(), journal.saveEntries()]);
|
await Promise.all([journal.saveBalance(), journal.saveEntries()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -183,7 +209,7 @@ export default class VendorsService {
|
|||||||
|
|
||||||
this.logger.info(
|
this.logger.info(
|
||||||
'[customer] trying to revert opening balance journal entries.',
|
'[customer] trying to revert opening balance journal entries.',
|
||||||
{ tenantId, customerId }
|
{ tenantId, vendorId }
|
||||||
);
|
);
|
||||||
await this.contactService.revertJEntriesContactsOpeningBalance(
|
await this.contactService.revertJEntriesContactsOpeningBalance(
|
||||||
tenantId,
|
tenantId,
|
||||||
@@ -216,7 +242,8 @@ export default class VendorsService {
|
|||||||
*/
|
*/
|
||||||
public async deleteBulkVendors(
|
public async deleteBulkVendors(
|
||||||
tenantId: number,
|
tenantId: number,
|
||||||
vendorsIds: number[]
|
vendorsIds: number[],
|
||||||
|
authorizedUser: ISystemUser
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const { Contact } = this.tenancy.models(tenantId);
|
const { Contact } = this.tenancy.models(tenantId);
|
||||||
|
|
||||||
@@ -228,9 +255,11 @@ export default class VendorsService {
|
|||||||
|
|
||||||
await Contact.query().whereIn('id', vendorsIds).delete();
|
await Contact.query().whereIn('id', vendorsIds).delete();
|
||||||
|
|
||||||
|
// Triggers `onVendorsBulkDeleted` event.
|
||||||
await this.eventDispatcher.dispatch(events.vendors.onBulkDeleted, {
|
await this.eventDispatcher.dispatch(events.vendors.onBulkDeleted, {
|
||||||
tenantId,
|
tenantId,
|
||||||
vendorsIds,
|
vendorsIds,
|
||||||
|
authorizedUser,
|
||||||
});
|
});
|
||||||
|
|
||||||
this.logger.info('[vendor] bulk deleted successfully.', {
|
this.logger.info('[vendor] bulk deleted successfully.', {
|
||||||
@@ -266,7 +295,7 @@ export default class VendorsService {
|
|||||||
*/
|
*/
|
||||||
private async vendorsHaveNoBillsOrThrowError(
|
private async vendorsHaveNoBillsOrThrowError(
|
||||||
tenantId: number,
|
tenantId: number,
|
||||||
vendorsIds: number[],
|
vendorsIds: number[]
|
||||||
) {
|
) {
|
||||||
const { billRepository } = this.tenancy.repositories(tenantId);
|
const { billRepository } = this.tenancy.repositories(tenantId);
|
||||||
|
|
||||||
@@ -299,12 +328,12 @@ export default class VendorsService {
|
|||||||
filterMeta: IFilterMeta;
|
filterMeta: IFilterMeta;
|
||||||
}> {
|
}> {
|
||||||
const { Vendor } = this.tenancy.models(tenantId);
|
const { Vendor } = this.tenancy.models(tenantId);
|
||||||
|
|
||||||
const dynamicFilter = await this.dynamicListService.dynamicList(
|
const dynamicFilter = await this.dynamicListService.dynamicList(
|
||||||
tenantId,
|
tenantId,
|
||||||
Vendor,
|
Vendor,
|
||||||
vendorsFilter
|
vendorsFilter
|
||||||
);
|
);
|
||||||
|
|
||||||
const { results, pagination } = await Vendor.query()
|
const { results, pagination } = await Vendor.query()
|
||||||
.onBuild((builder) => {
|
.onBuild((builder) => {
|
||||||
dynamicFilter.buildQuery()(builder);
|
dynamicFilter.buildQuery()(builder);
|
||||||
|
|||||||
@@ -19,8 +19,12 @@ export default class CustomersSubscriber {
|
|||||||
* Handles the writing opening balance journal entries once the customer created.
|
* Handles the writing opening balance journal entries once the customer created.
|
||||||
*/
|
*/
|
||||||
@On(events.customers.onCreated)
|
@On(events.customers.onCreated)
|
||||||
async handleWriteOpenBalanceEntries({ tenantId, customerId, customer }) {
|
async handleWriteOpenBalanceEntries({
|
||||||
|
tenantId,
|
||||||
|
customerId,
|
||||||
|
customer,
|
||||||
|
authorizedUser,
|
||||||
|
}) {
|
||||||
// Writes the customer opening balance journal entries.
|
// Writes the customer opening balance journal entries.
|
||||||
if (customer.openingBalance) {
|
if (customer.openingBalance) {
|
||||||
await this.customersService.writeCustomerOpeningBalanceJournal(
|
await this.customersService.writeCustomerOpeningBalanceJournal(
|
||||||
@@ -28,6 +32,7 @@ export default class CustomersSubscriber {
|
|||||||
customer.id,
|
customer.id,
|
||||||
customer.openingBalance,
|
customer.openingBalance,
|
||||||
customer.openingBalanceAt,
|
customer.openingBalanceAt,
|
||||||
|
authorizedUser.id
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -36,10 +41,14 @@ export default class CustomersSubscriber {
|
|||||||
* Handles the deleting opeing balance journal entrise once the customer deleted.
|
* Handles the deleting opeing balance journal entrise once the customer deleted.
|
||||||
*/
|
*/
|
||||||
@On(events.customers.onDeleted)
|
@On(events.customers.onDeleted)
|
||||||
async handleRevertOpeningBalanceEntries({ tenantId, customerId }) {
|
async handleRevertOpeningBalanceEntries({
|
||||||
|
tenantId,
|
||||||
|
customerId,
|
||||||
|
authorizedUser,
|
||||||
|
}) {
|
||||||
await this.customersService.revertOpeningBalanceEntries(
|
await this.customersService.revertOpeningBalanceEntries(
|
||||||
tenantId, customerId,
|
tenantId,
|
||||||
|
customerId
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,10 +57,14 @@ export default class CustomersSubscriber {
|
|||||||
* customers deleted.
|
* customers deleted.
|
||||||
*/
|
*/
|
||||||
@On(events.customers.onBulkDeleted)
|
@On(events.customers.onBulkDeleted)
|
||||||
async handleBulkRevertOpeningBalanceEntries({ tenantId, customersIds }) {
|
async handleBulkRevertOpeningBalanceEntries({
|
||||||
|
tenantId,
|
||||||
|
customersIds,
|
||||||
|
authorizedUser,
|
||||||
|
}) {
|
||||||
await this.customersService.revertOpeningBalanceEntries(
|
await this.customersService.revertOpeningBalanceEntries(
|
||||||
tenantId, customersIds,
|
tenantId,
|
||||||
|
customersIds
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,13 +22,15 @@ export default class VendorsSubscriber {
|
|||||||
* Writes the open balance journal entries once the vendor created.
|
* Writes the open balance journal entries once the vendor created.
|
||||||
*/
|
*/
|
||||||
@On(events.vendors.onCreated)
|
@On(events.vendors.onCreated)
|
||||||
async handleWriteOpeningBalanceEntries({ tenantId, vendorId, vendor }) {
|
async handleWriteOpeningBalanceEntries({ tenantId, vendorId, vendor, authorizedUser }) {
|
||||||
// Writes the vendor opening balance journal entries.
|
// Writes the vendor opening balance journal entries.
|
||||||
if (vendor.openingBalance) {
|
if (vendor.openingBalance) {
|
||||||
await this.vendorsService.writeVendorOpeningBalanceJournal(
|
await this.vendorsService.writeVendorOpeningBalanceJournal(
|
||||||
tenantId,
|
tenantId,
|
||||||
vendor.id,
|
vendor.id,
|
||||||
vendor.openingBalance,
|
vendor.openingBalance,
|
||||||
|
vendor.openingBalanceAt,
|
||||||
|
authorizedUser.id
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -37,7 +39,7 @@ export default class VendorsSubscriber {
|
|||||||
* Revert the opening balance journal entries once the vendor deleted.
|
* Revert the opening balance journal entries once the vendor deleted.
|
||||||
*/
|
*/
|
||||||
@On(events.vendors.onDeleted)
|
@On(events.vendors.onDeleted)
|
||||||
async handleRevertOpeningBalanceEntries({ tenantId, vendorId }) {
|
async handleRevertOpeningBalanceEntries({ tenantId, vendorId, authorizedUser }) {
|
||||||
await this.vendorsService.revertOpeningBalanceEntries(
|
await this.vendorsService.revertOpeningBalanceEntries(
|
||||||
tenantId, vendorId,
|
tenantId, vendorId,
|
||||||
);
|
);
|
||||||
@@ -47,7 +49,7 @@ export default class VendorsSubscriber {
|
|||||||
* Revert the opening balance journal entries once the vendors deleted in bulk.
|
* Revert the opening balance journal entries once the vendors deleted in bulk.
|
||||||
*/
|
*/
|
||||||
@On(events.vendors.onBulkDeleted)
|
@On(events.vendors.onBulkDeleted)
|
||||||
async handleBulkRevertOpeningBalanceEntries({ tenantId, vendorsIds }) {
|
async handleBulkRevertOpeningBalanceEntries({ tenantId, vendorsIds, authorizedUser }) {
|
||||||
await this.vendorsService.revertOpeningBalanceEntries(
|
await this.vendorsService.revertOpeningBalanceEntries(
|
||||||
tenantId, vendorsIds,
|
tenantId, vendorsIds,
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user