mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-16 04:40:32 +00:00
- feat: Optimize tenancy software architecture.
This commit is contained in:
@@ -28,13 +28,11 @@ export default {
|
||||
this.getManualJournal.validation,
|
||||
asyncMiddleware(this.getManualJournal.handler)
|
||||
);
|
||||
|
||||
router.get(
|
||||
'/manual-journals',
|
||||
this.manualJournals.validation,
|
||||
asyncMiddleware(this.manualJournals.handler)
|
||||
);
|
||||
|
||||
router.post(
|
||||
'/make-journal-entries',
|
||||
this.validateMediaIds,
|
||||
@@ -42,13 +40,11 @@ export default {
|
||||
this.makeJournalEntries.validation,
|
||||
asyncMiddleware(this.makeJournalEntries.handler)
|
||||
);
|
||||
|
||||
router.post(
|
||||
'/manual-journals/:id/publish',
|
||||
this.publishManualJournal.validation,
|
||||
asyncMiddleware(this.publishManualJournal.handler)
|
||||
);
|
||||
|
||||
router.post(
|
||||
'/manual-journals/:id',
|
||||
this.validateMediaIds,
|
||||
@@ -56,31 +52,26 @@ export default {
|
||||
this.editManualJournal.validation,
|
||||
asyncMiddleware(this.editManualJournal.handler)
|
||||
);
|
||||
|
||||
router.delete(
|
||||
'/manual-journals/:id',
|
||||
this.deleteManualJournal.validation,
|
||||
asyncMiddleware(this.deleteManualJournal.handler)
|
||||
);
|
||||
|
||||
router.delete(
|
||||
'/manual-journals',
|
||||
this.deleteBulkManualJournals.validation,
|
||||
asyncMiddleware(this.deleteBulkManualJournals.handler)
|
||||
);
|
||||
|
||||
router.post(
|
||||
'/recurring-journal-entries',
|
||||
this.recurringJournalEntries.validation,
|
||||
asyncMiddleware(this.recurringJournalEntries.handler)
|
||||
);
|
||||
|
||||
router.post(
|
||||
'quick-journal-entries',
|
||||
this.quickJournalEntries.validation,
|
||||
asyncMiddleware(this.quickJournalEntries.handler)
|
||||
);
|
||||
|
||||
return router;
|
||||
},
|
||||
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
|
||||
|
||||
|
||||
export default class BaseController {
|
||||
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Inject, Service } from 'typedi';
|
||||
import { Router, Request, Response } from 'express';
|
||||
import { check, param, query, ValidationChain } from 'express-validator';
|
||||
import { check, param, query, ValidationChain, matchedData } from 'express-validator';
|
||||
import asyncMiddleware from '@/http/middleware/asyncMiddleware';
|
||||
import validateMiddleware from '@/http/middleware/validateMiddleware';
|
||||
import ItemsService from '@/services/Items/ItemsService';
|
||||
@@ -7,23 +8,27 @@ import DynamicListing from '@/services/DynamicListing/DynamicListing';
|
||||
import DynamicListingBuilder from '@/services/DynamicListing/DynamicListingBuilder';
|
||||
import { dynamicListingErrorsToResponse } from '@/services/DynamicListing/hasDynamicListing';
|
||||
|
||||
@Service()
|
||||
export default class ItemsController {
|
||||
@Inject()
|
||||
itemsService: ItemsService;
|
||||
|
||||
/**
|
||||
* Router constructor.
|
||||
*/
|
||||
static router() {
|
||||
router() {
|
||||
const router = Router();
|
||||
|
||||
router.post(
|
||||
'/',
|
||||
this.validateItemSchema,
|
||||
validateMiddleware,
|
||||
asyncMiddleware(this.validateCategoryExistance),
|
||||
asyncMiddleware(this.validateCostAccountExistance),
|
||||
asyncMiddleware(this.validateSellAccountExistance),
|
||||
asyncMiddleware(this.validateInventoryAccountExistance),
|
||||
asyncMiddleware(this.validateItemNameExistance),
|
||||
asyncMiddleware(this.newItem),
|
||||
asyncMiddleware(this.validateCategoryExistance.bind(this)),
|
||||
asyncMiddleware(this.validateCostAccountExistance.bind(this)),
|
||||
asyncMiddleware(this.validateSellAccountExistance.bind(this)),
|
||||
asyncMiddleware(this.validateInventoryAccountExistance.bind(this)),
|
||||
asyncMiddleware(this.validateItemNameExistance.bind(this)),
|
||||
asyncMiddleware(this.newItem.bind(this)),
|
||||
);
|
||||
router.post(
|
||||
'/:id', [
|
||||
@@ -31,49 +36,41 @@ export default class ItemsController {
|
||||
...this.validateSpecificItemSchema,
|
||||
],
|
||||
validateMiddleware,
|
||||
asyncMiddleware(this.validateItemExistance),
|
||||
asyncMiddleware(this.validateCategoryExistance),
|
||||
asyncMiddleware(this.validateCostAccountExistance),
|
||||
asyncMiddleware(this.validateSellAccountExistance),
|
||||
asyncMiddleware(this.validateInventoryAccountExistance),
|
||||
asyncMiddleware(this.validateItemNameExistance),
|
||||
asyncMiddleware(this.editItem),
|
||||
asyncMiddleware(this.validateItemExistance.bind(this)),
|
||||
asyncMiddleware(this.validateCategoryExistance.bind(this)),
|
||||
asyncMiddleware(this.validateCostAccountExistance.bind(this)),
|
||||
asyncMiddleware(this.validateSellAccountExistance.bind(this)),
|
||||
asyncMiddleware(this.validateInventoryAccountExistance.bind(this)),
|
||||
asyncMiddleware(this.validateItemNameExistance.bind(this)),
|
||||
asyncMiddleware(this.editItem.bind(this)),
|
||||
);
|
||||
router.delete(
|
||||
'/:id',
|
||||
this.validateSpecificItemSchema,
|
||||
validateMiddleware,
|
||||
asyncMiddleware(this.validateItemExistance),
|
||||
asyncMiddleware(this.deleteItem),
|
||||
asyncMiddleware(this.validateItemExistance.bind(this)),
|
||||
asyncMiddleware(this.deleteItem.bind(this)),
|
||||
);
|
||||
router.get(
|
||||
'/:id',
|
||||
this.validateSpecificItemSchema,
|
||||
validateMiddleware,
|
||||
asyncMiddleware(this.validateItemExistance),
|
||||
asyncMiddleware(this.getItem),
|
||||
asyncMiddleware(this.validateItemExistance.bind(this)),
|
||||
asyncMiddleware(this.getItem.bind(this)),
|
||||
);
|
||||
router.get(
|
||||
'/',
|
||||
this.validateListQuerySchema,
|
||||
validateMiddleware,
|
||||
asyncMiddleware(this.listItems),
|
||||
asyncMiddleware(this.listItems.bind(this)),
|
||||
);
|
||||
return router;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate item schema.
|
||||
*
|
||||
* @param {Request} req -
|
||||
* @param {Response} res -
|
||||
* @return {ValidationChain[]} - validation chain.
|
||||
*/
|
||||
static get validateItemSchema(
|
||||
req: Request,
|
||||
res: Response,
|
||||
next: Function,
|
||||
): ValidationChain[] {
|
||||
get validateItemSchema(): ValidationChain[] {
|
||||
return [
|
||||
check('name').exists(),
|
||||
check('type').exists().trim().escape()
|
||||
@@ -122,7 +119,7 @@ export default class ItemsController {
|
||||
/**
|
||||
* Validate specific item params schema.
|
||||
*/
|
||||
static get validateSpecificItemSchema(): ValidationChain[] {
|
||||
get validateSpecificItemSchema(): ValidationChain[] {
|
||||
return [
|
||||
param('id').exists().isNumeric().toInt(),
|
||||
];
|
||||
@@ -132,7 +129,7 @@ export default class ItemsController {
|
||||
/**
|
||||
* Validate list query schema
|
||||
*/
|
||||
static get validateListQuerySchema() {
|
||||
get validateListQuerySchema() {
|
||||
return [
|
||||
query('column_sort_order').optional().isIn(['created_at', 'name', 'amount', 'sku']),
|
||||
query('sort_order').optional().isIn(['desc', 'asc']),
|
||||
@@ -149,7 +146,7 @@ export default class ItemsController {
|
||||
* @param {Response} res -
|
||||
* @param {NextFunction} next -
|
||||
*/
|
||||
static async validateItemExistance(req: Request, res: Response, next: Function) {
|
||||
async validateItemExistance(req: Request, res: Response, next: Function) {
|
||||
const { Item } = req.models;
|
||||
const itemId: number = req.params.id;
|
||||
|
||||
@@ -169,7 +166,7 @@ export default class ItemsController {
|
||||
* @param {Response} res
|
||||
* @param {NextFunction} next
|
||||
*/
|
||||
static async validateItemNameExistance(req: Request, res: Response, next: Function) {
|
||||
async validateItemNameExistance(req: Request, res: Response, next: Function) {
|
||||
const { Item } = req.models;
|
||||
const item = req.body;
|
||||
const itemId: number = req.params.id;
|
||||
@@ -195,7 +192,7 @@ export default class ItemsController {
|
||||
* @param {Response} res
|
||||
* @param {Function} next
|
||||
*/
|
||||
static async validateCategoryExistance(req: Request, res: Response, next: Function) {
|
||||
async validateCategoryExistance(req: Request, res: Response, next: Function) {
|
||||
const { ItemCategory } = req.models;
|
||||
const item = req.body;
|
||||
|
||||
@@ -217,7 +214,7 @@ export default class ItemsController {
|
||||
* @param {Response} res
|
||||
* @param {Function} next
|
||||
*/
|
||||
static async validateCostAccountExistance(req: Request, res: Response, next: Function) {
|
||||
async validateCostAccountExistance(req: Request, res: Response, next: Function) {
|
||||
const { Account, AccountType } = req.models;
|
||||
const item = req.body;
|
||||
|
||||
@@ -244,7 +241,7 @@ export default class ItemsController {
|
||||
* @param {Response} res
|
||||
* @param {NextFunction} next
|
||||
*/
|
||||
static async validateSellAccountExistance(req: Request, res: Response, next: Function) {
|
||||
async validateSellAccountExistance(req: Request, res: Response, next: Function) {
|
||||
const { Account, AccountType } = req.models;
|
||||
const item = req.body;
|
||||
|
||||
@@ -271,7 +268,7 @@ export default class ItemsController {
|
||||
* @param {Response} res
|
||||
* @param {NextFunction} next
|
||||
*/
|
||||
static async validateInventoryAccountExistance(req: Request, res: Response, next: Function) {
|
||||
async validateInventoryAccountExistance(req: Request, res: Response, next: Function) {
|
||||
const { Account, AccountType } = req.models;
|
||||
const item = req.body;
|
||||
|
||||
@@ -297,9 +294,14 @@ export default class ItemsController {
|
||||
* @param {Request} req
|
||||
* @param {Response} res
|
||||
*/
|
||||
static async newItem(req: Request, res: Response,) {
|
||||
const item = req.body;
|
||||
const storedItem = await ItemsService.newItem(item);
|
||||
async newItem(req: Request, res: Response,) {
|
||||
const { tenantId } = req;
|
||||
|
||||
const item = matchedData(req, {
|
||||
locations: ['body'],
|
||||
includeOptionals: true
|
||||
});
|
||||
const storedItem = await this.itemsService.newItem(tenantId, item);
|
||||
|
||||
return res.status(200).send({ id: storedItem.id });
|
||||
}
|
||||
@@ -309,10 +311,15 @@ export default class ItemsController {
|
||||
* @param {Request} req
|
||||
* @param {Response} res
|
||||
*/
|
||||
static async editItem(req: Request, res: Response) {
|
||||
const item = req.body;
|
||||
async editItem(req: Request, res: Response) {
|
||||
const { tenantId } = req;
|
||||
|
||||
const itemId: number = req.params.id;
|
||||
const updatedItem = await ItemsService.editItem(item, itemId);
|
||||
const item = matchedData(req, {
|
||||
locations: ['body'],
|
||||
includeOptionals: true
|
||||
});
|
||||
const updatedItem = await this.itemsService.editItem(tenantId, item, itemId);
|
||||
|
||||
return res.status(200).send({ id: itemId });
|
||||
}
|
||||
@@ -322,9 +329,11 @@ export default class ItemsController {
|
||||
* @param {Request} req
|
||||
* @param {Response} res
|
||||
*/
|
||||
static async deleteItem(req: Request, res: Response) {
|
||||
async deleteItem(req: Request, res: Response) {
|
||||
const itemId: number = req.params.id;
|
||||
await ItemsService.deleteItem(itemId);
|
||||
const { tenantId } = req;
|
||||
|
||||
await this.itemsService.deleteItem(tenantId, itemId);
|
||||
|
||||
return res.status(200).send({ id: itemId });
|
||||
}
|
||||
@@ -335,9 +344,11 @@ export default class ItemsController {
|
||||
* @param {Response} res
|
||||
* @return {Response}
|
||||
*/
|
||||
static async getItem(req: Request, res: Response) {
|
||||
async getItem(req: Request, res: Response) {
|
||||
const itemId: number = req.params.id;
|
||||
const storedItem = await ItemsService.getItemWithMetadata(itemId);
|
||||
const { tenantId } = req;
|
||||
|
||||
const storedItem = await this.itemsService.getItemWithMetadata(tenantId, itemId);
|
||||
|
||||
return res.status(200).send({ item: storedItem });
|
||||
}
|
||||
@@ -347,7 +358,7 @@ export default class ItemsController {
|
||||
* @param {Request} req
|
||||
* @param {Response} res
|
||||
*/
|
||||
static async listItems(req: Request, res: Response) {
|
||||
async listItems(req: Request, res: Response) {
|
||||
const filter = {
|
||||
filter_roles: [],
|
||||
sort_order: 'asc',
|
||||
|
||||
@@ -1,63 +1,75 @@
|
||||
import express from 'express';
|
||||
import { check, param, query } from 'express-validator';
|
||||
import { Router, Request, Response } from 'express';
|
||||
import { check, param, query, matchedData } from 'express-validator';
|
||||
import { Service, Inject } from 'typedi';
|
||||
import { difference } from 'lodash';
|
||||
import { BillOTD } from '@/interfaces';
|
||||
import validateMiddleware from '@/http/middleware/validateMiddleware';
|
||||
import asyncMiddleware from '@/http/middleware/asyncMiddleware';
|
||||
import BillsService from '@/services/Purchases/Bills';
|
||||
import BaseController from '@/http/controllers/BaseController';
|
||||
import VendorsServices from '@/services/Vendors/VendorsService';
|
||||
import ItemsService from '@/services/Items/ItemsService';
|
||||
import TenancyService from '@/services/Tenancy/TenancyService';
|
||||
import DynamicListingBuilder from '@/services/DynamicListing/DynamicListingBuilder';
|
||||
import DynamicListing from '@/services/DynamicListing/DynamicListing';
|
||||
import { dynamicListingErrorsToResponse } from '@/services/DynamicListing/HasDynamicListing';
|
||||
import { difference } from 'lodash';
|
||||
|
||||
@Service()
|
||||
export default class BillsController extends BaseController {
|
||||
@Inject()
|
||||
itemsService: ItemsService;
|
||||
|
||||
@Inject()
|
||||
billsService: BillsService;
|
||||
|
||||
@Inject()
|
||||
tenancy: TenancyService;
|
||||
|
||||
/**
|
||||
* Router constructor.
|
||||
*/
|
||||
static router() {
|
||||
const router = express.Router();
|
||||
router() {
|
||||
const router = Router();
|
||||
|
||||
router.post(
|
||||
'/',
|
||||
[...this.billValidationSchema],
|
||||
validateMiddleware,
|
||||
asyncMiddleware(this.validateVendorExistance),
|
||||
asyncMiddleware(this.validateItemsIds),
|
||||
asyncMiddleware(this.validateBillNumberExists),
|
||||
asyncMiddleware(this.validateNonPurchasableEntriesItems),
|
||||
asyncMiddleware(this.newBill)
|
||||
asyncMiddleware(this.validateVendorExistance.bind(this)),
|
||||
asyncMiddleware(this.validateItemsIds.bind(this)),
|
||||
asyncMiddleware(this.validateBillNumberExists.bind(this)),
|
||||
asyncMiddleware(this.validateNonPurchasableEntriesItems.bind(this)),
|
||||
asyncMiddleware(this.newBill.bind(this))
|
||||
);
|
||||
router.post(
|
||||
'/:id',
|
||||
[...this.billValidationSchema, ...this.specificBillValidationSchema],
|
||||
validateMiddleware,
|
||||
asyncMiddleware(this.validateBillExistance),
|
||||
asyncMiddleware(this.validateVendorExistance),
|
||||
asyncMiddleware(this.validateItemsIds),
|
||||
asyncMiddleware(this.validateEntriesIdsExistance),
|
||||
asyncMiddleware(this.validateNonPurchasableEntriesItems),
|
||||
asyncMiddleware(this.editBill)
|
||||
asyncMiddleware(this.validateBillExistance.bind(this)),
|
||||
asyncMiddleware(this.validateVendorExistance.bind(this)),
|
||||
asyncMiddleware(this.validateItemsIds.bind(this)),
|
||||
asyncMiddleware(this.validateEntriesIdsExistance.bind(this)),
|
||||
asyncMiddleware(this.validateNonPurchasableEntriesItems.bind(this)),
|
||||
asyncMiddleware(this.editBill.bind(this))
|
||||
);
|
||||
router.get(
|
||||
'/:id',
|
||||
[...this.specificBillValidationSchema],
|
||||
validateMiddleware,
|
||||
asyncMiddleware(this.validateBillExistance),
|
||||
asyncMiddleware(this.getBill)
|
||||
asyncMiddleware(this.validateBillExistance.bind(this)),
|
||||
asyncMiddleware(this.getBill.bind(this))
|
||||
);
|
||||
router.get(
|
||||
'/',
|
||||
[...this.billsListingValidationSchema],
|
||||
validateMiddleware,
|
||||
asyncMiddleware(this.listingBills)
|
||||
asyncMiddleware(this.listingBills.bind(this))
|
||||
);
|
||||
router.delete(
|
||||
'/:id',
|
||||
[...this.specificBillValidationSchema],
|
||||
validateMiddleware,
|
||||
asyncMiddleware(this.validateBillExistance),
|
||||
asyncMiddleware(this.deleteBill)
|
||||
asyncMiddleware(this.validateBillExistance.bind(this)),
|
||||
asyncMiddleware(this.deleteBill.bind(this))
|
||||
);
|
||||
return router;
|
||||
}
|
||||
@@ -65,7 +77,7 @@ export default class BillsController extends BaseController {
|
||||
/**
|
||||
* Common validation schema.
|
||||
*/
|
||||
static get billValidationSchema() {
|
||||
get billValidationSchema() {
|
||||
return [
|
||||
check('bill_number').exists().trim().escape(),
|
||||
check('bill_date').exists().isISO8601(),
|
||||
@@ -87,14 +99,14 @@ export default class BillsController extends BaseController {
|
||||
/**
|
||||
* Bill validation schema.
|
||||
*/
|
||||
static get specificBillValidationSchema() {
|
||||
get specificBillValidationSchema() {
|
||||
return [param('id').exists().isNumeric().toInt()];
|
||||
}
|
||||
|
||||
/**
|
||||
* Bills list validation schema.
|
||||
*/
|
||||
static get billsListingValidationSchema() {
|
||||
get billsListingValidationSchema() {
|
||||
return [
|
||||
query('custom_view_id').optional().isNumeric().toInt(),
|
||||
query('stringified_filter_roles').optional().isJSON(),
|
||||
@@ -107,14 +119,17 @@ export default class BillsController extends BaseController {
|
||||
|
||||
/**
|
||||
* Validates whether the vendor is exist.
|
||||
* @async
|
||||
* @param {Request} req
|
||||
* @param {Response} res
|
||||
* @param {Function} next
|
||||
*/
|
||||
static async validateVendorExistance(req, res, next) {
|
||||
const isVendorExists = await VendorsServices.isVendorExists(
|
||||
req.body.vendor_id
|
||||
);
|
||||
async validateVendorExistance(req: Request, res: Response, next: Function) {
|
||||
const { tenantId } = req;
|
||||
const { Vendor } = req.models;
|
||||
|
||||
const isVendorExists = await Vendor.query().findById(req.body.vendor_id);
|
||||
|
||||
if (!isVendorExists) {
|
||||
return res.status(400).send({
|
||||
errors: [{ type: 'VENDOR.ID.NOT.FOUND', code: 300 }],
|
||||
@@ -125,12 +140,17 @@ export default class BillsController extends BaseController {
|
||||
|
||||
/**
|
||||
* Validates the given bill existance.
|
||||
* @async
|
||||
* @param {Request} req
|
||||
* @param {Response} res
|
||||
* @param {Function} next
|
||||
*/
|
||||
static async validateBillExistance(req, res, next) {
|
||||
const isBillExists = await BillsService.isBillExists(req.params.id);
|
||||
async validateBillExistance(req: Request, res: Response, next: Function) {
|
||||
const billId: number = req.params.id;
|
||||
const { tenantId } = req;
|
||||
|
||||
const isBillExists = await this.billsService.isBillExists(tenantId, billId);
|
||||
|
||||
if (!isBillExists) {
|
||||
return res.status(400).send({
|
||||
errors: [{ type: 'BILL.NOT.FOUND', code: 200 }],
|
||||
@@ -141,13 +161,17 @@ export default class BillsController extends BaseController {
|
||||
|
||||
/**
|
||||
* Validates the entries items ids.
|
||||
* @async
|
||||
* @param {Request} req
|
||||
* @param {Response} res
|
||||
* @param {Function} next
|
||||
*/
|
||||
static async validateItemsIds(req, res, next) {
|
||||
async validateItemsIds(req: Request, res: Response, next: Function) {
|
||||
const { tenantId } = req;
|
||||
const itemsIds = req.body.entries.map((e) => e.item_id);
|
||||
const notFoundItemsIds = await ItemsService.isItemsIdsExists(itemsIds);
|
||||
|
||||
const notFoundItemsIds = await this.itemsService.isItemsIdsExists(tenantId, itemsIds);
|
||||
|
||||
if (notFoundItemsIds.length > 0) {
|
||||
return res.status(400).send({
|
||||
errors: [{ type: 'ITEMS.IDS.NOT.FOUND', code: 400 }],
|
||||
@@ -158,15 +182,17 @@ export default class BillsController extends BaseController {
|
||||
|
||||
/**
|
||||
* Validates the bill number existance.
|
||||
* @async
|
||||
* @param {Request} req
|
||||
* @param {Response} res
|
||||
* @param {Function} next
|
||||
*/
|
||||
static async validateBillNumberExists(req, res, next) {
|
||||
const isBillNoExists = await BillsService.isBillNoExists(
|
||||
req.body.bill_number
|
||||
);
|
||||
async validateBillNumberExists(req: Request, res: Response, next: Function) {
|
||||
const { tenantId } = req;
|
||||
|
||||
const isBillNoExists = await this.billsService.isBillNoExists(
|
||||
tenantId, req.body.bill_number,
|
||||
);
|
||||
if (isBillNoExists) {
|
||||
return res.status(400).send({
|
||||
errors: [{ type: 'BILL.NUMBER.EXISTS', code: 500 }],
|
||||
@@ -181,20 +207,20 @@ export default class BillsController extends BaseController {
|
||||
* @param {Response} res
|
||||
* @param {Function} next
|
||||
*/
|
||||
static async validateEntriesIdsExistance(req, res, next) {
|
||||
async validateEntriesIdsExistance(req: Request, res: Response, next: Function) {
|
||||
const { id: billId } = req.params;
|
||||
const bill = { ...req.body };
|
||||
const { ItemEntry } = req.models;
|
||||
|
||||
const entriesIds = bill.entries.filter((e) => e.id).map((e) => e.id);
|
||||
|
||||
const storedEntries = await ItemEntry.tenant()
|
||||
.query()
|
||||
const storedEntries = await ItemEntry.query()
|
||||
.whereIn('reference_id', [billId])
|
||||
.whereIn('reference_type', ['Bill']);
|
||||
|
||||
const storedEntriesIds = storedEntries.map((entry) => entry.id);
|
||||
const notFoundEntriesIds = difference(entriesIds, storedEntriesIds);
|
||||
|
||||
if (notFoundEntriesIds.length > 0) {
|
||||
return res.status(400).send({
|
||||
errors: [{ type: 'BILL.ENTRIES.IDS.NOT.FOUND', code: 600 }],
|
||||
@@ -209,7 +235,7 @@ export default class BillsController extends BaseController {
|
||||
* @param {Response} res
|
||||
* @param {Function} next
|
||||
*/
|
||||
static async validateNonPurchasableEntriesItems(req, res, next) {
|
||||
async validateNonPurchasableEntriesItems(req: Request, res: Response, next: Function) {
|
||||
const { Item } = req.models;
|
||||
const bill = { ...req.body };
|
||||
const itemsIds = bill.entries.map(e => e.item_id);
|
||||
@@ -235,17 +261,15 @@ export default class BillsController extends BaseController {
|
||||
* @param {Response} res
|
||||
* @param {Function} next
|
||||
*/
|
||||
static async newBill(req, res, next) {
|
||||
async newBill(req: Request, res: Response, next: Function) {
|
||||
const { tenantId } = req;
|
||||
const { ItemEntry } = req.models;
|
||||
|
||||
const bill = {
|
||||
...req.body,
|
||||
entries: req.body.entries.map((entry) => ({
|
||||
...entry,
|
||||
amount: ItemEntry.calcAmount(entry),
|
||||
})),
|
||||
};
|
||||
const storedBill = await BillsService.createBill(bill);
|
||||
const billOTD: BillOTD = matchedData(req, {
|
||||
locations: ['body'],
|
||||
includeOptionals: true
|
||||
});
|
||||
const storedBill = await this.billsService.createBill(tenantId, billOTD);
|
||||
|
||||
return res.status(200).send({ id: storedBill.id });
|
||||
}
|
||||
@@ -255,17 +279,16 @@ export default class BillsController extends BaseController {
|
||||
* @param {Request} req
|
||||
* @param {Response} res
|
||||
*/
|
||||
static async editBill(req, res) {
|
||||
const { ItemEntry } = req.models;
|
||||
async editBill(req: Request, res: Response) {
|
||||
const { id: billId } = req.params;
|
||||
const bill = {
|
||||
...req.body,
|
||||
entries: req.body.entries.map((entry) => ({
|
||||
...entry,
|
||||
amount: ItemEntry.calcAmount(entry),
|
||||
})),
|
||||
};
|
||||
const editedBill = await BillsService.editBill(billId, bill);
|
||||
const { ItemEntry } = req.models;
|
||||
const { tenantId } = req;
|
||||
|
||||
const billOTD: BillOTD = matchedData(req, {
|
||||
locations: ['body'],
|
||||
includeOptionals: true
|
||||
});
|
||||
const editedBill = await this.billsService.editBill(tenantId, billId, billOTD);
|
||||
|
||||
return res.status(200).send({ id: billId });
|
||||
}
|
||||
@@ -276,9 +299,11 @@ export default class BillsController extends BaseController {
|
||||
* @param {Response} res
|
||||
* @return {Response}
|
||||
*/
|
||||
static async getBill(req, res) {
|
||||
async getBill(req: Request, res: Response) {
|
||||
const { tenantId } = req;
|
||||
const { id: billId } = req.params;
|
||||
const bill = await BillsService.getBillWithMetadata(billId);
|
||||
|
||||
const bill = await this.billsService.getBillWithMetadata(tenantId, billId);
|
||||
|
||||
return res.status(200).send({ bill });
|
||||
}
|
||||
@@ -289,9 +314,11 @@ export default class BillsController extends BaseController {
|
||||
* @param {Response} res -
|
||||
* @return {Response}
|
||||
*/
|
||||
static async deleteBill(req, res) {
|
||||
async deleteBill(req: Request, res: Response) {
|
||||
const billId = req.params.id;
|
||||
await BillsService.deleteBill(billId);
|
||||
const { tenantId } = req;
|
||||
|
||||
await this.billsService.deleteBill(tenantId, billId);
|
||||
|
||||
return res.status(200).send({ id: billId });
|
||||
}
|
||||
@@ -302,7 +329,7 @@ export default class BillsController extends BaseController {
|
||||
* @param {Response} res -
|
||||
* @return {Response}
|
||||
*/
|
||||
static async listingBills(req, res) {
|
||||
async listingBills(req: Request, res: Response) {
|
||||
const filter = {
|
||||
filter_roles: [],
|
||||
sort_order: 'asc',
|
||||
@@ -1,6 +1,7 @@
|
||||
|
||||
import { Router } from 'express';
|
||||
import { check, param, query, ValidationChain } from 'express-validator';
|
||||
import { Service, Inject } from 'typedi';
|
||||
import { check, param, query, ValidationChain, matchedData } from 'express-validator';
|
||||
import { difference } from 'lodash';
|
||||
import asyncMiddleware from '@/http/middleware/asyncMiddleware';
|
||||
import validateMiddleware from '@/http/middleware/validateMiddleware';
|
||||
@@ -13,55 +14,62 @@ import { dynamicListingErrorsToResponse } from '@/services/DynamicListing/hasDyn
|
||||
|
||||
/**
|
||||
* Bills payments controller.
|
||||
* @controller
|
||||
* @service
|
||||
*/
|
||||
@Service()
|
||||
export default class BillsPayments extends BaseController {
|
||||
@Inject()
|
||||
billPaymentService: BillPaymentsService;
|
||||
|
||||
@Inject()
|
||||
accountsService: AccountsService;
|
||||
|
||||
/**
|
||||
* Router constructor.
|
||||
*/
|
||||
static router() {
|
||||
router() {
|
||||
const router = Router();
|
||||
|
||||
router.post('/', [
|
||||
...this.billPaymentSchemaValidation,
|
||||
],
|
||||
validateMiddleware,
|
||||
asyncMiddleware(this.validateBillPaymentVendorExistance),
|
||||
asyncMiddleware(this.validatePaymentAccount),
|
||||
asyncMiddleware(this.validatePaymentNumber),
|
||||
asyncMiddleware(this.validateEntriesBillsExistance),
|
||||
asyncMiddleware(this.validateVendorsDueAmount),
|
||||
asyncMiddleware(this.createBillPayment),
|
||||
asyncMiddleware(this.validateBillPaymentVendorExistance.bind(this)),
|
||||
asyncMiddleware(this.validatePaymentAccount.bind(this)),
|
||||
asyncMiddleware(this.validatePaymentNumber.bind(this)),
|
||||
asyncMiddleware(this.validateEntriesBillsExistance.bind(this)),
|
||||
asyncMiddleware(this.validateVendorsDueAmount.bind(this)),
|
||||
asyncMiddleware(this.createBillPayment.bind(this)),
|
||||
);
|
||||
router.post('/:id', [
|
||||
...this.billPaymentSchemaValidation,
|
||||
...this.specificBillPaymentValidateSchema,
|
||||
],
|
||||
validateMiddleware,
|
||||
asyncMiddleware(this.validateBillPaymentVendorExistance),
|
||||
asyncMiddleware(this.validatePaymentAccount),
|
||||
asyncMiddleware(this.validatePaymentNumber),
|
||||
asyncMiddleware(this.validateEntriesIdsExistance),
|
||||
asyncMiddleware(this.validateEntriesBillsExistance),
|
||||
asyncMiddleware(this.validateVendorsDueAmount),
|
||||
asyncMiddleware(this.editBillPayment),
|
||||
asyncMiddleware(this.validateBillPaymentVendorExistance.bind(this)),
|
||||
asyncMiddleware(this.validatePaymentAccount.bind(this)),
|
||||
asyncMiddleware(this.validatePaymentNumber.bind(this)),
|
||||
asyncMiddleware(this.validateEntriesIdsExistance.bind(this)),
|
||||
asyncMiddleware(this.validateEntriesBillsExistance.bind(this)),
|
||||
asyncMiddleware(this.validateVendorsDueAmount.bind(this)),
|
||||
asyncMiddleware(this.editBillPayment.bind(this)),
|
||||
)
|
||||
router.delete('/:id',
|
||||
this.specificBillPaymentValidateSchema,
|
||||
validateMiddleware,
|
||||
asyncMiddleware(this.validateBillPaymentExistance),
|
||||
asyncMiddleware(this.deleteBillPayment),
|
||||
asyncMiddleware(this.validateBillPaymentExistance.bind(this)),
|
||||
asyncMiddleware(this.deleteBillPayment.bind(this)),
|
||||
);
|
||||
router.get('/:id',
|
||||
this.specificBillPaymentValidateSchema,
|
||||
validateMiddleware,
|
||||
asyncMiddleware(this.validateBillPaymentExistance),
|
||||
asyncMiddleware(this.getBillPayment),
|
||||
asyncMiddleware(this.validateBillPaymentExistance.bind(this)),
|
||||
asyncMiddleware(this.getBillPayment.bind(this)),
|
||||
);
|
||||
router.get('/',
|
||||
this.listingValidationSchema,
|
||||
validateMiddleware,
|
||||
asyncMiddleware(this.getBillsPayments)
|
||||
asyncMiddleware(this.getBillsPayments.bind(this))
|
||||
);
|
||||
return router;
|
||||
}
|
||||
@@ -69,7 +77,7 @@ export default class BillsPayments extends BaseController {
|
||||
/**
|
||||
* Bill payments schema validation.
|
||||
*/
|
||||
static get billPaymentSchemaValidation(): ValidationChain[] {
|
||||
get billPaymentSchemaValidation(): ValidationChain[] {
|
||||
return [
|
||||
check('vendor_id').exists().isNumeric().toInt(),
|
||||
check('payment_account_id').exists().isNumeric().toInt(),
|
||||
@@ -87,19 +95,33 @@ export default class BillsPayments extends BaseController {
|
||||
/**
|
||||
* Specific bill payment schema validation.
|
||||
*/
|
||||
static get specificBillPaymentValidateSchema(): ValidationChain[] {
|
||||
get specificBillPaymentValidateSchema(): ValidationChain[] {
|
||||
return [
|
||||
param('id').exists().isNumeric().toInt(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Bills payment list validation schema.
|
||||
*/
|
||||
get listingValidationSchema(): ValidationChain[] {
|
||||
return [
|
||||
query('custom_view_id').optional().isNumeric().toInt(),
|
||||
query('stringified_filter_roles').optional().isJSON(),
|
||||
query('column_sort_by').optional(),
|
||||
query('sort_order').optional().isIn(['desc', 'asc']),
|
||||
query('page').optional().isNumeric().toInt(),
|
||||
query('page_size').optional().isNumeric().toInt(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate whether the bill payment vendor exists on the storage.
|
||||
* @param {Request} req
|
||||
* @param {Response} res
|
||||
* @param {Function} next
|
||||
*/
|
||||
static async validateBillPaymentVendorExistance(req: Request, res: Response, next: any ) {
|
||||
async validateBillPaymentVendorExistance(req: Request, res: Response, next: any ) {
|
||||
const billPayment = req.body;
|
||||
const { Vendor } = req.models;
|
||||
const isVendorExists = await Vendor.query().findById(billPayment.vendor_id);
|
||||
@@ -118,7 +140,7 @@ export default class BillsPayments extends BaseController {
|
||||
* @param {Response} res
|
||||
* @param {Function} next
|
||||
*/
|
||||
static async validateBillPaymentExistance(req: Request, res: Response, next: any ) {
|
||||
async validateBillPaymentExistance(req: Request, res: Response, next: any ) {
|
||||
const { id: billPaymentId } = req.params;
|
||||
const { BillPayment } = req.models;
|
||||
const foundBillPayment = await BillPayment.query().findById(billPaymentId);
|
||||
@@ -137,11 +159,15 @@ export default class BillsPayments extends BaseController {
|
||||
* @param {Response} res
|
||||
* @param {Function} next
|
||||
*/
|
||||
static async validatePaymentAccount(req: Request, res: Response, next: any) {
|
||||
async validatePaymentAccount(req: Request, res: Response, next: any) {
|
||||
const { tenantId } = req;
|
||||
const billPayment = { ...req.body };
|
||||
const isAccountExists = await AccountsService.isAccountExists(
|
||||
|
||||
const isAccountExists = await this.accountsService.isAccountExists(
|
||||
tenantId,
|
||||
billPayment.payment_account_id
|
||||
);
|
||||
|
||||
if (!isAccountExists) {
|
||||
return res.status(400).send({
|
||||
errors: [{ type: 'PAYMENT.ACCOUNT.NOT.FOUND', code: 200 }],
|
||||
@@ -156,7 +182,7 @@ export default class BillsPayments extends BaseController {
|
||||
* @param {Response} res
|
||||
* @param {Function} res
|
||||
*/
|
||||
static async validatePaymentNumber(req: Request, res: Response, next: any) {
|
||||
async validatePaymentNumber(req: Request, res: Response, next: any) {
|
||||
const billPayment = { ...req.body };
|
||||
const { id: billPaymentId } = req.params;
|
||||
const { BillPayment } = req.models;
|
||||
@@ -164,7 +190,6 @@ export default class BillsPayments extends BaseController {
|
||||
const foundBillPayment = await BillPayment.query()
|
||||
.onBuild((builder: any) => {
|
||||
builder.where('payment_number', billPayment.payment_number)
|
||||
|
||||
if (billPaymentId) {
|
||||
builder.whereNot('id', billPaymentId);
|
||||
}
|
||||
@@ -185,7 +210,7 @@ export default class BillsPayments extends BaseController {
|
||||
* @param {Response} res
|
||||
* @param {NextFunction} next
|
||||
*/
|
||||
static async validateEntriesBillsExistance(req: Request, res: Response, next: any) {
|
||||
async validateEntriesBillsExistance(req: Request, res: Response, next: any) {
|
||||
const { Bill } = req.models;
|
||||
const billPayment = { ...req.body };
|
||||
const entriesBillsIds = billPayment.entries.map((e: any) => e.bill_id);
|
||||
@@ -210,7 +235,7 @@ export default class BillsPayments extends BaseController {
|
||||
* @param {NextFunction} next
|
||||
* @return {void}
|
||||
*/
|
||||
static async validateVendorsDueAmount(req: Request, res: Response, next: Function) {
|
||||
async validateVendorsDueAmount(req: Request, res: Response, next: Function) {
|
||||
const { Bill } = req.models;
|
||||
const billsIds = req.body.entries.map((entry: any) => entry.bill_id);
|
||||
const storedBills = await Bill.query()
|
||||
@@ -248,7 +273,7 @@ export default class BillsPayments extends BaseController {
|
||||
* @param {Response} res
|
||||
* @return {Response}
|
||||
*/
|
||||
static async validateEntriesIdsExistance(req: Request, res: Response, next: Function) {
|
||||
async validateEntriesIdsExistance(req: Request, res: Response, next: Function) {
|
||||
const { BillPaymentEntry } = req.models;
|
||||
|
||||
const billPayment = { id: req.params.id, ...req.body };
|
||||
@@ -256,7 +281,7 @@ export default class BillsPayments extends BaseController {
|
||||
.filter((entry: any) => entry.id)
|
||||
.map((entry: any) => entry.id);
|
||||
|
||||
const storedEntries = await BillPaymentEntry.tenant().query()
|
||||
const storedEntries = await BillPaymentEntry.query()
|
||||
.where('bill_payment_id', billPayment.id);
|
||||
|
||||
const storedEntriesIds = storedEntries.map((entry: any) => entry.id);
|
||||
@@ -277,9 +302,15 @@ export default class BillsPayments extends BaseController {
|
||||
* @param {Response} res
|
||||
* @param {Response} res
|
||||
*/
|
||||
static async createBillPayment(req: Request, res: Response) {
|
||||
const billPayment = { ...req.body };
|
||||
const storedPayment = await BillPaymentsService.createBillPayment(billPayment);
|
||||
async createBillPayment(req: Request, res: Response) {
|
||||
const { tenantId } = req;
|
||||
|
||||
const billPayment = matchedData(req, {
|
||||
locations: ['body'],
|
||||
includeOptionals: true,
|
||||
});
|
||||
const storedPayment = await this.billPaymentService
|
||||
.createBillPayment(tenantId, billPayment);
|
||||
|
||||
return res.status(200).send({ id: storedPayment.id });
|
||||
}
|
||||
@@ -289,10 +320,14 @@ export default class BillsPayments extends BaseController {
|
||||
* @param {Request} req
|
||||
* @param {Response} res
|
||||
*/
|
||||
static async editBillPayment(req: Request, res: Response) {
|
||||
const billPayment = { ...req.body };
|
||||
const { id: billPaymentId } = req.params;
|
||||
async editBillPayment(req: Request, res: Response) {
|
||||
const { tenantId } = req;
|
||||
|
||||
const billPayment = matchedData(req, {
|
||||
locations: ['body'],
|
||||
includeOptionals: true,
|
||||
});
|
||||
const { id: billPaymentId } = req.params;
|
||||
const { BillPayment } = req.models;
|
||||
|
||||
const oldBillPayment = await BillPayment.query()
|
||||
@@ -300,7 +335,8 @@ export default class BillsPayments extends BaseController {
|
||||
.withGraphFetched('entries')
|
||||
.first();
|
||||
|
||||
await BillPaymentsService.editBillPayment(
|
||||
await this.billPaymentService.editBillPayment(
|
||||
tenantId,
|
||||
billPaymentId,
|
||||
billPayment,
|
||||
oldBillPayment,
|
||||
@@ -315,11 +351,13 @@ export default class BillsPayments extends BaseController {
|
||||
* @param {Response} res -
|
||||
* @return {Response} res -
|
||||
*/
|
||||
static async deleteBillPayment(req: Request, res: Response) {
|
||||
async deleteBillPayment(req: Request, res: Response) {
|
||||
const { tenantId } = req;
|
||||
|
||||
const { id: billPaymentId } = req.params;
|
||||
const billPayment = req.body;
|
||||
|
||||
await BillPaymentsService.deleteBillPayment(billPaymentId);
|
||||
await this.billPaymentService.deleteBillPayment(tenantId, billPaymentId);
|
||||
|
||||
return res.status(200).send({ id: billPaymentId });
|
||||
}
|
||||
@@ -329,34 +367,23 @@ export default class BillsPayments extends BaseController {
|
||||
* @param {Request} req
|
||||
* @param {Response} res
|
||||
*/
|
||||
static async getBillPayment(req: Request, res: Response) {
|
||||
async getBillPayment(req: Request, res: Response) {
|
||||
const { tenantId } = req;
|
||||
const { id: billPaymentId } = req.params;
|
||||
const billPayment = await BillPaymentsService.getBillPaymentWithMetadata(billPaymentId);
|
||||
|
||||
const billPayment = await this.billPaymentService
|
||||
.getBillPaymentWithMetadata(tenantId, billPaymentId);
|
||||
|
||||
return res.status(200).send({ bill_payment: { ...billPayment } });
|
||||
}
|
||||
|
||||
/**
|
||||
* Bills payment list validation schema.
|
||||
*/
|
||||
static get listingValidationSchema(): ValidationChain[] {
|
||||
return [
|
||||
query('custom_view_id').optional().isNumeric().toInt(),
|
||||
query('stringified_filter_roles').optional().isJSON(),
|
||||
query('column_sort_by').optional(),
|
||||
query('sort_order').optional().isIn(['desc', 'asc']),
|
||||
query('page').optional().isNumeric().toInt(),
|
||||
query('page_size').optional().isNumeric().toInt(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve bills payments listing with pagination metadata.
|
||||
* @param {Request} req -
|
||||
* @param {Response} res -
|
||||
* @return {Response}
|
||||
*/
|
||||
static async getBillsPayments(req: Request, res: Response) {
|
||||
async getBillsPayments(req: Request, res: Response) {
|
||||
const filter = {
|
||||
filter_roles: [],
|
||||
sort_order: 'asc',
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import express from 'express';
|
||||
import { Container } from 'typedi';
|
||||
import Bills from '@/http/controllers/Purchases/Bills'
|
||||
import BillPayments from '@/http/controllers/Purchases/BillsPayments';
|
||||
|
||||
@@ -7,8 +8,8 @@ export default {
|
||||
router() {
|
||||
const router = express.Router();
|
||||
|
||||
router.use('/bills', Bills.router());
|
||||
router.use('/bill_payments', BillPayments.router());
|
||||
router.use('/bills', Container.get(Bills).router());
|
||||
router.use('/bill_payments', Container.get(BillPayments).router());
|
||||
|
||||
return router;
|
||||
}
|
||||
@@ -1,13 +1,14 @@
|
||||
import express from 'express';
|
||||
import { check, param, query } from 'express-validator';
|
||||
import { Router, Request, Response } from 'express';
|
||||
import { check, param, query, ValidationChain, matchedData } from 'express-validator';
|
||||
import { difference } from 'lodash';
|
||||
import { PaymentReceiveEntry } from '@/models';
|
||||
import { Inject, Service } from 'typedi';
|
||||
import { IPaymentReceive, IPaymentReceiveOTD } from '@/interfaces';
|
||||
import BaseController from '@/http/controllers/BaseController';
|
||||
import validateMiddleware from '@/http/middleware/validateMiddleware';
|
||||
import asyncMiddleware from '@/http/middleware/asyncMiddleware';
|
||||
import PaymentReceiveService from '@/services/Sales/PaymentsReceives';
|
||||
import CustomersService from '@/services/Customers/CustomersService';
|
||||
import SaleInvoicesService from '@/services/Sales/SalesInvoices';
|
||||
import SaleInvoiceService from '@/services/Sales/SalesInvoices';
|
||||
import AccountsService from '@/services/Accounts/AccountsService';
|
||||
import DynamicListing from '@/services/DynamicListing/DynamicListing';
|
||||
import DynamicListingBuilder from '@/services/DynamicListing/DynamicListingBuilder';
|
||||
@@ -15,70 +16,134 @@ import { dynamicListingErrorsToResponse } from '@/services/DynamicListing/hasDyn
|
||||
|
||||
/**
|
||||
* Payments receives controller.
|
||||
* @controller
|
||||
* @service
|
||||
*/
|
||||
@Service()
|
||||
export default class PaymentReceivesController extends BaseController {
|
||||
@Inject()
|
||||
paymentReceiveService: PaymentReceiveService;
|
||||
|
||||
@Inject()
|
||||
customersService: CustomersService;
|
||||
|
||||
@Inject()
|
||||
accountsService: AccountsService;
|
||||
|
||||
@Inject()
|
||||
saleInvoiceService: SaleInvoiceService;
|
||||
|
||||
/**
|
||||
* Router constructor.
|
||||
*/
|
||||
static router() {
|
||||
const router = express.Router();
|
||||
router() {
|
||||
const router = Router();
|
||||
|
||||
router.post(
|
||||
'/:id',
|
||||
this.editPaymentReceiveValidation,
|
||||
validateMiddleware,
|
||||
asyncMiddleware(this.validatePaymentReceiveExistance),
|
||||
asyncMiddleware(this.validatePaymentReceiveNoExistance),
|
||||
asyncMiddleware(this.validateCustomerExistance),
|
||||
asyncMiddleware(this.validateDepositAccount),
|
||||
asyncMiddleware(this.validateInvoicesIDs),
|
||||
asyncMiddleware(this.validateEntriesIdsExistance),
|
||||
asyncMiddleware(this.validateInvoicesPaymentsAmount),
|
||||
asyncMiddleware(this.editPaymentReceive),
|
||||
asyncMiddleware(this.validatePaymentReceiveExistance.bind(this)),
|
||||
asyncMiddleware(this.validatePaymentReceiveNoExistance.bind(this)),
|
||||
asyncMiddleware(this.validateCustomerExistance.bind(this)),
|
||||
asyncMiddleware(this.validateDepositAccount.bind(this)),
|
||||
asyncMiddleware(this.validateInvoicesIDs.bind(this)),
|
||||
asyncMiddleware(this.validateEntriesIdsExistance.bind(this)),
|
||||
asyncMiddleware(this.validateInvoicesPaymentsAmount.bind(this)),
|
||||
asyncMiddleware(this.editPaymentReceive.bind(this)),
|
||||
);
|
||||
router.post(
|
||||
'/',
|
||||
this.newPaymentReceiveValidation,
|
||||
validateMiddleware,
|
||||
asyncMiddleware(this.validatePaymentReceiveNoExistance),
|
||||
asyncMiddleware(this.validateCustomerExistance),
|
||||
asyncMiddleware(this.validateDepositAccount),
|
||||
asyncMiddleware(this.validateInvoicesIDs),
|
||||
asyncMiddleware(this.validateInvoicesPaymentsAmount),
|
||||
asyncMiddleware(this.newPaymentReceive),
|
||||
asyncMiddleware(this.validatePaymentReceiveNoExistance.bind(this)),
|
||||
asyncMiddleware(this.validateCustomerExistance.bind(this)),
|
||||
asyncMiddleware(this.validateDepositAccount.bind(this)),
|
||||
asyncMiddleware(this.validateInvoicesIDs.bind(this)),
|
||||
asyncMiddleware(this.validateInvoicesPaymentsAmount.bind(this)),
|
||||
asyncMiddleware(this.newPaymentReceive.bind(this)),
|
||||
);
|
||||
router.get(
|
||||
'/:id',
|
||||
this.paymentReceiveValidation,
|
||||
validateMiddleware,
|
||||
asyncMiddleware(this.validatePaymentReceiveExistance),
|
||||
asyncMiddleware(this.getPaymentReceive)
|
||||
asyncMiddleware(this.validatePaymentReceiveExistance.bind(this)),
|
||||
asyncMiddleware(this.getPaymentReceive.bind(this))
|
||||
);
|
||||
router.get(
|
||||
'/',
|
||||
this.validatePaymentReceiveList,
|
||||
validateMiddleware,
|
||||
asyncMiddleware(this.getPaymentReceiveList),
|
||||
asyncMiddleware(this.getPaymentReceiveList.bind(this)),
|
||||
);
|
||||
router.delete(
|
||||
'/:id',
|
||||
this.paymentReceiveValidation,
|
||||
validateMiddleware,
|
||||
asyncMiddleware(this.validatePaymentReceiveExistance),
|
||||
asyncMiddleware(this.deletePaymentReceive),
|
||||
asyncMiddleware(this.validatePaymentReceiveExistance.bind(this)),
|
||||
asyncMiddleware(this.deletePaymentReceive.bind(this)),
|
||||
);
|
||||
return router;
|
||||
}
|
||||
|
||||
/**
|
||||
* Payment receive schema.
|
||||
* @return {Array}
|
||||
*/
|
||||
get paymentReceiveSchema(): ValidationChain[] {
|
||||
return [
|
||||
check('customer_id').exists().isNumeric().toInt(),
|
||||
check('payment_date').exists(),
|
||||
check('reference_no').optional(),
|
||||
check('deposit_account_id').exists().isNumeric().toInt(),
|
||||
check('payment_receive_no').exists().trim().escape(),
|
||||
check('statement').optional().trim().escape(),
|
||||
|
||||
check('entries').isArray({ min: 1 }),
|
||||
|
||||
check('entries.*.invoice_id').exists().isNumeric().toInt(),
|
||||
check('entries.*.payment_amount').exists().isNumeric().toInt(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Payment receive list validation schema.
|
||||
*/
|
||||
get validatePaymentReceiveList(): ValidationChain[] {
|
||||
return [
|
||||
query('custom_view_id').optional().isNumeric().toInt(),
|
||||
query('stringified_filter_roles').optional().isJSON(),
|
||||
query('column_sort_by').optional(),
|
||||
query('sort_order').optional().isIn(['desc', 'asc']),
|
||||
query('page').optional().isNumeric().toInt(),
|
||||
query('page_size').optional().isNumeric().toInt(),
|
||||
]
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate payment receive parameters.
|
||||
*/
|
||||
get paymentReceiveValidation() {
|
||||
return [param('id').exists().isNumeric().toInt()];
|
||||
}
|
||||
|
||||
/**
|
||||
* New payment receive validation schema.
|
||||
* @return {Array}
|
||||
*/
|
||||
get newPaymentReceiveValidation() {
|
||||
return [...this.paymentReceiveSchema];
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the payment receive number existance.
|
||||
* @param {Request} req
|
||||
* @param {Response} res
|
||||
* @param {Function} next
|
||||
*/
|
||||
static async validatePaymentReceiveNoExistance(req, res, next) {
|
||||
const isPaymentNoExists = await PaymentReceiveService.isPaymentReceiveNoExists(
|
||||
async validatePaymentReceiveNoExistance(req: Request, res: Response, next: Function) {
|
||||
const tenantId = req.tenantId;
|
||||
const isPaymentNoExists = await this.paymentReceiveService.isPaymentReceiveNoExists(
|
||||
tenantId,
|
||||
req.body.payment_receive_no,
|
||||
req.params.id,
|
||||
);
|
||||
@@ -96,13 +161,16 @@ export default class PaymentReceivesController extends BaseController {
|
||||
* @param {Response} res
|
||||
* @param {Function} next
|
||||
*/
|
||||
static async validatePaymentReceiveExistance(req, res, next) {
|
||||
const isPaymentNoExists = await PaymentReceiveService.isPaymentReceiveExists(
|
||||
req.params.id
|
||||
);
|
||||
async validatePaymentReceiveExistance(req: Request, res: Response, next: Function) {
|
||||
const tenantId = req.tenantId;
|
||||
const isPaymentNoExists = await this.paymentReceiveService
|
||||
.isPaymentReceiveExists(
|
||||
tenantId,
|
||||
req.params.id
|
||||
);
|
||||
if (!isPaymentNoExists) {
|
||||
return res.status(400).send({
|
||||
errors: [{ type: 'PAYMENT.RECEIVE.NO.EXISTS', code: 600 }],
|
||||
errors: [{ type: 'PAYMENT.RECEIVE.NOT.EXISTS', code: 600 }],
|
||||
});
|
||||
}
|
||||
next();
|
||||
@@ -114,8 +182,10 @@ export default class PaymentReceivesController extends BaseController {
|
||||
* @param {Response} res
|
||||
* @param {Function} next
|
||||
*/
|
||||
static async validateDepositAccount(req, res, next) {
|
||||
const isDepositAccExists = await AccountsService.isAccountExists(
|
||||
async validateDepositAccount(req: Request, res: Response, next: Function) {
|
||||
const tenantId = req.tenantId;
|
||||
const isDepositAccExists = await this.accountsService.isAccountExists(
|
||||
tenantId,
|
||||
req.body.deposit_account_id
|
||||
);
|
||||
if (!isDepositAccExists) {
|
||||
@@ -132,10 +202,11 @@ export default class PaymentReceivesController extends BaseController {
|
||||
* @param {Response} res
|
||||
* @param {Function} next
|
||||
*/
|
||||
static async validateCustomerExistance(req, res, next) {
|
||||
const isCustomerExists = await CustomersService.isCustomerExists(
|
||||
req.body.customer_id
|
||||
);
|
||||
async validateCustomerExistance(req: Request, res: Response, next: Function) {
|
||||
const { Customer } = req.models;
|
||||
|
||||
const isCustomerExists = await Customer.query().findById(req.body.customer_id);
|
||||
|
||||
if (!isCustomerExists) {
|
||||
return res.status(400).send({
|
||||
errors: [{ type: 'CUSTOMER.ID.NOT.EXISTS', code: 200 }],
|
||||
@@ -150,10 +221,14 @@ export default class PaymentReceivesController extends BaseController {
|
||||
* @param {Response} res -
|
||||
* @param {Function} next -
|
||||
*/
|
||||
static async validateInvoicesIDs(req, res, next) {
|
||||
async validateInvoicesIDs(req: Request, res: Response, next: Function) {
|
||||
const paymentReceive = { ...req.body };
|
||||
const invoicesIds = paymentReceive.entries.map((e) => e.invoice_id);
|
||||
const notFoundInvoicesIDs = await SaleInvoicesService.isInvoicesExist(
|
||||
const { tenantId } = req;
|
||||
const invoicesIds = paymentReceive.entries
|
||||
.map((e) => e.invoice_id);
|
||||
|
||||
const notFoundInvoicesIDs = await this.saleInvoiceService.isInvoicesExist(
|
||||
tenantId,
|
||||
invoicesIds,
|
||||
paymentReceive.customer_id,
|
||||
);
|
||||
@@ -171,19 +246,19 @@ export default class PaymentReceivesController extends BaseController {
|
||||
* @param {Response} res -
|
||||
* @param {Function} next -
|
||||
*/
|
||||
static async validateInvoicesPaymentsAmount(req, res, next) {
|
||||
async validateInvoicesPaymentsAmount(req: Request, res: Response, next: Function) {
|
||||
const { SaleInvoice } = req.models;
|
||||
const invoicesIds = req.body.entries.map((e) => e.invoice_id);
|
||||
const storedInvoices = await SaleInvoice.tenant()
|
||||
.query()
|
||||
|
||||
const storedInvoices = await SaleInvoice.query()
|
||||
.whereIn('id', invoicesIds);
|
||||
|
||||
const storedInvoicesMap = new Map(
|
||||
storedInvoices.map((invoice) => [invoice.id, invoice])
|
||||
);
|
||||
const hasWrongPaymentAmount = [];
|
||||
const hasWrongPaymentAmount: any[] = [];
|
||||
|
||||
req.body.entries.forEach((entry, index) => {
|
||||
req.body.entries.forEach((entry, index: number) => {
|
||||
const entryInvoice = storedInvoicesMap.get(entry.invoice_id);
|
||||
const { dueAmount } = entryInvoice;
|
||||
|
||||
@@ -211,13 +286,15 @@ export default class PaymentReceivesController extends BaseController {
|
||||
* @param {Response} res
|
||||
* @return {Response}
|
||||
*/
|
||||
static async validateEntriesIdsExistance(req, res, next) {
|
||||
async validateEntriesIdsExistance(req: Request, res: Response, next: Function) {
|
||||
const paymentReceive = { id: req.params.id, ...req.body };
|
||||
const entriesIds = paymentReceive.entries
|
||||
.filter(entry => entry.id)
|
||||
.map(entry => entry.id);
|
||||
|
||||
const storedEntries = await PaymentReceiveEntry.tenant().query()
|
||||
const { PaymentReceiveEntry } = req.models;
|
||||
|
||||
const storedEntries = await PaymentReceiveEntry.query()
|
||||
.where('payment_receive_id', paymentReceive.id);
|
||||
|
||||
const storedEntriesIds = storedEntries.map((entry) => entry.id);
|
||||
@@ -231,49 +308,28 @@ export default class PaymentReceivesController extends BaseController {
|
||||
next();
|
||||
}
|
||||
|
||||
/**
|
||||
* Payment receive schema.
|
||||
* @return {Array}
|
||||
*/
|
||||
static get paymentReceiveSchema() {
|
||||
return [
|
||||
check('customer_id').exists().isNumeric().toInt(),
|
||||
check('payment_date').exists(),
|
||||
check('reference_no').optional(),
|
||||
check('deposit_account_id').exists().isNumeric().toInt(),
|
||||
check('payment_receive_no').exists().trim().escape(),
|
||||
check('statement').optional().trim().escape(),
|
||||
|
||||
check('entries').isArray({ min: 1 }),
|
||||
|
||||
check('entries.*.invoice_id').exists().isNumeric().toInt(),
|
||||
check('entries.*.payment_amount').exists().isNumeric().toInt(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* New payment receive validation schema.
|
||||
* @return {Array}
|
||||
*/
|
||||
static get newPaymentReceiveValidation() {
|
||||
return [...this.paymentReceiveSchema];
|
||||
}
|
||||
|
||||
/**
|
||||
* Records payment receive to the given customer with associated invoices.
|
||||
*/
|
||||
static async newPaymentReceive(req, res) {
|
||||
const paymentReceive = { ...req.body };
|
||||
const storedPaymentReceive = await PaymentReceiveService.createPaymentReceive(
|
||||
paymentReceive
|
||||
);
|
||||
async newPaymentReceive(req: Request, res: Response) {
|
||||
const { tenantId } = req;
|
||||
const paymentReceive: IPaymentReceiveOTD = matchedData(req, {
|
||||
locations: ['body'],
|
||||
includeOptionals: true,
|
||||
});
|
||||
|
||||
const storedPaymentReceive = await this.paymentReceiveService
|
||||
.createPaymentReceive(
|
||||
tenantId,
|
||||
paymentReceive,
|
||||
);
|
||||
return res.status(200).send({ id: storedPaymentReceive.id });
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit payment receive validation.
|
||||
*/
|
||||
static get editPaymentReceiveValidation() {
|
||||
get editPaymentReceiveValidation() {
|
||||
return [
|
||||
param('id').exists().isNumeric().toInt(),
|
||||
...this.paymentReceiveSchema,
|
||||
@@ -286,18 +342,23 @@ export default class PaymentReceivesController extends BaseController {
|
||||
* @param {Response} res
|
||||
* @return {Response}
|
||||
*/
|
||||
static async editPaymentReceive(req, res) {
|
||||
const paymentReceive = { ...req.body };
|
||||
async editPaymentReceive(req: Request, res: Response) {
|
||||
const { tenantId } = req;
|
||||
const { id: paymentReceiveId } = req.params;
|
||||
const { PaymentReceive } = req.models;
|
||||
|
||||
const paymentReceive: IPaymentReceiveOTD = matchedData(req, {
|
||||
locations: ['body'],
|
||||
});
|
||||
|
||||
// Retrieve the payment receive before updating.
|
||||
const oldPaymentReceive = await PaymentReceive.query()
|
||||
const oldPaymentReceive: IPaymentReceive = await PaymentReceive.query()
|
||||
.where('id', paymentReceiveId)
|
||||
.withGraphFetched('entries')
|
||||
.first();
|
||||
|
||||
await PaymentReceiveService.editPaymentReceive(
|
||||
await this.paymentReceiveService.editPaymentReceive(
|
||||
tenantId,
|
||||
paymentReceiveId,
|
||||
paymentReceive,
|
||||
oldPaymentReceive,
|
||||
@@ -305,28 +366,23 @@ export default class PaymentReceivesController extends BaseController {
|
||||
return res.status(200).send({ id: paymentReceiveId });
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate payment receive parameters.
|
||||
*/
|
||||
static get paymentReceiveValidation() {
|
||||
return [param('id').exists().isNumeric().toInt()];
|
||||
}
|
||||
|
||||
/**
|
||||
* Delets the given payment receive id.
|
||||
* @param {Request} req
|
||||
* @param {Response} res
|
||||
*/
|
||||
static async deletePaymentReceive(req, res) {
|
||||
async deletePaymentReceive(req: Request, res: Response) {
|
||||
const { tenantId } = req;
|
||||
const { id: paymentReceiveId } = req.params;
|
||||
|
||||
const { PaymentReceive } = req.models;
|
||||
|
||||
const storedPaymentReceive = await PaymentReceive.query()
|
||||
.where('id', paymentReceiveId)
|
||||
.withGraphFetched('entries')
|
||||
.first();
|
||||
|
||||
await PaymentReceiveService.deletePaymentReceive(
|
||||
await this.paymentReceiveService.deletePaymentReceive(
|
||||
tenantId,
|
||||
paymentReceiveId,
|
||||
storedPaymentReceive
|
||||
);
|
||||
@@ -339,7 +395,7 @@ export default class PaymentReceivesController extends BaseController {
|
||||
* @param {Request} req -
|
||||
* @param {Response} res -
|
||||
*/
|
||||
static async getPaymentReceive(req, res) {
|
||||
async getPaymentReceive(req: Request, res: Response) {
|
||||
const { id: paymentReceiveId } = req.params;
|
||||
const paymentReceive = await PaymentReceiveService.getPaymentReceive(
|
||||
paymentReceiveId
|
||||
@@ -347,27 +403,13 @@ export default class PaymentReceivesController extends BaseController {
|
||||
return res.status(200).send({ paymentReceive });
|
||||
}
|
||||
|
||||
/**
|
||||
* Payment receive list validation schema.
|
||||
*/
|
||||
static get validatePaymentReceiveList() {
|
||||
return [
|
||||
query('custom_view_id').optional().isNumeric().toInt(),
|
||||
query('stringified_filter_roles').optional().isJSON(),
|
||||
query('column_sort_by').optional(),
|
||||
query('sort_order').optional().isIn(['desc', 'asc']),
|
||||
query('page').optional().isNumeric().toInt(),
|
||||
query('page_size').optional().isNumeric().toInt(),
|
||||
]
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve payment receive list with pagination metadata.
|
||||
* @param {Request} req
|
||||
* @param {Response} res
|
||||
* @return {Response}
|
||||
*/
|
||||
static async getPaymentReceiveList(req, res) {
|
||||
async getPaymentReceiveList(req: Request, res: Response) {
|
||||
const filter = {
|
||||
filter_roles: [],
|
||||
sort_order: 'asc',
|
||||
@@ -1,6 +1,7 @@
|
||||
import express from 'express';
|
||||
import { check, param, query } from 'express-validator';
|
||||
import { ItemEntry } from '@/models';
|
||||
import { Router, Request, Response } from 'express';
|
||||
import { check, param, query, matchedData } from 'express-validator';
|
||||
import { Inject, Service } from 'typedi';
|
||||
import { ISaleEstimate, ISaleEstimateOTD } from '@/interfaces';
|
||||
import BaseController from '@/http/controllers/BaseController'
|
||||
import validateMiddleware from '@/http/middleware/validateMiddleware';
|
||||
import asyncMiddleware from '@/http/middleware/asyncMiddleware';
|
||||
@@ -10,21 +11,31 @@ import ItemsService from '@/services/Items/ItemsService';
|
||||
import DynamicListingBuilder from '@/services/DynamicListing/DynamicListingBuilder';
|
||||
import DynamicListing from '@/services/DynamicListing/DynamicListing';
|
||||
|
||||
@Service()
|
||||
export default class SalesEstimatesController extends BaseController {
|
||||
@Inject()
|
||||
saleEstimateService: SaleEstimateService;
|
||||
|
||||
@Inject()
|
||||
itemsService: ItemsService;
|
||||
|
||||
@Inject()
|
||||
customersService: CustomersService;
|
||||
|
||||
/**
|
||||
* Router constructor.
|
||||
*/
|
||||
static router() {
|
||||
const router = express.Router();
|
||||
router() {
|
||||
const router = Router();
|
||||
|
||||
router.post(
|
||||
'/',
|
||||
this.estimateValidationSchema,
|
||||
validateMiddleware,
|
||||
asyncMiddleware(this.validateEstimateCustomerExistance),
|
||||
asyncMiddleware(this.validateEstimateNumberExistance),
|
||||
asyncMiddleware(this.validateEstimateEntriesItemsExistance),
|
||||
asyncMiddleware(this.newEstimate)
|
||||
asyncMiddleware(this.validateEstimateCustomerExistance.bind(this)),
|
||||
asyncMiddleware(this.validateEstimateNumberExistance.bind(this)),
|
||||
asyncMiddleware(this.validateEstimateEntriesItemsExistance.bind(this)),
|
||||
asyncMiddleware(this.newEstimate.bind(this))
|
||||
);
|
||||
router.post(
|
||||
'/:id', [
|
||||
@@ -32,33 +43,33 @@ export default class SalesEstimatesController extends BaseController {
|
||||
...this.estimateValidationSchema,
|
||||
],
|
||||
validateMiddleware,
|
||||
asyncMiddleware(this.validateEstimateIdExistance),
|
||||
asyncMiddleware(this.validateEstimateCustomerExistance),
|
||||
asyncMiddleware(this.validateEstimateNumberExistance),
|
||||
asyncMiddleware(this.validateEstimateEntriesItemsExistance),
|
||||
asyncMiddleware(this.valdiateInvoiceEntriesIdsExistance),
|
||||
asyncMiddleware(this.editEstimate)
|
||||
asyncMiddleware(this.validateEstimateIdExistance.bind(this)),
|
||||
asyncMiddleware(this.validateEstimateCustomerExistance.bind(this)),
|
||||
asyncMiddleware(this.validateEstimateNumberExistance.bind(this)),
|
||||
asyncMiddleware(this.validateEstimateEntriesItemsExistance.bind(this)),
|
||||
asyncMiddleware(this.valdiateInvoiceEntriesIdsExistance.bind(this)),
|
||||
asyncMiddleware(this.editEstimate.bind(this))
|
||||
);
|
||||
router.delete(
|
||||
'/:id', [
|
||||
this.validateSpecificEstimateSchema,
|
||||
],
|
||||
validateMiddleware,
|
||||
asyncMiddleware(this.validateEstimateIdExistance),
|
||||
asyncMiddleware(this.deleteEstimate)
|
||||
asyncMiddleware(this.validateEstimateIdExistance.bind(this)),
|
||||
asyncMiddleware(this.deleteEstimate.bind(this))
|
||||
);
|
||||
router.get(
|
||||
'/:id',
|
||||
this.validateSpecificEstimateSchema,
|
||||
validateMiddleware,
|
||||
asyncMiddleware(this.validateEstimateIdExistance),
|
||||
asyncMiddleware(this.getEstimate)
|
||||
asyncMiddleware(this.validateEstimateIdExistance.bind(this)),
|
||||
asyncMiddleware(this.getEstimate.bind(this))
|
||||
);
|
||||
router.get(
|
||||
'/',
|
||||
this.validateEstimateListSchema,
|
||||
validateMiddleware,
|
||||
asyncMiddleware(this.getEstimates)
|
||||
asyncMiddleware(this.getEstimates.bind(this))
|
||||
);
|
||||
return router;
|
||||
}
|
||||
@@ -66,7 +77,7 @@ export default class SalesEstimatesController extends BaseController {
|
||||
/**
|
||||
* Estimate validation schema.
|
||||
*/
|
||||
static get estimateValidationSchema() {
|
||||
get estimateValidationSchema() {
|
||||
return [
|
||||
check('customer_id').exists().isNumeric().toInt(),
|
||||
check('estimate_date').exists().isISO8601(),
|
||||
@@ -90,7 +101,7 @@ export default class SalesEstimatesController extends BaseController {
|
||||
/**
|
||||
* Specific sale estimate validation schema.
|
||||
*/
|
||||
static get validateSpecificEstimateSchema() {
|
||||
get validateSpecificEstimateSchema() {
|
||||
return [
|
||||
param('id').exists().isNumeric().toInt(),
|
||||
];
|
||||
@@ -99,7 +110,7 @@ export default class SalesEstimatesController extends BaseController {
|
||||
/**
|
||||
* Sales estimates list validation schema.
|
||||
*/
|
||||
static get validateEstimateListSchema() {
|
||||
get validateEstimateListSchema() {
|
||||
return [
|
||||
query('custom_view_id').optional().isNumeric().toInt(),
|
||||
query('stringified_filter_roles').optional().isJSON(),
|
||||
@@ -116,12 +127,13 @@ export default class SalesEstimatesController extends BaseController {
|
||||
* @param {Response} res
|
||||
* @param {Function} next
|
||||
*/
|
||||
static async validateEstimateCustomerExistance(req, res, next) {
|
||||
async validateEstimateCustomerExistance(req: Request, res: Response, next: Function) {
|
||||
const estimate = { ...req.body };
|
||||
const isCustomerExists = await CustomersService.isCustomerExists(
|
||||
estimate.customer_id
|
||||
);
|
||||
if (!isCustomerExists) {
|
||||
const { Customer } = req.models
|
||||
|
||||
const foundCustomer = await Customer.query().findById(estimate.customer_id);
|
||||
|
||||
if (!foundCustomer) {
|
||||
return res.status(404).send({
|
||||
errors: [{ type: 'CUSTOMER.ID.NOT.FOUND', code: 200 }],
|
||||
});
|
||||
@@ -135,10 +147,12 @@ export default class SalesEstimatesController extends BaseController {
|
||||
* @param {Response} res
|
||||
* @param {Function} next
|
||||
*/
|
||||
static async validateEstimateNumberExistance(req, res, next) {
|
||||
async validateEstimateNumberExistance(req: Request, res: Response, next: Function) {
|
||||
const estimate = { ...req.body };
|
||||
const { tenantId } = req;
|
||||
|
||||
const isEstNumberUnqiue = await SaleEstimateService.isEstimateNumberUnique(
|
||||
const isEstNumberUnqiue = await this.saleEstimateService.isEstimateNumberUnique(
|
||||
tenantId,
|
||||
estimate.estimate_number,
|
||||
req.params.id,
|
||||
);
|
||||
@@ -147,7 +161,7 @@ export default class SalesEstimatesController extends BaseController {
|
||||
errors: [{ type: 'ESTIMATE.NUMBER.IS.NOT.UNQIUE', code: 300 }],
|
||||
});
|
||||
}
|
||||
next();
|
||||
next();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -156,12 +170,13 @@ export default class SalesEstimatesController extends BaseController {
|
||||
* @param {Response} res
|
||||
* @param {Function} next
|
||||
*/
|
||||
static async validateEstimateEntriesItemsExistance(req, res, next) {
|
||||
async validateEstimateEntriesItemsExistance(req: Request, res: Response, next: Function) {
|
||||
const tenantId = req.tenantId;
|
||||
const estimate = { ...req.body };
|
||||
const estimateItemsIds = estimate.entries.map(e => e.item_id);
|
||||
|
||||
// Validate items ids in estimate entries exists.
|
||||
const notFoundItemsIds = await ItemsService.isItemsIdsExists(estimateItemsIds);
|
||||
const notFoundItemsIds = await this.itemsService.isItemsIdsExists(tenantId, estimateItemsIds);
|
||||
|
||||
if (notFoundItemsIds.length > 0) {
|
||||
return res.boom.badRequest(null, {
|
||||
@@ -177,9 +192,12 @@ export default class SalesEstimatesController extends BaseController {
|
||||
* @param {Response} res
|
||||
* @param {Function} next
|
||||
*/
|
||||
static async validateEstimateIdExistance(req, res, next) {
|
||||
async validateEstimateIdExistance(req: Request, res: Response, next: Function) {
|
||||
const { id: estimateId } = req.params;
|
||||
const storedEstimate = await SaleEstimateService.getEstimate(estimateId);
|
||||
const { tenantId } = req;
|
||||
|
||||
const storedEstimate = await this.saleEstimateService
|
||||
.getEstimate(tenantId, estimateId);
|
||||
|
||||
if (!storedEstimate) {
|
||||
return res.status(404).send({
|
||||
@@ -195,14 +213,16 @@ export default class SalesEstimatesController extends BaseController {
|
||||
* @param {Response} res
|
||||
* @param {Function} next
|
||||
*/
|
||||
static async valdiateInvoiceEntriesIdsExistance(req, res, next) {
|
||||
async valdiateInvoiceEntriesIdsExistance(req: Request, res: Response, next: Function) {
|
||||
const { ItemEntry } = req.models;
|
||||
|
||||
const { id: saleInvoiceId } = req.params;
|
||||
const saleInvoice = { ...req.body };
|
||||
const entriesIds = saleInvoice.entries
|
||||
.filter(e => e.id)
|
||||
.map((e) => e.id);
|
||||
|
||||
const foundEntries = await ItemEntry.tenant().query()
|
||||
const foundEntries = await ItemEntry.query()
|
||||
.whereIn('id', entriesIds)
|
||||
.where('reference_type', 'SaleInvoice')
|
||||
.where('reference_id', saleInvoiceId);
|
||||
@@ -221,15 +241,14 @@ export default class SalesEstimatesController extends BaseController {
|
||||
* @param {Response} res -
|
||||
* @return {Response} res -
|
||||
*/
|
||||
static async newEstimate(req, res) {
|
||||
const estimate = {
|
||||
...req.body,
|
||||
entries: req.body.entries.map((entry) => ({
|
||||
...entry,
|
||||
amount: ItemEntry.calcAmount(entry),
|
||||
})),
|
||||
};
|
||||
const storedEstimate = await SaleEstimateService.createEstimate(estimate);
|
||||
async newEstimate(req: Request, res: Response) {
|
||||
const { tenantId } = req;
|
||||
const estimateOTD: ISaleEstimateOTD = matchedData(req, {
|
||||
locations: ['body'],
|
||||
includeOptionals: true,
|
||||
});
|
||||
const storedEstimate = await this.saleEstimateService
|
||||
.createEstimate(tenantId, estimateOTD);
|
||||
|
||||
return res.status(200).send({ id: storedEstimate.id });
|
||||
}
|
||||
@@ -239,12 +258,16 @@ export default class SalesEstimatesController extends BaseController {
|
||||
* @param {Request} req
|
||||
* @param {Response} res
|
||||
*/
|
||||
static async editEstimate(req, res) {
|
||||
async editEstimate(req: Request, res: Response) {
|
||||
const { id: estimateId } = req.params;
|
||||
const estimate = { ...req.body };
|
||||
const { tenantId } = req;
|
||||
|
||||
const estimateOTD: ISaleEstimateOTD = matchedData(req, {
|
||||
locations: ['body'],
|
||||
includeOptionals: true,
|
||||
});
|
||||
// Update estimate with associated estimate entries.
|
||||
await SaleEstimateService.editEstimate(estimateId, estimate);
|
||||
await this.saleEstimateService.editEstimate(tenantId, estimateId, estimateOTD);
|
||||
|
||||
return res.status(200).send({ id: estimateId });
|
||||
}
|
||||
@@ -254,9 +277,11 @@ export default class SalesEstimatesController extends BaseController {
|
||||
* @param {Request} req
|
||||
* @param {Response} res
|
||||
*/
|
||||
static async deleteEstimate(req, res) {
|
||||
async deleteEstimate(req: Request, res: Response) {
|
||||
const { id: estimateId } = req.params;
|
||||
await SaleEstimateService.deleteEstimate(estimateId);
|
||||
const { tenantId } = req;
|
||||
|
||||
await this.saleEstimateService.deleteEstimate(tenantId, estimateId);
|
||||
|
||||
return res.status(200).send({ id: estimateId });
|
||||
}
|
||||
@@ -264,9 +289,12 @@ export default class SalesEstimatesController extends BaseController {
|
||||
/**
|
||||
* Retrieve the given estimate with associated entries.
|
||||
*/
|
||||
static async getEstimate(req, res) {
|
||||
async getEstimate(req: Request, res: Response) {
|
||||
const { id: estimateId } = req.params;
|
||||
const estimate = await SaleEstimateService.getEstimateWithEntries(estimateId);
|
||||
const { tenantId } = req;
|
||||
|
||||
const estimate = await this.saleEstimateService
|
||||
.getEstimateWithEntries(tenantId, estimateId);
|
||||
|
||||
return res.status(200).send({ estimate });
|
||||
}
|
||||
@@ -276,7 +304,7 @@ export default class SalesEstimatesController extends BaseController {
|
||||
* @param {Request} req
|
||||
* @param {Response} res
|
||||
*/
|
||||
static async getEstimates(req, res) {
|
||||
async getEstimates(req: Request, res: Response) {
|
||||
const filter = {
|
||||
filter_roles: [],
|
||||
sort_order: 'asc',
|
||||
@@ -288,7 +316,7 @@ export default class SalesEstimatesController extends BaseController {
|
||||
filter.filter_roles = JSON.parse(filter.stringified_filter_roles);
|
||||
}
|
||||
const { SaleEstimate, Resource, View } = req.models;
|
||||
const resource = await Resource.tenant().query()
|
||||
const resource = await Resource.query()
|
||||
.remember()
|
||||
.where('name', 'sales_estimates')
|
||||
.withGraphFetched('fields')
|
||||
@@ -1,34 +1,40 @@
|
||||
import express from 'express';
|
||||
import { check, param, query } from 'express-validator';
|
||||
import { check, param, query, matchedData } from 'express-validator';
|
||||
import { difference } from 'lodash';
|
||||
import { raw } from 'objection';
|
||||
import { ItemEntry } from '@/models';
|
||||
import { Service, Inject } from 'typedi';
|
||||
import validateMiddleware from '@/http/middleware/validateMiddleware';
|
||||
import asyncMiddleware from '@/http/middleware/asyncMiddleware';
|
||||
import SaleInvoiceService from '@/services/Sales/SalesInvoices';
|
||||
import ItemsService from '@/services/Items/ItemsService';
|
||||
import CustomersService from '@/services/Customers/CustomersService';
|
||||
import DynamicListing from '@/services/DynamicListing/DynamicListing';
|
||||
import DynamicListingBuilder from '@/services/DynamicListing/DynamicListingBuilder';
|
||||
import { dynamicListingErrorsToResponse } from '@/services/DynamicListing/hasDynamicListing';
|
||||
import { Customer, Item } from '../../../models';
|
||||
import { ISaleInvoiceOTD } from '@/interfaces';
|
||||
|
||||
@Service()
|
||||
export default class SaleInvoicesController {
|
||||
@Inject()
|
||||
itemsService: ItemsService;
|
||||
|
||||
@Inject()
|
||||
saleInvoiceService: SaleInvoiceService;
|
||||
|
||||
/**
|
||||
* Router constructor.
|
||||
*/
|
||||
static router() {
|
||||
router() {
|
||||
const router = express.Router();
|
||||
|
||||
router.post(
|
||||
'/',
|
||||
this.saleInvoiceValidationSchema,
|
||||
validateMiddleware,
|
||||
asyncMiddleware(this.validateInvoiceCustomerExistance),
|
||||
asyncMiddleware(this.validateInvoiceNumberUnique),
|
||||
asyncMiddleware(this.validateInvoiceItemsIdsExistance),
|
||||
asyncMiddleware(this.validateNonSellableEntriesItems),
|
||||
asyncMiddleware(this.newSaleInvoice)
|
||||
asyncMiddleware(this.validateInvoiceCustomerExistance.bind(this)),
|
||||
asyncMiddleware(this.validateInvoiceNumberUnique.bind(this)),
|
||||
asyncMiddleware(this.validateInvoiceItemsIdsExistance.bind(this)),
|
||||
asyncMiddleware(this.validateNonSellableEntriesItems.bind(this)),
|
||||
asyncMiddleware(this.newSaleInvoice.bind(this))
|
||||
);
|
||||
router.post(
|
||||
'/:id',
|
||||
@@ -37,38 +43,38 @@ export default class SaleInvoicesController {
|
||||
...this.specificSaleInvoiceValidation,
|
||||
],
|
||||
validateMiddleware,
|
||||
asyncMiddleware(this.validateInvoiceExistance),
|
||||
asyncMiddleware(this.validateInvoiceCustomerExistance),
|
||||
asyncMiddleware(this.validateInvoiceNumberUnique),
|
||||
asyncMiddleware(this.validateInvoiceItemsIdsExistance),
|
||||
asyncMiddleware(this.valdiateInvoiceEntriesIdsExistance),
|
||||
asyncMiddleware(this.validateEntriesIdsExistance),
|
||||
asyncMiddleware(this.validateNonSellableEntriesItems),
|
||||
asyncMiddleware(this.editSaleInvoice)
|
||||
asyncMiddleware(this.validateInvoiceExistance.bind(this)),
|
||||
asyncMiddleware(this.validateInvoiceCustomerExistance.bind(this)),
|
||||
asyncMiddleware(this.validateInvoiceNumberUnique.bind(this)),
|
||||
asyncMiddleware(this.validateInvoiceItemsIdsExistance.bind(this)),
|
||||
asyncMiddleware(this.valdiateInvoiceEntriesIdsExistance.bind(this)),
|
||||
asyncMiddleware(this.validateEntriesIdsExistance.bind(this)),
|
||||
asyncMiddleware(this.validateNonSellableEntriesItems.bind(this)),
|
||||
asyncMiddleware(this.editSaleInvoice.bind(this))
|
||||
);
|
||||
router.delete(
|
||||
'/:id',
|
||||
this.specificSaleInvoiceValidation,
|
||||
validateMiddleware,
|
||||
asyncMiddleware(this.validateInvoiceExistance),
|
||||
asyncMiddleware(this.deleteSaleInvoice)
|
||||
asyncMiddleware(this.validateInvoiceExistance.bind(this)),
|
||||
asyncMiddleware(this.deleteSaleInvoice.bind(this))
|
||||
);
|
||||
router.get(
|
||||
'/due_invoices',
|
||||
this.dueSalesInvoicesListValidationSchema,
|
||||
asyncMiddleware(this.getDueSalesInvoice),
|
||||
asyncMiddleware(this.getDueSalesInvoice.bind(this)),
|
||||
);
|
||||
router.get(
|
||||
'/:id',
|
||||
this.specificSaleInvoiceValidation,
|
||||
validateMiddleware,
|
||||
asyncMiddleware(this.validateInvoiceExistance),
|
||||
asyncMiddleware(this.getSaleInvoice)
|
||||
asyncMiddleware(this.validateInvoiceExistance.bind(this)),
|
||||
asyncMiddleware(this.getSaleInvoice.bind(this))
|
||||
);
|
||||
router.get(
|
||||
'/',
|
||||
this.saleInvoiceListValidationSchema,
|
||||
asyncMiddleware(this.getSalesInvoices)
|
||||
asyncMiddleware(this.getSalesInvoices.bind(this))
|
||||
)
|
||||
return router;
|
||||
}
|
||||
@@ -76,7 +82,7 @@ export default class SaleInvoicesController {
|
||||
/**
|
||||
* Sale invoice validation schema.
|
||||
*/
|
||||
static get saleInvoiceValidationSchema() {
|
||||
get saleInvoiceValidationSchema() {
|
||||
return [
|
||||
check('customer_id').exists().isNumeric().toInt(),
|
||||
check('invoice_date').exists().isISO8601(),
|
||||
@@ -102,14 +108,14 @@ export default class SaleInvoicesController {
|
||||
/**
|
||||
* Specific sale invoice validation schema.
|
||||
*/
|
||||
static get specificSaleInvoiceValidation() {
|
||||
get specificSaleInvoiceValidation() {
|
||||
return [param('id').exists().isNumeric().toInt()];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sales invoices list validation schema.
|
||||
*/
|
||||
static get saleInvoiceListValidationSchema() {
|
||||
get saleInvoiceListValidationSchema() {
|
||||
return [
|
||||
query('custom_view_id').optional().isNumeric().toInt(),
|
||||
query('stringified_filter_roles').optional().isJSON(),
|
||||
@@ -120,8 +126,10 @@ export default class SaleInvoicesController {
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
static get dueSalesInvoicesListValidationSchema() {
|
||||
/**
|
||||
* Due sale invoice list validation schema.
|
||||
*/
|
||||
get dueSalesInvoicesListValidationSchema() {
|
||||
return [
|
||||
query('customer_id').optional().isNumeric().toInt(),
|
||||
]
|
||||
@@ -133,11 +141,12 @@ export default class SaleInvoicesController {
|
||||
* @param {Response} res
|
||||
* @param {Function} next
|
||||
*/
|
||||
static async validateInvoiceCustomerExistance(req, res, next) {
|
||||
async validateInvoiceCustomerExistance(req: Request, res: Response, next: Function) {
|
||||
const saleInvoice = { ...req.body };
|
||||
const isCustomerIDExists = await CustomersService.isCustomerExists(
|
||||
saleInvoice.customer_id
|
||||
);
|
||||
const { Customer } = req.models;
|
||||
|
||||
const isCustomerIDExists = await Customer.query().findById(saleInvoice.customer_id);
|
||||
|
||||
if (!isCustomerIDExists) {
|
||||
return res.status(400).send({
|
||||
errors: [{ type: 'CUSTOMER.ID.NOT.EXISTS', code: 200 }],
|
||||
@@ -148,15 +157,17 @@ export default class SaleInvoicesController {
|
||||
|
||||
/**
|
||||
* Validate whether sale invoice items ids esits on the storage.
|
||||
* @param {Request} req
|
||||
* @param {Response} res
|
||||
* @param {Function} next
|
||||
* @param {Request} req -
|
||||
* @param {Response} res -
|
||||
* @param {Function} next -
|
||||
*/
|
||||
static async validateInvoiceItemsIdsExistance(req, res, next) {
|
||||
async validateInvoiceItemsIdsExistance(req: Request, res: Response, next: Function) {
|
||||
const { tenantId } = req;
|
||||
const saleInvoice = { ...req.body };
|
||||
const entriesItemsIds = saleInvoice.entries.map((e) => e.item_id);
|
||||
const isItemsIdsExists = await ItemsService.isItemsIdsExists(
|
||||
entriesItemsIds
|
||||
|
||||
const isItemsIdsExists = await this.itemsService.isItemsIdsExists(
|
||||
tenantId, entriesItemsIds,
|
||||
);
|
||||
if (isItemsIdsExists.length > 0) {
|
||||
return res.status(400).send({
|
||||
@@ -173,9 +184,12 @@ export default class SaleInvoicesController {
|
||||
* @param {Response} res
|
||||
* @param {Function} next
|
||||
*/
|
||||
static async validateInvoiceNumberUnique(req, res, next) {
|
||||
async validateInvoiceNumberUnique(req: Request, res: Response, next: Function) {
|
||||
const { tenantId } = req;
|
||||
const saleInvoice = { ...req.body };
|
||||
const isInvoiceNoExists = await SaleInvoiceService.isSaleInvoiceNumberExists(
|
||||
|
||||
const isInvoiceNoExists = await this.saleInvoiceService.isSaleInvoiceNumberExists(
|
||||
tenantId,
|
||||
saleInvoice.invoice_no,
|
||||
req.params.id
|
||||
);
|
||||
@@ -195,10 +209,12 @@ export default class SaleInvoicesController {
|
||||
* @param {Response} res
|
||||
* @param {Function} next
|
||||
*/
|
||||
static async validateInvoiceExistance(req, res, next) {
|
||||
async validateInvoiceExistance(req: Request, res: Response, next: Function) {
|
||||
const { id: saleInvoiceId } = req.params;
|
||||
const isSaleInvoiceExists = await SaleInvoiceService.isSaleInvoiceExists(
|
||||
saleInvoiceId
|
||||
const { tenantId } = req;
|
||||
|
||||
const isSaleInvoiceExists = await this.saleInvoiceService.isSaleInvoiceExists(
|
||||
tenantId, saleInvoiceId,
|
||||
);
|
||||
if (!isSaleInvoiceExists) {
|
||||
return res
|
||||
@@ -214,12 +230,13 @@ export default class SaleInvoicesController {
|
||||
* @param {Response} res
|
||||
* @param {Function} next
|
||||
*/
|
||||
static async valdiateInvoiceEntriesIdsExistance(req, res, next) {
|
||||
async valdiateInvoiceEntriesIdsExistance(req: Request, res: Response, next: Function) {
|
||||
const { tenantId } = req;
|
||||
const saleInvoice = { ...req.body };
|
||||
const entriesItemsIds = saleInvoice.entries.map((e) => e.item_id);
|
||||
|
||||
const isItemsIdsExists = await ItemsService.isItemsIdsExists(
|
||||
entriesItemsIds
|
||||
const isItemsIdsExists = await this.itemsService.isItemsIdsExists(
|
||||
tenantId, entriesItemsIds,
|
||||
);
|
||||
if (isItemsIdsExists.length > 0) {
|
||||
return res.status(400).send({
|
||||
@@ -235,14 +252,16 @@ export default class SaleInvoicesController {
|
||||
* @param {Response} res
|
||||
* @param {Function} next
|
||||
*/
|
||||
static async validateEntriesIdsExistance(req, res, next) {
|
||||
async validateEntriesIdsExistance(req: Request, res: Response, next: Function) {
|
||||
const { ItemEntry } = req.models;
|
||||
const { id: saleInvoiceId } = req.params;
|
||||
const saleInvoice = { ...req.body };
|
||||
|
||||
const entriesIds = saleInvoice.entries
|
||||
.filter(e => e.id)
|
||||
.map(e => e.id);
|
||||
|
||||
const storedEntries = await ItemEntry.tenant().query()
|
||||
|
||||
const storedEntries = await ItemEntry.query()
|
||||
.whereIn('reference_id', [saleInvoiceId])
|
||||
.whereIn('reference_type', ['SaleInvoice']);
|
||||
|
||||
@@ -265,7 +284,7 @@ export default class SaleInvoicesController {
|
||||
* @param {Response} res
|
||||
* @param {Function} next
|
||||
*/
|
||||
static async validateNonSellableEntriesItems(req, res, next) {
|
||||
async validateNonSellableEntriesItems(req: Request, res: Response, next: Function) {
|
||||
const { Item } = req.models;
|
||||
const saleInvoice = { ...req.body };
|
||||
const itemsIds = saleInvoice.entries.map(e => e.item_id);
|
||||
@@ -291,22 +310,17 @@ export default class SaleInvoicesController {
|
||||
* @param {Response} res
|
||||
* @param {Function} next
|
||||
*/
|
||||
static async newSaleInvoice(req, res) {
|
||||
const errorReasons = [];
|
||||
const saleInvoice = {
|
||||
...req.body,
|
||||
entries: req.body.entries.map((entry) => ({
|
||||
...entry,
|
||||
amount: ItemEntry.calcAmount(entry),
|
||||
})),
|
||||
};
|
||||
async newSaleInvoice(req: Request, res: Response) {
|
||||
const { tenantId } = req;
|
||||
const saleInvoiceOTD: ISaleInvoiceOTD = matchedData(req, {
|
||||
locations: ['body'],
|
||||
includeOptionals: true
|
||||
});
|
||||
|
||||
// Creates a new sale invoice with associated entries.
|
||||
const storedSaleInvoice = await SaleInvoiceService.createSaleInvoice(
|
||||
saleInvoice
|
||||
const storedSaleInvoice = await this.saleInvoiceService.createSaleInvoice(
|
||||
tenantId, saleInvoiceOTD,
|
||||
);
|
||||
|
||||
// InventoryService.trackingInventoryLotsCost();
|
||||
|
||||
return res.status(200).send({ id: storedSaleInvoice.id });
|
||||
}
|
||||
|
||||
@@ -316,19 +330,18 @@ export default class SaleInvoicesController {
|
||||
* @param {Response} res
|
||||
* @param {Function} next
|
||||
*/
|
||||
static async editSaleInvoice(req, res) {
|
||||
async editSaleInvoice(req: Request, res: Response) {
|
||||
const { tenantId } = req;
|
||||
const { id: saleInvoiceId } = req.params;
|
||||
const saleInvoice = {
|
||||
...req.body,
|
||||
entries: req.body.entries.map((entry) => ({
|
||||
...entry,
|
||||
amount: ItemEntry.calcAmount(entry),
|
||||
})),
|
||||
};
|
||||
// Update the given sale invoice details.
|
||||
await SaleInvoiceService.editSaleInvoice(saleInvoiceId, saleInvoice);
|
||||
|
||||
return res.status(200).send({ id: saleInvoice.id });
|
||||
const saleInvoiceOTD: ISaleInvoiceOTD = matchedData(req, {
|
||||
locations: ['body'],
|
||||
includeOptionals: true
|
||||
});
|
||||
// Update the given sale invoice details.
|
||||
await this.saleInvoiceService.editSaleInvoice(tenantId, saleInvoiceId, saleInvoiceOTD);
|
||||
|
||||
return res.status(200).send({ id: saleInvoiceId });
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -337,10 +350,12 @@ export default class SaleInvoicesController {
|
||||
* @param {Response} res
|
||||
* @param {Function} next
|
||||
*/
|
||||
static async deleteSaleInvoice(req, res) {
|
||||
async deleteSaleInvoice(req: Request, res: Response) {
|
||||
const { id: saleInvoiceId } = req.params;
|
||||
const { tenantId } = req;
|
||||
|
||||
// Deletes the sale invoice with associated entries and journal transaction.
|
||||
await SaleInvoiceService.deleteSaleInvoice(saleInvoiceId);
|
||||
await this.saleInvoiceService.deleteSaleInvoice(tenantId, saleInvoiceId);
|
||||
|
||||
return res.status(200).send({ id: saleInvoiceId });
|
||||
}
|
||||
@@ -350,10 +365,12 @@ export default class SaleInvoicesController {
|
||||
* @param {Request} req
|
||||
* @param {Response} res
|
||||
*/
|
||||
static async getSaleInvoice(req, res) {
|
||||
async getSaleInvoice(req: Request, res: Response) {
|
||||
const { id: saleInvoiceId } = req.params;
|
||||
const saleInvoice = await SaleInvoiceService.getSaleInvoiceWithEntries(
|
||||
saleInvoiceId
|
||||
const { tenantId } = req;
|
||||
|
||||
const saleInvoice = await this.saleInvoiceService.getSaleInvoiceWithEntries(
|
||||
tenantId, saleInvoiceId,
|
||||
);
|
||||
return res.status(200).send({ sale_invoice: saleInvoice });
|
||||
}
|
||||
@@ -363,13 +380,14 @@ export default class SaleInvoicesController {
|
||||
* @param {Request} req
|
||||
* @param {Response} res
|
||||
*/
|
||||
static async getDueSalesInvoice(req, res) {
|
||||
async getDueSalesInvoice(req: Request, res: Response) {
|
||||
const { Customer, SaleInvoice } = req.models;
|
||||
const { tenantId } = req;
|
||||
|
||||
const filter = {
|
||||
customer_id: null,
|
||||
...req.query,
|
||||
};
|
||||
const { Customer, SaleInvoice } = req.models;
|
||||
|
||||
if (filter.customer_id) {
|
||||
const foundCustomer = await Customer.query().findById(filter.customer_id);
|
||||
|
||||
@@ -381,7 +399,6 @@ export default class SaleInvoicesController {
|
||||
}
|
||||
const dueSalesInvoices = await SaleInvoice.query().onBuild((query) => {
|
||||
query.where(raw('BALANCE - PAYMENT_AMOUNT > 0'));
|
||||
|
||||
if (filter.customer_id) {
|
||||
query.where('customer_id', filter.customer_id);
|
||||
}
|
||||
@@ -397,7 +414,7 @@ export default class SaleInvoicesController {
|
||||
* @param {Response} res
|
||||
* @param {Function} next
|
||||
*/
|
||||
static async getSalesInvoices(req, res) {
|
||||
async getSalesInvoices(req, res) {
|
||||
const filter = {
|
||||
filter_roles: [],
|
||||
sort_order: 'asc',
|
||||
@@ -1,9 +1,8 @@
|
||||
import express from 'express';
|
||||
import { check, param, query } from 'express-validator';
|
||||
import { ItemEntry } from '@/models';
|
||||
import { Router, Request, Response } from 'express';
|
||||
import { check, param, query, matchedData } from 'express-validator';
|
||||
import { Inject, Service } from 'typedi';
|
||||
import validateMiddleware from '@/http/middleware/validateMiddleware';
|
||||
import asyncMiddleware from '@/http/middleware/asyncMiddleware';
|
||||
import CustomersService from '@/services/Customers/CustomersService';
|
||||
import AccountsService from '@/services/Accounts/AccountsService';
|
||||
import ItemsService from '@/services/Items/ItemsService';
|
||||
import SaleReceiptService from '@/services/Sales/SalesReceipts';
|
||||
@@ -13,12 +12,22 @@ import {
|
||||
dynamicListingErrorsToResponse
|
||||
} from '@/services/DynamicListing/HasDynamicListing';
|
||||
|
||||
@Service()
|
||||
export default class SalesReceiptsController {
|
||||
@Inject()
|
||||
saleReceiptService: SaleReceiptService;
|
||||
|
||||
@Inject()
|
||||
accountsService: AccountsService;
|
||||
|
||||
@Inject()
|
||||
itemsService: ItemsService;
|
||||
|
||||
/**
|
||||
* Router constructor.
|
||||
*/
|
||||
static router() {
|
||||
const router = express.Router();
|
||||
router() {
|
||||
const router = Router();
|
||||
|
||||
router.post(
|
||||
'/:id', [
|
||||
@@ -26,34 +35,34 @@ export default class SalesReceiptsController {
|
||||
...this.salesReceiptsValidationSchema,
|
||||
],
|
||||
validateMiddleware,
|
||||
asyncMiddleware(this.validateSaleReceiptExistance),
|
||||
asyncMiddleware(this.validateReceiptCustomerExistance),
|
||||
asyncMiddleware(this.validateReceiptDepositAccountExistance),
|
||||
asyncMiddleware(this.validateReceiptItemsIdsExistance),
|
||||
asyncMiddleware(this.validateReceiptEntriesIds),
|
||||
asyncMiddleware(this.editSaleReceipt)
|
||||
asyncMiddleware(this.validateSaleReceiptExistance.bind(this)),
|
||||
asyncMiddleware(this.validateReceiptCustomerExistance.bind(this)),
|
||||
asyncMiddleware(this.validateReceiptDepositAccountExistance.bind(this)),
|
||||
asyncMiddleware(this.validateReceiptItemsIdsExistance.bind(this)),
|
||||
asyncMiddleware(this.validateReceiptEntriesIds.bind(this)),
|
||||
asyncMiddleware(this.editSaleReceipt.bind(this))
|
||||
);
|
||||
router.post(
|
||||
'/',
|
||||
this.salesReceiptsValidationSchema,
|
||||
validateMiddleware,
|
||||
asyncMiddleware(this.validateReceiptCustomerExistance),
|
||||
asyncMiddleware(this.validateReceiptDepositAccountExistance),
|
||||
asyncMiddleware(this.validateReceiptItemsIdsExistance),
|
||||
asyncMiddleware(this.newSaleReceipt)
|
||||
asyncMiddleware(this.validateReceiptCustomerExistance.bind(this)),
|
||||
asyncMiddleware(this.validateReceiptDepositAccountExistance.bind(this)),
|
||||
asyncMiddleware(this.validateReceiptItemsIdsExistance.bind(this)),
|
||||
asyncMiddleware(this.newSaleReceipt.bind(this))
|
||||
);
|
||||
router.delete(
|
||||
'/:id',
|
||||
this.specificReceiptValidationSchema,
|
||||
validateMiddleware,
|
||||
asyncMiddleware(this.validateSaleReceiptExistance),
|
||||
asyncMiddleware(this.deleteSaleReceipt)
|
||||
asyncMiddleware(this.validateSaleReceiptExistance.bind(this)),
|
||||
asyncMiddleware(this.deleteSaleReceipt.bind(this))
|
||||
);
|
||||
router.get(
|
||||
'/',
|
||||
this.listSalesReceiptsValidationSchema,
|
||||
validateMiddleware,
|
||||
asyncMiddleware(this.listingSalesReceipts)
|
||||
asyncMiddleware(this.listingSalesReceipts.bind(this))
|
||||
);
|
||||
return router;
|
||||
}
|
||||
@@ -62,7 +71,7 @@ export default class SalesReceiptsController {
|
||||
* Sales receipt validation schema.
|
||||
* @return {Array}
|
||||
*/
|
||||
static get salesReceiptsValidationSchema() {
|
||||
get salesReceiptsValidationSchema() {
|
||||
return [
|
||||
check('customer_id').exists().isNumeric().toInt(),
|
||||
check('deposit_account_id').exists().isNumeric().toInt(),
|
||||
@@ -88,7 +97,7 @@ export default class SalesReceiptsController {
|
||||
/**
|
||||
* Specific sale receipt validation schema.
|
||||
*/
|
||||
static get specificReceiptValidationSchema() {
|
||||
get specificReceiptValidationSchema() {
|
||||
return [
|
||||
param('id').exists().isNumeric().toInt()
|
||||
];
|
||||
@@ -97,7 +106,7 @@ export default class SalesReceiptsController {
|
||||
/**
|
||||
* List sales receipts validation schema.
|
||||
*/
|
||||
static get listSalesReceiptsValidationSchema() {
|
||||
get listSalesReceiptsValidationSchema() {
|
||||
return [
|
||||
query('custom_view_id').optional().isNumeric().toInt(),
|
||||
query('stringified_filter_roles').optional().isJSON(),
|
||||
@@ -113,11 +122,15 @@ export default class SalesReceiptsController {
|
||||
* @param {Request} req
|
||||
* @param {Response} res
|
||||
*/
|
||||
static async validateSaleReceiptExistance(req, res, next) {
|
||||
async validateSaleReceiptExistance(req: Request, res: Response, next: Function) {
|
||||
const { tenantId } = req;
|
||||
const { id: saleReceiptId } = req.params;
|
||||
const isSaleReceiptExists = await SaleReceiptService.isSaleReceiptExists(
|
||||
saleReceiptId
|
||||
);
|
||||
|
||||
const isSaleReceiptExists = await this.saleReceiptService
|
||||
.isSaleReceiptExists(
|
||||
tenantId,
|
||||
saleReceiptId,
|
||||
);
|
||||
if (!isSaleReceiptExists) {
|
||||
return res.status(404).send({
|
||||
errors: [{ type: 'SALE.RECEIPT.NOT.FOUND', code: 200 }],
|
||||
@@ -132,12 +145,13 @@ export default class SalesReceiptsController {
|
||||
* @param {Response} res
|
||||
* @param {Function} next
|
||||
*/
|
||||
static async validateReceiptCustomerExistance(req, res, next) {
|
||||
async validateReceiptCustomerExistance(req: Request, res: Response, next: Function) {
|
||||
const saleReceipt = { ...req.body };
|
||||
const isCustomerExists = await CustomersService.isCustomerExists(
|
||||
saleReceipt.customer_id
|
||||
);
|
||||
if (!isCustomerExists) {
|
||||
const { Customer } = req.models;
|
||||
|
||||
const foundCustomer = await Customer.query().findById(saleReceipt.customer_id);
|
||||
|
||||
if (!foundCustomer) {
|
||||
return res.status(400).send({
|
||||
errors: [{ type: 'CUSTOMER.ID.NOT.EXISTS', code: 200 }],
|
||||
});
|
||||
@@ -151,9 +165,12 @@ export default class SalesReceiptsController {
|
||||
* @param {Response} res
|
||||
* @param {Function} next
|
||||
*/
|
||||
static async validateReceiptDepositAccountExistance(req, res, next) {
|
||||
async validateReceiptDepositAccountExistance(req: Request, res: Response, next: Function) {
|
||||
const { tenantId } = req;
|
||||
|
||||
const saleReceipt = { ...req.body };
|
||||
const isDepositAccountExists = await AccountsService.isAccountExists(
|
||||
const isDepositAccountExists = await this.accountsService.isAccountExists(
|
||||
tenantId,
|
||||
saleReceipt.deposit_account_id
|
||||
);
|
||||
if (!isDepositAccountExists) {
|
||||
@@ -170,10 +187,14 @@ export default class SalesReceiptsController {
|
||||
* @param {Response} res
|
||||
* @param {Function} next
|
||||
*/
|
||||
static async validateReceiptItemsIdsExistance(req, res, next) {
|
||||
async validateReceiptItemsIdsExistance(req: Request, res: Response, next: Function) {
|
||||
const { tenantId } = req;
|
||||
|
||||
const saleReceipt = { ...req.body };
|
||||
const estimateItemsIds = saleReceipt.entries.map((e) => e.item_id);
|
||||
const notFoundItemsIds = await ItemsService.isItemsIdsExists(
|
||||
|
||||
const notFoundItemsIds = await this.itemsService.isItemsIdsExists(
|
||||
tenantId,
|
||||
estimateItemsIds
|
||||
);
|
||||
if (notFoundItemsIds.length > 0) {
|
||||
@@ -188,15 +209,19 @@ export default class SalesReceiptsController {
|
||||
* @param {Response} res
|
||||
* @param {Function} next
|
||||
*/
|
||||
static async validateReceiptEntriesIds(req, res, next) {
|
||||
async validateReceiptEntriesIds(req: Request, res: Response, next: Function) {
|
||||
const { tenantId } = req;
|
||||
|
||||
const saleReceipt = { ...req.body };
|
||||
const { id: saleReceiptId } = req.params;
|
||||
|
||||
// Validate the entries IDs that not stored or associated to the sale receipt.
|
||||
const notExistsEntriesIds = await SaleReceiptService.isSaleReceiptEntriesIDsExists(
|
||||
saleReceiptId,
|
||||
saleReceipt
|
||||
);
|
||||
const notExistsEntriesIds = await this.saleReceiptService
|
||||
.isSaleReceiptEntriesIDsExists(
|
||||
tenantId,
|
||||
saleReceiptId,
|
||||
saleReceipt,
|
||||
);
|
||||
if (notExistsEntriesIds.length > 0) {
|
||||
return res.status(400).send({ errors: [{
|
||||
type: 'ENTRIES.IDS.NOT.FOUND',
|
||||
@@ -212,19 +237,19 @@ export default class SalesReceiptsController {
|
||||
* @param {Request} req
|
||||
* @param {Response} res
|
||||
*/
|
||||
static async newSaleReceipt(req, res) {
|
||||
const saleReceipt = {
|
||||
...req.body,
|
||||
entries: req.body.entries.map((entry) => ({
|
||||
...entry,
|
||||
amount: ItemEntry.calcAmount(entry),
|
||||
})),
|
||||
};
|
||||
async newSaleReceipt(req: Request, res: Response) {
|
||||
const { tenantId } = req;
|
||||
|
||||
const saleReceipt = matchedData(req, {
|
||||
locations: ['body'],
|
||||
includeOptionals: true,
|
||||
});
|
||||
// Store the given sale receipt details with associated entries.
|
||||
const storedSaleReceipt = await SaleReceiptService.createSaleReceipt(
|
||||
saleReceipt
|
||||
);
|
||||
const storedSaleReceipt = await this.saleReceiptService
|
||||
.createSaleReceipt(
|
||||
tenantId,
|
||||
saleReceipt,
|
||||
);
|
||||
return res.status(200).send({ id: storedSaleReceipt.id });
|
||||
}
|
||||
|
||||
@@ -233,11 +258,12 @@ export default class SalesReceiptsController {
|
||||
* @param {Request} req
|
||||
* @param {Response} res
|
||||
*/
|
||||
static async deleteSaleReceipt(req, res) {
|
||||
async deleteSaleReceipt(req: Request, res: Response) {
|
||||
const { tenantId } = req;
|
||||
const { id: saleReceiptId } = req.params;
|
||||
|
||||
// Deletes the sale receipt.
|
||||
await SaleReceiptService.deleteSaleReceipt(saleReceiptId);
|
||||
await this.saleReceiptService.deleteSaleReceipt(tenantId, saleReceiptId);
|
||||
|
||||
return res.status(200).send({ id: saleReceiptId });
|
||||
}
|
||||
@@ -248,9 +274,12 @@ export default class SalesReceiptsController {
|
||||
* @param {Request} req
|
||||
* @param {Response} res
|
||||
*/
|
||||
static async editSaleReceipt(req, res) {
|
||||
async editSaleReceipt(req: Request, res: Response) {
|
||||
const { tenantId } = req;
|
||||
|
||||
const { id: saleReceiptId } = req.params;
|
||||
const saleReceipt = { ...req.body };
|
||||
|
||||
const errorReasons = [];
|
||||
|
||||
// Handle all errors with reasons messages.
|
||||
@@ -258,7 +287,11 @@ export default class SalesReceiptsController {
|
||||
return res.boom.badRequest(null, { errors: errorReasons });
|
||||
}
|
||||
// Update the given sale receipt details.
|
||||
await SaleReceiptService.editSaleReceipt(saleReceiptId, saleReceipt);
|
||||
await this.saleReceiptService.editSaleReceipt(
|
||||
tenantId,
|
||||
saleReceiptId,
|
||||
saleReceipt,
|
||||
);
|
||||
|
||||
return res.status(200).send();
|
||||
}
|
||||
@@ -268,7 +301,7 @@ export default class SalesReceiptsController {
|
||||
* @param {Request} req
|
||||
* @param {Response} res
|
||||
*/
|
||||
static async listingSalesReceipts(req, res) {
|
||||
async listingSalesReceipts(req: Request, res: Response) {
|
||||
const filter = {
|
||||
filter_roles: [],
|
||||
sort_order: 'asc',
|
||||
@@ -280,7 +313,7 @@ export default class SalesReceiptsController {
|
||||
filter.filter_roles = JSON.parse(filter.stringified_filter_roles);
|
||||
}
|
||||
const { SaleReceipt, Resource, View } = req.models;
|
||||
const resource = await Resource.tenant().query()
|
||||
const resource = await Resource.query()
|
||||
.remember()
|
||||
.where('name', 'sales_receipts')
|
||||
.withGraphFetched('fields')
|
||||
@@ -1,4 +1,5 @@
|
||||
import express from 'express';
|
||||
import { Container } from 'typedi';
|
||||
import SalesEstimates from './SalesEstimates';
|
||||
import SalesReceipts from './SalesReceipts';
|
||||
import SalesInvoices from './SalesInvoices'
|
||||
@@ -11,10 +12,10 @@ export default {
|
||||
router() {
|
||||
const router = express.Router();
|
||||
|
||||
router.use('/invoices', SalesInvoices.router());
|
||||
router.use('/estimates', SalesEstimates.router());
|
||||
router.use('/receipts', SalesReceipts.router());
|
||||
router.use('/payment_receives', PaymentReceives.router());
|
||||
router.use('/invoices', Container.get(SalesInvoices).router());
|
||||
router.use('/estimates', Container.get(SalesEstimates).router());
|
||||
router.use('/receipts', Container.get(SalesReceipts).router());
|
||||
router.use('/payment_receives', Container.get(PaymentReceives).router());
|
||||
|
||||
return router;
|
||||
}
|
||||
@@ -25,14 +25,15 @@ export default class VouchersController {
|
||||
this.generateVoucherSchema,
|
||||
validateMiddleware,
|
||||
PrettierMiddleware,
|
||||
asyncMiddleware(this.validatePlanExistance),
|
||||
asyncMiddleware(this.validatePlanExistance.bind(this)),
|
||||
asyncMiddleware(this.generateVoucher.bind(this)),
|
||||
);
|
||||
router.post(
|
||||
'/disable/:voucherId',
|
||||
validateMiddleware,
|
||||
PrettierMiddleware,
|
||||
asyncMiddleware(this.validateVoucherExistance),
|
||||
asyncMiddleware(this.validateNotDisabledVoucher),
|
||||
asyncMiddleware(this.validateVoucherExistance.bind(this)),
|
||||
asyncMiddleware(this.validateNotDisabledVoucher.bind(this)),
|
||||
asyncMiddleware(this.disableVoucher.bind(this)),
|
||||
);
|
||||
router.post(
|
||||
@@ -45,7 +46,7 @@ export default class VouchersController {
|
||||
router.delete(
|
||||
'/:voucherId',
|
||||
PrettierMiddleware,
|
||||
asyncMiddleware(this.validateVoucherExistance),
|
||||
asyncMiddleware(this.validateVoucherExistance.bind(this)),
|
||||
asyncMiddleware(this.deleteVoucher.bind(this)),
|
||||
);
|
||||
router.get(
|
||||
@@ -158,23 +159,21 @@ export default class VouchersController {
|
||||
* @param {Response} res
|
||||
* @return {Response}
|
||||
*/
|
||||
async generateVoucher(req: Request, res: Response) {
|
||||
async generateVoucher(req: Request, res: Response, next: Function) {
|
||||
const { loop = 10, period, periodInterval, planId } = req.body;
|
||||
const generatedVouchers: string[] = [];
|
||||
const asyncOpers = [];
|
||||
|
||||
times(loop, () => {
|
||||
const generateOper = this.voucherService
|
||||
.generateVoucher(period, periodInterval, planId)
|
||||
.then((generatedVoucher: any) => {
|
||||
generatedVouchers.push(generatedVoucher)
|
||||
});
|
||||
asyncOpers.push(generateOper);
|
||||
});
|
||||
|
||||
return res.status(200).send({
|
||||
vouchers: generatedVouchers,
|
||||
});
|
||||
try {
|
||||
await this.voucherService.generateVouchers(
|
||||
loop, period, periodInterval, planId,
|
||||
);
|
||||
return res.status(200).send({
|
||||
code: 100,
|
||||
message: 'The vouchers have been generated successfully.'
|
||||
});
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -49,7 +49,7 @@ export default (app) => {
|
||||
dashboard.use('/api/account_types', AccountTypes.router());
|
||||
dashboard.use('/api/accounting', Accounting.router());
|
||||
dashboard.use('/api/views', Views.router());
|
||||
dashboard.use('/api/items', Items.router());
|
||||
dashboard.use('/api/items', Container.get(Items).router());
|
||||
dashboard.use('/api/item_categories', Container.get(ItemCategories));
|
||||
dashboard.use('/api/expenses', Expenses.router());
|
||||
dashboard.use('/api/financial_statements', FinancialStatements.router());
|
||||
@@ -61,7 +61,7 @@ export default (app) => {
|
||||
dashboard.use('/api/resources', Resources.router());
|
||||
dashboard.use('/api/exchange_rates', ExchangeRates.router());
|
||||
dashboard.use('/api/media', Media.router());
|
||||
|
||||
|
||||
app.use('/agendash', Agendash.router());
|
||||
app.use('/', dashboard);
|
||||
};
|
||||
|
||||
@@ -2,6 +2,7 @@ import fs from 'fs';
|
||||
import path from 'path';
|
||||
import TenantsManager from '@/system/TenantsManager';
|
||||
import TenantModel from '@/models/TenantModel';
|
||||
import { Container } from 'typedi';
|
||||
|
||||
function loadModelsFromDirectory() {
|
||||
const models = {};
|
||||
@@ -45,6 +46,7 @@ export default async (req, res, next) => {
|
||||
req.knex = knex;
|
||||
req.organizationId = organizationId;
|
||||
req.tenant = tenant;
|
||||
req.tenantId = tenant.id;
|
||||
req.models = {
|
||||
...Object.values(models).reduce((acc, model) => {
|
||||
if (typeof model.resource.default !== 'undefined' &&
|
||||
@@ -56,5 +58,8 @@ export default async (req, res, next) => {
|
||||
return acc;
|
||||
}, {}),
|
||||
};
|
||||
Container.of(`tenant-${tenant.id}`).set('models', {
|
||||
...req.models,
|
||||
});
|
||||
next();
|
||||
};
|
||||
3
server/src/interfaces/Bill.ts
Normal file
3
server/src/interfaces/Bill.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export interface IBillOTD {};
|
||||
export interface IBill {};
|
||||
|
||||
@@ -10,4 +10,6 @@ export interface IBillPayment {
|
||||
reference: string,
|
||||
billNo: string,
|
||||
entries: IBillPaymentEntry[],
|
||||
}
|
||||
}
|
||||
|
||||
export interface IBillPaymentOTD {};
|
||||
4
server/src/interfaces/PaymentReceive.ts
Normal file
4
server/src/interfaces/PaymentReceive.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
|
||||
|
||||
export interface IPaymentReceive { };
|
||||
export interface IPaymentReceiveOTD { };
|
||||
4
server/src/interfaces/SaleEstimate.ts
Normal file
4
server/src/interfaces/SaleEstimate.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
|
||||
|
||||
export interface ISaleEstimate {};
|
||||
export interface ISaleEstimateOTD {};
|
||||
@@ -1,5 +1,9 @@
|
||||
import { IInventoryTransaction, IInventoryLotCost } from './InventoryTransaction';
|
||||
import { IBillPaymentEntry, IBillPayment } from './BillPayment';
|
||||
import {
|
||||
IBillPaymentEntry,
|
||||
IBillPayment,
|
||||
IBillPaymentOTD,
|
||||
} from './BillPayment';
|
||||
import { IInventoryCostMethod } from './InventoryCostMethod';
|
||||
import { IItemEntry } from './ItemEntry';
|
||||
import { IItem } from './Item';
|
||||
@@ -16,10 +20,20 @@ import {
|
||||
ISaleInvoice,
|
||||
ISaleInvoiceOTD,
|
||||
} from './SaleInvoice';
|
||||
import {
|
||||
IPaymentReceive,
|
||||
IPaymentReceiveOTD,
|
||||
} from './PaymentReceive';
|
||||
import {
|
||||
ISaleEstimate,
|
||||
ISaleEstimateOTD,
|
||||
} from './SaleEstimate';
|
||||
|
||||
export {
|
||||
IBillPaymentEntry,
|
||||
IBillPayment,
|
||||
IBillPaymentOTD,
|
||||
|
||||
IInventoryTransaction,
|
||||
IInventoryLotCost,
|
||||
IInventoryCostMethod,
|
||||
@@ -38,4 +52,10 @@ export {
|
||||
|
||||
ISaleInvoice,
|
||||
ISaleInvoiceOTD,
|
||||
|
||||
ISaleEstimate,
|
||||
ISaleEstimateOTD,
|
||||
|
||||
IPaymentReceive,
|
||||
IPaymentReceiveOTD,
|
||||
};
|
||||
8
server/src/jobs/MailNotifcationSubscribeEnd.ts
Normal file
8
server/src/jobs/MailNotifcationSubscribeEnd.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
|
||||
|
||||
export default class MailNotificationSubscribeEnd {
|
||||
|
||||
handler(job) {
|
||||
|
||||
}
|
||||
}
|
||||
6
server/src/jobs/MailNotificationSubscribeEnd.ts
Normal file
6
server/src/jobs/MailNotificationSubscribeEnd.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
|
||||
|
||||
export default class MailNotificationSubscribeEnd {
|
||||
|
||||
|
||||
}
|
||||
13
server/src/jobs/SMSNotificationSubscribeEnd.ts
Normal file
13
server/src/jobs/SMSNotificationSubscribeEnd.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
|
||||
|
||||
|
||||
|
||||
export default class SMSNotificationSubscribeEnd {
|
||||
|
||||
|
||||
|
||||
handler(job) {
|
||||
const { tenantId, subscriptionSlug } = job.attrs.data;
|
||||
|
||||
}
|
||||
}
|
||||
8
server/src/jobs/SMSNotificationTrialEnd.ts
Normal file
8
server/src/jobs/SMSNotificationTrialEnd.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
|
||||
|
||||
export default class MailNotificationSubscribeEnd {
|
||||
|
||||
handler(job) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -30,6 +30,22 @@ export default ({ agenda }: { agenda: Agenda }) => {
|
||||
'send-voucher-via-email',
|
||||
{ priority: 'high', concurrency: 1, },
|
||||
new SendVoucherViaEmailJob().handler,
|
||||
)
|
||||
);
|
||||
// agenda.define(
|
||||
// 'send-sms-notification-subscribe-end',
|
||||
// { priority: 'high', concurrency: 1, },
|
||||
// );
|
||||
// agenda.define(
|
||||
// 'send-mail-notification-subscribe-end',
|
||||
// { priority: 'high', concurrency: 1, },
|
||||
// );
|
||||
// agenda.define(
|
||||
// 'send-sms-notification-trial-end',
|
||||
// { priority: 'high', concurrency: 1, },
|
||||
// );
|
||||
// agenda.define(
|
||||
// 'send-mail-notification-trial-end',
|
||||
// { priority: 'high', concurrency: 1, },
|
||||
// );
|
||||
agenda.start();
|
||||
};
|
||||
|
||||
@@ -74,7 +74,7 @@ export default class Bill extends mixin(TenantModel, [CachableModel]) {
|
||||
* @return {Array}
|
||||
*/
|
||||
static async getNotFoundBills(billsIds, vendorId) {
|
||||
const storedBills = await this.tenant().query()
|
||||
const storedBills = await this.query()
|
||||
.onBuild((builder) => {
|
||||
builder.whereIn('id', billsIds);
|
||||
|
||||
@@ -94,8 +94,7 @@ export default class Bill extends mixin(TenantModel, [CachableModel]) {
|
||||
|
||||
static changePaymentAmount(billId, amount) {
|
||||
const changeMethod = amount > 0 ? 'increment' : 'decrement';
|
||||
return this.tenant()
|
||||
.query()
|
||||
return this.query()
|
||||
.where('id', billId)
|
||||
[changeMethod]('payment_amount', Math.abs(amount));
|
||||
}
|
||||
|
||||
@@ -33,10 +33,9 @@ export default class Customer extends TenantModel {
|
||||
* @param {Numeric} amount
|
||||
*/
|
||||
static async changeBalance(customerId, amount) {
|
||||
const changeMethod = amount > 0 ? 'increment' : 'decrement';
|
||||
const changeMethod = (amount > 0) ? 'increment' : 'decrement';
|
||||
|
||||
await this.tenant()
|
||||
.query()
|
||||
return this.query()
|
||||
.where('id', customerId)
|
||||
[changeMethod]('balance', Math.abs(amount));
|
||||
}
|
||||
@@ -47,8 +46,7 @@ export default class Customer extends TenantModel {
|
||||
* @param {Integer} amount
|
||||
*/
|
||||
static async incrementBalance(customerId, amount) {
|
||||
await this.tenant()
|
||||
.query()
|
||||
return this.query()
|
||||
.where('id', customerId)
|
||||
.increment('balance', amount);
|
||||
}
|
||||
@@ -59,9 +57,25 @@ export default class Customer extends TenantModel {
|
||||
* @param {integer} amount -
|
||||
*/
|
||||
static async decrementBalance(customerId, amount) {
|
||||
await this.tenant()
|
||||
.query()
|
||||
await this.query()
|
||||
.where('id', customerId)
|
||||
.decrement('balance', amount);
|
||||
}
|
||||
|
||||
static changeDiffBalance(customerId, oldCustomerId, amount, oldAmount) {
|
||||
const diffAmount = amount - oldAmount;
|
||||
const asyncOpers = [];
|
||||
|
||||
if (customerId != oldCustomerId) {
|
||||
const oldCustomerOper = this.changeBalance(oldCustomerId, (oldAmount * -1));
|
||||
const customerOper = this.changeBalance(customerId, amount);
|
||||
|
||||
asyncOpers.push(customerOper);
|
||||
asyncOpers.push(oldCustomerOper);
|
||||
} else {
|
||||
const balanceChangeOper = this.changeBalance(customerId, diffAmount);
|
||||
asyncOpers.push(balanceChangeOper);
|
||||
}
|
||||
return Promise.all(asyncOpers);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,13 +17,12 @@ export default class ItemEntry extends TenantModel {
|
||||
return ['created_at', 'updated_at'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Relationship mapping.
|
||||
*/
|
||||
static get relationMappings() {
|
||||
return {
|
||||
static get virtualAttributes() {
|
||||
return ['amount'];
|
||||
}
|
||||
|
||||
};
|
||||
static amount() {
|
||||
return this.calcAmount(this);
|
||||
}
|
||||
|
||||
static calcAmount(itemEntry) {
|
||||
|
||||
@@ -119,8 +119,7 @@ export default class SaleInvoice extends mixin(TenantModel, [CachableModel]) {
|
||||
static async changePaymentAmount(invoiceId, amount) {
|
||||
const changeMethod = amount > 0 ? 'increment' : 'decrement';
|
||||
|
||||
await this.tenant()
|
||||
.query()
|
||||
await this.query()
|
||||
.where('id', invoiceId)
|
||||
[changeMethod]('payment_amount', Math.abs(amount));
|
||||
}
|
||||
|
||||
@@ -25,8 +25,7 @@ export default class Vendor extends TenantModel {
|
||||
static async changeBalance(vendorId, amount) {
|
||||
const changeMethod = amount > 0 ? 'increment' : 'decrement';
|
||||
|
||||
return this.tenant()
|
||||
.query()
|
||||
return this.query()
|
||||
.where('id', vendorId)
|
||||
[changeMethod]('balance', Math.abs(amount));
|
||||
}
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
import { Account, AccountType } from '@/models';
|
||||
|
||||
export default class AccountsService {
|
||||
static async isAccountExists(accountId) {
|
||||
const foundAccounts = await Account.tenant().query().where('id', accountId);
|
||||
return foundAccounts.length > 0;
|
||||
}
|
||||
|
||||
static async getAccountByType(accountTypeKey) {
|
||||
const accountType = await AccountType.tenant()
|
||||
.query()
|
||||
.where('key', accountTypeKey)
|
||||
.first();
|
||||
|
||||
const account = await Account.tenant()
|
||||
.query()
|
||||
.where('account_type_id', accountType.id)
|
||||
.first();
|
||||
|
||||
return account;
|
||||
}
|
||||
}
|
||||
29
server/src/services/Accounts/AccountsService.ts
Normal file
29
server/src/services/Accounts/AccountsService.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { Inject, Service } from 'typedi';
|
||||
import TenancyService from '@/services/Tenancy/TenancyService';
|
||||
|
||||
@Service()
|
||||
export default class AccountsService {
|
||||
@Inject()
|
||||
tenancy: TenancyService;
|
||||
|
||||
async isAccountExists(tenantId: number, accountId: number) {
|
||||
const { Account } = this.tenancy.models(tenantId);
|
||||
const foundAccounts = await Account.query()
|
||||
.where('id', accountId);
|
||||
|
||||
return foundAccounts.length > 0;
|
||||
}
|
||||
|
||||
async getAccountByType(tenantId: number, accountTypeKey: string) {
|
||||
const { AccountType, Account } = this.tenancy.models(tenantId);
|
||||
const accountType = await AccountType.query()
|
||||
.where('key', accountTypeKey)
|
||||
.first();
|
||||
|
||||
const account = await Account.query()
|
||||
.where('account_type_id', accountType.id)
|
||||
.first();
|
||||
|
||||
return account;
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import Customer from "../../models/Customer";
|
||||
export default class CustomersService {
|
||||
|
||||
static async isCustomerExists(customerId) {
|
||||
const foundCustomeres = await Customer.tenant().query().where('id', customerId);
|
||||
const foundCustomeres = await Customer.query().where('id', customerId);
|
||||
return foundCustomeres.length > 0;
|
||||
}
|
||||
}
|
||||
@@ -1,23 +1,26 @@
|
||||
import { Container } from 'typedi';
|
||||
import {
|
||||
InventoryTransaction,
|
||||
Item,
|
||||
Option,
|
||||
} from '@/models';
|
||||
import { Container, Service, Inject } from 'typedi';
|
||||
import InventoryAverageCost from '@/services/Inventory/InventoryAverageCost';
|
||||
import InventoryCostLotTracker from '@/services/Inventory/InventoryCostLotTracker';
|
||||
import TenancyService from '@/services/Tenancy/TenancyService';
|
||||
|
||||
type TCostMethod = 'FIFO' | 'LIFO' | 'AVG';
|
||||
|
||||
@Service()
|
||||
export default class InventoryService {
|
||||
@Inject()
|
||||
tenancy: TenancyService;
|
||||
|
||||
/**
|
||||
* Computes the given item cost and records the inventory lots transactions
|
||||
* and journal entries based on the cost method FIFO, LIFO or average cost rate.
|
||||
* @param {number} tenantId -
|
||||
* @param {Date} fromDate -
|
||||
* @param {number} itemId -
|
||||
*/
|
||||
static async computeItemCost(fromDate: Date, itemId: number) {
|
||||
const item = await Item.tenant().query()
|
||||
async computeItemCost(tenantId: number, fromDate: Date, itemId: number) {
|
||||
const { Item } = this.tenancy.models(tenantId);
|
||||
|
||||
const item = await Item.query()
|
||||
.findById(itemId)
|
||||
.withGraphFetched('category');
|
||||
|
||||
@@ -42,30 +45,34 @@ export default class InventoryService {
|
||||
}
|
||||
|
||||
/**
|
||||
* SChedule item cost compute job.
|
||||
* Schedule item cost compute job.
|
||||
* @param {number} tenantId
|
||||
* @param {number} itemId
|
||||
* @param {Date} startingDate
|
||||
*/
|
||||
static async scheduleComputeItemCost(itemId: number, startingDate: Date|string) {
|
||||
async scheduleComputeItemCost(tenantId: number, itemId: number, startingDate: Date|string) {
|
||||
const agenda = Container.get('agenda');
|
||||
|
||||
return agenda.schedule('in 3 seconds', 'compute-item-cost', {
|
||||
startingDate, itemId,
|
||||
startingDate, itemId, tenantId,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Records the inventory transactions.
|
||||
* @param {number} tenantId - Tenant id.
|
||||
* @param {Bill} bill
|
||||
* @param {number} billId
|
||||
*/
|
||||
static async recordInventoryTransactions(
|
||||
async recordInventoryTransactions(
|
||||
tenantId: number,
|
||||
entries: [],
|
||||
deleteOld: boolean,
|
||||
) {
|
||||
const { InventoryTransaction, Item } = this.tenancy.models(tenantId);
|
||||
|
||||
const entriesItemsIds = entries.map((e: any) => e.item_id);
|
||||
const inventoryItems = await Item.tenant()
|
||||
.query()
|
||||
const inventoryItems = await Item.query()
|
||||
.whereIn('id', entriesItemsIds)
|
||||
.where('type', 'inventory');
|
||||
|
||||
@@ -78,11 +85,12 @@ export default class InventoryService {
|
||||
inventoryEntries.forEach(async (entry: any) => {
|
||||
if (deleteOld) {
|
||||
await this.deleteInventoryTransactions(
|
||||
tenantId,
|
||||
entry.transactionId,
|
||||
entry.transactionType,
|
||||
);
|
||||
}
|
||||
await InventoryTransaction.tenant().query().insert({
|
||||
await InventoryTransaction.query().insert({
|
||||
...entry,
|
||||
lotNumber: entry.lotNumber,
|
||||
});
|
||||
@@ -91,15 +99,19 @@ export default class InventoryService {
|
||||
|
||||
/**
|
||||
* Deletes the given inventory transactions.
|
||||
* @param {number} tenantId - Tenant id.
|
||||
* @param {string} transactionType
|
||||
* @param {number} transactionId
|
||||
* @return {Promise}
|
||||
*/
|
||||
static deleteInventoryTransactions(
|
||||
deleteInventoryTransactions(
|
||||
tenantId: number,
|
||||
transactionId: number,
|
||||
transactionType: string,
|
||||
) {
|
||||
return InventoryTransaction.tenant().query()
|
||||
const { InventoryTransaction } = this.tenancy.models(tenantId);
|
||||
|
||||
return InventoryTransaction.query()
|
||||
.where('transaction_type', transactionType)
|
||||
.where('transaction_id', transactionId)
|
||||
.delete();
|
||||
@@ -107,21 +119,24 @@ export default class InventoryService {
|
||||
|
||||
/**
|
||||
* Retrieve the lot number after the increment.
|
||||
* @param {number} tenantId - Tenant id.
|
||||
*/
|
||||
static async nextLotNumber() {
|
||||
async nextLotNumber(tenantId: number) {
|
||||
const { Option } = this.tenancy.models(tenantId);
|
||||
|
||||
const LOT_NUMBER_KEY = 'lot_number_increment';
|
||||
const effectRows = await Option.tenant().query()
|
||||
const effectRows = await Option.query()
|
||||
.where('key', LOT_NUMBER_KEY)
|
||||
.increment('value', 1);
|
||||
|
||||
if (effectRows === 0) {
|
||||
await Option.tenant().query()
|
||||
await Option.query()
|
||||
.insert({
|
||||
key: LOT_NUMBER_KEY,
|
||||
value: 1,
|
||||
});
|
||||
}
|
||||
const options = await Option.tenant().query();
|
||||
const options = await Option.query();
|
||||
return options.getMeta(LOT_NUMBER_KEY, 1);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
import { pick } from 'lodash';
|
||||
import { InventoryTransaction } from '@/models';
|
||||
import { IInventoryTransaction } from '@/interfaces';
|
||||
import InventoryCostMethod from '@/services/Inventory/InventoryCostMethod';
|
||||
|
||||
@@ -10,10 +9,12 @@ export default class InventoryAverageCostMethod extends InventoryCostMethod impl
|
||||
|
||||
/**
|
||||
* Constructor method.
|
||||
* @param {number} tenantId - The given tenant id.
|
||||
* @param {Date} startingDate -
|
||||
* @param {number} itemId -
|
||||
* @param {number} itemId - The given inventory item id.
|
||||
*/
|
||||
constructor(
|
||||
tenantId: number,
|
||||
startingDate: Date,
|
||||
itemId: number,
|
||||
) {
|
||||
@@ -39,11 +40,10 @@ export default class InventoryAverageCostMethod extends InventoryCostMethod impl
|
||||
* @param {string} referenceType
|
||||
*/
|
||||
public async computeItemCost() {
|
||||
const { InventoryTransaction } = this.tenantModels;
|
||||
const openingAvgCost = await this.getOpeningAvaregeCost(this.startingDate, this.itemId);
|
||||
|
||||
const afterInvTransactions: IInventoryTransaction[] = await InventoryTransaction
|
||||
.tenant()
|
||||
.query()
|
||||
const afterInvTransactions: IInventoryTransaction[] = await InventoryTransaction.query()
|
||||
.modify('filterDateRange', this.startingDate)
|
||||
.orderBy('date', 'ASC')
|
||||
.orderByRaw("FIELD(direction, 'IN', 'OUT')")
|
||||
@@ -66,6 +66,7 @@ export default class InventoryAverageCostMethod extends InventoryCostMethod impl
|
||||
* @return {number}
|
||||
*/
|
||||
public async getOpeningAvaregeCost(startingDate: Date, itemId: number) {
|
||||
const { InventoryTransaction } = this.tenantModels;
|
||||
const commonBuilder = (builder: any) => {
|
||||
if (startingDate) {
|
||||
builder.where('date', '<', startingDate);
|
||||
@@ -81,16 +82,14 @@ export default class InventoryAverageCostMethod extends InventoryCostMethod impl
|
||||
// Calculates the total inventory total quantity and rate `IN` transactions.
|
||||
|
||||
// @todo total `IN` transactions.
|
||||
const inInvSumationOper: Promise<any> = InventoryTransaction.tenant()
|
||||
.query()
|
||||
const inInvSumationOper: Promise<any> = InventoryTransaction.query()
|
||||
.onBuild(commonBuilder)
|
||||
.where('direction', 'IN')
|
||||
.first();
|
||||
|
||||
// Calculates the total inventory total quantity and rate `OUT` transactions.
|
||||
// @todo total `OUT` transactions.
|
||||
const outInvSumationOper: Promise<any> = InventoryTransaction.tenant()
|
||||
.query()
|
||||
const outInvSumationOper: Promise<any> = InventoryTransaction.query()
|
||||
.onBuild(commonBuilder)
|
||||
.where('direction', 'OUT')
|
||||
.first();
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
import { omit, pick, chain } from 'lodash';
|
||||
import { pick, chain } from 'lodash';
|
||||
import moment from 'moment';
|
||||
import {
|
||||
InventoryTransaction,
|
||||
InventoryLotCostTracker,
|
||||
Item,
|
||||
} from "@/models";
|
||||
import { IInventoryLotCost, IInventoryTransaction } from "@/interfaces";
|
||||
import InventoryCostMethod from '@/services/Inventory/InventoryCostMethod';
|
||||
|
||||
@@ -28,7 +23,12 @@ export default class InventoryCostLotTracker extends InventoryCostMethod impleme
|
||||
* @param {number} itemId -
|
||||
* @param {string} costMethod -
|
||||
*/
|
||||
constructor(startingDate: Date, itemId: number, costMethod: TCostMethod = 'FIFO') {
|
||||
constructor(
|
||||
tenantId: number,
|
||||
startingDate: Date,
|
||||
itemId: number,
|
||||
costMethod: TCostMethod = 'FIFO'
|
||||
) {
|
||||
super();
|
||||
|
||||
this.startingDate = startingDate;
|
||||
@@ -83,13 +83,14 @@ export default class InventoryCostLotTracker extends InventoryCostMethod impleme
|
||||
* @private
|
||||
*/
|
||||
private async fetchInvINTransactions() {
|
||||
const { InventoryTransaction, InventoryLotCostTracker } = this.tenantModels;
|
||||
|
||||
const commonBuilder = (builder: any) => {
|
||||
builder.orderBy('date', (this.costMethod === 'LIFO') ? 'DESC': 'ASC');
|
||||
builder.where('item_id', this.itemId);
|
||||
};
|
||||
const afterInvTransactions: IInventoryTransaction[] =
|
||||
await InventoryTransaction.tenant()
|
||||
.query()
|
||||
await InventoryTransaction.query()
|
||||
.modify('filterDateRange', this.startingDate)
|
||||
.orderByRaw("FIELD(direction, 'IN', 'OUT')")
|
||||
.onBuild(commonBuilder)
|
||||
@@ -97,8 +98,7 @@ export default class InventoryCostLotTracker extends InventoryCostMethod impleme
|
||||
.withGraphFetched('item');
|
||||
|
||||
const availiableINLots: IInventoryLotCost[] =
|
||||
await InventoryLotCostTracker.tenant()
|
||||
.query()
|
||||
await InventoryLotCostTracker.query()
|
||||
.modify('filterDateRange', null, this.startingDate)
|
||||
.orderBy('date', 'ASC')
|
||||
.where('direction', 'IN')
|
||||
@@ -117,9 +117,10 @@ export default class InventoryCostLotTracker extends InventoryCostMethod impleme
|
||||
* @private
|
||||
*/
|
||||
private async fetchInvOUTTransactions() {
|
||||
const { InventoryTransaction } = this.tenantModels;
|
||||
|
||||
const afterOUTTransactions: IInventoryTransaction[] =
|
||||
await InventoryTransaction.tenant()
|
||||
.query()
|
||||
await InventoryTransaction.query()
|
||||
.modify('filterDateRange', this.startingDate)
|
||||
.orderBy('date', 'ASC')
|
||||
.orderBy('lot_number', 'ASC')
|
||||
@@ -132,8 +133,8 @@ export default class InventoryCostLotTracker extends InventoryCostMethod impleme
|
||||
|
||||
private async fetchItemsMapped() {
|
||||
const itemsIds = chain(this.inTransactions).map((e) => e.itemId).uniq().value();
|
||||
const storedItems = await Item.tenant()
|
||||
.query()
|
||||
const { Item } = this.tenantModels;
|
||||
const storedItems = await Item.query()
|
||||
.where('type', 'inventory')
|
||||
.whereIn('id', itemsIds);
|
||||
|
||||
@@ -145,9 +146,9 @@ export default class InventoryCostLotTracker extends InventoryCostMethod impleme
|
||||
* @private
|
||||
*/
|
||||
private async fetchRevertInvJReferenceIds() {
|
||||
const { InventoryTransaction } = this.tenantModels;
|
||||
const revertJEntriesTransactions: IInventoryTransaction[] =
|
||||
await InventoryTransaction.tenant()
|
||||
.query()
|
||||
await InventoryTransaction.query()
|
||||
.select(['transactionId', 'transactionType'])
|
||||
.modify('filterDateRange', this.startingDate)
|
||||
.where('direction', 'OUT')
|
||||
@@ -164,16 +165,15 @@ export default class InventoryCostLotTracker extends InventoryCostMethod impleme
|
||||
* @return {Promise}
|
||||
*/
|
||||
public async revertInventoryLots(startingDate: Date) {
|
||||
const { InventoryLotCostTracker } = this.tenantModels;
|
||||
const asyncOpers: any[] = [];
|
||||
const inventoryLotsTrans = await InventoryLotCostTracker.tenant()
|
||||
.query()
|
||||
const inventoryLotsTrans = await InventoryLotCostTracker.query()
|
||||
.modify('filterDateRange', this.startingDate)
|
||||
.orderBy('date', 'DESC')
|
||||
.where('item_id', this.itemId)
|
||||
.where('direction', 'OUT');
|
||||
|
||||
const deleteInvLotsTrans = InventoryLotCostTracker.tenant()
|
||||
.query()
|
||||
const deleteInvLotsTrans = InventoryLotCostTracker.query()
|
||||
.modify('filterDateRange', this.startingDate)
|
||||
.where('item_id', this.itemId)
|
||||
.delete();
|
||||
@@ -181,8 +181,7 @@ export default class InventoryCostLotTracker extends InventoryCostMethod impleme
|
||||
inventoryLotsTrans.forEach((inventoryLot: IInventoryLotCost) => {
|
||||
if (!inventoryLot.lotNumber) { return; }
|
||||
|
||||
const incrementOper = InventoryLotCostTracker.tenant()
|
||||
.query()
|
||||
const incrementOper = InventoryLotCostTracker.query()
|
||||
.where('lot_number', inventoryLot.lotNumber)
|
||||
.where('direction', 'IN')
|
||||
.increment('remaining', inventoryLot.quantity);
|
||||
|
||||
@@ -1,28 +1,42 @@
|
||||
import { omit } from 'lodash';
|
||||
import { Inject } from 'typedi';
|
||||
import TenancyService from '@/services/Tenancy/TenancyService';
|
||||
import { IInventoryLotCost } from '@/interfaces';
|
||||
import { InventoryLotCostTracker } from '@/models';
|
||||
|
||||
export default class InventoryCostMethod {
|
||||
@Inject()
|
||||
tenancy: TenancyService;
|
||||
tenantModels: any;
|
||||
|
||||
/**
|
||||
* Constructor method.
|
||||
* @param {number} tenantId - The given tenant id.
|
||||
*/
|
||||
constructor(tenantId: number, startingDate: Date, itemId: number) {
|
||||
this.tenantModels = this.tenantModels.models(tenantId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the inventory lots costs transactions in bulk.
|
||||
* @param {IInventoryLotCost[]} costLotsTransactions
|
||||
* @return {Promise[]}
|
||||
*/
|
||||
public storeInventoryLotsCost(costLotsTransactions: IInventoryLotCost[]): Promise<object> {
|
||||
const { InventoryLotCostTracker } = this.tenantModels;
|
||||
const opers: any = [];
|
||||
|
||||
costLotsTransactions.forEach((transaction: IInventoryLotCost) => {
|
||||
if (transaction.lotTransId && transaction.decrement) {
|
||||
const decrementOper = InventoryLotCostTracker.tenant()
|
||||
.query()
|
||||
const decrementOper = InventoryLotCostTracker.query()
|
||||
.where('id', transaction.lotTransId)
|
||||
.decrement('remaining', transaction.decrement);
|
||||
opers.push(decrementOper);
|
||||
|
||||
} else if(!transaction.lotTransId) {
|
||||
const operation = InventoryLotCostTracker.tenant().query()
|
||||
.insert({
|
||||
...omit(transaction, ['decrement', 'invTransId', 'lotTransId']),
|
||||
});
|
||||
const operation = InventoryLotCostTracker.query()
|
||||
.insert({
|
||||
...omit(transaction, ['decrement', 'invTransId', 'lotTransId']),
|
||||
});
|
||||
opers.push(operation);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
import { difference } from "lodash";
|
||||
import { Item, ItemTransaction } from '@/models';
|
||||
|
||||
export default class ItemsService {
|
||||
|
||||
static async newItem(item) {
|
||||
const storedItem = await Item.tenant()
|
||||
.query()
|
||||
.insertAndFetch({
|
||||
...item,
|
||||
});
|
||||
return storedItem;
|
||||
}
|
||||
|
||||
static async editItem(item, itemId) {
|
||||
const updateItem = await Item.tenant()
|
||||
.query()
|
||||
.findById(itemId)
|
||||
.patch({
|
||||
...item,
|
||||
});
|
||||
return updateItem;
|
||||
}
|
||||
|
||||
static async deleteItem(itemId) {
|
||||
return Item.tenant()
|
||||
.query()
|
||||
.findById(itemId)
|
||||
.delete();
|
||||
}
|
||||
|
||||
static async getItemWithMetadata(itemId) {
|
||||
return Item.tenant()
|
||||
.query()
|
||||
.findById(itemId)
|
||||
.withGraphFetched(
|
||||
'costAccount',
|
||||
'sellAccount',
|
||||
'inventoryAccount',
|
||||
'category'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the given items IDs exists or not returns the not found ones.
|
||||
* @param {Array} itemsIDs
|
||||
* @return {Array}
|
||||
*/
|
||||
static async isItemsIdsExists(itemsIDs) {
|
||||
const storedItems = await Item.tenant().query().whereIn('id', itemsIDs);
|
||||
const storedItemsIds = storedItems.map((t) => t.id);
|
||||
|
||||
const notFoundItemsIds = difference(
|
||||
itemsIDs,
|
||||
storedItemsIds,
|
||||
);
|
||||
return notFoundItemsIds;
|
||||
}
|
||||
}
|
||||
70
server/src/services/Items/ItemsService.ts
Normal file
70
server/src/services/Items/ItemsService.ts
Normal file
@@ -0,0 +1,70 @@
|
||||
import { difference } from "lodash";
|
||||
import { Service, Inject } from "typedi";
|
||||
import TenancyService from '@/services/Tenancy/TenancyService';
|
||||
|
||||
@Service()
|
||||
export default class ItemsService {
|
||||
@Inject()
|
||||
tenancy: TenancyService;
|
||||
|
||||
async newItem(tenantId: number, item: any) {
|
||||
const { Item } = this.tenancy.models(tenantId);
|
||||
const storedItem = await Item.query()
|
||||
.insertAndFetch({
|
||||
...item,
|
||||
});
|
||||
return storedItem;
|
||||
}
|
||||
|
||||
async editItem(tenantId: number, item: any, itemId: number) {
|
||||
const { Item } = this.tenancy.models(tenantId);
|
||||
const updateItem = await Item.query()
|
||||
.findById(itemId)
|
||||
.patch({
|
||||
...item,
|
||||
});
|
||||
return updateItem;
|
||||
}
|
||||
|
||||
async deleteItem(tenantId: number, itemId: number) {
|
||||
const { Item } = this.tenancy.models(tenantId);
|
||||
return Item.query()
|
||||
.findById(itemId)
|
||||
.delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the item details of the given id with associated details.
|
||||
* @param {number} tenantId
|
||||
* @param {number} itemId
|
||||
*/
|
||||
async getItemWithMetadata(tenantId: number, itemId: number) {
|
||||
const { Item } = this.tenancy.models(tenantId);
|
||||
return Item.query()
|
||||
.findById(itemId)
|
||||
.withGraphFetched(
|
||||
'costAccount',
|
||||
'sellAccount',
|
||||
'inventoryAccount',
|
||||
'category'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the given items IDs exists or not returns the not found ones.
|
||||
* @param {Array} itemsIDs
|
||||
* @return {Array}
|
||||
*/
|
||||
async isItemsIdsExists(tenantId: number, itemsIDs: number[]) {
|
||||
const { Item } = this.tenancy.models(tenantId);
|
||||
|
||||
const storedItems = await Item.query().whereIn('id', itemsIDs);
|
||||
const storedItemsIds = storedItems.map((t) => t.id);
|
||||
|
||||
const notFoundItemsIds = difference(
|
||||
itemsIDs,
|
||||
storedItemsIds,
|
||||
);
|
||||
return notFoundItemsIds;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Service, Container, Inject } from 'typedi';
|
||||
import cryptoRandomString from 'crypto-random-string';
|
||||
import { times } from 'lodash';
|
||||
import { Voucher } from "@/system/models";
|
||||
import { IVoucher } from '@/interfaces';
|
||||
import VoucherMailMessages from '@/services/Payment/VoucherMailMessages';
|
||||
@@ -26,6 +27,8 @@ export default class VoucherService {
|
||||
let voucherCode: string;
|
||||
let repeat: boolean = true;
|
||||
|
||||
console.log(Voucher);
|
||||
|
||||
while(repeat) {
|
||||
voucherCode = cryptoRandomString({ length: 10, type: 'numeric' });
|
||||
const foundVouchers = await Voucher.query().where('voucher_code', voucherCode);
|
||||
@@ -39,6 +42,29 @@ export default class VoucherService {
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {number} loop
|
||||
* @param {number} voucherPeriod
|
||||
* @param {string} periodInterval
|
||||
* @param {number} planId
|
||||
*/
|
||||
async generateVouchers(
|
||||
loop = 1,
|
||||
voucherPeriod: numner,
|
||||
periodInterval: string = 'days',
|
||||
planId: number,
|
||||
) {
|
||||
const asyncOpers: Promise<any>[] = [];
|
||||
|
||||
times(loop, () => {
|
||||
const generateOper = this.generateVoucher(voucherPeriod, periodInterval, planId);
|
||||
asyncOpers.push(generateOper);
|
||||
});
|
||||
return Promise.all(asyncOpers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables the given voucher id on the storage.
|
||||
* @param {number} voucherId
|
||||
|
||||
@@ -1,26 +1,30 @@
|
||||
import express from 'express';
|
||||
import { Inject, Service } from 'typedi';
|
||||
import { omit, sumBy } from 'lodash';
|
||||
import moment from 'moment';
|
||||
import {
|
||||
BillPayment,
|
||||
BillPaymentEntry,
|
||||
Vendor,
|
||||
Bill,
|
||||
Account,
|
||||
AccountTransaction,
|
||||
} from '@/models';
|
||||
import { IBillPaymentOTD, IBillPayment } from '@/interfaces';
|
||||
import ServiceItemsEntries from '@/services/Sales/ServiceItemsEntries';
|
||||
import AccountsService from '@/services/Accounts/AccountsService';
|
||||
import JournalPoster from '@/services/Accounting/JournalPoster';
|
||||
import JournalEntry from '@/services/Accounting/JournalEntry';
|
||||
import JournalPosterService from '@/services/Sales/JournalPosterService';
|
||||
import TenancyService from '@/services/Tenancy/TenancyService';
|
||||
import { formatDateFields } from '@/utils';
|
||||
|
||||
/**
|
||||
* Bill payments service.
|
||||
* @service
|
||||
*/
|
||||
@Service()
|
||||
export default class BillPaymentsService {
|
||||
@Inject()
|
||||
accountsService: AccountsService;
|
||||
|
||||
@Inject()
|
||||
tenancy: TenancyService;
|
||||
|
||||
@Inject()
|
||||
journalService: JournalPosterService;
|
||||
|
||||
/**
|
||||
* Creates a new bill payment transcations and store it to the storage
|
||||
* with associated bills entries and journal transactions.
|
||||
@@ -32,24 +36,24 @@ export default class BillPaymentsService {
|
||||
* - Increment the payment amount of the given vendor bills.
|
||||
* - Decrement the vendor balance.
|
||||
* - Records payment journal entries.
|
||||
*
|
||||
* @param {BillPaymentDTO} billPayment
|
||||
* @param {number} tenantId - Tenant id.
|
||||
* @param {BillPaymentDTO} billPayment - Bill payment object.
|
||||
*/
|
||||
static async createBillPayment(billPaymentDTO) {
|
||||
async createBillPayment(tenantId: number, billPaymentDTO: IBillPaymentOTD) {
|
||||
const { Bill, BillPayment, BillPaymentEntry, Vendor } = this.tenancy.models(tenantId);
|
||||
|
||||
const billPayment = {
|
||||
amount: sumBy(billPaymentDTO.entries, 'payment_amount'),
|
||||
...formatDateFields(billPaymentDTO, ['payment_date']),
|
||||
}
|
||||
const storedBillPayment = await BillPayment.tenant()
|
||||
.query()
|
||||
const storedBillPayment = await BillPayment.query()
|
||||
.insert({
|
||||
...omit(billPayment, ['entries']),
|
||||
});
|
||||
const storeOpers = [];
|
||||
const storeOpers: Promise<any>[] = [];
|
||||
|
||||
billPayment.entries.forEach((entry) => {
|
||||
const oper = BillPaymentEntry.tenant()
|
||||
.query()
|
||||
const oper = BillPaymentEntry.query()
|
||||
.insert({
|
||||
bill_payment_id: storedBillPayment.id,
|
||||
...entry,
|
||||
@@ -69,7 +73,7 @@ export default class BillPaymentsService {
|
||||
);
|
||||
// Records the journal transactions after bills payment
|
||||
// and change diff acoount balance.
|
||||
const recordJournalTransaction = this.recordPaymentReceiveJournalEntries({
|
||||
const recordJournalTransaction = this.recordPaymentReceiveJournalEntries(tenantId, {
|
||||
id: storedBillPayment.id,
|
||||
...billPayment,
|
||||
});
|
||||
@@ -93,18 +97,23 @@ export default class BillPaymentsService {
|
||||
* - Re-insert the journal transactions and update the diff accounts balance.
|
||||
* - Update the diff vendor balance.
|
||||
* - Update the diff bill payment amount.
|
||||
*
|
||||
* @param {number} tenantId - Tenant id
|
||||
* @param {Integer} billPaymentId
|
||||
* @param {BillPaymentDTO} billPayment
|
||||
* @param {IBillPayment} oldBillPayment
|
||||
*/
|
||||
static async editBillPayment(billPaymentId, billPaymentDTO, oldBillPayment) {
|
||||
async editBillPayment(
|
||||
tenantId: number,
|
||||
billPaymentId: number,
|
||||
billPaymentDTO,
|
||||
oldBillPayment,
|
||||
) {
|
||||
const { BillPayment, BillPaymentEntry, Vendor } = this.tenancy.models(tenantId);
|
||||
const billPayment = {
|
||||
amount: sumBy(billPaymentDTO.entries, 'payment_amount'),
|
||||
...formatDateFields(billPaymentDTO, ['payment_date']),
|
||||
};
|
||||
const updateBillPayment = await BillPayment.tenant()
|
||||
.query()
|
||||
const updateBillPayment = await BillPayment.query()
|
||||
.where('id', billPaymentId)
|
||||
.update({
|
||||
...omit(billPayment, ['entries']),
|
||||
@@ -118,22 +127,19 @@ export default class BillPaymentsService {
|
||||
entriesHasIds
|
||||
);
|
||||
if (entriesIdsShouldDelete.length > 0) {
|
||||
const deleteOper = BillPaymentEntry.tenant()
|
||||
.query()
|
||||
const deleteOper = BillPaymentEntry.query()
|
||||
.bulkDelete(entriesIdsShouldDelete);
|
||||
opers.push(deleteOper);
|
||||
}
|
||||
// Entries that should be update to the storage.
|
||||
if (entriesHasIds.length > 0) {
|
||||
const updateOper = BillPaymentEntry.tenant()
|
||||
.query()
|
||||
const updateOper = BillPaymentEntry.query()
|
||||
.bulkUpdate(entriesHasIds, { where: 'id' });
|
||||
opers.push(updateOper);
|
||||
}
|
||||
// Entries that should be inserted to the storage.
|
||||
if (entriesHasNoIds.length > 0) {
|
||||
const insertOper = BillPaymentEntry.tenant()
|
||||
.query()
|
||||
const insertOper = BillPaymentEntry.query()
|
||||
.bulkInsert(
|
||||
entriesHasNoIds.map((e) => ({ ...e, bill_payment_id: billPaymentId }))
|
||||
);
|
||||
@@ -141,7 +147,7 @@ export default class BillPaymentsService {
|
||||
}
|
||||
// Records the journal transactions after bills payment and change
|
||||
// different acoount balance.
|
||||
const recordJournalTransaction = this.recordPaymentReceiveJournalEntries({
|
||||
const recordJournalTransaction = this.recordPaymentReceiveJournalEntries(tenantId, {
|
||||
id: storedBillPayment.id,
|
||||
...billPayment,
|
||||
});
|
||||
@@ -161,18 +167,19 @@ export default class BillPaymentsService {
|
||||
|
||||
/**
|
||||
* Deletes the bill payment and associated transactions.
|
||||
* @param {number} tenantId - Tenant id.
|
||||
* @param {Integer} billPaymentId - The given bill payment id.
|
||||
* @return {Promise}
|
||||
*/
|
||||
static async deleteBillPayment(billPaymentId) {
|
||||
const billPayment = await BillPayment.tenant().query().where('id', billPaymentId).first();
|
||||
async deleteBillPayment(tenantId: number, billPaymentId: number) {
|
||||
const { BillPayment, BillPaymentEntry, Vendor } = this.tenancy.models(tenantId);
|
||||
const billPayment = await BillPayment.query().where('id', billPaymentId).first();
|
||||
|
||||
await BillPayment.tenant().query()
|
||||
await BillPayment.query()
|
||||
.where('id', billPaymentId)
|
||||
.delete();
|
||||
|
||||
await BillPaymentEntry.tenant()
|
||||
.query()
|
||||
await BillPaymentEntry.query()
|
||||
.where('bill_payment_id', billPaymentId)
|
||||
.delete();
|
||||
|
||||
@@ -192,17 +199,21 @@ export default class BillPaymentsService {
|
||||
|
||||
/**
|
||||
* Records bill payment receive journal transactions.
|
||||
* @param {number} tenantId -
|
||||
* @param {BillPayment} billPayment
|
||||
* @param {Integer} billPaymentId
|
||||
*/
|
||||
static async recordPaymentReceiveJournalEntries(billPayment) {
|
||||
async recordPaymentReceiveJournalEntries(tenantId: number, billPayment) {
|
||||
const { AccountTransaction, Account } = this.tenancy.models(tenantId);
|
||||
|
||||
const paymentAmount = sumBy(billPayment.entries, 'payment_amount');
|
||||
const formattedDate = moment(billPayment.payment_date).format('YYYY-MM-DD');
|
||||
const payableAccount = await AccountsService.getAccountByType(
|
||||
const payableAccount = await this.accountsService.getAccountByType(
|
||||
tenantId,
|
||||
'accounts_payable'
|
||||
);
|
||||
|
||||
const accountsDepGraph = await Account.tenant().depGraph().query();
|
||||
const accountsDepGraph = await Account.depGraph().query();
|
||||
const journal = new JournalPoster(accountsDepGraph);
|
||||
|
||||
const commonJournal = {
|
||||
@@ -213,8 +224,7 @@ export default class BillPaymentsService {
|
||||
date: formattedDate,
|
||||
};
|
||||
if (billPayment.id) {
|
||||
const transactions = await AccountTransaction.tenant()
|
||||
.query()
|
||||
const transactions = await AccountTransaction.query()
|
||||
.whereIn('reference_type', ['BillPayment'])
|
||||
.where('reference_id', billPayment.id)
|
||||
.withGraphFetched('account.type');
|
||||
@@ -246,11 +256,12 @@ export default class BillPaymentsService {
|
||||
|
||||
/**
|
||||
* Retrieve bill payment with associated metadata.
|
||||
* @param {number} billPaymentId
|
||||
* @param {number} billPaymentId - The bill payment id.
|
||||
* @return {object}
|
||||
*/
|
||||
static async getBillPaymentWithMetadata(billPaymentId) {
|
||||
const billPayment = await BillPayment.tenant().query()
|
||||
async getBillPaymentWithMetadata(tenantId: number, billPaymentId: number) {
|
||||
const { BillPayment } = this.tenancy.models(tenantId);
|
||||
const billPayment = await BillPayment.query()
|
||||
.where('id', billPaymentId)
|
||||
.withGraphFetched('entries')
|
||||
.withGraphFetched('vendor')
|
||||
@@ -265,8 +276,9 @@ export default class BillPaymentsService {
|
||||
* @param {Integer} billPaymentId
|
||||
* @return {boolean}
|
||||
*/
|
||||
static async isBillPaymentExists(billPaymentId) {
|
||||
const billPayment = await BillPayment.tenant().query()
|
||||
async isBillPaymentExists(tenantId: number, billPaymentId: number) {
|
||||
const { BillPayment } = this.tenancy.models(tenantId);
|
||||
const billPayment = await BillPayment.query()
|
||||
.where('id', billPaymentId)
|
||||
.first();
|
||||
|
||||
@@ -1,13 +1,6 @@
|
||||
import { omit, sumBy, pick } from 'lodash';
|
||||
import moment from 'moment';
|
||||
import {
|
||||
Account,
|
||||
Bill,
|
||||
Vendor,
|
||||
ItemEntry,
|
||||
Item,
|
||||
AccountTransaction,
|
||||
} from '@/models';
|
||||
import { Inject, Service } from 'typedi';
|
||||
import JournalPoster from '@/services/Accounting/JournalPoster';
|
||||
import JournalEntry from '@/services/Accounting/JournalEntry';
|
||||
import AccountsService from '@/services/Accounts/AccountsService';
|
||||
@@ -15,13 +8,25 @@ import JournalPosterService from '@/services/Sales/JournalPosterService';
|
||||
import InventoryService from '@/services/Inventory/Inventory';
|
||||
import HasItemsEntries from '@/services/Sales/HasItemsEntries';
|
||||
import SalesInvoicesCost from '@/services/Sales/SalesInvoicesCost';
|
||||
import TenancyService from '@/services/Tenancy/TenancyService';
|
||||
import { formatDateFields } from '@/utils';
|
||||
import{ IBillOTD } from '@/interfaces';
|
||||
|
||||
/**
|
||||
* Vendor bills services.
|
||||
* @service
|
||||
*/
|
||||
@Service()
|
||||
export default class BillsService extends SalesInvoicesCost {
|
||||
@Inject()
|
||||
inventoryService: InventoryService;
|
||||
|
||||
@Inject()
|
||||
accountsService: AccountsService;
|
||||
|
||||
@Inject()
|
||||
tenancy: TenancyService;
|
||||
|
||||
/**
|
||||
* Creates a new bill and stored it to the storage.
|
||||
*
|
||||
@@ -33,26 +38,29 @@ export default class BillsService extends SalesInvoicesCost {
|
||||
* - Record bill journal transactions on the given accounts.
|
||||
* - Record bill items inventory transactions.
|
||||
* ----
|
||||
* @param {IBill} bill -
|
||||
* @param {number} tenantId - The given tenant id.
|
||||
* @param {IBillOTD} billDTO -
|
||||
* @return {void}
|
||||
*/
|
||||
static async createBill(billDTO) {
|
||||
const invLotNumber = await InventoryService.nextLotNumber();
|
||||
async createBill(tenantId: number, billDTO: IBillOTD) {
|
||||
const { Vendor, Bill, ItemEntry } = this.tenancy.models(tenantId);
|
||||
|
||||
const invLotNumber = await this.inventoryService.nextLotNumber(tenantId);
|
||||
const amount = sumBy(billDTO.entries, e => ItemEntry.calcAmount(e));
|
||||
|
||||
const bill = {
|
||||
...formatDateFields(billDTO, ['bill_date', 'due_date']),
|
||||
amount: sumBy(billDTO.entries, 'amount'),
|
||||
amount,
|
||||
invLotNumber: billDTO.invLotNumber || invLotNumber
|
||||
};
|
||||
const saveEntriesOpers = [];
|
||||
|
||||
const storedBill = await Bill.tenant()
|
||||
.query()
|
||||
const storedBill = await Bill.query()
|
||||
.insert({
|
||||
...omit(bill, ['entries']),
|
||||
});
|
||||
bill.entries.forEach((entry) => {
|
||||
const oper = ItemEntry.tenant()
|
||||
.query()
|
||||
const oper = ItemEntry.query()
|
||||
.insertAndFetch({
|
||||
reference_type: 'Bill',
|
||||
reference_id: storedBill.id,
|
||||
@@ -70,10 +78,10 @@ export default class BillsService extends SalesInvoicesCost {
|
||||
|
||||
// Rewrite the inventory transactions for inventory items.
|
||||
const writeInvTransactionsOper = this.recordInventoryTransactions(
|
||||
bill, storedBill.id
|
||||
tenantId, bill, storedBill.id
|
||||
);
|
||||
// Writes the journal entries for the given bill transaction.
|
||||
const writeJEntriesOper = this.recordJournalTransactions({
|
||||
const writeJEntriesOper = this.recordJournalTransactions(tenantId, {
|
||||
id: storedBill.id, ...bill,
|
||||
});
|
||||
await Promise.all([
|
||||
@@ -83,7 +91,7 @@ export default class BillsService extends SalesInvoicesCost {
|
||||
]);
|
||||
// Schedule bill re-compute based on the item cost
|
||||
// method and starting date.
|
||||
await this.scheduleComputeBillItemsCost(bill);
|
||||
await this.scheduleComputeBillItemsCost(tenantId, bill);
|
||||
|
||||
return storedBill;
|
||||
}
|
||||
@@ -100,26 +108,29 @@ export default class BillsService extends SalesInvoicesCost {
|
||||
* - Re-write the inventory transactions.
|
||||
* - Re-write the bill journal transactions.
|
||||
*
|
||||
* @param {number} tenantId - The given tenant id.
|
||||
* @param {Integer} billId - The given bill id.
|
||||
* @param {IBill} bill - The given new bill details.
|
||||
* @param {billDTO} billDTO - The given new bill details.
|
||||
*/
|
||||
static async editBill(billId, billDTO) {
|
||||
const oldBill = await Bill.tenant().query().findById(billId);
|
||||
async editBill(tenantId: number, billId: number, billDTO: billDTO) {
|
||||
const { Bill, ItemEntry, Vendor } = this.tenancy.models(tenantId);
|
||||
|
||||
const oldBill = await Bill.query().findById(billId);
|
||||
const amount = sumBy(billDTO.entries, e => ItemEntry.calcAmount(e));
|
||||
|
||||
const bill = {
|
||||
...formatDateFields(billDTO, ['bill_date', 'due_date']),
|
||||
amount: sumBy(billDTO.entries, 'amount'),
|
||||
amount,
|
||||
invLotNumber: oldBill.invLotNumber,
|
||||
};
|
||||
// Update the bill transaction.
|
||||
const updatedBill = await Bill.tenant()
|
||||
.query()
|
||||
const updatedBill = await Bill.query()
|
||||
.where('id', billId)
|
||||
.update({
|
||||
...omit(bill, ['entries', 'invLotNumber'])
|
||||
});
|
||||
// Old stored entries.
|
||||
const storedEntries = await ItemEntry.tenant()
|
||||
.query()
|
||||
const storedEntries = await ItemEntry.query()
|
||||
.where('reference_id', billId)
|
||||
.where('reference_type', 'Bill');
|
||||
|
||||
@@ -135,10 +146,11 @@ export default class BillsService extends SalesInvoicesCost {
|
||||
oldBill.amount,
|
||||
);
|
||||
// Re-write the inventory transactions for inventory items.
|
||||
const writeInvTransactionsOper = this.recordInventoryTransactions(bill, billId, true);
|
||||
|
||||
const writeInvTransactionsOper = this.recordInventoryTransactions(
|
||||
tenantId, bill, billId, true
|
||||
);
|
||||
// Writes the journal entries for the given bill transaction.
|
||||
const writeJEntriesOper = this.recordJournalTransactions({
|
||||
const writeJEntriesOper = this.recordJournalTransactions(tenantId, {
|
||||
id: billId,
|
||||
...bill,
|
||||
}, billId);
|
||||
@@ -151,7 +163,7 @@ export default class BillsService extends SalesInvoicesCost {
|
||||
]);
|
||||
// Schedule sale invoice re-compute based on the item cost
|
||||
// method and starting date.
|
||||
await this.scheduleComputeBillItemsCost(bill);
|
||||
await this.scheduleComputeBillItemsCost(tenantId, bill);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -159,21 +171,22 @@ export default class BillsService extends SalesInvoicesCost {
|
||||
* @param {Integer} billId
|
||||
* @return {void}
|
||||
*/
|
||||
static async deleteBill(billId) {
|
||||
const bill = await Bill.tenant().query()
|
||||
async deleteBill(tenantId: number, billId: number) {
|
||||
const { Bill, ItemEntry, Vendor } = this.tenancy.models(tenantId);
|
||||
|
||||
const bill = await Bill.query()
|
||||
.where('id', billId)
|
||||
.withGraphFetched('entries')
|
||||
.first();
|
||||
|
||||
// Delete all associated bill entries.
|
||||
const deleteBillEntriesOper = ItemEntry.tenant()
|
||||
.query()
|
||||
const deleteBillEntriesOper = ItemEntry.query()
|
||||
.where('reference_type', 'Bill')
|
||||
.where('reference_id', billId)
|
||||
.delete();
|
||||
|
||||
// Delete the bill transaction.
|
||||
const deleteBillOper = Bill.tenant().query().where('id', billId).delete();
|
||||
const deleteBillOper = Bill.query().where('id', billId).delete();
|
||||
|
||||
// Delete associated bill journal transactions.
|
||||
const deleteTransactionsOper = JournalPosterService.deleteJournalTransactions(
|
||||
@@ -181,8 +194,8 @@ export default class BillsService extends SalesInvoicesCost {
|
||||
'Bill'
|
||||
);
|
||||
// Delete bill associated inventory transactions.
|
||||
const deleteInventoryTransOper = InventoryService.deleteInventoryTransactions(
|
||||
billId, 'Bill'
|
||||
const deleteInventoryTransOper = this.inventoryService.deleteInventoryTransactions(
|
||||
tenantId, billId, 'Bill'
|
||||
);
|
||||
// Revert vendor balance.
|
||||
const revertVendorBalance = Vendor.changeBalance(bill.vendorId, bill.amount * -1);
|
||||
@@ -196,7 +209,7 @@ export default class BillsService extends SalesInvoicesCost {
|
||||
]);
|
||||
// Schedule sale invoice re-compute based on the item cost
|
||||
// method and starting date.
|
||||
await this.scheduleComputeBillItemsCost(bill);
|
||||
await this.scheduleComputeBillItemsCost(tenantId, bill);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -204,7 +217,12 @@ export default class BillsService extends SalesInvoicesCost {
|
||||
* @param {Bill} bill
|
||||
* @param {number} billId
|
||||
*/
|
||||
static recordInventoryTransactions(bill, billId, override) {
|
||||
recordInventoryTransactions(
|
||||
tenantId: number,
|
||||
bill: any,
|
||||
billId: number,
|
||||
override?: boolean
|
||||
) {
|
||||
const inventoryTransactions = bill.entries
|
||||
.map((entry) => ({
|
||||
...pick(entry, ['item_id', 'quantity', 'rate']),
|
||||
@@ -216,8 +234,8 @@ export default class BillsService extends SalesInvoicesCost {
|
||||
entryId: entry.id,
|
||||
}));
|
||||
|
||||
return InventoryService.recordInventoryTransactions(
|
||||
inventoryTransactions, override
|
||||
return this.inventoryService.recordInventoryTransactions(
|
||||
tenantId, inventoryTransactions, override
|
||||
);
|
||||
}
|
||||
|
||||
@@ -227,19 +245,21 @@ export default class BillsService extends SalesInvoicesCost {
|
||||
* @param {IBill} bill
|
||||
* @param {Integer} billId
|
||||
*/
|
||||
static async recordJournalTransactions(bill, billId) {
|
||||
async recordJournalTransactions(tenantId: number, bill: any, billId?: number) {
|
||||
const { AccountTransaction, Item, Account } = this.tenancy.models(tenantId);
|
||||
|
||||
const entriesItemsIds = bill.entries.map((entry) => entry.item_id);
|
||||
const payableTotal = sumBy(bill.entries, 'amount');
|
||||
const formattedDate = moment(bill.bill_date).format('YYYY-MM-DD');
|
||||
|
||||
const storedItems = await Item.tenant()
|
||||
.query()
|
||||
const storedItems = await Item.query()
|
||||
.whereIn('id', entriesItemsIds);
|
||||
|
||||
const storedItemsMap = new Map(storedItems.map((item) => [item.id, item]));
|
||||
const payableAccount = await AccountsService.getAccountByType('accounts_payable');
|
||||
|
||||
const accountsDepGraph = await Account.tenant().depGraph().query();
|
||||
const payableAccount = await this.accountsService.getAccountByType(
|
||||
tenantId, 'accounts_payable'
|
||||
);
|
||||
const accountsDepGraph = await Account.depGraph().query();
|
||||
const journal = new JournalPoster(accountsDepGraph);
|
||||
|
||||
const commonJournalMeta = {
|
||||
@@ -251,8 +271,7 @@ export default class BillsService extends SalesInvoicesCost {
|
||||
accural: true,
|
||||
};
|
||||
if (billId) {
|
||||
const transactions = await AccountTransaction.tenant()
|
||||
.query()
|
||||
const transactions = await AccountTransaction.query()
|
||||
.whereIn('reference_type', ['Bill'])
|
||||
.whereIn('reference_id', [billId])
|
||||
.withGraphFetched('account.type');
|
||||
@@ -291,11 +310,14 @@ export default class BillsService extends SalesInvoicesCost {
|
||||
|
||||
/**
|
||||
* Detarmines whether the bill exists on the storage.
|
||||
* @param {Integer} billId
|
||||
* @param {number} tenantId - The given tenant id.
|
||||
* @param {Integer} billId - The given bill id.
|
||||
* @return {Boolean}
|
||||
*/
|
||||
static async isBillExists(billId) {
|
||||
const foundBills = await Bill.tenant().query().where('id', billId);
|
||||
async isBillExists(tenantId: number, billId: number) {
|
||||
const { Bill } = this.tenancy.models(tenantId);
|
||||
|
||||
const foundBills = await Bill.query().where('id', billId);
|
||||
return foundBills.length > 0;
|
||||
}
|
||||
|
||||
@@ -304,18 +326,23 @@ export default class BillsService extends SalesInvoicesCost {
|
||||
* @param {Array} billsIds
|
||||
* @return {Boolean}
|
||||
*/
|
||||
static async isBillsExist(billsIds) {
|
||||
const bills = await Bill.tenant().query().whereIn('id', billsIds);
|
||||
async isBillsExist(tenantId: number, billsIds: number[]) {
|
||||
const { Bill } = this.tenancy.models(tenantId);
|
||||
|
||||
const bills = await Bill.query().whereIn('id', billsIds);
|
||||
return bills.length > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detarmines whether the given bill id exists on the storage.
|
||||
* @param {number} tenantId
|
||||
* @param {Integer} billNumber
|
||||
* @return {boolean}
|
||||
*/
|
||||
static async isBillNoExists(billNumber) {
|
||||
const foundBills = await Bill.tenant()
|
||||
.query()
|
||||
async isBillNoExists(tenantId: number, billNumber : string) {
|
||||
const { Bill } = this.tenancy.models(tenantId);
|
||||
|
||||
const foundBills = await Bill.query()
|
||||
.where('bill_number', billNumber);
|
||||
return foundBills.length > 0;
|
||||
}
|
||||
@@ -325,8 +352,10 @@ export default class BillsService extends SalesInvoicesCost {
|
||||
* @param {Integer} billId -
|
||||
* @returns {Promise}
|
||||
*/
|
||||
static getBill(billId) {
|
||||
return Bill.tenant().query().where('id', billId).first();
|
||||
getBill(tenantId: number, billId: number) {
|
||||
const { Bill } = this.tenancy.models(tenantId);
|
||||
|
||||
return Bill.query().where('id', billId).first();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -334,9 +363,10 @@ export default class BillsService extends SalesInvoicesCost {
|
||||
* @param {Integer} billId -
|
||||
* @returns {Promise}
|
||||
*/
|
||||
static getBillWithMetadata(billId) {
|
||||
return Bill.tenant()
|
||||
.query()
|
||||
getBillWithMetadata(tenantId: number, billId: number) {
|
||||
const { Bill } = this.tenancy.models(tenantId);
|
||||
|
||||
return Bill.query()
|
||||
.where('id', billId)
|
||||
.withGraphFetched('vendor')
|
||||
.withGraphFetched('entries')
|
||||
@@ -345,21 +375,27 @@ export default class BillsService extends SalesInvoicesCost {
|
||||
|
||||
/**
|
||||
* Schedules compute bill items cost based on each item cost method.
|
||||
* @param {IBill} bill
|
||||
* @param {number} tenantId -
|
||||
* @param {IBill} bill -
|
||||
* @return {Promise}
|
||||
*/
|
||||
static async scheduleComputeBillItemsCost(bill) {
|
||||
async scheduleComputeBillItemsCost(tenantId: number, bill) {
|
||||
const { Item } = this.tenancy.models(tenantId);
|
||||
const billItemsIds = bill.entries.map((entry) => entry.item_id);
|
||||
|
||||
// Retrieves inventory items only.
|
||||
const inventoryItems = await Item.tenant().query()
|
||||
const inventoryItems = await Item.query()
|
||||
.whereIn('id', billItemsIds)
|
||||
.where('type', 'inventory');
|
||||
|
||||
const inventoryItemsIds = inventoryItems.map(i => i.id);
|
||||
|
||||
if (inventoryItemsIds.length > 0) {
|
||||
await this.scheduleComputeItemsCost(inventoryItemsIds, bill.bill_date);
|
||||
await this.scheduleComputeItemsCost(
|
||||
tenantId,
|
||||
inventoryItemsIds,
|
||||
bill.bill_date
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,13 @@
|
||||
import { difference, omit } from 'lodash';
|
||||
import { Service, Inject } from 'typedi';
|
||||
import TenancyService from '@/services/Tenancy/TenancyService';
|
||||
import { ItemEntry } from '@/models';
|
||||
|
||||
@Service()
|
||||
export default class HasItemEntries {
|
||||
@Inject()
|
||||
tenancy: TenancyService;
|
||||
|
||||
/**
|
||||
* Patch items entries to the storage.
|
||||
*
|
||||
@@ -9,15 +15,17 @@ export default class HasItemEntries {
|
||||
* @param {Array} oldEntries -
|
||||
* @param {String} referenceType -
|
||||
* @param {String|Number} referenceId -
|
||||
*
|
||||
* @return {Promise}
|
||||
*/
|
||||
static async patchItemsEntries(
|
||||
async patchItemsEntries(
|
||||
tenantId: number,
|
||||
newEntries: Array<any>,
|
||||
oldEntries: Array<any>,
|
||||
referenceType: string,
|
||||
referenceId: string|number
|
||||
) {
|
||||
const { ItemEntry } = this.tenancy.models(tenantId);
|
||||
|
||||
const entriesHasIds = newEntries.filter((entry) => entry.id);
|
||||
const entriesHasNoIds = newEntries.filter((entry) => !entry.id);
|
||||
const entriesIds = entriesHasIds.map(entry => entry.id);
|
||||
@@ -31,15 +39,13 @@ export default class HasItemEntries {
|
||||
entriesIds,
|
||||
);
|
||||
if (entriesIdsShouldDelete.length > 0) {
|
||||
const deleteOper = ItemEntry.tenant()
|
||||
.query()
|
||||
const deleteOper = ItemEntry.query()
|
||||
.whereIn('id', entriesIdsShouldDelete)
|
||||
.delete();
|
||||
opers.push(deleteOper);
|
||||
}
|
||||
entriesHasIds.forEach((entry) => {
|
||||
const updateOper = ItemEntry.tenant()
|
||||
.query()
|
||||
const updateOper = ItemEntry.query()
|
||||
.where('id', entry.id)
|
||||
.update({
|
||||
...omit(entry, excludeAttrs),
|
||||
@@ -47,8 +53,7 @@ export default class HasItemEntries {
|
||||
opers.push(updateOper);
|
||||
});
|
||||
entriesHasNoIds.forEach((entry) => {
|
||||
const insertOper = ItemEntry.tenant()
|
||||
.query()
|
||||
const insertOper = ItemEntry.query()
|
||||
.insert({
|
||||
reference_id: referenceId,
|
||||
reference_type: referenceType,
|
||||
@@ -59,7 +64,7 @@ export default class HasItemEntries {
|
||||
return Promise.all([...opers]);
|
||||
}
|
||||
|
||||
static filterNonInventoryEntries(entries: [], items: []) {
|
||||
filterNonInventoryEntries(entries: [], items: []) {
|
||||
const nonInventoryItems = items.filter((item: any) => item.type !== 'inventory');
|
||||
const nonInventoryItemsIds = nonInventoryItems.map((i: any) => i.id);
|
||||
|
||||
@@ -69,7 +74,7 @@ export default class HasItemEntries {
|
||||
));
|
||||
}
|
||||
|
||||
static filterInventoryEntries(entries: [], items: []) {
|
||||
filterInventoryEntries(entries: [], items: []) {
|
||||
const inventoryItems = items.filter((item: any) => item.type === 'inventory');
|
||||
const inventoryItemsIds = inventoryItems.map((i: any) => i.id);
|
||||
|
||||
|
||||
@@ -1,12 +1,26 @@
|
||||
import { Account, AccountTransaction } from '@/models';
|
||||
import { Service, Inject } from 'typedi';
|
||||
import JournalPoster from '@/services/Accounting/JournalPoster';
|
||||
import TenancyService from '@/services/Tenancy/TenancyService';
|
||||
|
||||
|
||||
@Service()
|
||||
export default class JournalPosterService {
|
||||
@Inject()
|
||||
tenancy: TenancyService;
|
||||
|
||||
/**
|
||||
* Deletes the journal transactions that associated to the given reference id.
|
||||
* @param {number} tenantId - The given tenant id.
|
||||
* @param {number} referenceId - The transaction reference id.
|
||||
* @param {string} referenceType - The transaction reference type.
|
||||
* @return {Promise}
|
||||
*/
|
||||
static async deleteJournalTransactions(referenceId, referenceType) {
|
||||
async deleteJournalTransactions(
|
||||
tenantId: number,
|
||||
referenceId: number,
|
||||
referenceType: string
|
||||
) {
|
||||
const { Account, AccountTransaction } = this.tenancy.models(tenantId);
|
||||
|
||||
const transactions = await AccountTransaction.tenant()
|
||||
.query()
|
||||
.whereIn('reference_type', [referenceType])
|
||||
@@ -1,13 +1,7 @@
|
||||
import { omit, sumBy, chain } from 'lodash';
|
||||
import moment from 'moment';
|
||||
import {
|
||||
AccountTransaction,
|
||||
PaymentReceive,
|
||||
PaymentReceiveEntry,
|
||||
SaleInvoice,
|
||||
Customer,
|
||||
Account,
|
||||
} from '@/models';
|
||||
import { Service, Inject } from 'typedi';
|
||||
import { IPaymentReceiveOTD } from '@/interfaces';
|
||||
import AccountsService from '@/services/Accounts/AccountsService';
|
||||
import JournalPoster from '@/services/Accounting/JournalPoster';
|
||||
import JournalEntry from '@/services/Accounting/JournalEntry';
|
||||
@@ -15,23 +9,41 @@ import JournalPosterService from '@/services/Sales/JournalPosterService';
|
||||
import ServiceItemsEntries from '@/services/Sales/ServiceItemsEntries';
|
||||
import PaymentReceiveEntryRepository from '@/repositories/PaymentReceiveEntryRepository';
|
||||
import CustomerRepository from '@/repositories/CustomerRepository';
|
||||
import TenancyService from '@/services/Tenancy/TenancyService';
|
||||
import { formatDateFields } from '@/utils';
|
||||
|
||||
/**
|
||||
* Payment receive service.
|
||||
* @service
|
||||
*/
|
||||
@Service()
|
||||
export default class PaymentReceiveService {
|
||||
@Inject()
|
||||
accountsService: AccountsService;
|
||||
|
||||
@Inject()
|
||||
tenancy: TenancyService;
|
||||
|
||||
@Inject()
|
||||
journalService: JournalPosterService;
|
||||
|
||||
/**
|
||||
* Creates a new payment receive and store it to the storage
|
||||
* with associated invoices payment and journal transactions.
|
||||
* @async
|
||||
* @param {number} tenantId - Tenant id.
|
||||
* @param {IPaymentReceive} paymentReceive
|
||||
*/
|
||||
static async createPaymentReceive(paymentReceive: any) {
|
||||
async createPaymentReceive(tenantId: number, paymentReceive: IPaymentReceiveOTD) {
|
||||
const {
|
||||
PaymentReceive,
|
||||
PaymentReceiveEntry,
|
||||
SaleInvoice,
|
||||
Customer,
|
||||
} = this.tenancy.models(tenantId);
|
||||
|
||||
const paymentAmount = sumBy(paymentReceive.entries, 'payment_amount');
|
||||
const storedPaymentReceive = await PaymentReceive.tenant()
|
||||
.query()
|
||||
const storedPaymentReceive = await PaymentReceive.query()
|
||||
.insert({
|
||||
amount: paymentAmount,
|
||||
...formatDateFields(omit(paymentReceive, ['entries']), ['payment_date']),
|
||||
@@ -39,15 +51,13 @@ export default class PaymentReceiveService {
|
||||
const storeOpers: Array<any> = [];
|
||||
|
||||
paymentReceive.entries.forEach((entry: any) => {
|
||||
const oper = PaymentReceiveEntry.tenant()
|
||||
.query()
|
||||
const oper = PaymentReceiveEntry.query()
|
||||
.insert({
|
||||
payment_receive_id: storedPaymentReceive.id,
|
||||
...entry,
|
||||
});
|
||||
// Increment the invoice payment amount.
|
||||
const invoice = SaleInvoice.tenant()
|
||||
.query()
|
||||
const invoice = SaleInvoice.query()
|
||||
.where('id', entry.invoice_id)
|
||||
.increment('payment_amount', entry.payment_amount);
|
||||
|
||||
@@ -59,10 +69,10 @@ export default class PaymentReceiveService {
|
||||
paymentAmount,
|
||||
);
|
||||
// Records the sale invoice journal transactions.
|
||||
const recordJournalTransactions = this.recordPaymentReceiveJournalEntries({
|
||||
id: storedPaymentReceive.id,
|
||||
...paymentReceive,
|
||||
});
|
||||
const recordJournalTransactions = this.recordPaymentReceiveJournalEntries(tenantId,{
|
||||
id: storedPaymentReceive.id,
|
||||
...paymentReceive,
|
||||
});
|
||||
await Promise.all([
|
||||
...storeOpers,
|
||||
customerIncrementOper,
|
||||
@@ -82,19 +92,22 @@ export default class PaymentReceiveService {
|
||||
* - Update the different customer balances.
|
||||
* - Update the different invoice payment amount.
|
||||
* @async
|
||||
* @param {Integer} paymentReceiveId
|
||||
* @param {IPaymentReceive} paymentReceive
|
||||
* @param {IPaymentReceive} oldPaymentReceive
|
||||
* @param {number} tenantId -
|
||||
* @param {Integer} paymentReceiveId -
|
||||
* @param {IPaymentReceive} paymentReceive -
|
||||
* @param {IPaymentReceive} oldPaymentReceive -
|
||||
*/
|
||||
static async editPaymentReceive(
|
||||
async editPaymentReceive(
|
||||
tenantId: number,
|
||||
paymentReceiveId: number,
|
||||
paymentReceive: any,
|
||||
oldPaymentReceive: any
|
||||
) {
|
||||
const { PaymentReceive } = this.tenancy.models(tenantId);
|
||||
|
||||
const paymentAmount = sumBy(paymentReceive.entries, 'payment_amount');
|
||||
// Update the payment receive transaction.
|
||||
const updatePaymentReceive = await PaymentReceive.tenant()
|
||||
.query()
|
||||
const updatePaymentReceive = await PaymentReceive.query()
|
||||
.where('id', paymentReceiveId)
|
||||
.update({
|
||||
amount: paymentAmount,
|
||||
@@ -131,6 +144,7 @@ export default class PaymentReceiveService {
|
||||
}
|
||||
// Re-write the journal transactions of the given payment receive.
|
||||
const recordJournalTransactions = this.recordPaymentReceiveJournalEntries(
|
||||
tenantId,
|
||||
{
|
||||
id: oldPaymentReceive.id,
|
||||
...paymentReceive,
|
||||
@@ -147,6 +161,7 @@ export default class PaymentReceiveService {
|
||||
);
|
||||
// Change the difference between the old and new invoice payment amount.
|
||||
const diffInvoicePaymentAmount = this.saveChangeInvoicePaymentAmount(
|
||||
tenantId,
|
||||
oldPaymentReceive.entries,
|
||||
paymentReceive.entries
|
||||
);
|
||||
@@ -169,24 +184,26 @@ export default class PaymentReceiveService {
|
||||
* - Revert the customer balance.
|
||||
* - Revert the payment amount of the associated invoices.
|
||||
* @async
|
||||
* @param {Integer} paymentReceiveId
|
||||
* @param {IPaymentReceive} paymentReceive
|
||||
* @param {number} tenantId - Tenant id.
|
||||
* @param {Integer} paymentReceiveId - Payment receive id.
|
||||
* @param {IPaymentReceive} paymentReceive - Payment receive object.
|
||||
*/
|
||||
static async deletePaymentReceive(paymentReceiveId: number, paymentReceive: any) {
|
||||
async deletePaymentReceive(tenantId: number, paymentReceiveId: number, paymentReceive: any) {
|
||||
const { PaymentReceive, PaymentReceiveEntry, Customer } = this.tenancy.models(tenantId);
|
||||
|
||||
// Deletes the payment receive transaction.
|
||||
await PaymentReceive.tenant()
|
||||
.query()
|
||||
await PaymentReceive.query()
|
||||
.where('id', paymentReceiveId)
|
||||
.delete();
|
||||
|
||||
// Deletes the payment receive associated entries.
|
||||
await PaymentReceiveEntry.tenant()
|
||||
.query()
|
||||
await PaymentReceiveEntry.query()
|
||||
.where('payment_receive_id', paymentReceiveId)
|
||||
.delete();
|
||||
|
||||
// Delete all associated journal transactions to payment receive transaction.
|
||||
const deleteTransactionsOper = JournalPosterService.deleteJournalTransactions(
|
||||
const deleteTransactionsOper = this.journalService.deleteJournalTransactions(
|
||||
tenantId,
|
||||
paymentReceiveId,
|
||||
'PaymentReceive'
|
||||
);
|
||||
@@ -197,6 +214,7 @@ export default class PaymentReceiveService {
|
||||
);
|
||||
// Revert the invoices payments amount.
|
||||
const revertInvoicesPaymentAmount = this.revertInvoicePaymentAmount(
|
||||
tenantId,
|
||||
paymentReceive.entries.map((entry: any) => ({
|
||||
invoiceId: entry.invoiceId,
|
||||
revertAmount: entry.paymentAmount,
|
||||
@@ -211,11 +229,12 @@ export default class PaymentReceiveService {
|
||||
|
||||
/**
|
||||
* Retrieve the payment receive details of the given id.
|
||||
* @param {Integer} paymentReceiveId
|
||||
* @param {number} tenantId - Tenant id.
|
||||
* @param {Integer} paymentReceiveId - Payment receive id.
|
||||
*/
|
||||
static async getPaymentReceive(paymentReceiveId: number) {
|
||||
const paymentReceive = await PaymentReceive.tenant()
|
||||
.query()
|
||||
async getPaymentReceive(tenantId: number, paymentReceiveId: number) {
|
||||
const { PaymentReceive } = this.tenancy.models(tenantId);
|
||||
const paymentReceive = await PaymentReceive.query()
|
||||
.where('id', paymentReceiveId)
|
||||
.withGraphFetched('entries.invoice')
|
||||
.first();
|
||||
@@ -226,9 +245,9 @@ export default class PaymentReceiveService {
|
||||
* Retrieve the payment receive details with associated invoices.
|
||||
* @param {Integer} paymentReceiveId
|
||||
*/
|
||||
static async getPaymentReceiveWithInvoices(paymentReceiveId: number) {
|
||||
return PaymentReceive.tenant()
|
||||
.query()
|
||||
async getPaymentReceiveWithInvoices(tenantId: number, paymentReceiveId: number) {
|
||||
const { PaymentReceive } = this.tenancy.models(tenantId);
|
||||
return PaymentReceive.query()
|
||||
.where('id', paymentReceiveId)
|
||||
.withGraphFetched('invoices')
|
||||
.first();
|
||||
@@ -236,11 +255,12 @@ export default class PaymentReceiveService {
|
||||
|
||||
/**
|
||||
* Detarmines whether the payment receive exists on the storage.
|
||||
* @param {number} tenantId - Tenant id.
|
||||
* @param {Integer} paymentReceiveId
|
||||
*/
|
||||
static async isPaymentReceiveExists(paymentReceiveId: number) {
|
||||
const paymentReceives = await PaymentReceive.tenant()
|
||||
.query()
|
||||
async isPaymentReceiveExists(tenantId: number, paymentReceiveId: number) {
|
||||
const { PaymentReceive } = this.tenancy.models(tenantId);
|
||||
const paymentReceives = await PaymentReceive.query()
|
||||
.where('id', paymentReceiveId);
|
||||
return paymentReceives.length > 0;
|
||||
}
|
||||
@@ -248,15 +268,17 @@ export default class PaymentReceiveService {
|
||||
/**
|
||||
* Detarmines the payment receive number existance.
|
||||
* @async
|
||||
* @param {number} tenantId - Tenant id.
|
||||
* @param {Integer} paymentReceiveNumber - Payment receive number.
|
||||
* @param {Integer} paymentReceiveId - Payment receive id.
|
||||
*/
|
||||
static async isPaymentReceiveNoExists(
|
||||
async isPaymentReceiveNoExists(
|
||||
tenantId: number,
|
||||
paymentReceiveNumber: string|number,
|
||||
paymentReceiveId: number
|
||||
) {
|
||||
const paymentReceives = await PaymentReceive.tenant()
|
||||
.query()
|
||||
const { PaymentReceive } = this.tenancy.models(tenantId);
|
||||
const paymentReceives = await PaymentReceive.query()
|
||||
.where('payment_receive_no', paymentReceiveNumber)
|
||||
.onBuild((query) => {
|
||||
if (paymentReceiveId) {
|
||||
@@ -273,21 +295,25 @@ export default class PaymentReceiveService {
|
||||
* --------
|
||||
* - Account receivable -> Debit
|
||||
* - Payment account [current asset] -> Credit
|
||||
*
|
||||
* @async
|
||||
* @param {number} tenantId - Tenant id.
|
||||
* @param {IPaymentReceive} paymentReceive
|
||||
* @param {Number} paymentReceiveId
|
||||
*/
|
||||
static async recordPaymentReceiveJournalEntries(
|
||||
async recordPaymentReceiveJournalEntries(
|
||||
tenantId: number,
|
||||
paymentReceive: any,
|
||||
paymentReceiveId?: number
|
||||
) {
|
||||
const { Account, AccountTransaction } = this.tenancy.models(tenantId);
|
||||
|
||||
const paymentAmount = sumBy(paymentReceive.entries, 'payment_amount');
|
||||
const formattedDate = moment(paymentReceive.payment_date).format('YYYY-MM-DD');
|
||||
const receivableAccount = await AccountsService.getAccountByType(
|
||||
const receivableAccount = await this.accountsService.getAccountByType(
|
||||
tenantId,
|
||||
'accounts_receivable'
|
||||
);
|
||||
const accountsDepGraph = await Account.tenant().depGraph().query();
|
||||
const accountsDepGraph = await Account.depGraph().query();
|
||||
const journal = new JournalPoster(accountsDepGraph);
|
||||
const commonJournal = {
|
||||
debit: 0,
|
||||
@@ -297,8 +323,7 @@ export default class PaymentReceiveService {
|
||||
date: formattedDate,
|
||||
};
|
||||
if (paymentReceiveId) {
|
||||
const transactions = await AccountTransaction.tenant()
|
||||
.query()
|
||||
const transactions = await AccountTransaction.query()
|
||||
.whereIn('reference_type', ['PaymentReceive'])
|
||||
.where('reference_id', paymentReceiveId)
|
||||
.withGraphFetched('account.type');
|
||||
@@ -330,15 +355,18 @@ export default class PaymentReceiveService {
|
||||
|
||||
/**
|
||||
* Revert the payment amount of the given invoices ids.
|
||||
* @async
|
||||
* @param {number} tenantId - Tenant id.
|
||||
* @param {Array} revertInvoices
|
||||
* @return {Promise}
|
||||
*/
|
||||
static async revertInvoicePaymentAmount(revertInvoices: any[]) {
|
||||
async revertInvoicePaymentAmount(tenantId: number, revertInvoices: any[]) {
|
||||
const { SaleInvoice } = this.tenancy.models(tenantId);
|
||||
const opers: Promise<T>[] = [];
|
||||
|
||||
revertInvoices.forEach((revertInvoice) => {
|
||||
const { revertAmount, invoiceId } = revertInvoice;
|
||||
const oper = SaleInvoice.tenant()
|
||||
.query()
|
||||
const oper = SaleInvoice.query()
|
||||
.where('id', invoiceId)
|
||||
.decrement('payment_amount', revertAmount);
|
||||
opers.push(oper);
|
||||
@@ -348,14 +376,18 @@ export default class PaymentReceiveService {
|
||||
|
||||
/**
|
||||
* Saves difference changing between old and new invoice payment amount.
|
||||
* @async
|
||||
* @param {number} tenantId - Tenant id.
|
||||
* @param {Array} paymentReceiveEntries
|
||||
* @param {Array} newPaymentReceiveEntries
|
||||
* @return
|
||||
*/
|
||||
static async saveChangeInvoicePaymentAmount(
|
||||
async saveChangeInvoicePaymentAmount(
|
||||
tenantId: number,
|
||||
paymentReceiveEntries: [],
|
||||
newPaymentReceiveEntries: [],
|
||||
) {
|
||||
const { SaleInvoice } = this.tenancy.models(tenantId);
|
||||
const opers: Promise<T>[] = [];
|
||||
const newEntriesTable = chain(newPaymentReceiveEntries)
|
||||
.groupBy('invoice_id')
|
||||
|
||||
@@ -1,31 +1,44 @@
|
||||
import { omit, difference, sumBy, mixin } from 'lodash';
|
||||
import moment from 'moment';
|
||||
import { SaleEstimate, ItemEntry } from '@/models';
|
||||
import { Service, Inject } from 'typedi';
|
||||
import HasItemsEntries from '@/services/Sales/HasItemsEntries';
|
||||
import { formatDateFields } from '@/utils';
|
||||
import TenancyService from '@/services/Tenancy/TenancyService';
|
||||
|
||||
/**
|
||||
* Sale estimate service.
|
||||
* @Service
|
||||
*/
|
||||
@Service()
|
||||
export default class SaleEstimateService {
|
||||
@Inject()
|
||||
tenancy: TenancyService;
|
||||
|
||||
@Inject()
|
||||
itemsEntriesService: HasItemsEntries;
|
||||
|
||||
/**
|
||||
* Creates a new estimate with associated entries.
|
||||
* @async
|
||||
* @param {number} tenantId - The tenant id.
|
||||
* @param {EstimateDTO} estimate
|
||||
* @return {void}
|
||||
*/
|
||||
static async createEstimate(estimateDTO: any) {
|
||||
async createEstimate(tenantId: number, estimateDTO: any) {
|
||||
const { SaleEstimate, ItemEntry } = this.tenancy.models(tenantId);
|
||||
|
||||
const amount = sumBy(estimateDTO.entries, e => ItemEntry.calcAmount(e));
|
||||
const estimate = {
|
||||
amount: sumBy(estimateDTO.entries, 'amount'),
|
||||
amount,
|
||||
...formatDateFields(estimateDTO, ['estimate_date', 'expiration_date']),
|
||||
};
|
||||
const storedEstimate = await SaleEstimate.tenant()
|
||||
.query()
|
||||
const storedEstimate = await SaleEstimate.query()
|
||||
.insert({
|
||||
...omit(estimate, ['entries']),
|
||||
});
|
||||
const storeEstimateEntriesOpers: any[] = [];
|
||||
|
||||
estimate.entries.forEach((entry: any) => {
|
||||
const oper = ItemEntry.tenant()
|
||||
.query()
|
||||
const oper = ItemEntry.query()
|
||||
.insert({
|
||||
reference_type: 'SaleEstimate',
|
||||
reference_id: storedEstimate.id,
|
||||
@@ -41,27 +54,33 @@ export default class SaleEstimateService {
|
||||
/**
|
||||
* Edit details of the given estimate with associated entries.
|
||||
* @async
|
||||
* @param {number} tenantId - The tenant id.
|
||||
* @param {Integer} estimateId
|
||||
* @param {EstimateDTO} estimate
|
||||
* @return {void}
|
||||
*/
|
||||
static async editEstimate(estimateId: number, estimateDTO: any) {
|
||||
async editEstimate(tenantId: number, estimateId: number, estimateDTO: any) {
|
||||
const { SaleEstimate, ItemEntry } = this.tenancy.models(tenantId);
|
||||
const amount = sumBy(estimateDTO.entries, e => ItemEntry.calcAmount(e));
|
||||
|
||||
const estimate = {
|
||||
amount: sumBy(estimateDTO.entries, 'amount'),
|
||||
amount,
|
||||
...formatDateFields(estimateDTO, ['estimate_date', 'expiration_date']),
|
||||
};
|
||||
const updatedEstimate = await SaleEstimate.tenant()
|
||||
.query()
|
||||
const updatedEstimate = await SaleEstimate.query()
|
||||
.update({
|
||||
...omit(estimate, ['entries']),
|
||||
});
|
||||
const storedEstimateEntries = await ItemEntry.tenant()
|
||||
.query()
|
||||
const storedEstimateEntries = await ItemEntry.query()
|
||||
.where('reference_id', estimateId)
|
||||
.where('reference_type', 'SaleEstimate');
|
||||
|
||||
const patchItemsEntries = HasItemsEntries.patchItemsEntries(
|
||||
estimate.entries, storedEstimateEntries, 'SaleEstimate', estimateId
|
||||
const patchItemsEntries = this.itemsEntriesService.patchItemsEntries(
|
||||
tenantId,
|
||||
estimate.entries,
|
||||
storedEstimateEntries,
|
||||
'SaleEstimate',
|
||||
estimateId,
|
||||
);
|
||||
return Promise.all([
|
||||
patchItemsEntries,
|
||||
@@ -71,32 +90,32 @@ export default class SaleEstimateService {
|
||||
/**
|
||||
* Deletes the given estimate id with associated entries.
|
||||
* @async
|
||||
* @param {number} tenantId - The tenant id.
|
||||
* @param {IEstimate} estimateId
|
||||
* @return {void}
|
||||
*/
|
||||
static async deleteEstimate(estimateId: number) {
|
||||
await ItemEntry.tenant()
|
||||
.query()
|
||||
async deleteEstimate(tenantId: number, estimateId: number) {
|
||||
const { SaleEstimate, ItemEntry } = this.tenancy.models(tenantId);
|
||||
await ItemEntry.query()
|
||||
.where('reference_id', estimateId)
|
||||
.where('reference_type', 'SaleEstimate')
|
||||
.delete();
|
||||
|
||||
await SaleEstimate.tenant()
|
||||
.query()
|
||||
await SaleEstimate.query()
|
||||
.where('id', estimateId)
|
||||
.delete();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Validates the given estimate ID exists.
|
||||
* @async
|
||||
* @param {number} tenantId - The tenant id.
|
||||
* @param {Numeric} estimateId
|
||||
* @return {Boolean}
|
||||
*/
|
||||
static async isEstimateExists(estimateId: number) {
|
||||
const foundEstimate = await SaleEstimate.tenant()
|
||||
.query()
|
||||
async isEstimateExists(estimateId: number) {
|
||||
const { SaleEstimate } = this.tenancy.models(tenantId);
|
||||
const foundEstimate = await SaleEstimate.query()
|
||||
.where('id', estimateId);
|
||||
return foundEstimate.length !== 0;
|
||||
}
|
||||
@@ -104,16 +123,17 @@ export default class SaleEstimateService {
|
||||
/**
|
||||
* Validates the given estimate entries IDs.
|
||||
* @async
|
||||
* @param {Numeric} estimateId
|
||||
* @param {number} tenantId - The tenant id.
|
||||
* @param {Numeric} estimateId - the sale estimate id.
|
||||
* @param {IEstimate} estimate
|
||||
*/
|
||||
static async isEstimateEntriesIDsExists(estimateId: number, estimate: any) {
|
||||
async isEstimateEntriesIDsExists(tenantId: number, estimateId: number, estimate: any) {
|
||||
const { ItemEntry } = this.tenancy.models(tenantId);
|
||||
const estimateEntriesIds = estimate.entries
|
||||
.filter((e: any) => e.id)
|
||||
.map((e: any) => e.id);
|
||||
|
||||
const estimateEntries = await ItemEntry.tenant()
|
||||
.query()
|
||||
const estimateEntries = await ItemEntry.query()
|
||||
.whereIn('id', estimateEntriesIds)
|
||||
.where('reference_id', estimateId)
|
||||
.where('reference_type', 'SaleEstimate');
|
||||
@@ -128,12 +148,14 @@ export default class SaleEstimateService {
|
||||
|
||||
/**
|
||||
* Retrieve the estimate details of the given estimate id.
|
||||
* @async
|
||||
* @param {number} tenantId - The tenant id.
|
||||
* @param {Integer} estimateId
|
||||
* @return {IEstimate}
|
||||
*/
|
||||
static async getEstimate(estimateId: number) {
|
||||
const estimate = await SaleEstimate.tenant()
|
||||
.query()
|
||||
async getEstimate(tenantId: number, estimateId: number) {
|
||||
const { SaleEstimate } = this.tenancy.models(tenantId);
|
||||
const estimate = await SaleEstimate.query()
|
||||
.where('id', estimateId)
|
||||
.first();
|
||||
|
||||
@@ -142,11 +164,13 @@ export default class SaleEstimateService {
|
||||
|
||||
/**
|
||||
* Retrieve the estimate details with associated entries.
|
||||
* @async
|
||||
* @param {number} tenantId - The tenant id.
|
||||
* @param {Integer} estimateId
|
||||
*/
|
||||
static async getEstimateWithEntries(estimateId: number) {
|
||||
const estimate = await SaleEstimate.tenant()
|
||||
.query()
|
||||
async getEstimateWithEntries(tenantId: number, estimateId: number) {
|
||||
const { SaleEstimate } = this.tenancy.models(tenantId);
|
||||
const estimate = await SaleEstimate.query()
|
||||
.where('id', estimateId)
|
||||
.withGraphFetched('entries')
|
||||
.withGraphFetched('customer')
|
||||
@@ -157,13 +181,15 @@ export default class SaleEstimateService {
|
||||
|
||||
/**
|
||||
* Detarmines the estimate number uniqness.
|
||||
* @async
|
||||
* @param {number} tenantId - The tenant id.
|
||||
* @param {String} estimateNumber
|
||||
* @param {Integer} excludeEstimateId
|
||||
* @return {Boolean}
|
||||
*/
|
||||
static async isEstimateNumberUnique(estimateNumber: string, excludeEstimateId: number) {
|
||||
const foundEstimates = await SaleEstimate.tenant()
|
||||
.query()
|
||||
async isEstimateNumberUnique(tenantId: number, estimateNumber: string, excludeEstimateId: number) {
|
||||
const { SaleEstimate } = this.tenancy.models(tenantId);
|
||||
const foundEstimates = await SaleEstimate.query()
|
||||
.onBuild((query: any) => {
|
||||
query.where('estimate_number', estimateNumber);
|
||||
|
||||
|
||||
@@ -1,52 +1,56 @@
|
||||
import { Service, Inject } from 'typedi';
|
||||
import { omit, sumBy, difference, pick, chain } from 'lodash';
|
||||
import {
|
||||
SaleInvoice,
|
||||
AccountTransaction,
|
||||
InventoryTransaction,
|
||||
Account,
|
||||
ItemEntry,
|
||||
Customer,
|
||||
Item,
|
||||
} from '@/models';
|
||||
import { ISaleInvoice, ISaleInvoiceOTD, IItemEntry } from '@/interfaces';
|
||||
import JournalPoster from '@/services/Accounting/JournalPoster';
|
||||
import HasItemsEntries from '@/services/Sales/HasItemsEntries';
|
||||
import CustomerRepository from '@/repositories/CustomerRepository';
|
||||
import InventoryService from '@/services/Inventory/Inventory';
|
||||
import SalesInvoicesCost from '@/services/Sales/SalesInvoicesCost';
|
||||
import { ISaleInvoice, ISaleInvoiceOTD, IItemEntry } from '@/interfaces';
|
||||
import TenancyService from '@/services/Tenancy/TenancyService';
|
||||
import { formatDateFields } from '@/utils';
|
||||
|
||||
/**
|
||||
* Sales invoices service
|
||||
* @service
|
||||
*/
|
||||
@Service()
|
||||
export default class SaleInvoicesService extends SalesInvoicesCost {
|
||||
@Inject()
|
||||
tenancy: TenancyService;
|
||||
|
||||
@Inject()
|
||||
inventoryService: InventoryService;
|
||||
|
||||
@Inject()
|
||||
itemsEntriesService: HasItemsEntries;
|
||||
|
||||
/**
|
||||
* Creates a new sale invoices and store it to the storage
|
||||
* with associated to entries and journal transactions.
|
||||
* @async
|
||||
* @param {ISaleInvoice}
|
||||
* @param {number} tenantId =
|
||||
* @param {ISaleInvoice} saleInvoiceDTO -
|
||||
* @return {ISaleInvoice}
|
||||
*/
|
||||
static async createSaleInvoice(saleInvoiceDTO: ISaleInvoiceOTD) {
|
||||
const balance = sumBy(saleInvoiceDTO.entries, 'amount');
|
||||
const invLotNumber = await InventoryService.nextLotNumber();
|
||||
async createSaleInvoice(tenantId: number, saleInvoiceDTO: ISaleInvoiceOTD) {
|
||||
const { SaleInvoice, Customer, ItemEntry } = this.tenancy.models(tenantId);
|
||||
|
||||
const balance = sumBy(saleInvoiceDTO.entries, e => ItemEntry.calcAmount(e));
|
||||
const invLotNumber = await this.inventoryService.nextLotNumber(tenantId);
|
||||
|
||||
const saleInvoice: ISaleInvoice = {
|
||||
...formatDateFields(saleInvoiceDTO, ['invoiceDate', 'dueDate']),
|
||||
...formatDateFields(saleInvoiceDTO, ['invoice_date', 'due_date']),
|
||||
balance,
|
||||
paymentAmount: 0,
|
||||
invLotNumber,
|
||||
};
|
||||
const storedInvoice = await SaleInvoice.tenant()
|
||||
.query()
|
||||
const storedInvoice = await SaleInvoice.query()
|
||||
.insert({
|
||||
...omit(saleInvoice, ['entries']),
|
||||
});
|
||||
const opers: Array<any> = [];
|
||||
|
||||
saleInvoice.entries.forEach((entry: any) => {
|
||||
const oper = ItemEntry.tenant()
|
||||
.query()
|
||||
const oper = ItemEntry.query()
|
||||
.insertAndFetch({
|
||||
reference_type: 'SaleInvoice',
|
||||
reference_id: storedInvoice.id,
|
||||
@@ -67,12 +71,11 @@ export default class SaleInvoicesService extends SalesInvoicesCost {
|
||||
...opers, incrementOper,
|
||||
]);
|
||||
// Records the inventory transactions for inventory items.
|
||||
await this.recordInventoryTranscactions(
|
||||
saleInvoice, storedInvoice.id
|
||||
);
|
||||
await this.recordInventoryTranscactions(tenantId, saleInvoice, storedInvoice.id);
|
||||
|
||||
// Schedule sale invoice re-compute based on the item cost
|
||||
// method and starting date.
|
||||
await this.scheduleComputeInvoiceItemsCost(storedInvoice.id);
|
||||
await this.scheduleComputeInvoiceItemsCost(tenantId, storedInvoice.id);
|
||||
|
||||
return storedInvoice;
|
||||
}
|
||||
@@ -80,12 +83,15 @@ export default class SaleInvoicesService extends SalesInvoicesCost {
|
||||
/**
|
||||
* Edit the given sale invoice.
|
||||
* @async
|
||||
* @param {number} tenantId -
|
||||
* @param {Number} saleInvoiceId -
|
||||
* @param {ISaleInvoice} saleInvoice -
|
||||
*/
|
||||
static async editSaleInvoice(saleInvoiceId: number, saleInvoiceDTO: any) {
|
||||
const balance = sumBy(saleInvoiceDTO.entries, 'amount');
|
||||
const oldSaleInvoice = await SaleInvoice.tenant().query()
|
||||
async editSaleInvoice(tenantId: number, saleInvoiceId: number, saleInvoiceDTO: any) {
|
||||
const { SaleInvoice, ItemEntry, Customer } = this.tenancy.models(tenantId);
|
||||
|
||||
const balance = sumBy(saleInvoiceDTO.entries, e => ItemEntry.calcAmount(e));
|
||||
const oldSaleInvoice = await SaleInvoice.query()
|
||||
.where('id', saleInvoiceId)
|
||||
.first();
|
||||
|
||||
@@ -94,24 +100,22 @@ export default class SaleInvoicesService extends SalesInvoicesCost {
|
||||
balance,
|
||||
invLotNumber: oldSaleInvoice.invLotNumber,
|
||||
};
|
||||
const updatedSaleInvoices: ISaleInvoice = await SaleInvoice.tenant()
|
||||
.query()
|
||||
const updatedSaleInvoices: ISaleInvoice = await SaleInvoice.query()
|
||||
.where('id', saleInvoiceId)
|
||||
.update({
|
||||
...omit(saleInvoice, ['entries', 'invLotNumber']),
|
||||
});
|
||||
// Fetches the sale invoice items entries.
|
||||
const storedEntries = await ItemEntry.tenant()
|
||||
.query()
|
||||
const storedEntries = await ItemEntry.query()
|
||||
.where('reference_id', saleInvoiceId)
|
||||
.where('reference_type', 'SaleInvoice');
|
||||
|
||||
// Patch update the sale invoice items entries.
|
||||
const patchItemsEntriesOper = HasItemsEntries.patchItemsEntries(
|
||||
saleInvoice.entries, storedEntries, 'SaleInvoice', saleInvoiceId,
|
||||
const patchItemsEntriesOper = this.itemsEntriesService.patchItemsEntries(
|
||||
tenantId, saleInvoice.entries, storedEntries, 'SaleInvoice', saleInvoiceId,
|
||||
);
|
||||
// Changes the diff customer balance between old and new amount.
|
||||
const changeCustomerBalanceOper = CustomerRepository.changeDiffBalance(
|
||||
const changeCustomerBalanceOper = Customer.changeDiffBalance(
|
||||
saleInvoice.customer_id,
|
||||
oldSaleInvoice.customerId,
|
||||
balance,
|
||||
@@ -119,7 +123,7 @@ export default class SaleInvoicesService extends SalesInvoicesCost {
|
||||
);
|
||||
// Records the inventory transactions for inventory items.
|
||||
const recordInventoryTransOper = this.recordInventoryTranscactions(
|
||||
saleInvoice, saleInvoiceId, true,
|
||||
tenantId, saleInvoice, saleInvoiceId, true,
|
||||
);
|
||||
await Promise.all([
|
||||
patchItemsEntriesOper,
|
||||
@@ -128,23 +132,31 @@ export default class SaleInvoicesService extends SalesInvoicesCost {
|
||||
]);
|
||||
// Schedule sale invoice re-compute based on the item cost
|
||||
// method and starting date.
|
||||
await this.scheduleComputeInvoiceItemsCost(saleInvoiceId, true);
|
||||
await this.scheduleComputeInvoiceItemsCost(tenantId, saleInvoiceId, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the given sale invoice with associated entries
|
||||
* and journal transactions.
|
||||
* @async
|
||||
* @param {Number} saleInvoiceId
|
||||
* @param {Number} saleInvoiceId - The given sale invoice id.
|
||||
*/
|
||||
static async deleteSaleInvoice(saleInvoiceId: number) {
|
||||
const oldSaleInvoice = await SaleInvoice.tenant().query()
|
||||
async deleteSaleInvoice(tenantId: number, saleInvoiceId: number) {
|
||||
const {
|
||||
SaleInvoice,
|
||||
ItemEntry,
|
||||
Customer,
|
||||
Account,
|
||||
InventoryTransaction,
|
||||
AccountTransaction,
|
||||
} = this.tenancy.models(tenantId);
|
||||
|
||||
const oldSaleInvoice = await SaleInvoice.query()
|
||||
.findById(saleInvoiceId)
|
||||
.withGraphFetched('entries');
|
||||
|
||||
await SaleInvoice.tenant().query().where('id', saleInvoiceId).delete();
|
||||
await ItemEntry.tenant()
|
||||
.query()
|
||||
await SaleInvoice.query().where('id', saleInvoiceId).delete();
|
||||
await ItemEntry.query()
|
||||
.where('reference_id', saleInvoiceId)
|
||||
.where('reference_type', 'SaleInvoice')
|
||||
.delete();
|
||||
@@ -153,26 +165,25 @@ export default class SaleInvoicesService extends SalesInvoicesCost {
|
||||
oldSaleInvoice.customerId,
|
||||
oldSaleInvoice.balance * -1,
|
||||
);
|
||||
const invoiceTransactions = await AccountTransaction.tenant()
|
||||
.query()
|
||||
const invoiceTransactions = await AccountTransaction.query()
|
||||
.whereIn('reference_type', ['SaleInvoice'])
|
||||
.where('reference_id', saleInvoiceId)
|
||||
.withGraphFetched('account.type');
|
||||
|
||||
const accountsDepGraph = await Account.tenant().depGraph().query();
|
||||
const accountsDepGraph = await Account.depGraph().query();
|
||||
const journal = new JournalPoster(accountsDepGraph);
|
||||
|
||||
journal.loadEntries(invoiceTransactions);
|
||||
journal.removeEntries();
|
||||
|
||||
const inventoryTransactions = await InventoryTransaction.tenant()
|
||||
.query()
|
||||
const inventoryTransactions = await InventoryTransaction.query()
|
||||
.where('transaction_type', 'SaleInvoice')
|
||||
.where('transaction_id', saleInvoiceId);
|
||||
|
||||
// Revert inventory transactions.
|
||||
const revertInventoryTransactionsOper = this.revertInventoryTransactions(
|
||||
inventoryTransactions
|
||||
tenantId,
|
||||
inventoryTransactions,
|
||||
);
|
||||
// Await all async operations.
|
||||
await Promise.all([
|
||||
@@ -183,7 +194,7 @@ export default class SaleInvoicesService extends SalesInvoicesCost {
|
||||
]);
|
||||
// Schedule sale invoice re-compute based on the item cost
|
||||
// method and starting date.
|
||||
await this.scheduleComputeItemsCost(oldSaleInvoice)
|
||||
await this.scheduleComputeItemsCost(tenantId, oldSaleInvoice)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -192,7 +203,7 @@ export default class SaleInvoicesService extends SalesInvoicesCost {
|
||||
* @param {number} saleInvoiceId -
|
||||
* @param {boolean} override -
|
||||
*/
|
||||
static recordInventoryTranscactions(saleInvoice, saleInvoiceId: number, override?: boolean){
|
||||
recordInventoryTranscactions(tenantId: number, saleInvoice, saleInvoiceId: number, override?: boolean){
|
||||
const inventortyTransactions = saleInvoice.entries
|
||||
.map((entry) => ({
|
||||
...pick(entry, ['item_id', 'quantity', 'rate',]),
|
||||
@@ -204,8 +215,8 @@ export default class SaleInvoicesService extends SalesInvoicesCost {
|
||||
entryId: entry.id,
|
||||
}));
|
||||
|
||||
return InventoryService.recordInventoryTransactions(
|
||||
inventortyTransactions, override,
|
||||
return this.inventoryService.recordInventoryTransactions(
|
||||
tenantId, inventortyTransactions, override,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -214,15 +225,15 @@ export default class SaleInvoicesService extends SalesInvoicesCost {
|
||||
* @param {string} transactionType
|
||||
* @param {number} transactionId
|
||||
*/
|
||||
static async revertInventoryTransactions(inventoryTransactions: array) {
|
||||
async revertInventoryTransactions(tenantId: number, inventoryTransactions: array) {
|
||||
const { InventoryTransaction } = this.tenancy.models(tenantId);
|
||||
const opers: Promise<[]>[] = [];
|
||||
|
||||
inventoryTransactions.forEach((trans: any) => {
|
||||
switch(trans.direction) {
|
||||
case 'OUT':
|
||||
if (trans.inventoryTransactionId) {
|
||||
const revertRemaining = InventoryTransaction.tenant()
|
||||
.query()
|
||||
const revertRemaining = InventoryTransaction.query()
|
||||
.where('id', trans.inventoryTransactionId)
|
||||
.where('direction', 'OUT')
|
||||
.increment('remaining', trans.quanitity);
|
||||
@@ -231,8 +242,7 @@ export default class SaleInvoicesService extends SalesInvoicesCost {
|
||||
}
|
||||
break;
|
||||
case 'IN':
|
||||
const removeRelationOper = InventoryTransaction.tenant()
|
||||
.query()
|
||||
const removeRelationOper = InventoryTransaction.query()
|
||||
.where('inventory_transaction_id', trans.id)
|
||||
.where('direction', 'IN')
|
||||
.update({
|
||||
@@ -250,8 +260,9 @@ export default class SaleInvoicesService extends SalesInvoicesCost {
|
||||
* @async
|
||||
* @param {Number} saleInvoiceId
|
||||
*/
|
||||
static async getSaleInvoiceWithEntries(saleInvoiceId: number) {
|
||||
return SaleInvoice.tenant().query()
|
||||
async getSaleInvoiceWithEntries(tenantId: number, saleInvoiceId: number) {
|
||||
const { SaleInvoice } = this.tenancy.models(tenantId);
|
||||
return SaleInvoice.query()
|
||||
.where('id', saleInvoiceId)
|
||||
.withGraphFetched('entries')
|
||||
.withGraphFetched('customer')
|
||||
@@ -263,10 +274,11 @@ export default class SaleInvoicesService extends SalesInvoicesCost {
|
||||
* @param {Integer} saleInvoiceId
|
||||
* @return {Boolean}
|
||||
*/
|
||||
static async isSaleInvoiceExists(saleInvoiceId: number) {
|
||||
const foundSaleInvoice = await SaleInvoice.tenant()
|
||||
.query()
|
||||
async isSaleInvoiceExists(tenantId: number, saleInvoiceId: number) {
|
||||
const { SaleInvoice } = this.tenancy.models(tenantId);
|
||||
const foundSaleInvoice = await SaleInvoice.query()
|
||||
.where('id', saleInvoiceId);
|
||||
|
||||
return foundSaleInvoice.length !== 0;
|
||||
}
|
||||
|
||||
@@ -277,12 +289,15 @@ export default class SaleInvoicesService extends SalesInvoicesCost {
|
||||
* @param {Number} saleInvoiceId
|
||||
* @return {Boolean}
|
||||
*/
|
||||
static async isSaleInvoiceNumberExists(saleInvoiceNumber: string|number, saleInvoiceId: number) {
|
||||
const foundSaleInvoice = await SaleInvoice.tenant()
|
||||
.query()
|
||||
async isSaleInvoiceNumberExists(
|
||||
tenantId: number,
|
||||
saleInvoiceNumber: string|number,
|
||||
saleInvoiceId: number
|
||||
) {
|
||||
const { SaleInvoice } = this.tenancy.models(tenantId);
|
||||
const foundSaleInvoice = await SaleInvoice.query()
|
||||
.onBuild((query: any) => {
|
||||
query.where('invoice_no', saleInvoiceNumber);
|
||||
|
||||
if (saleInvoiceId) {
|
||||
query.whereNot('id', saleInvoiceId);
|
||||
}
|
||||
@@ -296,9 +311,9 @@ export default class SaleInvoicesService extends SalesInvoicesCost {
|
||||
* @param {Array} invoicesIds
|
||||
* @return {Array}
|
||||
*/
|
||||
static async isInvoicesExist(invoicesIds: Array<number>) {
|
||||
const storedInvoices = await SaleInvoice.tenant()
|
||||
.query()
|
||||
async isInvoicesExist(tenantId: number, invoicesIds: Array<number>) {
|
||||
const { SaleInvoice } = this.tenancy.models(tenantId);
|
||||
const storedInvoices = await SaleInvoice.query()
|
||||
.onBuild((builder: any) => {
|
||||
builder.whereIn('id', invoicesIds);
|
||||
return builder;
|
||||
@@ -314,9 +329,13 @@ export default class SaleInvoicesService extends SalesInvoicesCost {
|
||||
* @param {ISaleInvoice} saleInvoice
|
||||
* @return {Promise}
|
||||
*/
|
||||
static async scheduleComputeInvoiceItemsCost(saleInvoiceId: number, override?: boolean) {
|
||||
const saleInvoice: ISaleInvoice = await SaleInvoice.tenant()
|
||||
.query()
|
||||
async scheduleComputeInvoiceItemsCost(
|
||||
tenantId: number,
|
||||
saleInvoiceId: number,
|
||||
override?: boolean
|
||||
) {
|
||||
const { SaleInvoice } = this.tenancy.models(tenantId);
|
||||
const saleInvoice: ISaleInvoice = await SaleInvoice.query()
|
||||
.findById(saleInvoiceId)
|
||||
.withGraphFetched('entries.item');
|
||||
|
||||
@@ -326,9 +345,10 @@ export default class SaleInvoicesService extends SalesInvoicesCost {
|
||||
.uniq().value();
|
||||
|
||||
if (inventoryItemsIds.length === 0) {
|
||||
await this.writeNonInventoryInvoiceJournals(saleInvoice, override);
|
||||
await this.writeNonInventoryInvoiceJournals(tenantId, saleInvoice, override);
|
||||
} else {
|
||||
await this.scheduleComputeItemsCost(
|
||||
tenantId,
|
||||
inventoryItemsIds,
|
||||
saleInvoice.invoice_date,
|
||||
);
|
||||
@@ -339,13 +359,14 @@ export default class SaleInvoicesService extends SalesInvoicesCost {
|
||||
* Writes the sale invoice journal entries.
|
||||
* @param {SaleInvoice} saleInvoice -
|
||||
*/
|
||||
static async writeNonInventoryInvoiceJournals(saleInvoice: ISaleInvoice, override: boolean) {
|
||||
const accountsDepGraph = await Account.tenant().depGraph().query();
|
||||
async writeNonInventoryInvoiceJournals(tenantId: number, saleInvoice: ISaleInvoice, override: boolean) {
|
||||
const { Account, AccountTransaction } = this.tenancy.models(tenantId);
|
||||
|
||||
const accountsDepGraph = await Account.depGraph().query();
|
||||
const journal = new JournalPoster(accountsDepGraph);
|
||||
|
||||
if (override) {
|
||||
const oldTransactions = await AccountTransaction.tenant()
|
||||
.query()
|
||||
const oldTransactions = await AccountTransaction.query()
|
||||
.where('reference_type', 'SaleInvoice')
|
||||
.where('reference_id', saleInvoice.id)
|
||||
.withGraphFetched('account.type');
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
import { Container } from 'typedi';
|
||||
import {
|
||||
SaleInvoice,
|
||||
Account,
|
||||
AccountTransaction,
|
||||
Item,
|
||||
} from '@/models';
|
||||
import { Container, Service, Inject } from 'typedi';
|
||||
import JournalPoster from '@/services/Accounting/JournalPoster';
|
||||
import JournalEntry from '@/services/Accounting/JournalEntry';
|
||||
import InventoryService from '@/services/Inventory/Inventory';
|
||||
import { ISaleInvoice, IItemEntry, IItem } from '@/interfaces';
|
||||
import { ISaleInvoice } from '../../interfaces';
|
||||
import TenancyService from '@/services/Tenancy/TenancyService';
|
||||
import { ISaleInvoice, IItemEntry } from '@/interfaces';
|
||||
|
||||
@Service()
|
||||
export default class SaleInvoicesCost {
|
||||
@Inject()
|
||||
inventoryService: InventoryService;
|
||||
|
||||
@Inject()
|
||||
tenancy: TenancyService;
|
||||
|
||||
/**
|
||||
* Schedule sale invoice re-compute based on the item
|
||||
* cost method and starting date.
|
||||
@@ -19,11 +20,16 @@ export default class SaleInvoicesCost {
|
||||
* @param {Date} startingDate - Starting compute cost date.
|
||||
* @return {Promise<Agenda>}
|
||||
*/
|
||||
static async scheduleComputeItemsCost(inventoryItemsIds: number[], startingDate: Date) {
|
||||
async scheduleComputeItemsCost(
|
||||
tenantId: number,
|
||||
inventoryItemsIds: number[],
|
||||
startingDate: Date
|
||||
) {
|
||||
const asyncOpers: Promise<[]>[] = [];
|
||||
|
||||
inventoryItemsIds.forEach((inventoryItemId: number) => {
|
||||
const oper: Promise<[]> = InventoryService.scheduleComputeItemCost(
|
||||
const oper: Promise<[]> = this.inventoryService.scheduleComputeItemCost(
|
||||
tenantId,
|
||||
inventoryItemId,
|
||||
startingDate,
|
||||
);
|
||||
@@ -37,21 +43,22 @@ export default class SaleInvoicesCost {
|
||||
* @param {Date} startingDate
|
||||
* @return {Promise<agenda>}
|
||||
*/
|
||||
static scheduleWriteJournalEntries(startingDate?: Date) {
|
||||
scheduleWriteJournalEntries(tenantId: number, startingDate?: Date) {
|
||||
const agenda = Container.get('agenda');
|
||||
return agenda.schedule('in 3 seconds', 'rewrite-invoices-journal-entries', {
|
||||
startingDate,
|
||||
startingDate, tenantId,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes journal entries from sales invoices.
|
||||
* @param {number} tenantId - The tenant id.
|
||||
* @param {Date} startingDate
|
||||
* @param {boolean} override
|
||||
*/
|
||||
static async writeJournalEntries(startingDate: Date, override: boolean) {
|
||||
const salesInvoices = await SaleInvoice.tenant()
|
||||
.query()
|
||||
async writeJournalEntries(tenantId: number, startingDate: Date, override: boolean) {
|
||||
const { AccountTransaction, SaleInvoice, Account } = this.tenancy.models(tenantId);
|
||||
const salesInvoices = await SaleInvoice.query()
|
||||
.onBuild((builder: any) => {
|
||||
builder.modify('filterDateRange', startingDate);
|
||||
builder.orderBy('invoice_date', 'ASC');
|
||||
@@ -59,12 +66,11 @@ export default class SaleInvoicesCost {
|
||||
builder.withGraphFetched('entries.item')
|
||||
builder.withGraphFetched('costTransactions(groupedEntriesCost)');
|
||||
});
|
||||
const accountsDepGraph = await Account.tenant().depGraph().query();
|
||||
const accountsDepGraph = await Account.depGraph().query();
|
||||
const journal = new JournalPoster(accountsDepGraph);
|
||||
|
||||
if (override) {
|
||||
const oldTransactions = await AccountTransaction.tenant()
|
||||
.query()
|
||||
const oldTransactions = await AccountTransaction.query()
|
||||
.whereIn('reference_type', ['SaleInvoice'])
|
||||
.onBuild((builder: any) => {
|
||||
builder.modify('filterDateRange', startingDate);
|
||||
@@ -90,7 +96,7 @@ export default class SaleInvoicesCost {
|
||||
* @param {ISaleInvoice} saleInvoice
|
||||
* @param {JournalPoster} journal
|
||||
*/
|
||||
static saleInvoiceJournal(saleInvoice: ISaleInvoice, journal: JournalPoster) {
|
||||
saleInvoiceJournal(saleInvoice: ISaleInvoice, journal: JournalPoster) {
|
||||
let inventoryTotal: number = 0;
|
||||
const receivableAccount = { id: 10 };
|
||||
const commonEntry = {
|
||||
|
||||
@@ -1,36 +1,43 @@
|
||||
import { omit, difference, sumBy } from 'lodash';
|
||||
import {
|
||||
SaleReceipt,
|
||||
Account,
|
||||
ItemEntry,
|
||||
} from '@/models';
|
||||
import JournalPoster from '@/services/Accounting/JournalPoster';
|
||||
import { Service, Inject } from 'typedi';
|
||||
import JournalPosterService from '@/services/Sales/JournalPosterService';
|
||||
import HasItemEntries from '@/services/Sales/HasItemsEntries';
|
||||
import TenancyService from '@/services/Tenancy/TenancyService';
|
||||
import { formatDateFields } from '@/utils';
|
||||
|
||||
export default class SalesReceipt {
|
||||
@Service()
|
||||
export default class SalesReceiptService {
|
||||
@Inject()
|
||||
tenancy: TenancyService;
|
||||
|
||||
@Inject()
|
||||
journalService: JournalPosterService;
|
||||
|
||||
@Inject()
|
||||
itemsEntriesService: HasItemEntries;
|
||||
|
||||
/**
|
||||
* Creates a new sale receipt with associated entries.
|
||||
* @async
|
||||
* @param {ISaleReceipt} saleReceipt
|
||||
* @return {Object}
|
||||
*/
|
||||
static async createSaleReceipt(saleReceiptDTO: any) {
|
||||
async createSaleReceipt(tenantId: number, saleReceiptDTO: any) {
|
||||
const { SaleReceipt, ItemEntry } = this.tenancy.models(tenantId);
|
||||
|
||||
const amount = sumBy(saleReceiptDTO.entries, e => ItemEntry.calcAmount(e));
|
||||
const saleReceipt = {
|
||||
amount: sumBy(saleReceiptDTO.entries, 'amount');
|
||||
amount,
|
||||
...formatDateFields(saleReceiptDTO, ['receipt_date'])
|
||||
};
|
||||
const storedSaleReceipt = await SaleReceipt.tenant()
|
||||
.query()
|
||||
const storedSaleReceipt = await SaleReceipt.query()
|
||||
.insert({
|
||||
...omit(saleReceipt, ['entries']),
|
||||
});
|
||||
const storeSaleReceiptEntriesOpers: Array<any> = [];
|
||||
|
||||
saleReceipt.entries.forEach((entry: any) => {
|
||||
const oper = ItemEntry.tenant()
|
||||
.query()
|
||||
const oper = ItemEntry.query()
|
||||
.insert({
|
||||
reference_type: 'SaleReceipt',
|
||||
reference_id: storedSaleReceipt.id,
|
||||
@@ -48,25 +55,30 @@ export default class SalesReceipt {
|
||||
* @param {ISaleReceipt} saleReceipt
|
||||
* @return {void}
|
||||
*/
|
||||
static async editSaleReceipt(saleReceiptId: number, saleReceiptDTO: any) {
|
||||
async editSaleReceipt(tenantId: number, saleReceiptId: number, saleReceiptDTO: any) {
|
||||
const { SaleReceipt, ItemEntry } = this.tenancy.models(tenantId);
|
||||
|
||||
const amount = sumBy(saleReceiptDTO.entries, e => ItemEntry.calcAmount(e));
|
||||
const saleReceipt = {
|
||||
amount: sumBy(saleReceiptDTO.entries, 'amount'),
|
||||
amount,
|
||||
...formatDateFields(saleReceiptDTO, ['receipt_date'])
|
||||
};
|
||||
const updatedSaleReceipt = await SaleReceipt.tenant()
|
||||
.query()
|
||||
const updatedSaleReceipt = await SaleReceipt.query()
|
||||
.where('id', saleReceiptId)
|
||||
.update({
|
||||
...omit(saleReceipt, ['entries']),
|
||||
});
|
||||
const storedSaleReceiptEntries = await ItemEntry.tenant()
|
||||
.query()
|
||||
const storedSaleReceiptEntries = await ItemEntry.query()
|
||||
.where('reference_id', saleReceiptId)
|
||||
.where('reference_type', 'SaleReceipt');
|
||||
|
||||
// Patch sale receipt items entries.
|
||||
const patchItemsEntries = HasItemEntries.patchItemsEntries(
|
||||
saleReceipt.entries, storedSaleReceiptEntries, 'SaleReceipt', saleReceiptId,
|
||||
const patchItemsEntries = this.itemsEntriesService.patchItemsEntries(
|
||||
tenantId,
|
||||
saleReceipt.entries,
|
||||
storedSaleReceiptEntries,
|
||||
'SaleReceipt',
|
||||
saleReceiptId,
|
||||
);
|
||||
return Promise.all([patchItemsEntries]);
|
||||
}
|
||||
@@ -76,20 +88,20 @@ export default class SalesReceipt {
|
||||
* @param {Integer} saleReceiptId
|
||||
* @return {void}
|
||||
*/
|
||||
static async deleteSaleReceipt(saleReceiptId: number) {
|
||||
const deleteSaleReceiptOper = SaleReceipt.tenant()
|
||||
.query()
|
||||
async deleteSaleReceipt(tenantId: number, saleReceiptId: number) {
|
||||
const { SaleReceipt, ItemEntry } = this.tenancy.models(tenantId);
|
||||
const deleteSaleReceiptOper = SaleReceipt.query()
|
||||
.where('id', saleReceiptId)
|
||||
.delete();
|
||||
|
||||
const deleteItemsEntriesOper = ItemEntry.tenant()
|
||||
.query()
|
||||
const deleteItemsEntriesOper = ItemEntry.query()
|
||||
.where('reference_id', saleReceiptId)
|
||||
.where('reference_type', 'SaleReceipt')
|
||||
.delete();
|
||||
|
||||
// Delete all associated journal transactions to payment receive transaction.
|
||||
const deleteTransactionsOper = JournalPosterService.deleteJournalTransactions(
|
||||
const deleteTransactionsOper = this.journalService.deleteJournalTransactions(
|
||||
tenantId,
|
||||
saleReceiptId,
|
||||
'SaleReceipt'
|
||||
);
|
||||
@@ -105,9 +117,9 @@ export default class SalesReceipt {
|
||||
* @param {Integer} saleReceiptId
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
static async isSaleReceiptExists(saleReceiptId: number) {
|
||||
const foundSaleReceipt = await SaleReceipt.tenant()
|
||||
.query()
|
||||
async isSaleReceiptExists(tenantId: number, saleReceiptId: number) {
|
||||
const { SaleReceipt } = this.tenancy.models(tenantId);
|
||||
const foundSaleReceipt = await SaleReceipt.query()
|
||||
.where('id', saleReceiptId);
|
||||
return foundSaleReceipt.length !== 0;
|
||||
}
|
||||
@@ -117,13 +129,13 @@ export default class SalesReceipt {
|
||||
* @param {Integer} saleReceiptId
|
||||
* @param {ISaleReceipt} saleReceipt
|
||||
*/
|
||||
static async isSaleReceiptEntriesIDsExists(saleReceiptId: number, saleReceipt: any) {
|
||||
async isSaleReceiptEntriesIDsExists(tenantId: number, saleReceiptId: number, saleReceipt: any) {
|
||||
const { ItemEntry } = this.tenancy.models(tenantId);
|
||||
const entriesIDs = saleReceipt.entries
|
||||
.filter((e) => e.id)
|
||||
.map((e) => e.id);
|
||||
|
||||
const storedEntries = await ItemEntry.tenant()
|
||||
.query()
|
||||
const storedEntries = await ItemEntry.query()
|
||||
.whereIn('id', entriesIDs)
|
||||
.where('reference_id', saleReceiptId)
|
||||
.where('reference_type', 'SaleReceipt');
|
||||
@@ -140,21 +152,12 @@ export default class SalesReceipt {
|
||||
* Retrieve sale receipt with associated entries.
|
||||
* @param {Integer} saleReceiptId
|
||||
*/
|
||||
static async getSaleReceiptWithEntries(saleReceiptId: number) {
|
||||
const saleReceipt = await SaleReceipt.tenant().query()
|
||||
async getSaleReceiptWithEntries(tenantId: number, saleReceiptId: number) {
|
||||
const { SaleReceipt } = this.tenancy.models(tenantId);
|
||||
const saleReceipt = await SaleReceipt.query()
|
||||
.where('id', saleReceiptId)
|
||||
.withGraphFetched('entries');
|
||||
|
||||
return saleReceipt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Records journal transactions for sale receipt.
|
||||
* @param {ISaleReceipt} saleReceipt
|
||||
* @return {Promise}
|
||||
*/
|
||||
static async _recordJournalTransactions(saleReceipt: any) {
|
||||
const accountsDepGraph = await Account.tenant().depGraph().query();
|
||||
const journalPoster = new JournalPoster(accountsDepGraph);
|
||||
}
|
||||
}
|
||||
|
||||
21
server/src/services/Tenancy/TenancyService.ts
Normal file
21
server/src/services/Tenancy/TenancyService.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { Container } from 'typedi';
|
||||
|
||||
export default class HasTenancyService {
|
||||
/**
|
||||
* Retrieve the given tenant container.
|
||||
* @param {number} tenantId
|
||||
* @return {Container}
|
||||
*/
|
||||
tenantContainer(tenantId: number) {
|
||||
return Container.of(`tenant-${tenantId}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve models of the givne tenant id.
|
||||
* @param {number} tenantId - The tenant id.
|
||||
*/
|
||||
models(tenantId: number) {
|
||||
console.log(tenantId);
|
||||
return this.tenantContainer(tenantId).get('models');
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@ import moment from 'moment';
|
||||
import SystemModel from '@/system/models/SystemModel';
|
||||
import { IVouchersFilter } from '@/interfaces';
|
||||
|
||||
export default class Voucher extends mixin(SystemModel) {
|
||||
export default class Voucher extends SystemModel {
|
||||
/**
|
||||
* Table name.
|
||||
*/
|
||||
@@ -40,7 +40,7 @@ export default class Voucher extends mixin(SystemModel) {
|
||||
},
|
||||
|
||||
// Filters vouchers list.
|
||||
filter(builder, vouchersFilter: IVouchersFilter) {
|
||||
filter(builder, vouchersFilter) {
|
||||
if (vouchersFilter.active) {
|
||||
builder.modify('filterActiveVoucher')
|
||||
}
|
||||
@@ -80,7 +80,7 @@ export default class Voucher extends mixin(SystemModel) {
|
||||
* @param {string} voucherCode
|
||||
* @return {Promise}
|
||||
*/
|
||||
static deleteVoucher(voucherCode: string, viaAttribute: string = 'voucher_code') {
|
||||
static deleteVoucher(voucherCode, viaAttribute = 'voucher_code') {
|
||||
return this.query()
|
||||
.where(viaAttribute, voucherCode)
|
||||
.delete();
|
||||
@@ -91,7 +91,7 @@ export default class Voucher extends mixin(SystemModel) {
|
||||
* @param {string} voucherCode
|
||||
* @return {Promise}
|
||||
*/
|
||||
static markVoucherAsDisabled(voucherCode: string, viaAttribute: string = 'voucher_code') {
|
||||
static markVoucherAsDisabled(voucherCode, viaAttribute = 'voucher_code') {
|
||||
return this.query()
|
||||
.where(viaAttribute, voucherCode)
|
||||
.patch({
|
||||
@@ -104,7 +104,7 @@ export default class Voucher extends mixin(SystemModel) {
|
||||
* Marks the given voucher code as sent on the storage.
|
||||
* @param {string} voucherCode
|
||||
*/
|
||||
static markVoucherAsSent(voucherCode: string, viaAttribute: string = 'voucher_code') {
|
||||
static markVoucherAsSent(voucherCode, viaAttribute = 'voucher_code') {
|
||||
return this.query()
|
||||
.where(viaAttribute, voucherCode)
|
||||
.patch({
|
||||
@@ -118,7 +118,7 @@ export default class Voucher extends mixin(SystemModel) {
|
||||
* @param {string} voucherCode
|
||||
* @return {Promise}
|
||||
*/
|
||||
static markVoucherAsUsed(voucherCode: string, viaAttribute: string = 'voucher_code') {
|
||||
static markVoucherAsUsed(voucherCode, viaAttribute = 'voucher_code') {
|
||||
return this.query()
|
||||
.where(viaAttribute, voucherCode)
|
||||
.patch({
|
||||
@@ -1,4 +1,5 @@
|
||||
import BaseModel from '@/models/Model';
|
||||
|
||||
export default class SystemModel extends BaseModel{
|
||||
|
||||
}
|
||||
@@ -144,7 +144,7 @@ function applyMixins(derivedCtor, baseCtors) {
|
||||
});
|
||||
}
|
||||
|
||||
const formatDateFields = (inputDTO, fields, format = 'YYYY-DD-MM') => {
|
||||
const formatDateFields = (inputDTO, fields, format = 'YYYY-MM-DD') => {
|
||||
const _inputDTO = { ...inputDTO };
|
||||
|
||||
fields.forEach((field) => {
|
||||
|
||||
@@ -10,5 +10,10 @@
|
||||
"esModuleInterop": true,
|
||||
"experimentalDecorators": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"baseUrl": "./",
|
||||
"paths": {
|
||||
"@": ["src/"],
|
||||
"~": ["tests/"]
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user