mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-21 07:10:33 +00:00
Merge branch 'master' of https://github.com/abouolia/Bigcapital into sales
This commit is contained in:
@@ -9,6 +9,8 @@ exports.up = function(knex) {
|
|||||||
table.string('reference_no');
|
table.string('reference_no');
|
||||||
table.integer('deposit_account_id').unsigned();
|
table.integer('deposit_account_id').unsigned();
|
||||||
table.string('payment_receive_no');
|
table.string('payment_receive_no');
|
||||||
|
table.text('description');
|
||||||
|
table.integer('user_id').unsigned();
|
||||||
table.timestamps();
|
table.timestamps();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ exports.seed = (knex) => {
|
|||||||
{ id: 12, name: 'sales_payment_receives' },
|
{ id: 12, name: 'sales_payment_receives' },
|
||||||
{ id: 13, name: 'bills' },
|
{ id: 13, name: 'bills' },
|
||||||
{ id: 14, name: 'bill_payments' },
|
{ id: 14, name: 'bill_payments' },
|
||||||
|
{ id: 16, name: 'payment_receives' },
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,247 +0,0 @@
|
|||||||
import express from 'express';
|
|
||||||
import {
|
|
||||||
check,
|
|
||||||
query,
|
|
||||||
param,
|
|
||||||
validationResult,
|
|
||||||
} from 'express-validator';
|
|
||||||
import { pick, difference, groupBy } from 'lodash';
|
|
||||||
import asyncMiddleware from "@/http/middleware/asyncMiddleware";
|
|
||||||
import JWTAuth from '@/http/middleware/jwtAuth';
|
|
||||||
import Budget from '@/models/Budget';
|
|
||||||
import BudgetEntry from '@/models/BudgetEntry';
|
|
||||||
import Account from '@/models/Account';
|
|
||||||
import moment from '@/services/Moment';
|
|
||||||
import BudgetEntriesSet from '@/collection/BudgetEntriesSet';
|
|
||||||
import AccountType from '@/models/AccountType';
|
|
||||||
import NestedSet from '@/collection/NestedSet';
|
|
||||||
import { dateRangeFormat } from '@/utils';
|
|
||||||
|
|
||||||
|
|
||||||
export default {
|
|
||||||
/**
|
|
||||||
* Router constructor.
|
|
||||||
*/
|
|
||||||
router() {
|
|
||||||
const router = express.Router();
|
|
||||||
|
|
||||||
router.use(JWTAuth);
|
|
||||||
|
|
||||||
router.post('/',
|
|
||||||
this.newBudget.validation,
|
|
||||||
asyncMiddleware(this.newBudget.handler));
|
|
||||||
|
|
||||||
router.get('/:id',
|
|
||||||
this.getBudget.validation,
|
|
||||||
asyncMiddleware(this.getBudget.handler));
|
|
||||||
|
|
||||||
router.get('/:id',
|
|
||||||
this.deleteBudget.validation,
|
|
||||||
asyncMiddleware(this.deleteBudget.handler));
|
|
||||||
|
|
||||||
router.get('/',
|
|
||||||
this.listBudgets.validation,
|
|
||||||
asyncMiddleware(this.listBudgets.handler));
|
|
||||||
|
|
||||||
return router;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve budget details of the given id.
|
|
||||||
*/
|
|
||||||
getBudget: {
|
|
||||||
validation: [
|
|
||||||
param('id').exists().isNumeric().toInt(),
|
|
||||||
],
|
|
||||||
async handler(req, res) {
|
|
||||||
const validationErrors = validationResult(req);
|
|
||||||
|
|
||||||
if (!validationErrors.isEmpty()) {
|
|
||||||
return res.boom.badData(null, {
|
|
||||||
code: 'validation_error', ...validationErrors,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
const { id } = req.params;
|
|
||||||
const budget = await Budget.query().findById(id);
|
|
||||||
|
|
||||||
if (!budget) {
|
|
||||||
return res.status(404).send({
|
|
||||||
errors: [{ type: 'budget.not.found', code: 100 }],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
const accountTypes = await AccountType.query().where('balance_sheet', true);
|
|
||||||
|
|
||||||
const [budgetEntries, accounts] = await Promise.all([
|
|
||||||
BudgetEntry.query().where('budget_id', budget.id),
|
|
||||||
Account.query().whereIn('account_type_id', accountTypes.map((a) => a.id)),
|
|
||||||
]);
|
|
||||||
|
|
||||||
const accountsNestedSet = new NestedSet(accounts);
|
|
||||||
|
|
||||||
const columns = [];
|
|
||||||
const fromDate = moment(budget.year).startOf('year')
|
|
||||||
.add(budget.rangeOffset, budget.rangeBy).toDate();
|
|
||||||
|
|
||||||
const toDate = moment(budget.year).endOf('year').toDate();
|
|
||||||
|
|
||||||
const dateRange = moment.range(fromDate, toDate);
|
|
||||||
const dateRangeCollection = Array.from(dateRange.by(budget.rangeBy, {
|
|
||||||
step: budget.rangeIncrement, excludeEnd: false, excludeStart: false,
|
|
||||||
}));
|
|
||||||
|
|
||||||
dateRangeCollection.forEach((date) => {
|
|
||||||
columns.push(date.format(dateRangeFormat(budget.rangeBy)));
|
|
||||||
});
|
|
||||||
const budgetEntriesSet = BudgetEntriesSet.from(budgetEntries, {
|
|
||||||
orderSize: columns.length,
|
|
||||||
});
|
|
||||||
budgetEntriesSet.setZeroPlaceholder();
|
|
||||||
budgetEntriesSet.calcTotalSummary();
|
|
||||||
|
|
||||||
return res.status(200).send({
|
|
||||||
columns,
|
|
||||||
accounts: budgetEntriesSet.toArray(),
|
|
||||||
total: budgetEntriesSet.toArrayTotalSummary(),
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete the given budget.
|
|
||||||
*/
|
|
||||||
deleteBudget: {
|
|
||||||
validation: [
|
|
||||||
param('id').exists(),
|
|
||||||
],
|
|
||||||
async handler(req, res) {
|
|
||||||
const validationErrors = validationResult(req);
|
|
||||||
|
|
||||||
if (!validationErrors.isEmpty()) {
|
|
||||||
return res.boom.badData(null, {
|
|
||||||
code: 'validation_error', ...validationErrors,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const { id } = req.params;
|
|
||||||
const budget = await Budget.query().findById(id);
|
|
||||||
|
|
||||||
if (!budget) {
|
|
||||||
return res.status(404).send({
|
|
||||||
errors: [{ type: 'budget.not.found', code: 100 }],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
await BudgetEntry.query().where('budget_id', budget.id).delete();
|
|
||||||
await budget.delete();
|
|
||||||
|
|
||||||
return res.status(200).send();
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Saves the new budget.
|
|
||||||
*/
|
|
||||||
newBudget: {
|
|
||||||
validation: [
|
|
||||||
check('name').exists(),
|
|
||||||
check('fiscal_year').exists(),
|
|
||||||
check('period').exists().isIn(['year', 'month', 'quarter', 'half-year']),
|
|
||||||
check('accounts_type').exists().isIn(['balance_sheet', 'profit_loss']),
|
|
||||||
check('accounts').isArray(),
|
|
||||||
check('accounts.*.account_id').exists().isNumeric().toInt(),
|
|
||||||
check('accounts.*.entries').exists().isArray(),
|
|
||||||
check('accounts.*.entries.*.amount').exists().isNumeric().toFloat(),
|
|
||||||
check('accounts.*.entries.*.order').exists().isNumeric().toInt(),
|
|
||||||
],
|
|
||||||
async handler(req, res) {
|
|
||||||
const validationErrors = validationResult(req);
|
|
||||||
|
|
||||||
if (!validationErrors.isEmpty()) {
|
|
||||||
return res.boom.badData(null, {
|
|
||||||
code: 'validation_error', ...validationErrors,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const form = { ...req.body };
|
|
||||||
const submitAccountsIds = form.accounts.map((a) => a.account_id);
|
|
||||||
const storedAccounts = await Account.query().whereIn('id', submitAccountsIds);
|
|
||||||
const storedAccountsIds = storedAccounts.map((a) => a.id);
|
|
||||||
|
|
||||||
const errorReasons = [];
|
|
||||||
const notFoundAccountsIds = difference(submitAccountsIds, storedAccountsIds);
|
|
||||||
|
|
||||||
if (notFoundAccountsIds.length > 0) {
|
|
||||||
errorReasons.push({
|
|
||||||
type: 'ACCOUNT.NOT.FOUND', code: 200, accounts: notFoundAccountsIds,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (errorReasons.length > 0) {
|
|
||||||
return res.status(400).send({ errors: errorReasons });
|
|
||||||
}
|
|
||||||
// validation entries order.
|
|
||||||
const budget = await Budget.query().insert({
|
|
||||||
...pick(form, ['name', 'fiscal_year', 'period', 'accounts_type']),
|
|
||||||
});
|
|
||||||
|
|
||||||
const promiseOpers = [];
|
|
||||||
|
|
||||||
form.accounts.forEach((account) => {
|
|
||||||
account.entries.forEach((entry) => {
|
|
||||||
const budgetEntry = BudgetEntry.query().insert({
|
|
||||||
account_id: account.account_id,
|
|
||||||
amount: entry.amount,
|
|
||||||
order: entry.order,
|
|
||||||
});
|
|
||||||
promiseOpers.push(budgetEntry);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
await Promise.all(promiseOpers);
|
|
||||||
|
|
||||||
return res.status(200).send({ id: budget.id });
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* List of paginated budgets items.
|
|
||||||
*/
|
|
||||||
listBudgets: {
|
|
||||||
validation: [
|
|
||||||
query('year').optional(),
|
|
||||||
query('income_statement').optional().isBoolean().toBoolean(),
|
|
||||||
query('profit_loss').optional().isBoolean().toBoolean(),
|
|
||||||
query('page').optional().isNumeric().toInt(),
|
|
||||||
query('page_size').isNumeric().toInt(),
|
|
||||||
query('custom_view_id').optional().isNumeric().toInt(),
|
|
||||||
],
|
|
||||||
async handler(req, res) {
|
|
||||||
const validationErrors = validationResult(req);
|
|
||||||
|
|
||||||
if (!validationErrors.isEmpty()) {
|
|
||||||
return res.boom.badData(null, {
|
|
||||||
code: 'validation_error', ...validationErrors,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const filter = {
|
|
||||||
page_size: 10,
|
|
||||||
page: 1,
|
|
||||||
...req.query,
|
|
||||||
};
|
|
||||||
const budgets = await Budget.query().runBefore((result, q) => {
|
|
||||||
if (filter.profit_loss) {
|
|
||||||
q.modify('filterByYear', filter.year);
|
|
||||||
}
|
|
||||||
if (filter.income_statement) {
|
|
||||||
q.modify('filterByIncomeStatement', filter.income_statement);
|
|
||||||
}
|
|
||||||
if (filter.profit_loss) {
|
|
||||||
q.modify('filterByProfitLoss', filter.profit_loss);
|
|
||||||
}
|
|
||||||
q.page(filter.page, filter.page_size);
|
|
||||||
return result;
|
|
||||||
});
|
|
||||||
return res.status(200).send({
|
|
||||||
items: budgets.items,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
@@ -1,122 +0,0 @@
|
|||||||
import express from 'express';
|
|
||||||
import { query, validationResult } from 'express-validator';
|
|
||||||
import moment from 'moment';
|
|
||||||
import jwtAuth from '@/http/middleware/jwtAuth';
|
|
||||||
import asyncMiddleware from '@/http/middleware/asyncMiddleware';
|
|
||||||
import Budget from '@/models/Budget';
|
|
||||||
import Account from '@/models/Account';
|
|
||||||
import AccountType from '@/models/AccountType';
|
|
||||||
import NestedSet from '@/collection/NestedSet';
|
|
||||||
import BudgetEntry from '@/models/BudgetEntry';
|
|
||||||
import { dateRangeFormat } from '@/utils';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Router constructor.
|
|
||||||
*/
|
|
||||||
router() {
|
|
||||||
const router = express.Router();
|
|
||||||
|
|
||||||
router.use(jwtAuth);
|
|
||||||
|
|
||||||
router.get('/budget_verses_actual/:reportId',
|
|
||||||
this.budgetVersesActual.validation,
|
|
||||||
asyncMiddleware(this.budgetVersesActual.handler));
|
|
||||||
|
|
||||||
return router;
|
|
||||||
},
|
|
||||||
|
|
||||||
budgetVersesActual: {
|
|
||||||
validation: [
|
|
||||||
query('basis').optional().isIn(['cash', 'accural']),
|
|
||||||
query('period').optional(),
|
|
||||||
query('active_accounts').optional().toBoolean(),
|
|
||||||
],
|
|
||||||
async handler(req, res) {
|
|
||||||
const validationErrors = validationResult(req);
|
|
||||||
|
|
||||||
if (!validationErrors.isEmpty()) {
|
|
||||||
return res.boom.badData(null, {
|
|
||||||
code: 'validation_error', ...validationErrors,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
const { reportId } = req.params;
|
|
||||||
const form = { ...req.body };
|
|
||||||
const errorReasons = [];
|
|
||||||
|
|
||||||
const budget = await Budget.query().findById(reportId);
|
|
||||||
|
|
||||||
if (!budget) {
|
|
||||||
errorReasons.push({ type: 'BUDGET_NOT_FOUND', code: 100 });
|
|
||||||
}
|
|
||||||
const budgetEntries = await BudgetEntry.query().where('budget_id', budget.id);
|
|
||||||
|
|
||||||
if (errorReasons.length > 0) {
|
|
||||||
return res.status(400).send({ errors: errorReasons });
|
|
||||||
}
|
|
||||||
const accountTypes = await AccountType.query()
|
|
||||||
.where('balance_sheet', budget.accountTypes === 'balance_sheet')
|
|
||||||
.where('income_sheet', budget.accountTypes === 'profit_losss');
|
|
||||||
|
|
||||||
const accounts = await Account.query().runBefore((result, q) => {
|
|
||||||
const accountTypesIds = accountTypes.map((t) => t.id);
|
|
||||||
|
|
||||||
if (accountTypesIds.length > 0) {
|
|
||||||
q.whereIn('account_type_id', accountTypesIds);
|
|
||||||
}
|
|
||||||
q.where('active', form.active_accounts === true);
|
|
||||||
q.withGraphFetched('transactions');
|
|
||||||
});
|
|
||||||
|
|
||||||
// const accountsNestedSet = NestedSet.from(accounts);
|
|
||||||
|
|
||||||
const fromDate = moment(budget.year).startOf('year')
|
|
||||||
.add(budget.rangeOffset, budget.rangeBy).toDate();
|
|
||||||
|
|
||||||
const toDate = moment(budget.year).endOf('year').toDate();
|
|
||||||
|
|
||||||
const dateRange = moment.range(fromDate, toDate);
|
|
||||||
const dateRangeCollection = Array.from(dateRange.by(budget.rangeBy, {
|
|
||||||
step: budget.rangeIncrement, excludeEnd: false, excludeStart: false,
|
|
||||||
}));
|
|
||||||
|
|
||||||
// // const accounts = {
|
|
||||||
// // assets: [
|
|
||||||
// // {
|
|
||||||
// // name: '',
|
|
||||||
// // code: '',
|
|
||||||
// // totalEntries: [
|
|
||||||
// // {
|
|
||||||
|
|
||||||
// // }
|
|
||||||
// // ],
|
|
||||||
// // children: [
|
|
||||||
// // {
|
|
||||||
// // name: '',
|
|
||||||
// // code: '',
|
|
||||||
// // entries: [
|
|
||||||
// // {
|
|
||||||
|
|
||||||
// // }
|
|
||||||
// // ]
|
|
||||||
// // }
|
|
||||||
// // ]
|
|
||||||
// // }
|
|
||||||
// // ]
|
|
||||||
// // }
|
|
||||||
|
|
||||||
return res.status(200).send({
|
|
||||||
columns: dateRangeCollection.map(d => d.format(dateRangeFormat(budget.rangeBy))),
|
|
||||||
// accounts: {
|
|
||||||
// asset: [],
|
|
||||||
// liabilities: [],
|
|
||||||
// equaity: [],
|
|
||||||
|
|
||||||
// income: [],
|
|
||||||
// expenses: [],
|
|
||||||
// }
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
|
|
||||||
export default {
|
|
||||||
|
|
||||||
|
|
||||||
router() {
|
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
addExchangePrice: {
|
|
||||||
validation: {
|
|
||||||
|
|
||||||
},
|
|
||||||
async handler(req, res) {
|
|
||||||
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
@@ -2,15 +2,18 @@
|
|||||||
import { Router } from 'express';
|
import { Router } from 'express';
|
||||||
import { check, param, query, ValidationChain } from 'express-validator';
|
import { check, param, query, ValidationChain } from 'express-validator';
|
||||||
import asyncMiddleware from '@/http/middleware/asyncMiddleware';
|
import asyncMiddleware from '@/http/middleware/asyncMiddleware';
|
||||||
|
import validateMiddleware from '@/http/middleware/validateMiddleware';
|
||||||
import BaseController from '@/http/controllers/BaseController';
|
import BaseController from '@/http/controllers/BaseController';
|
||||||
import BillPaymentsService from '@/services/Purchases/BillPayments';
|
import BillPaymentsService from '@/services/Purchases/BillPayments';
|
||||||
import AccountsService from '@/services/Accounts/AccountsService';
|
import AccountsService from '@/services/Accounts/AccountsService';
|
||||||
import ItemsService from '@/services/Items/ItemsService';
|
|
||||||
import { IBillPaymentEntry, IBillPayment } from '@/interfaces/BillPayment';
|
|
||||||
import DynamicListingBuilder from '@/services/DynamicListing/DynamicListingBuilder';
|
import DynamicListingBuilder from '@/services/DynamicListing/DynamicListingBuilder';
|
||||||
import DynamicListing from '@/services/DynamicListing/DynamicListing';
|
import DynamicListing from '@/services/DynamicListing/DynamicListing';
|
||||||
import { dynamicListingErrorsToResponse } from '@/services/DynamicListing/hasDynamicListing';
|
import { dynamicListingErrorsToResponse } from '@/services/DynamicListing/hasDynamicListing';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bills payments controller.
|
||||||
|
* @controller
|
||||||
|
*/
|
||||||
export default class BillsPayments extends BaseController {
|
export default class BillsPayments extends BaseController {
|
||||||
/**
|
/**
|
||||||
* Router constructor.
|
* Router constructor.
|
||||||
@@ -21,38 +24,43 @@ export default class BillsPayments extends BaseController {
|
|||||||
router.post('/', [
|
router.post('/', [
|
||||||
...this.billPaymentSchemaValidation,
|
...this.billPaymentSchemaValidation,
|
||||||
],
|
],
|
||||||
|
validateMiddleware,
|
||||||
asyncMiddleware(this.validateBillPaymentVendorExistance),
|
asyncMiddleware(this.validateBillPaymentVendorExistance),
|
||||||
asyncMiddleware(this.validatePaymentAccount),
|
asyncMiddleware(this.validatePaymentAccount),
|
||||||
asyncMiddleware(this.validatePaymentNumber),
|
asyncMiddleware(this.validatePaymentNumber),
|
||||||
asyncMiddleware(this.validateItemsIds),
|
asyncMiddleware(this.validateEntriesBillsExistance),
|
||||||
|
asyncMiddleware(this.validateVendorsDueAmount),
|
||||||
asyncMiddleware(this.createBillPayment),
|
asyncMiddleware(this.createBillPayment),
|
||||||
);
|
);
|
||||||
router.post('/:id', [
|
router.post('/:id', [
|
||||||
...this.billPaymentSchemaValidation,
|
...this.billPaymentSchemaValidation,
|
||||||
...this.specificBillPaymentValidateSchema,
|
...this.specificBillPaymentValidateSchema,
|
||||||
],
|
],
|
||||||
|
validateMiddleware,
|
||||||
asyncMiddleware(this.validateBillPaymentVendorExistance),
|
asyncMiddleware(this.validateBillPaymentVendorExistance),
|
||||||
asyncMiddleware(this.validatePaymentAccount),
|
asyncMiddleware(this.validatePaymentAccount),
|
||||||
asyncMiddleware(this.validatePaymentNumber),
|
asyncMiddleware(this.validatePaymentNumber),
|
||||||
asyncMiddleware(this.validateItemsIds),
|
asyncMiddleware(this.validateEntriesBillsExistance),
|
||||||
asyncMiddleware(this.validateEntriesIds),
|
asyncMiddleware(this.validateVendorsDueAmount),
|
||||||
asyncMiddleware(this.editBillPayment),
|
asyncMiddleware(this.editBillPayment),
|
||||||
)
|
)
|
||||||
router.delete('/:id',
|
router.delete('/:id',
|
||||||
this.specificBillPaymentValidateSchema,
|
this.specificBillPaymentValidateSchema,
|
||||||
|
validateMiddleware,
|
||||||
asyncMiddleware(this.validateBillPaymentExistance),
|
asyncMiddleware(this.validateBillPaymentExistance),
|
||||||
asyncMiddleware(this.deleteBillPayment),
|
asyncMiddleware(this.deleteBillPayment),
|
||||||
);
|
);
|
||||||
router.get('/:id',
|
router.get('/:id',
|
||||||
this.specificBillPaymentValidateSchema,
|
this.specificBillPaymentValidateSchema,
|
||||||
|
validateMiddleware,
|
||||||
asyncMiddleware(this.validateBillPaymentExistance),
|
asyncMiddleware(this.validateBillPaymentExistance),
|
||||||
asyncMiddleware(this.getBillPayment),
|
asyncMiddleware(this.getBillPayment),
|
||||||
);
|
);
|
||||||
router.get('/',
|
router.get('/',
|
||||||
this.listingValidationSchema,
|
this.listingValidationSchema,
|
||||||
|
validateMiddleware,
|
||||||
asyncMiddleware(this.getBillsPayments)
|
asyncMiddleware(this.getBillsPayments)
|
||||||
);
|
);
|
||||||
|
|
||||||
return router;
|
return router;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,13 +77,8 @@ export default class BillsPayments extends BaseController {
|
|||||||
check('reference').optional().trim().escape(),
|
check('reference').optional().trim().escape(),
|
||||||
|
|
||||||
check('entries').exists().isArray({ min: 1 }),
|
check('entries').exists().isArray({ min: 1 }),
|
||||||
check('entries.*.id').optional().isNumeric().toInt(),
|
check('entries.*.bill_id').exists().isNumeric().toInt(),
|
||||||
check('entries.*.index').exists().isNumeric().toInt(),
|
check('entries.*.payment_amount').exists().isNumeric().toInt(),
|
||||||
check('entries.*.item_id').exists().isNumeric().toInt(),
|
|
||||||
check('entries.*.rate').exists().isNumeric().toFloat(),
|
|
||||||
check('entries.*.quantity').exists().isNumeric().toFloat(),
|
|
||||||
check('entries.*.discount').optional().isNumeric().toFloat(),
|
|
||||||
check('entries.*.description').optional().trim().escape(),
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,7 +100,7 @@ export default class BillsPayments extends BaseController {
|
|||||||
static async validateBillPaymentVendorExistance(req: Request, res: Response, next: any ) {
|
static async validateBillPaymentVendorExistance(req: Request, res: Response, next: any ) {
|
||||||
const billPayment = req.body;
|
const billPayment = req.body;
|
||||||
const { Vendor } = req.models;
|
const { Vendor } = req.models;
|
||||||
const isVendorExists = await Vendor.query('id', billPayment.vendor_id).first();
|
const isVendorExists = await Vendor.query().findById(billPayment.vendor_id);
|
||||||
|
|
||||||
if (!isVendorExists) {
|
if (!isVendorExists) {
|
||||||
return res.status(400).send({
|
return res.status(400).send({
|
||||||
@@ -121,7 +124,7 @@ export default class BillsPayments extends BaseController {
|
|||||||
errors: [{ type: 'BILL.PAYMENT.NOT.FOUND', code: 100 }],
|
errors: [{ type: 'BILL.PAYMENT.NOT.FOUND', code: 100 }],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
next(req, res, next);
|
next();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -132,14 +135,15 @@ export default class BillsPayments extends BaseController {
|
|||||||
*/
|
*/
|
||||||
static async validatePaymentAccount(req: Request, res: Response, next: any) {
|
static async validatePaymentAccount(req: Request, res: Response, next: any) {
|
||||||
const billPayment = { ...req.body };
|
const billPayment = { ...req.body };
|
||||||
const isAccountExists = AccountsService.isAccountExists(billPayment);
|
const isAccountExists = await AccountsService.isAccountExists(
|
||||||
|
billPayment.payment_account_id
|
||||||
|
);
|
||||||
if (!isAccountExists) {
|
if (!isAccountExists) {
|
||||||
return res.status(400).send({
|
return res.status(400).send({
|
||||||
errors: [{ type: 'PAYMENT.ACCOUNT.NOT.FOUND', code: 200 }],
|
errors: [{ type: 'PAYMENT.ACCOUNT.NOT.FOUND', code: 200 }],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
next(req, res, next);
|
next();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -149,61 +153,75 @@ export default class BillsPayments extends BaseController {
|
|||||||
* @param {Function} res
|
* @param {Function} res
|
||||||
*/
|
*/
|
||||||
static async validatePaymentNumber(req: Request, res: Response, next: any) {
|
static async validatePaymentNumber(req: Request, res: Response, next: any) {
|
||||||
|
const { BillPayment } = req.models;
|
||||||
const billPayment = { ...req.body };
|
const billPayment = { ...req.body };
|
||||||
const isNumberExists = await BillPaymentsService.isBillNoExists(billPayment);
|
const foundBillPayment = await BillPayment.query()
|
||||||
|
.where('payment_number', billPayment.payment_number)
|
||||||
if (!isNumberExists) {
|
.first();
|
||||||
|
|
||||||
|
if (foundBillPayment) {
|
||||||
return res.status(400).send({
|
return res.status(400).send({
|
||||||
errors: [{ type: 'PAYMENT.NUMBER.NOT.UNIQUE', code: 300 }],
|
errors: [{ type: 'PAYMENT.NUMBER.NOT.UNIQUE', code: 300 }],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
next(req, res, next);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* validate entries items ids existance on the storage.
|
|
||||||
* @param {Request} req
|
|
||||||
* @param {Response} res
|
|
||||||
* @param {Function} next
|
|
||||||
*/
|
|
||||||
static async validateItemsIds(req: Request, res: Response, next: Function) {
|
|
||||||
const billPayment: any = { ...req.body };
|
|
||||||
const itemsIds = billPayment.entries.map((e) => e.item_id);
|
|
||||||
const notFoundItemsIds = await ItemsService.isItemsIdsExists(
|
|
||||||
itemsIds
|
|
||||||
);
|
|
||||||
if (notFoundItemsIds.length > 0) {
|
|
||||||
return res.status(400).send({
|
|
||||||
errors: [{ type: 'ITEMS.IDS.NOT.FOUND', code: 400 }],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
next();
|
next();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validates the entries ids in edit bill payment.
|
* Validate whether the entries bills ids exist on the storage.
|
||||||
* @param {Request} req
|
* @param {Request} req
|
||||||
* @param {Response} res
|
* @param {Response} res
|
||||||
* @param {NextFunction} next
|
* @param {NextFunction} next
|
||||||
*/
|
*/
|
||||||
static async validateEntriesIds(req: Request, res: Response, next: Function) {
|
static async validateEntriesBillsExistance(req: Request, res: Response, next: any) {
|
||||||
const { BillPaymentEntry } = req.models;
|
const { Bill } = req.models;
|
||||||
const { id: billPaymentId } = req.params;
|
const billPayment = { ...req.body };
|
||||||
const billPayment = { id: billPaymentId, ...req.body };
|
const entriesBillsIds = billPayment.entries.map((e: any) => e.bill_id);
|
||||||
|
|
||||||
const entriesIds = billPayment.entries
|
const notFoundBillsIds = await Bill.getNotFoundBills(entriesBillsIds);
|
||||||
.filter((entry: IBillPaymentEntry) => entry.id)
|
|
||||||
.map((entry: IBillPaymentEntry) => entry.id);
|
|
||||||
|
|
||||||
const storedEntries = await BillPaymentEntry.tenant().query()
|
if (notFoundBillsIds.length > 0) {
|
||||||
.where('bill_payment_id', billPaymentId);
|
|
||||||
|
|
||||||
const storedEntriesIds = storedEntries.map((entry: IBillPaymentEntry) => entry.id);
|
|
||||||
const notFoundEntriesIds = difference(entriesIds, storedEntriesIds);
|
|
||||||
|
|
||||||
if (notFoundEntriesIds.length > 0) {
|
|
||||||
return res.status(400).send({
|
return res.status(400).send({
|
||||||
errors: [{ type: 'ENTEIES.IDS.NOT.FOUND', code: 800 }],
|
errors: [{ type: 'BILLS.IDS.NOT.EXISTS', code: 600 }],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate wether the payment amount bigger than the payable amount.
|
||||||
|
* @param {Request} req
|
||||||
|
* @param {Response} res
|
||||||
|
* @param {NextFunction} next
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
static 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()
|
||||||
|
.whereIn('id', billsIds);
|
||||||
|
|
||||||
|
const storedBillsMap = new Map(
|
||||||
|
storedBills.map((bill: any) => [bill.id, bill]),
|
||||||
|
);
|
||||||
|
interface invalidPaymentAmountError{
|
||||||
|
index: number,
|
||||||
|
due_amount: number
|
||||||
|
};
|
||||||
|
const hasWrongPaymentAmount: invalidPaymentAmountError[] = [];
|
||||||
|
const { entries } = req.body;
|
||||||
|
|
||||||
|
entries.forEach((entry: any, index: number) => {
|
||||||
|
const entryBill = storedBillsMap.get(entry.bill_id);
|
||||||
|
const { dueAmount } = entryBill;
|
||||||
|
|
||||||
|
if (dueAmount < entry.payment_amount) {
|
||||||
|
hasWrongPaymentAmount.push({ index, due_amount: dueAmount });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (hasWrongPaymentAmount.length > 0) {
|
||||||
|
return res.status(400).send({
|
||||||
|
errors: [{ type: 'INVALID.BILL.PAYMENT.AMOUNT', code: 400, indexes: hasWrongPaymentAmount }]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
next();
|
next();
|
||||||
@@ -297,7 +315,6 @@ export default class BillsPayments extends BaseController {
|
|||||||
errors: [{ type: 'BILL.PAYMENTS.RESOURCE.NOT_FOUND', code: 200 }],
|
errors: [{ type: 'BILL.PAYMENTS.RESOURCE.NOT_FOUND', code: 200 }],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const viewMeta = await View.query()
|
const viewMeta = await View.query()
|
||||||
.modify('allMetadata')
|
.modify('allMetadata')
|
||||||
.modify('specificOrFavourite', filter.custom_view_id)
|
.modify('specificOrFavourite', filter.custom_view_id)
|
||||||
|
|||||||
@@ -1,15 +1,22 @@
|
|||||||
import express from 'express';
|
import express from 'express';
|
||||||
import { check, param, query } from 'express-validator';
|
import { check, param, query } from 'express-validator';
|
||||||
import { difference } from 'lodash';
|
import { difference } from 'lodash';
|
||||||
|
import { PaymentReceiveEntry } from '@/models';
|
||||||
import BaseController from '@/http/controllers/BaseController';
|
import BaseController from '@/http/controllers/BaseController';
|
||||||
import validateMiddleware from '@/http/middleware/validateMiddleware';
|
import validateMiddleware from '@/http/middleware/validateMiddleware';
|
||||||
import asyncMiddleware from '@/http/middleware/asyncMiddleware';
|
import asyncMiddleware from '@/http/middleware/asyncMiddleware';
|
||||||
import PaymentReceiveService from '@/services/Sales/PaymentReceive';
|
import PaymentReceiveService from '@/services/Sales/PaymentsReceives';
|
||||||
import CustomersService from '@/services/Customers/CustomersService';
|
import CustomersService from '@/services/Customers/CustomersService';
|
||||||
import SaleInvoicesService from '@/services/Sales/SaleInvoice';
|
import SaleInvoicesService from '@/services/Sales/SalesInvoices';
|
||||||
import AccountsService from '@/services/Accounts/AccountsService';
|
import AccountsService from '@/services/Accounts/AccountsService';
|
||||||
import { PaymentReceiveEntry } from '@/models';
|
import DynamicListing from '@/services/DynamicListing/DynamicListing';
|
||||||
|
import DynamicListingBuilder from '@/services/DynamicListing/DynamicListingBuilder';
|
||||||
|
import { dynamicListingErrorsToResponse } from '@/services/DynamicListing/hasDynamicListing';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Payments receives controller.
|
||||||
|
* @controller
|
||||||
|
*/
|
||||||
export default class PaymentReceivesController extends BaseController {
|
export default class PaymentReceivesController extends BaseController {
|
||||||
/**
|
/**
|
||||||
* Router constructor.
|
* Router constructor.
|
||||||
@@ -27,10 +34,11 @@ export default class PaymentReceivesController extends BaseController {
|
|||||||
asyncMiddleware(this.validateDepositAccount),
|
asyncMiddleware(this.validateDepositAccount),
|
||||||
asyncMiddleware(this.validateInvoicesIDs),
|
asyncMiddleware(this.validateInvoicesIDs),
|
||||||
asyncMiddleware(this.validateEntriesIdsExistance),
|
asyncMiddleware(this.validateEntriesIdsExistance),
|
||||||
asyncMiddleware(this.editPaymentReceive)
|
asyncMiddleware(this.validateInvoicesPaymentsAmount),
|
||||||
|
asyncMiddleware(this.editPaymentReceive),
|
||||||
);
|
);
|
||||||
router.post(
|
router.post(
|
||||||
'/',
|
'/',
|
||||||
this.newPaymentReceiveValidation,
|
this.newPaymentReceiveValidation,
|
||||||
validateMiddleware,
|
validateMiddleware,
|
||||||
asyncMiddleware(this.validatePaymentReceiveNoExistance),
|
asyncMiddleware(this.validatePaymentReceiveNoExistance),
|
||||||
@@ -38,7 +46,7 @@ export default class PaymentReceivesController extends BaseController {
|
|||||||
asyncMiddleware(this.validateDepositAccount),
|
asyncMiddleware(this.validateDepositAccount),
|
||||||
asyncMiddleware(this.validateInvoicesIDs),
|
asyncMiddleware(this.validateInvoicesIDs),
|
||||||
asyncMiddleware(this.validateInvoicesPaymentsAmount),
|
asyncMiddleware(this.validateInvoicesPaymentsAmount),
|
||||||
asyncMiddleware(this.newPaymentReceive)
|
asyncMiddleware(this.newPaymentReceive),
|
||||||
);
|
);
|
||||||
router.get(
|
router.get(
|
||||||
'/:id',
|
'/:id',
|
||||||
@@ -58,7 +66,7 @@ export default class PaymentReceivesController extends BaseController {
|
|||||||
this.paymentReceiveValidation,
|
this.paymentReceiveValidation,
|
||||||
validateMiddleware,
|
validateMiddleware,
|
||||||
asyncMiddleware(this.validatePaymentReceiveExistance),
|
asyncMiddleware(this.validatePaymentReceiveExistance),
|
||||||
asyncMiddleware(this.deletePaymentReceive)
|
asyncMiddleware(this.deletePaymentReceive),
|
||||||
);
|
);
|
||||||
return router;
|
return router;
|
||||||
}
|
}
|
||||||
@@ -340,7 +348,7 @@ export default class PaymentReceivesController extends BaseController {
|
|||||||
/**
|
/**
|
||||||
* Payment receive list validation schema.
|
* Payment receive list validation schema.
|
||||||
*/
|
*/
|
||||||
static async validatePaymentReceiveList() {
|
static get validatePaymentReceiveList() {
|
||||||
return [
|
return [
|
||||||
query('custom_view_id').optional().isNumeric().toInt(),
|
query('custom_view_id').optional().isNumeric().toInt(),
|
||||||
query('stringified_filter_roles').optional().isJSON(),
|
query('stringified_filter_roles').optional().isJSON(),
|
||||||
@@ -407,7 +415,8 @@ export default class PaymentReceivesController extends BaseController {
|
|||||||
const paymentReceives = await PaymentReceive.query().onBuild((builder) => {
|
const paymentReceives = await PaymentReceive.query().onBuild((builder) => {
|
||||||
dynamicListing.buildQuery()(builder);
|
dynamicListing.buildQuery()(builder);
|
||||||
return builder;
|
return builder;
|
||||||
});
|
}).pagination(filter.page - 1, filter.page_size);
|
||||||
|
|
||||||
return res.status(200).send({
|
return res.status(200).send({
|
||||||
payment_receives: {
|
payment_receives: {
|
||||||
...paymentReceives,
|
...paymentReceives,
|
||||||
|
|||||||
@@ -103,9 +103,10 @@ export default class SalesEstimatesController extends BaseController {
|
|||||||
return [
|
return [
|
||||||
query('custom_view_id').optional().isNumeric().toInt(),
|
query('custom_view_id').optional().isNumeric().toInt(),
|
||||||
query('stringified_filter_roles').optional().isJSON(),
|
query('stringified_filter_roles').optional().isJSON(),
|
||||||
|
|
||||||
query('column_sort_by').optional(),
|
query('column_sort_by').optional(),
|
||||||
query('sort_order').optional().isIn(['desc', 'asc']),
|
query('sort_order').optional().isIn(['desc', 'asc']),
|
||||||
|
query('page').optional().isNumeric().toInt(),
|
||||||
|
query('page_size').optional().isNumeric().toInt(),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -201,7 +202,7 @@ export default class SalesEstimatesController extends BaseController {
|
|||||||
.filter(e => e.id)
|
.filter(e => e.id)
|
||||||
.map((e) => e.id);
|
.map((e) => e.id);
|
||||||
|
|
||||||
const foundEntries = await ItemEntry.query()
|
const foundEntries = await ItemEntry.tenant().query()
|
||||||
.whereIn('id', entriesIds)
|
.whereIn('id', entriesIds)
|
||||||
.where('reference_type', 'SaleInvoice')
|
.where('reference_type', 'SaleInvoice')
|
||||||
.where('reference_id', saleInvoiceId);
|
.where('reference_id', saleInvoiceId);
|
||||||
@@ -323,7 +324,7 @@ export default class SalesEstimatesController extends BaseController {
|
|||||||
return res.status(400).send({ errors: errorReasons });
|
return res.status(400).send({ errors: errorReasons });
|
||||||
}
|
}
|
||||||
|
|
||||||
const salesEstimates = await SaleEstimate.query().onBuild((query) => {
|
const salesEstimates = await SaleEstimate.query().onBuild((builder) => {
|
||||||
dynamicListing.buildQuery()(builder);
|
dynamicListing.buildQuery()(builder);
|
||||||
return builder;
|
return builder;
|
||||||
}).pagination(filter.page - 1, filter.page_size);
|
}).pagination(filter.page - 1, filter.page_size);
|
||||||
|
|||||||
@@ -1,16 +1,15 @@
|
|||||||
import express from 'express';
|
import express from 'express';
|
||||||
import { check, param, query } from 'express-validator';
|
import { check, param, query } from 'express-validator';
|
||||||
|
import { difference } from 'lodash';
|
||||||
import { ItemEntry } from '@/models';
|
import { ItemEntry } from '@/models';
|
||||||
import validateMiddleware from '@/http/middleware/validateMiddleware';
|
import validateMiddleware from '@/http/middleware/validateMiddleware';
|
||||||
import asyncMiddleware from '@/http/middleware/asyncMiddleware';
|
import asyncMiddleware from '@/http/middleware/asyncMiddleware';
|
||||||
import SaleInvoiceService from '@/services/Sales/SaleInvoice';
|
import SaleInvoiceService from '@/services/Sales/SalesInvoices';
|
||||||
import ItemsService from '@/services/Items/ItemsService';
|
import ItemsService from '@/services/Items/ItemsService';
|
||||||
import CustomersService from '@/services/Customers/CustomersService';
|
import CustomersService from '@/services/Customers/CustomersService';
|
||||||
import DynamicListing from '@/services/DynamicListing/DynamicListing';
|
import DynamicListing from '@/services/DynamicListing/DynamicListing';
|
||||||
import DynamicListingBuilder from '@/services/DynamicListing/DynamicListingBuilder';
|
import DynamicListingBuilder from '@/services/DynamicListing/DynamicListingBuilder';
|
||||||
import { dynamicListingErrorsToResponse } from '@/services/DynamicListing/hasDynamicListing';
|
import { dynamicListingErrorsToResponse } from '@/services/DynamicListing/hasDynamicListing';
|
||||||
import { SaleInvoice } from '../../../models';
|
|
||||||
import { difference } from 'lodash';
|
|
||||||
|
|
||||||
export default class SaleInvoicesController {
|
export default class SaleInvoicesController {
|
||||||
/**
|
/**
|
||||||
@@ -23,6 +22,7 @@ export default class SaleInvoicesController {
|
|||||||
'/',
|
'/',
|
||||||
this.saleInvoiceValidationSchema,
|
this.saleInvoiceValidationSchema,
|
||||||
validateMiddleware,
|
validateMiddleware,
|
||||||
|
asyncMiddleware(this.validateInvoiceCustomerExistance),
|
||||||
asyncMiddleware(this.validateInvoiceNumberUnique),
|
asyncMiddleware(this.validateInvoiceNumberUnique),
|
||||||
asyncMiddleware(this.validateInvoiceItemsIdsExistance),
|
asyncMiddleware(this.validateInvoiceItemsIdsExistance),
|
||||||
asyncMiddleware(this.newSaleInvoice)
|
asyncMiddleware(this.newSaleInvoice)
|
||||||
@@ -35,6 +35,7 @@ export default class SaleInvoicesController {
|
|||||||
],
|
],
|
||||||
validateMiddleware,
|
validateMiddleware,
|
||||||
asyncMiddleware(this.validateInvoiceExistance),
|
asyncMiddleware(this.validateInvoiceExistance),
|
||||||
|
asyncMiddleware(this.validateInvoiceCustomerExistance),
|
||||||
asyncMiddleware(this.validateInvoiceNumberUnique),
|
asyncMiddleware(this.validateInvoiceNumberUnique),
|
||||||
asyncMiddleware(this.validateInvoiceItemsIdsExistance),
|
asyncMiddleware(this.validateInvoiceItemsIdsExistance),
|
||||||
asyncMiddleware(this.valdiateInvoiceEntriesIdsExistance),
|
asyncMiddleware(this.valdiateInvoiceEntriesIdsExistance),
|
||||||
@@ -96,12 +97,17 @@ export default class SaleInvoicesController {
|
|||||||
return [param('id').exists().isNumeric().toInt()];
|
return [param('id').exists().isNumeric().toInt()];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sales invoices list validation schema.
|
||||||
|
*/
|
||||||
static get saleInvoiceListValidationSchema() {
|
static get saleInvoiceListValidationSchema() {
|
||||||
return [
|
return [
|
||||||
query('custom_view_id').optional().isNumeric().toInt(),
|
query('custom_view_id').optional().isNumeric().toInt(),
|
||||||
query('stringified_filter_roles').optional().isJSON(),
|
query('stringified_filter_roles').optional().isJSON(),
|
||||||
query('column_sort_by').optional(),
|
query('column_sort_by').optional(),
|
||||||
query('sort_order').optional().isIn(['desc', 'asc']),
|
query('sort_order').optional().isIn(['desc', 'asc']),
|
||||||
|
query('page').optional().isNumeric().toInt(),
|
||||||
|
query('page_size').optional().isNumeric().toInt(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,6 +151,7 @@ export default class SaleInvoicesController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
*
|
||||||
* Validate whether sale invoice number unqiue on the storage.
|
* Validate whether sale invoice number unqiue on the storage.
|
||||||
* @param {Request} req
|
* @param {Request} req
|
||||||
* @param {Response} res
|
* @param {Response} res
|
||||||
@@ -266,8 +273,13 @@ export default class SaleInvoicesController {
|
|||||||
*/
|
*/
|
||||||
static async editSaleInvoice(req, res) {
|
static async editSaleInvoice(req, res) {
|
||||||
const { id: saleInvoiceId } = req.params;
|
const { id: saleInvoiceId } = req.params;
|
||||||
const saleInvoice = { ...req.body };
|
const saleInvoice = {
|
||||||
|
...req.body,
|
||||||
|
entries: req.body.entries.map((entry) => ({
|
||||||
|
...entry,
|
||||||
|
amount: ItemEntry.calcAmount(entry),
|
||||||
|
})),
|
||||||
|
};
|
||||||
// Update the given sale invoice details.
|
// Update the given sale invoice details.
|
||||||
await SaleInvoiceService.editSaleInvoice(saleInvoiceId, saleInvoice);
|
await SaleInvoiceService.editSaleInvoice(saleInvoiceId, saleInvoice);
|
||||||
|
|
||||||
@@ -311,6 +323,8 @@ export default class SaleInvoicesController {
|
|||||||
const filter = {
|
const filter = {
|
||||||
filter_roles: [],
|
filter_roles: [],
|
||||||
sort_order: 'asc',
|
sort_order: 'asc',
|
||||||
|
page: 1,
|
||||||
|
page_size: 10,
|
||||||
...req.query,
|
...req.query,
|
||||||
};
|
};
|
||||||
if (filter.stringified_filter_roles) {
|
if (filter.stringified_filter_roles) {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import asyncMiddleware from '@/http/middleware/asyncMiddleware';
|
|||||||
import CustomersService from '@/services/Customers/CustomersService';
|
import CustomersService from '@/services/Customers/CustomersService';
|
||||||
import AccountsService from '@/services/Accounts/AccountsService';
|
import AccountsService from '@/services/Accounts/AccountsService';
|
||||||
import ItemsService from '@/services/Items/ItemsService';
|
import ItemsService from '@/services/Items/ItemsService';
|
||||||
import SaleReceiptService from '@/services/Sales/SalesReceipt';
|
import SaleReceiptService from '@/services/Sales/SalesReceipts';
|
||||||
import DynamicListingBuilder from '@/services/DynamicListing/DynamicListingBuilder';
|
import DynamicListingBuilder from '@/services/DynamicListing/DynamicListingBuilder';
|
||||||
import DynamicListing from '@/services/DynamicListing/DynamicListing';
|
import DynamicListing from '@/services/DynamicListing/DynamicListing';
|
||||||
import {
|
import {
|
||||||
@@ -51,7 +51,7 @@ export default class SalesReceiptsController {
|
|||||||
);
|
);
|
||||||
router.get(
|
router.get(
|
||||||
'/',
|
'/',
|
||||||
this.listingSalesReceipts,
|
this.listSalesReceiptsValidationSchema,
|
||||||
validateMiddleware,
|
validateMiddleware,
|
||||||
asyncMiddleware(this.listingSalesReceipts)
|
asyncMiddleware(this.listingSalesReceipts)
|
||||||
);
|
);
|
||||||
@@ -103,6 +103,8 @@ export default class SalesReceiptsController {
|
|||||||
query('stringified_filter_roles').optional().isJSON(),
|
query('stringified_filter_roles').optional().isJSON(),
|
||||||
query('column_sort_by').optional(),
|
query('column_sort_by').optional(),
|
||||||
query('sort_order').optional().isIn(['desc', 'asc']),
|
query('sort_order').optional().isIn(['desc', 'asc']),
|
||||||
|
query('page').optional().isNumeric().toInt(),
|
||||||
|
query('page_size').optional().isNumeric().toInt(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -272,6 +274,7 @@ export default class SalesReceiptsController {
|
|||||||
sort_order: 'asc',
|
sort_order: 'asc',
|
||||||
page: 1,
|
page: 1,
|
||||||
page_size: 10,
|
page_size: 10,
|
||||||
|
...req.query,
|
||||||
};
|
};
|
||||||
if (filter.stringified_filter_roles) {
|
if (filter.stringified_filter_roles) {
|
||||||
filter.filter_roles = JSON.parse(filter.stringified_filter_roles);
|
filter.filter_roles = JSON.parse(filter.stringified_filter_roles);
|
||||||
@@ -312,14 +315,17 @@ export default class SalesReceiptsController {
|
|||||||
const salesReceipts = await SaleReceipt.query().onBuild((builder) => {
|
const salesReceipts = await SaleReceipt.query().onBuild((builder) => {
|
||||||
builder.withGraphFetched('entries');
|
builder.withGraphFetched('entries');
|
||||||
dynamicListing.buildQuery()(builder);
|
dynamicListing.buildQuery()(builder);
|
||||||
return builder;
|
|
||||||
}).pagination(filter.page - 1, filter.page_size);
|
}).pagination(filter.page - 1, filter.page_size);
|
||||||
|
|
||||||
return res.status(200).send({
|
return res.status(200).send({
|
||||||
sales_receipts: salesReceipts,
|
sales_receipts: {
|
||||||
...(viewMeta ? {
|
...salesReceipts,
|
||||||
customViewId: viewMeta.id,
|
...(viewMeta ? {
|
||||||
} : {}),
|
view_meta: {
|
||||||
|
customViewId: viewMeta.id,
|
||||||
|
}
|
||||||
|
} : {}),
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import express from 'express';
|
import express from 'express';
|
||||||
import SalesEstimates from './SalesEstimates';
|
import SalesEstimates from './SalesEstimates';
|
||||||
import SalesReceipts from './SalesReceipt';
|
import SalesReceipts from './SalesReceipts';
|
||||||
import SalesInvoices from './SalesInvoices'
|
import SalesInvoices from './SalesInvoices'
|
||||||
import PaymentReceives from './PaymentReceives';
|
import PaymentReceives from './PaymentReceives';
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
import express from 'express';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
|
|
||||||
router() {
|
|
||||||
const router = express.Router();
|
|
||||||
|
|
||||||
return router;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
@@ -3,36 +3,26 @@ import express from 'express';
|
|||||||
import Authentication from '@/http/controllers/Authentication';
|
import Authentication from '@/http/controllers/Authentication';
|
||||||
import InviteUsers from '@/http/controllers/InviteUsers';
|
import InviteUsers from '@/http/controllers/InviteUsers';
|
||||||
import Users from '@/http/controllers/Users';
|
import Users from '@/http/controllers/Users';
|
||||||
// import Roles from '@/http/controllers/Roles';
|
|
||||||
import Items from '@/http/controllers/Items';
|
import Items from '@/http/controllers/Items';
|
||||||
import ItemCategories from '@/http/controllers/ItemCategories';
|
import ItemCategories from '@/http/controllers/ItemCategories';
|
||||||
import Accounts from '@/http/controllers/Accounts';
|
import Accounts from '@/http/controllers/Accounts';
|
||||||
import AccountTypes from '@/http/controllers/AccountTypes';
|
import AccountTypes from '@/http/controllers/AccountTypes';
|
||||||
// import AccountOpeningBalance from '@/http/controllers/AccountOpeningBalance';
|
|
||||||
import Views from '@/http/controllers/Views';
|
import Views from '@/http/controllers/Views';
|
||||||
// import CustomFields from '@/http/controllers/Fields';
|
|
||||||
import Accounting from '@/http/controllers/Accounting';
|
import Accounting from '@/http/controllers/Accounting';
|
||||||
import FinancialStatements from '@/http/controllers/FinancialStatements';
|
import FinancialStatements from '@/http/controllers/FinancialStatements';
|
||||||
import Expenses from '@/http/controllers/Expenses';
|
import Expenses from '@/http/controllers/Expenses';
|
||||||
import Options from '@/http/controllers/Options';
|
import Options from '@/http/controllers/Options';
|
||||||
// import Budget from '@/http/controllers/Budget';
|
|
||||||
// import BudgetReports from '@/http/controllers/BudgetReports';
|
|
||||||
import Currencies from '@/http/controllers/Currencies';
|
import Currencies from '@/http/controllers/Currencies';
|
||||||
import Customers from '@/http/controllers/Customers';
|
import Customers from '@/http/controllers/Customers';
|
||||||
import Vendors from '@/http/controllers/Vendors';
|
import Vendors from '@/http/controllers/Vendors';
|
||||||
import Sales from '@/http/controllers/Sales'
|
import Sales from '@/http/controllers/Sales'
|
||||||
// import Suppliers from '@/http/controllers/Suppliers';
|
|
||||||
import Purchases from '@/http/controllers/Purchases';
|
import Purchases from '@/http/controllers/Purchases';
|
||||||
// import CurrencyAdjustment from './controllers/CurrencyAdjustment';
|
|
||||||
import Resources from './controllers/Resources';
|
import Resources from './controllers/Resources';
|
||||||
import ExchangeRates from '@/http/controllers/ExchangeRates';
|
import ExchangeRates from '@/http/controllers/ExchangeRates';
|
||||||
// import SalesReports from '@/http/controllers/SalesReports';
|
|
||||||
// import PurchasesReports from '@/http/controllers/PurchasesReports';
|
|
||||||
import Media from '@/http/controllers/Media';
|
import Media from '@/http/controllers/Media';
|
||||||
import JWTAuth from '@/http/middleware/jwtAuth';
|
import JWTAuth from '@/http/middleware/jwtAuth';
|
||||||
import TenancyMiddleware from '@/http/middleware/TenancyMiddleware';
|
import TenancyMiddleware from '@/http/middleware/TenancyMiddleware';
|
||||||
|
|
||||||
|
|
||||||
export default (app) => {
|
export default (app) => {
|
||||||
// app.use('/api/oauth2', OAuth2.router());
|
// app.use('/api/oauth2', OAuth2.router());
|
||||||
app.use('/api/auth', Authentication.router());
|
app.use('/api/auth', Authentication.router());
|
||||||
@@ -45,31 +35,22 @@ export default (app) => {
|
|||||||
|
|
||||||
dashboard.use('/api/currencies', Currencies.router());
|
dashboard.use('/api/currencies', Currencies.router());
|
||||||
dashboard.use('/api/users', Users.router());
|
dashboard.use('/api/users', Users.router());
|
||||||
// app.use('/api/roles', Roles.router());
|
|
||||||
dashboard.use('/api/accounts', Accounts.router());
|
dashboard.use('/api/accounts', Accounts.router());
|
||||||
dashboard.use('/api/account_types', AccountTypes.router());
|
dashboard.use('/api/account_types', AccountTypes.router());
|
||||||
dashboard.use('/api/accounting', Accounting.router());
|
dashboard.use('/api/accounting', Accounting.router());
|
||||||
// app.use('/api/accounts_opening_balances', AccountOpeningBalance.router());
|
|
||||||
dashboard.use('/api/views', Views.router());
|
dashboard.use('/api/views', Views.router());
|
||||||
// app.use('/api/fields', CustomFields.router());
|
|
||||||
dashboard.use('/api/items', Items.router());
|
dashboard.use('/api/items', Items.router());
|
||||||
dashboard.use('/api/item_categories', ItemCategories.router());
|
dashboard.use('/api/item_categories', ItemCategories.router());
|
||||||
dashboard.use('/api/expenses', Expenses.router());
|
dashboard.use('/api/expenses', Expenses.router());
|
||||||
dashboard.use('/api/financial_statements', FinancialStatements.router());
|
dashboard.use('/api/financial_statements', FinancialStatements.router());
|
||||||
dashboard.use('/api/options', Options.router());
|
dashboard.use('/api/options', Options.router());
|
||||||
dashboard.use('/api/sales', Sales.router());
|
dashboard.use('/api/sales', Sales.router());
|
||||||
// app.use('/api/budget_reports', BudgetReports.router());
|
|
||||||
dashboard.use('/api/customers', Customers.router());
|
dashboard.use('/api/customers', Customers.router());
|
||||||
dashboard.use('/api/vendors', Vendors.router());
|
dashboard.use('/api/vendors', Vendors.router());
|
||||||
dashboard.use('/api/purchases', Purchases.router());
|
dashboard.use('/api/purchases', Purchases.router());
|
||||||
// app.use('/api/suppliers', Suppliers.router());
|
|
||||||
// app.use('/api/budget', Budget.router());
|
|
||||||
dashboard.use('/api/resources', Resources.router());
|
dashboard.use('/api/resources', Resources.router());
|
||||||
dashboard.use('/api/exchange_rates', ExchangeRates.router());
|
dashboard.use('/api/exchange_rates', ExchangeRates.router());
|
||||||
dashboard.use('/api/media', Media.router());
|
dashboard.use('/api/media', Media.router());
|
||||||
|
|
||||||
app.use('/', dashboard);
|
app.use('/', dashboard);
|
||||||
// app.use('/api/currency_adjustment', CurrencyAdjustment.router());
|
|
||||||
// app.use('/api/reports/sales', SalesReports.router());
|
|
||||||
// app.use('/api/reports/purchases', PurchasesReports.router());
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { Model, mixin } from 'objection';
|
import { Model, mixin } from 'objection';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
import { difference } from 'lodash';
|
||||||
import TenantModel from '@/models/TenantModel';
|
import TenantModel from '@/models/TenantModel';
|
||||||
import CachableQueryBuilder from '@/lib/Cachable/CachableQueryBuilder';
|
import CachableQueryBuilder from '@/lib/Cachable/CachableQueryBuilder';
|
||||||
import CachableModel from '@/lib/Cachable/CachableModel';
|
import CachableModel from '@/lib/Cachable/CachableModel';
|
||||||
@@ -29,8 +30,25 @@ export default class Bill extends mixin(TenantModel, [CachableModel]) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Due amount of the given.
|
* Due amount of the given.
|
||||||
|
* @return {number}
|
||||||
*/
|
*/
|
||||||
get dueAmount() {
|
get dueAmount() {
|
||||||
return Math.max(this.balance - this.paymentAmount, 0);
|
return this.amount - this.paymentAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the not found bills ids as array.
|
||||||
|
* @param {Array} billsIds
|
||||||
|
* @return {Array}
|
||||||
|
*/
|
||||||
|
static async getNotFoundBills(billsIds) {
|
||||||
|
const storedBills = await this.tenant().query().whereIn('id', billsIds);
|
||||||
|
const storedBillsIds = storedBills.map((t) => t.id);
|
||||||
|
|
||||||
|
const notFoundBillsIds = difference(
|
||||||
|
billsIds,
|
||||||
|
storedBillsIds,
|
||||||
|
);
|
||||||
|
return notFoundBillsIds;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,10 +39,11 @@ export default class BillPayment extends mixin(TenantModel, [CachableModel]) {
|
|||||||
*/
|
*/
|
||||||
static get relationMappings() {
|
static get relationMappings() {
|
||||||
const BillPaymentEntry = require('@/models/BillPaymentEntry');
|
const BillPaymentEntry = require('@/models/BillPaymentEntry');
|
||||||
|
const Vendor = require('@/models/Vendor');
|
||||||
|
|
||||||
return {
|
return {
|
||||||
/**
|
/**
|
||||||
* Account model may belongs to account type.
|
*
|
||||||
*/
|
*/
|
||||||
entries: {
|
entries: {
|
||||||
relation: Model.BelongsToOneRelation,
|
relation: Model.BelongsToOneRelation,
|
||||||
@@ -52,6 +53,17 @@ export default class BillPayment extends mixin(TenantModel, [CachableModel]) {
|
|||||||
to: 'bills_payments_entries.billPaymentId',
|
to: 'bills_payments_entries.billPaymentId',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
vendor: {
|
||||||
|
relation: Model.BelongsToOneRelation,
|
||||||
|
modelClass: this.relationBindKnex(Vendor.default),
|
||||||
|
join: {
|
||||||
|
from: 'bills_payments.vendorId',
|
||||||
|
to: 'vendors.id',
|
||||||
|
},
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,17 +3,17 @@ import { Customer } from '@/models';
|
|||||||
export default class CustomerRepository {
|
export default class CustomerRepository {
|
||||||
|
|
||||||
static changeDiffBalance(customerId, oldCustomerId, amount, oldAmount) {
|
static changeDiffBalance(customerId, oldCustomerId, amount, oldAmount) {
|
||||||
const diffAmount = (amount - oldAmount) * -1;
|
const diffAmount = amount - oldAmount;
|
||||||
const asyncOpers = [];
|
const asyncOpers = [];
|
||||||
|
|
||||||
if (customerId != oldCustomerId) {
|
if (customerId != oldCustomerId) {
|
||||||
const oldCustomerOper = Customer.changeBalance(
|
const oldCustomerOper = Customer.changeBalance(
|
||||||
oldCustomerId,
|
oldCustomerId,
|
||||||
oldAmount
|
(oldAmount * -1)
|
||||||
);
|
);
|
||||||
const customerOper = Customer.changeBalance(
|
const customerOper = Customer.changeBalance(
|
||||||
customerId,
|
customerId,
|
||||||
(amount + diffAmount) * -1
|
amount,
|
||||||
);
|
);
|
||||||
asyncOpers.push(customerOper);
|
asyncOpers.push(customerOper);
|
||||||
asyncOpers.push(oldCustomerOper);
|
asyncOpers.push(oldCustomerOper);
|
||||||
|
|||||||
7
server/src/repositories/SaleInvoiceRepository.js
Normal file
7
server/src/repositories/SaleInvoiceRepository.js
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
|
||||||
|
|
||||||
|
export default class SaleInvoiceRepository {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,8 +1,6 @@
|
|||||||
import express from 'express';
|
import express from 'express';
|
||||||
import { omit } from 'lodash';
|
import { omit, sumBy } from 'lodash';
|
||||||
import { check, query, validationResult, param } from 'express-validator';
|
|
||||||
import { BillPayment, BillPaymentEntry, Vendor } from '@/models';
|
import { BillPayment, BillPaymentEntry, Vendor } from '@/models';
|
||||||
import asyncMiddleware from '@/http/middleware/asyncMiddleware';
|
|
||||||
import ServiceItemsEntries from '../Sales/ServiceItemsEntries';
|
import ServiceItemsEntries from '../Sales/ServiceItemsEntries';
|
||||||
import AccountsService from '../Accounts/AccountsService';
|
import AccountsService from '../Accounts/AccountsService';
|
||||||
import JournalPoster from '../Accounting/JournalPoster';
|
import JournalPoster from '../Accounting/JournalPoster';
|
||||||
|
|||||||
@@ -1,19 +1,20 @@
|
|||||||
import { omit, sumBy, difference } from 'lodash';
|
import { omit, sumBy } from 'lodash';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import {
|
import {
|
||||||
|
Account,
|
||||||
Bill,
|
Bill,
|
||||||
Vendor,
|
Vendor,
|
||||||
InventoryTransaction,
|
|
||||||
ItemEntry,
|
ItemEntry,
|
||||||
Item,
|
Item,
|
||||||
Account,
|
InventoryTransaction,
|
||||||
|
AccountTransaction,
|
||||||
} from '@/models';
|
} from '@/models';
|
||||||
import JournalPoster from '@/services/Accounting/JournalPoster';
|
import JournalPoster from '@/services/Accounting/JournalPoster';
|
||||||
import JournalEntry from '@/services/Accounting/JournalEntry';
|
import JournalEntry from '@/services/Accounting/JournalEntry';
|
||||||
import AccountsService from '@/services/Accounts/AccountsService';
|
import AccountsService from '@/services/Accounts/AccountsService';
|
||||||
import JournalPosterService from '@/services/Sales/JournalPosterService';
|
import JournalPosterService from '@/services/Sales/JournalPosterService';
|
||||||
import InventoryService from '../Inventory/Inventory';
|
import InventoryService from '@/services/Inventory/Inventory';
|
||||||
import { AccountTransaction } from '../../models';
|
import HasItemsEntries from '@/services/Sales/HasItemsEntries';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Vendor bills services.
|
* Vendor bills services.
|
||||||
@@ -65,57 +66,7 @@ export default class BillsService {
|
|||||||
return storedBill;
|
return storedBill;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Patch items entries to the storage.
|
|
||||||
*
|
|
||||||
* @param {Array} newEntries
|
|
||||||
* @param {Array} oldEntries
|
|
||||||
* @param {String} referenceType
|
|
||||||
*
|
|
||||||
* @return {Promise}
|
|
||||||
*/
|
|
||||||
static async patchItemsEntries(newEntries, oldEntries, referenceType, billId) {
|
|
||||||
const entriesHasIds = newEntries.filter((entry) => entry.id);
|
|
||||||
const entriesHasNoIds = newEntries.filter((entry) => !entry.id);
|
|
||||||
|
|
||||||
const entriesIds = entriesHasIds.map(entry => entry.id);
|
|
||||||
|
|
||||||
const oldEntriesIds = oldEntries.map((e) => e.id);
|
|
||||||
const opers = [];
|
|
||||||
|
|
||||||
const entriesIdsShouldDelete = difference(
|
|
||||||
oldEntriesIds,
|
|
||||||
entriesIds,
|
|
||||||
);
|
|
||||||
if (entriesIdsShouldDelete.length > 0) {
|
|
||||||
const deleteOper = ItemEntry.tenant()
|
|
||||||
.query()
|
|
||||||
.whereIn('id', entriesIdsShouldDelete)
|
|
||||||
.delete();
|
|
||||||
opers.push(deleteOper);
|
|
||||||
}
|
|
||||||
entriesHasIds.forEach((entry) => {
|
|
||||||
const updateOper = ItemEntry.tenant()
|
|
||||||
.query()
|
|
||||||
.where('id', entry.id)
|
|
||||||
.update({
|
|
||||||
...omit(entry, ['id']),
|
|
||||||
});
|
|
||||||
opers.push(updateOper);
|
|
||||||
});
|
|
||||||
entriesHasNoIds.forEach((entry) => {
|
|
||||||
const insertOper = ItemEntry.tenant()
|
|
||||||
.query()
|
|
||||||
.insert({
|
|
||||||
reference_id: billId,
|
|
||||||
reference_type: referenceType,
|
|
||||||
...omit(entry, ['id', 'amount']),
|
|
||||||
});
|
|
||||||
opers.push(insertOper);
|
|
||||||
});
|
|
||||||
return Promise.all([...opers]);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Edits details of the given bill id with associated entries.
|
* Edits details of the given bill id with associated entries.
|
||||||
*
|
*
|
||||||
@@ -150,8 +101,9 @@ export default class BillsService {
|
|||||||
.where('reference_type', 'Bill');
|
.where('reference_type', 'Bill');
|
||||||
|
|
||||||
// Patch the bill entries.
|
// Patch the bill entries.
|
||||||
const patchEntriesOper = this.patchItemsEntries(bill.entries, storedEntries, 'Bill', billId);
|
const patchEntriesOper = HasItemsEntries.patchItemsEntries(
|
||||||
|
bill.entries, storedEntries, 'Bill', billId,
|
||||||
|
);
|
||||||
// Record bill journal transactions.
|
// Record bill journal transactions.
|
||||||
const recordTransactionsOper = this.recordJournalTransactions(bill, billId);
|
const recordTransactionsOper = this.recordJournalTransactions(bill, billId);
|
||||||
|
|
||||||
|
|||||||
56
server/src/services/Sales/HasItemsEntries.ts
Normal file
56
server/src/services/Sales/HasItemsEntries.ts
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
import { difference, omit } from 'lodash';
|
||||||
|
import { ItemEntry } from '@/models';
|
||||||
|
|
||||||
|
export default class HasItemEntries {
|
||||||
|
/**
|
||||||
|
* Patch items entries to the storage.
|
||||||
|
*
|
||||||
|
* @param {Array} newEntries -
|
||||||
|
* @param {Array} oldEntries -
|
||||||
|
* @param {String} referenceType -
|
||||||
|
* @param {String|Number} referenceId -
|
||||||
|
*
|
||||||
|
* @return {Promise}
|
||||||
|
*/
|
||||||
|
static async patchItemsEntries(newEntries: Array<any>, oldEntries: Array<any>, referenceType: string, referenceId: string|number) {
|
||||||
|
const entriesHasIds = newEntries.filter((entry) => entry.id);
|
||||||
|
const entriesHasNoIds = newEntries.filter((entry) => !entry.id);
|
||||||
|
const entriesIds = entriesHasIds.map(entry => entry.id);
|
||||||
|
|
||||||
|
const oldEntriesIds = oldEntries.map((e) => e.id);
|
||||||
|
const excludeAttrs = ['id', 'amount'];
|
||||||
|
const opers = [];
|
||||||
|
|
||||||
|
const entriesIdsShouldDelete = difference(
|
||||||
|
oldEntriesIds,
|
||||||
|
entriesIds,
|
||||||
|
);
|
||||||
|
if (entriesIdsShouldDelete.length > 0) {
|
||||||
|
const deleteOper = ItemEntry.tenant()
|
||||||
|
.query()
|
||||||
|
.whereIn('id', entriesIdsShouldDelete)
|
||||||
|
.delete();
|
||||||
|
opers.push(deleteOper);
|
||||||
|
}
|
||||||
|
entriesHasIds.forEach((entry) => {
|
||||||
|
const updateOper = ItemEntry.tenant()
|
||||||
|
.query()
|
||||||
|
.where('id', entry.id)
|
||||||
|
.update({
|
||||||
|
...omit(entry, excludeAttrs),
|
||||||
|
});
|
||||||
|
opers.push(updateOper);
|
||||||
|
});
|
||||||
|
entriesHasNoIds.forEach((entry) => {
|
||||||
|
const insertOper = ItemEntry.tenant()
|
||||||
|
.query()
|
||||||
|
.insert({
|
||||||
|
reference_id: referenceId,
|
||||||
|
reference_type: referenceType,
|
||||||
|
...omit(entry, excludeAttrs),
|
||||||
|
});
|
||||||
|
opers.push(insertOper);
|
||||||
|
});
|
||||||
|
return Promise.all([...opers]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { omit, sumBy, mapValues, groupBy, chain } from 'lodash';
|
import { omit, sumBy, chain } from 'lodash';
|
||||||
import moment, { updateLocale } from 'moment';
|
import moment from 'moment';
|
||||||
import {
|
import {
|
||||||
AccountTransaction,
|
AccountTransaction,
|
||||||
PaymentReceive,
|
PaymentReceive,
|
||||||
@@ -16,14 +16,18 @@ import ServiceItemsEntries from '@/services/Sales/ServiceItemsEntries';
|
|||||||
import PaymentReceiveEntryRepository from '@/repositories/PaymentReceiveEntryRepository';
|
import PaymentReceiveEntryRepository from '@/repositories/PaymentReceiveEntryRepository';
|
||||||
import CustomerRepository from '@/repositories/CustomerRepository';
|
import CustomerRepository from '@/repositories/CustomerRepository';
|
||||||
|
|
||||||
export default class PaymentReceiveService extends JournalPosterService {
|
/**
|
||||||
|
* Payment receive service.
|
||||||
|
* @service
|
||||||
|
*/
|
||||||
|
export default class PaymentReceiveService {
|
||||||
/**
|
/**
|
||||||
* Creates a new payment receive and store it to the storage
|
* Creates a new payment receive and store it to the storage
|
||||||
* with associated invoices payment and journal transactions.
|
* with associated invoices payment and journal transactions.
|
||||||
* @async
|
* @async
|
||||||
* @param {IPaymentReceive} paymentReceive
|
* @param {IPaymentReceive} paymentReceive
|
||||||
*/
|
*/
|
||||||
static async createPaymentReceive(paymentReceive) {
|
static async createPaymentReceive(paymentReceive: any) {
|
||||||
const paymentAmount = sumBy(paymentReceive.entries, 'payment_amount');
|
const paymentAmount = sumBy(paymentReceive.entries, 'payment_amount');
|
||||||
const storedPaymentReceive = await PaymentReceive.tenant()
|
const storedPaymentReceive = await PaymentReceive.tenant()
|
||||||
.query()
|
.query()
|
||||||
@@ -31,9 +35,9 @@ export default class PaymentReceiveService extends JournalPosterService {
|
|||||||
amount: paymentAmount,
|
amount: paymentAmount,
|
||||||
...omit(paymentReceive, ['entries']),
|
...omit(paymentReceive, ['entries']),
|
||||||
});
|
});
|
||||||
const storeOpers = [];
|
const storeOpers: Array<any> = [];
|
||||||
|
|
||||||
paymentReceive.entries.forEach((entry) => {
|
paymentReceive.entries.forEach((entry: any) => {
|
||||||
const oper = PaymentReceiveEntry.tenant()
|
const oper = PaymentReceiveEntry.tenant()
|
||||||
.query()
|
.query()
|
||||||
.insert({
|
.insert({
|
||||||
@@ -51,12 +55,13 @@ export default class PaymentReceiveService extends JournalPosterService {
|
|||||||
});
|
});
|
||||||
const customerIncrementOper = Customer.decrementBalance(
|
const customerIncrementOper = Customer.decrementBalance(
|
||||||
paymentReceive.customer_id,
|
paymentReceive.customer_id,
|
||||||
paymentAmount
|
paymentAmount,
|
||||||
);
|
);
|
||||||
|
// Records the sale invoice journal transactions.
|
||||||
const recordJournalTransactions = this.recordPaymentReceiveJournalEntries({
|
const recordJournalTransactions = this.recordPaymentReceiveJournalEntries({
|
||||||
id: storedPaymentReceive.id,
|
id: storedPaymentReceive.id,
|
||||||
...paymentReceive,
|
...paymentReceive,
|
||||||
});
|
});
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
...storeOpers,
|
...storeOpers,
|
||||||
customerIncrementOper,
|
customerIncrementOper,
|
||||||
@@ -81,9 +86,9 @@ export default class PaymentReceiveService extends JournalPosterService {
|
|||||||
* @param {IPaymentReceive} oldPaymentReceive
|
* @param {IPaymentReceive} oldPaymentReceive
|
||||||
*/
|
*/
|
||||||
static async editPaymentReceive(
|
static async editPaymentReceive(
|
||||||
paymentReceiveId,
|
paymentReceiveId: number,
|
||||||
paymentReceive,
|
paymentReceive: any,
|
||||||
oldPaymentReceive
|
oldPaymentReceive: any
|
||||||
) {
|
) {
|
||||||
const paymentAmount = sumBy(paymentReceive.entries, 'payment_amount');
|
const paymentAmount = sumBy(paymentReceive.entries, 'payment_amount');
|
||||||
// Update the payment receive transaction.
|
// Update the payment receive transaction.
|
||||||
@@ -129,14 +134,14 @@ export default class PaymentReceiveService extends JournalPosterService {
|
|||||||
id: oldPaymentReceive.id,
|
id: oldPaymentReceive.id,
|
||||||
...paymentReceive,
|
...paymentReceive,
|
||||||
},
|
},
|
||||||
paymentReceiveId
|
paymentReceiveId,
|
||||||
);
|
);
|
||||||
// Increment/decrement the customer balance after calc the diff
|
// Increment/decrement the customer balance after calc the diff
|
||||||
// between old and new value.
|
// between old and new value.
|
||||||
const changeCustomerBalance = CustomerRepository.changeDiffBalance(
|
const changeCustomerBalance = CustomerRepository.changeDiffBalance(
|
||||||
paymentReceive.customer_id,
|
paymentReceive.customer_id,
|
||||||
oldPaymentReceive.customerId,
|
oldPaymentReceive.customerId,
|
||||||
paymentAmount,
|
paymentAmount * -1,
|
||||||
oldPaymentReceive.amount,
|
oldPaymentReceive.amount,
|
||||||
);
|
);
|
||||||
// Change the difference between the old and new invoice payment amount.
|
// Change the difference between the old and new invoice payment amount.
|
||||||
@@ -164,8 +169,9 @@ export default class PaymentReceiveService extends JournalPosterService {
|
|||||||
* - Revert the payment amount of the associated invoices.
|
* - Revert the payment amount of the associated invoices.
|
||||||
* @async
|
* @async
|
||||||
* @param {Integer} paymentReceiveId
|
* @param {Integer} paymentReceiveId
|
||||||
|
* @param {IPaymentReceive} paymentReceive
|
||||||
*/
|
*/
|
||||||
static async deletePaymentReceive(paymentReceiveId, paymentReceive) {
|
static async deletePaymentReceive(paymentReceiveId: number, paymentReceive: any) {
|
||||||
// Deletes the payment receive transaction.
|
// Deletes the payment receive transaction.
|
||||||
await PaymentReceive.tenant()
|
await PaymentReceive.tenant()
|
||||||
.query()
|
.query()
|
||||||
@@ -179,7 +185,7 @@ export default class PaymentReceiveService extends JournalPosterService {
|
|||||||
.delete();
|
.delete();
|
||||||
|
|
||||||
// Delete all associated journal transactions to payment receive transaction.
|
// Delete all associated journal transactions to payment receive transaction.
|
||||||
const deleteTransactionsOper = this.deleteJournalTransactions(
|
const deleteTransactionsOper = JournalPosterService.deleteJournalTransactions(
|
||||||
paymentReceiveId,
|
paymentReceiveId,
|
||||||
'PaymentReceive'
|
'PaymentReceive'
|
||||||
);
|
);
|
||||||
@@ -190,7 +196,7 @@ export default class PaymentReceiveService extends JournalPosterService {
|
|||||||
);
|
);
|
||||||
// Revert the invoices payments amount.
|
// Revert the invoices payments amount.
|
||||||
const revertInvoicesPaymentAmount = this.revertInvoicePaymentAmount(
|
const revertInvoicesPaymentAmount = this.revertInvoicePaymentAmount(
|
||||||
paymentReceive.entries.map((entry) => ({
|
paymentReceive.entries.map((entry: any) => ({
|
||||||
invoiceId: entry.invoiceId,
|
invoiceId: entry.invoiceId,
|
||||||
revertAmount: entry.paymentAmount,
|
revertAmount: entry.paymentAmount,
|
||||||
}))
|
}))
|
||||||
@@ -206,7 +212,7 @@ export default class PaymentReceiveService extends JournalPosterService {
|
|||||||
* Retrieve the payment receive details of the given id.
|
* Retrieve the payment receive details of the given id.
|
||||||
* @param {Integer} paymentReceiveId
|
* @param {Integer} paymentReceiveId
|
||||||
*/
|
*/
|
||||||
static async getPaymentReceive(paymentReceiveId) {
|
static async getPaymentReceive(paymentReceiveId: number) {
|
||||||
const paymentReceive = await PaymentReceive.tenant()
|
const paymentReceive = await PaymentReceive.tenant()
|
||||||
.query()
|
.query()
|
||||||
.where('id', paymentReceiveId)
|
.where('id', paymentReceiveId)
|
||||||
@@ -219,7 +225,7 @@ export default class PaymentReceiveService extends JournalPosterService {
|
|||||||
* Retrieve the payment receive details with associated invoices.
|
* Retrieve the payment receive details with associated invoices.
|
||||||
* @param {Integer} paymentReceiveId
|
* @param {Integer} paymentReceiveId
|
||||||
*/
|
*/
|
||||||
static async getPaymentReceiveWithInvoices(paymentReceiveId) {
|
static async getPaymentReceiveWithInvoices(paymentReceiveId: number) {
|
||||||
return PaymentReceive.tenant()
|
return PaymentReceive.tenant()
|
||||||
.query()
|
.query()
|
||||||
.where('id', paymentReceiveId)
|
.where('id', paymentReceiveId)
|
||||||
@@ -231,7 +237,7 @@ export default class PaymentReceiveService extends JournalPosterService {
|
|||||||
* Detarmines whether the payment receive exists on the storage.
|
* Detarmines whether the payment receive exists on the storage.
|
||||||
* @param {Integer} paymentReceiveId
|
* @param {Integer} paymentReceiveId
|
||||||
*/
|
*/
|
||||||
static async isPaymentReceiveExists(paymentReceiveId) {
|
static async isPaymentReceiveExists(paymentReceiveId: number) {
|
||||||
const paymentReceives = await PaymentReceive.tenant()
|
const paymentReceives = await PaymentReceive.tenant()
|
||||||
.query()
|
.query()
|
||||||
.where('id', paymentReceiveId);
|
.where('id', paymentReceiveId);
|
||||||
@@ -245,8 +251,8 @@ export default class PaymentReceiveService extends JournalPosterService {
|
|||||||
* @param {Integer} paymentReceiveId - Payment receive id.
|
* @param {Integer} paymentReceiveId - Payment receive id.
|
||||||
*/
|
*/
|
||||||
static async isPaymentReceiveNoExists(
|
static async isPaymentReceiveNoExists(
|
||||||
paymentReceiveNumber,
|
paymentReceiveNumber: string|number,
|
||||||
paymentReceiveId
|
paymentReceiveId: number
|
||||||
) {
|
) {
|
||||||
const paymentReceives = await PaymentReceive.tenant()
|
const paymentReceives = await PaymentReceive.tenant()
|
||||||
.query()
|
.query()
|
||||||
@@ -261,17 +267,22 @@ export default class PaymentReceiveService extends JournalPosterService {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Records payment receive journal transactions.
|
* Records payment receive journal transactions.
|
||||||
|
*
|
||||||
|
* Invoice payment journals.
|
||||||
|
* --------
|
||||||
|
* - Account receivable -> Debit
|
||||||
|
* - Payment account [current asset] -> Credit
|
||||||
|
*
|
||||||
* @async
|
* @async
|
||||||
* @param {IPaymentReceive} paymentReceive
|
* @param {IPaymentReceive} paymentReceive
|
||||||
|
* @param {Number} paymentReceiveId
|
||||||
*/
|
*/
|
||||||
static async recordPaymentReceiveJournalEntries(
|
static async recordPaymentReceiveJournalEntries(
|
||||||
paymentReceive,
|
paymentReceive: any,
|
||||||
paymentReceiveId
|
paymentReceiveId?: number
|
||||||
) {
|
) {
|
||||||
const paymentAmount = sumBy(paymentReceive.entries, 'payment_amount');
|
const paymentAmount = sumBy(paymentReceive.entries, 'payment_amount');
|
||||||
const formattedDate = moment(paymentReceive.payment_date).format(
|
const formattedDate = moment(paymentReceive.payment_date).format('YYYY-MM-DD');
|
||||||
'YYYY-MM-DD'
|
|
||||||
);
|
|
||||||
const receivableAccount = await AccountsService.getAccountByType(
|
const receivableAccount = await AccountsService.getAccountByType(
|
||||||
'accounts_receivable'
|
'accounts_receivable'
|
||||||
);
|
);
|
||||||
@@ -320,8 +331,8 @@ export default class PaymentReceiveService extends JournalPosterService {
|
|||||||
* Revert the payment amount of the given invoices ids.
|
* Revert the payment amount of the given invoices ids.
|
||||||
* @param {Array} revertInvoices
|
* @param {Array} revertInvoices
|
||||||
*/
|
*/
|
||||||
static async revertInvoicePaymentAmount(revertInvoices) {
|
static async revertInvoicePaymentAmount(revertInvoices: any[]) {
|
||||||
const opers = [];
|
const opers: Promise<T>[] = [];
|
||||||
|
|
||||||
revertInvoices.forEach((revertInvoice) => {
|
revertInvoices.forEach((revertInvoice) => {
|
||||||
const { revertAmount, invoiceId } = revertInvoice;
|
const { revertAmount, invoiceId } = revertInvoice;
|
||||||
@@ -338,13 +349,13 @@ export default class PaymentReceiveService extends JournalPosterService {
|
|||||||
* Saves difference changing between old and new invoice payment amount.
|
* Saves difference changing between old and new invoice payment amount.
|
||||||
* @param {Array} paymentReceiveEntries
|
* @param {Array} paymentReceiveEntries
|
||||||
* @param {Array} newPaymentReceiveEntries
|
* @param {Array} newPaymentReceiveEntries
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
static async saveChangeInvoicePaymentAmount(
|
static async saveChangeInvoicePaymentAmount(
|
||||||
paymentReceiveEntries,
|
paymentReceiveEntries: [],
|
||||||
newPaymentReceiveEntries
|
newPaymentReceiveEntries: [],
|
||||||
) {
|
) {
|
||||||
const opers = [];
|
const opers: Promise<T>[] = [];
|
||||||
const newEntriesTable = chain(newPaymentReceiveEntries)
|
const newEntriesTable = chain(newPaymentReceiveEntries)
|
||||||
.groupBy('invoice_id')
|
.groupBy('invoice_id')
|
||||||
.mapValues((group) => (sumBy(group, 'payment_amount') || 0) * -1)
|
.mapValues((group) => (sumBy(group, 'payment_amount') || 0) * -1)
|
||||||
@@ -359,7 +370,7 @@ export default class PaymentReceiveService extends JournalPosterService {
|
|||||||
.values()
|
.values()
|
||||||
.value();
|
.value();
|
||||||
|
|
||||||
diffEntries.forEach((diffEntry) => {
|
diffEntries.forEach((diffEntry: any) => {
|
||||||
const oper = SaleInvoice.changePaymentAmount(
|
const oper = SaleInvoice.changePaymentAmount(
|
||||||
diffEntry.invoice_id,
|
diffEntry.invoice_id,
|
||||||
diffEntry.payment_amount
|
diffEntry.payment_amount
|
||||||
@@ -1,15 +1,15 @@
|
|||||||
import { omit, difference, sumBy } from 'lodash';
|
import { omit, difference, sumBy, mixin } from 'lodash';
|
||||||
import { SaleEstimate, ItemEntry } from '@/models';
|
import { SaleEstimate, ItemEntry } from '@/models';
|
||||||
import ServiceItemsEntries from '@/services/Sales/ServiceItemsEntries';
|
import HasItemsEntries from '@/services/Sales/HasItemsEntries';
|
||||||
|
|
||||||
export default class SaleEstimateService extends ServiceItemsEntries {
|
export default class SaleEstimateService {
|
||||||
/**
|
/**
|
||||||
* Creates a new estimate with associated entries.
|
* Creates a new estimate with associated entries.
|
||||||
* @async
|
* @async
|
||||||
* @param {IEstimate} estimate
|
* @param {IEstimate} estimate
|
||||||
* @return {void}
|
* @return {void}
|
||||||
*/
|
*/
|
||||||
static async createEstimate(estimate) {
|
static async createEstimate(estimate: any) {
|
||||||
const amount = sumBy(estimate.entries, 'amount');
|
const amount = sumBy(estimate.entries, 'amount');
|
||||||
const storedEstimate = await SaleEstimate.tenant()
|
const storedEstimate = await SaleEstimate.tenant()
|
||||||
.query()
|
.query()
|
||||||
@@ -17,15 +17,15 @@ export default class SaleEstimateService extends ServiceItemsEntries {
|
|||||||
amount,
|
amount,
|
||||||
...omit(estimate, ['entries']),
|
...omit(estimate, ['entries']),
|
||||||
});
|
});
|
||||||
const storeEstimateEntriesOpers = [];
|
const storeEstimateEntriesOpers: any[] = [];
|
||||||
|
|
||||||
estimate.entries.forEach((entry) => {
|
estimate.entries.forEach((entry: any) => {
|
||||||
const oper = ItemEntry.tenant()
|
const oper = ItemEntry.tenant()
|
||||||
.query()
|
.query()
|
||||||
.insert({
|
.insert({
|
||||||
reference_type: 'SaleEstimate',
|
reference_type: 'SaleEstimate',
|
||||||
reference_id: storedEstimate.id,
|
reference_id: storedEstimate.id,
|
||||||
...omit(entry, ['total', 'amount']),
|
...omit(entry, ['total', 'amount', 'id']),
|
||||||
});
|
});
|
||||||
storeEstimateEntriesOpers.push(oper);
|
storeEstimateEntriesOpers.push(oper);
|
||||||
});
|
});
|
||||||
@@ -40,7 +40,7 @@ export default class SaleEstimateService extends ServiceItemsEntries {
|
|||||||
* @param {IEstimate} estimateId
|
* @param {IEstimate} estimateId
|
||||||
* @return {void}
|
* @return {void}
|
||||||
*/
|
*/
|
||||||
static async deleteEstimate(estimateId) {
|
static async deleteEstimate(estimateId: number) {
|
||||||
await ItemEntry.tenant()
|
await ItemEntry.tenant()
|
||||||
.query()
|
.query()
|
||||||
.where('reference_id', estimateId)
|
.where('reference_id', estimateId)
|
||||||
@@ -56,7 +56,7 @@ export default class SaleEstimateService extends ServiceItemsEntries {
|
|||||||
* @param {IEstimate} estimate
|
* @param {IEstimate} estimate
|
||||||
* @return {void}
|
* @return {void}
|
||||||
*/
|
*/
|
||||||
static async editEstimate(estimateId, estimate) {
|
static async editEstimate(estimateId: number, estimate: any) {
|
||||||
const amount = sumBy(estimate.entries, 'amount');
|
const amount = sumBy(estimate.entries, 'amount');
|
||||||
const updatedEstimate = await SaleEstimate.tenant()
|
const updatedEstimate = await SaleEstimate.tenant()
|
||||||
.query()
|
.query()
|
||||||
@@ -69,45 +69,12 @@ export default class SaleEstimateService extends ServiceItemsEntries {
|
|||||||
.where('reference_id', estimateId)
|
.where('reference_id', estimateId)
|
||||||
.where('reference_type', 'SaleEstimate');
|
.where('reference_type', 'SaleEstimate');
|
||||||
|
|
||||||
const opers = [];
|
const patchItemsEntries = HasItemsEntries.patchItemsEntries(
|
||||||
const entriesHasID = estimate.entries.filter((entry) => entry.id);
|
estimate.entries, storedEstimateEntries, 'SaleEstimate', estimateId
|
||||||
const entriesHasNoIDs = estimate.entries.filter((entry) => !entry.id);
|
|
||||||
|
|
||||||
const storedEntriesIds = storedEstimateEntries.map((e) => e.id);
|
|
||||||
const formEstimateEntriesIds = entriesHasID.map((entry) => entry.id);
|
|
||||||
|
|
||||||
const entriesIdsShouldBeDeleted = difference(
|
|
||||||
storedEntriesIds,
|
|
||||||
formEstimateEntriesIds,
|
|
||||||
);
|
);
|
||||||
// Deletes the given sale estimate entries ids.
|
return Promise.all([
|
||||||
if (entriesIdsShouldBeDeleted.length > 0) {
|
patchItemsEntries,
|
||||||
const oper = ItemEntry.tenant()
|
]);
|
||||||
.query()
|
|
||||||
.whereIn('id', entriesIdsShouldBeDeleted)
|
|
||||||
.delete();
|
|
||||||
opers.push(oper);
|
|
||||||
}
|
|
||||||
// Insert the new sale estimate entries.
|
|
||||||
entriesHasNoIDs.forEach((entry) => {
|
|
||||||
const oper = ItemEntry.tenant()
|
|
||||||
.query()
|
|
||||||
.insert({
|
|
||||||
reference_type: 'SaleEstimate',
|
|
||||||
reference_id: estimateId,
|
|
||||||
...entry,
|
|
||||||
});
|
|
||||||
opers.push(oper);
|
|
||||||
});
|
|
||||||
entriesHasID.forEach((entry) => {
|
|
||||||
const oper = ItemEntry.tenant()
|
|
||||||
.query()
|
|
||||||
.patchAndFetchById(entry.id, {
|
|
||||||
...omit(entry, ['id']),
|
|
||||||
});
|
|
||||||
opers.push(oper);
|
|
||||||
});
|
|
||||||
return Promise.all([...opers]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -116,7 +83,7 @@ export default class SaleEstimateService extends ServiceItemsEntries {
|
|||||||
* @param {Numeric} estimateId
|
* @param {Numeric} estimateId
|
||||||
* @return {Boolean}
|
* @return {Boolean}
|
||||||
*/
|
*/
|
||||||
static async isEstimateExists(estimateId) {
|
static async isEstimateExists(estimateId: number) {
|
||||||
const foundEstimate = await SaleEstimate.tenant()
|
const foundEstimate = await SaleEstimate.tenant()
|
||||||
.query()
|
.query()
|
||||||
.where('id', estimateId);
|
.where('id', estimateId);
|
||||||
@@ -129,7 +96,7 @@ export default class SaleEstimateService extends ServiceItemsEntries {
|
|||||||
* @param {Numeric} estimateId
|
* @param {Numeric} estimateId
|
||||||
* @param {IEstimate} estimate
|
* @param {IEstimate} estimate
|
||||||
*/
|
*/
|
||||||
static async isEstimateEntriesIDsExists(estimateId, estimate) {
|
static async isEstimateEntriesIDsExists(estimateId: number, estimate: any) {
|
||||||
const estimateEntriesIds = estimate.entries
|
const estimateEntriesIds = estimate.entries
|
||||||
.filter((e) => e.id)
|
.filter((e) => e.id)
|
||||||
.map((e) => e.id);
|
.map((e) => e.id);
|
||||||
@@ -140,7 +107,7 @@ export default class SaleEstimateService extends ServiceItemsEntries {
|
|||||||
.where('reference_id', estimateId)
|
.where('reference_id', estimateId)
|
||||||
.where('reference_type', 'SaleEstimate');
|
.where('reference_type', 'SaleEstimate');
|
||||||
|
|
||||||
const storedEstimateEntriesIds = estimateEntries.map((e) => e.id);
|
const storedEstimateEntriesIds = estimateEntries.map((e: any) => e.id);
|
||||||
const notFoundEntriesIDs = difference(
|
const notFoundEntriesIDs = difference(
|
||||||
estimateEntriesIds,
|
estimateEntriesIds,
|
||||||
storedEstimateEntriesIds
|
storedEstimateEntriesIds
|
||||||
@@ -153,7 +120,7 @@ export default class SaleEstimateService extends ServiceItemsEntries {
|
|||||||
* @param {Integer} estimateId
|
* @param {Integer} estimateId
|
||||||
* @return {IEstimate}
|
* @return {IEstimate}
|
||||||
*/
|
*/
|
||||||
static async getEstimate(estimateId) {
|
static async getEstimate(estimateId: number) {
|
||||||
const estimate = await SaleEstimate.tenant()
|
const estimate = await SaleEstimate.tenant()
|
||||||
.query()
|
.query()
|
||||||
.where('id', estimateId)
|
.where('id', estimateId)
|
||||||
@@ -166,7 +133,7 @@ export default class SaleEstimateService extends ServiceItemsEntries {
|
|||||||
* Retrieve the estimate details with associated entries.
|
* Retrieve the estimate details with associated entries.
|
||||||
* @param {Integer} estimateId
|
* @param {Integer} estimateId
|
||||||
*/
|
*/
|
||||||
static async getEstimateWithEntries(estimateId) {
|
static async getEstimateWithEntries(estimateId: number) {
|
||||||
const estimate = await SaleEstimate.tenant()
|
const estimate = await SaleEstimate.tenant()
|
||||||
.query()
|
.query()
|
||||||
.where('id', estimateId)
|
.where('id', estimateId)
|
||||||
@@ -178,14 +145,14 @@ export default class SaleEstimateService extends ServiceItemsEntries {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Detarmines the estimate number uniqness.
|
* Detarmines the estimate number uniqness.
|
||||||
* @param {Integer} estimateNumber
|
* @param {String} estimateNumber
|
||||||
* @param {Integer} excludeEstimateId
|
* @param {Integer} excludeEstimateId
|
||||||
* @return {Boolean}
|
* @return {Boolean}
|
||||||
*/
|
*/
|
||||||
static async isEstimateNumberUnique(estimateNumber, excludeEstimateId) {
|
static async isEstimateNumberUnique(estimateNumber: string, excludeEstimateId: number) {
|
||||||
const foundEstimates = await SaleEstimate.tenant()
|
const foundEstimates = await SaleEstimate.tenant()
|
||||||
.query()
|
.query()
|
||||||
.onBuild((query) => {
|
.onBuild((query: any) => {
|
||||||
query.where('estimate_number', estimateNumber);
|
query.where('estimate_number', estimateNumber);
|
||||||
|
|
||||||
if (excludeEstimateId) {
|
if (excludeEstimateId) {
|
||||||
@@ -195,4 +162,4 @@ export default class SaleEstimateService extends ServiceItemsEntries {
|
|||||||
});
|
});
|
||||||
return foundEstimates.length > 0;
|
return foundEstimates.length > 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3,21 +3,26 @@ import {
|
|||||||
SaleInvoice,
|
SaleInvoice,
|
||||||
AccountTransaction,
|
AccountTransaction,
|
||||||
Account,
|
Account,
|
||||||
Item,
|
|
||||||
ItemEntry,
|
ItemEntry,
|
||||||
Customer,
|
Customer,
|
||||||
} from '@/models';
|
} from '@/models';
|
||||||
import JournalPoster from '@/services/Accounting/JournalPoster';
|
import JournalPoster from '@/services/Accounting/JournalPoster';
|
||||||
import ServiceItemsEntries from '@/services/Sales/ServiceItemsEntries';
|
import HasItemsEntries from '@/services/Sales/HasItemsEntries';
|
||||||
|
import CustomerRepository from '@/repositories/CustomerRepository';
|
||||||
|
|
||||||
export default class SaleInvoicesService extends ServiceItemsEntries {
|
/**
|
||||||
|
* Sales invoices service
|
||||||
|
* @service
|
||||||
|
*/
|
||||||
|
export default class SaleInvoicesService {
|
||||||
/**
|
/**
|
||||||
* Creates a new sale invoices and store it to the storage
|
* Creates a new sale invoices and store it to the storage
|
||||||
* with associated to entries and journal transactions.
|
* with associated to entries and journal transactions.
|
||||||
|
* @async
|
||||||
* @param {ISaleInvoice}
|
* @param {ISaleInvoice}
|
||||||
* @return {ISaleInvoice}
|
* @return {ISaleInvoice}
|
||||||
*/
|
*/
|
||||||
static async createSaleInvoice(saleInvoice) {
|
static async createSaleInvoice(saleInvoice: any) {
|
||||||
const balance = sumBy(saleInvoice.entries, 'amount');
|
const balance = sumBy(saleInvoice.entries, 'amount');
|
||||||
const storedInvoice = await SaleInvoice.tenant()
|
const storedInvoice = await SaleInvoice.tenant()
|
||||||
.query()
|
.query()
|
||||||
@@ -26,9 +31,9 @@ export default class SaleInvoicesService extends ServiceItemsEntries {
|
|||||||
balance,
|
balance,
|
||||||
payment_amount: 0,
|
payment_amount: 0,
|
||||||
});
|
});
|
||||||
const opers = [];
|
const opers: Array<any> = [];
|
||||||
|
|
||||||
saleInvoice.entries.forEach((entry) => {
|
saleInvoice.entries.forEach((entry: any) => {
|
||||||
const oper = ItemEntry.tenant()
|
const oper = ItemEntry.tenant()
|
||||||
.query()
|
.query()
|
||||||
.insert({
|
.insert({
|
||||||
@@ -47,79 +52,56 @@ export default class SaleInvoicesService extends ServiceItemsEntries {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Records the journal entries of sale invoice.
|
* Edit the given sale invoice.
|
||||||
* @param {ISaleInvoice} saleInvoice
|
* @async
|
||||||
* @return {void}
|
* @param {Number} saleInvoiceId -
|
||||||
|
* @param {ISaleInvoice} saleInvoice -
|
||||||
*/
|
*/
|
||||||
async recordJournalEntries(saleInvoice) {
|
static async editSaleInvoice(saleInvoiceId: number, saleInvoice: any) {
|
||||||
const accountsDepGraph = await Account.depGraph().query().remember();
|
const balance = sumBy(saleInvoice.entries, 'amount');
|
||||||
const journal = new JournalPoster(accountsDepGraph);
|
const oldSaleInvoice = await SaleInvoice.tenant().query()
|
||||||
const receivableTotal = sumBy(saleInvoice.entries, 'total');
|
.where('id', saleInvoiceId)
|
||||||
|
.first();
|
||||||
|
|
||||||
const receivableAccount = await Account.tenant().query();
|
const updatedSaleInvoices = await SaleInvoice.tenant()
|
||||||
const formattedDate = moment(saleInvoice.invoice_date).format('YYYY-MM-DD');
|
|
||||||
|
|
||||||
const saleItemsIds = saleInvoice.entries.map((e) => e.item_id);
|
|
||||||
const storedInvoiceItems = await Item.tenant()
|
|
||||||
.query()
|
.query()
|
||||||
.whereIn('id', saleItemsIds);
|
.where('id', saleInvoiceId)
|
||||||
|
.update({
|
||||||
const commonJournalMeta = {
|
balance,
|
||||||
debit: 0,
|
...omit(saleInvoice, ['entries']),
|
||||||
credit: 0,
|
|
||||||
referenceId: saleInvoice.id,
|
|
||||||
referenceType: 'SaleInvoice',
|
|
||||||
date: formattedDate,
|
|
||||||
};
|
|
||||||
const totalReceivableEntry = new journalEntry({
|
|
||||||
...commonJournalMeta,
|
|
||||||
debit: receivableTotal,
|
|
||||||
account: receivableAccount.id,
|
|
||||||
accountNormal: 'debit',
|
|
||||||
});
|
|
||||||
journal.debit(totalReceivableEntry);
|
|
||||||
|
|
||||||
saleInvoice.entries.forEach((entry) => {
|
|
||||||
const item = {};
|
|
||||||
const incomeEntry = JournalEntry({
|
|
||||||
...commonJournalMeta,
|
|
||||||
credit: entry.total,
|
|
||||||
account: item.sellAccountId,
|
|
||||||
accountNormal: 'credit',
|
|
||||||
note: '',
|
|
||||||
});
|
});
|
||||||
|
// Fetches the sale invoice items entries.
|
||||||
|
const storedEntries = await ItemEntry.tenant()
|
||||||
|
.query()
|
||||||
|
.where('reference_id', saleInvoiceId)
|
||||||
|
.where('reference_type', 'SaleInvoice');
|
||||||
|
|
||||||
if (item.type === 'inventory') {
|
// Patch update the sale invoice items entries.
|
||||||
const inventoryCredit = JournalEntry({
|
const patchItemsEntriesOper = HasItemsEntries.patchItemsEntries(
|
||||||
...commonJournalMeta,
|
saleInvoice.entries, storedEntries, 'SaleInvoice', saleInvoiceId,
|
||||||
credit: entry.total,
|
);
|
||||||
account: item.inventoryAccountId,
|
// Changes the diff customer balance between old and new amount.
|
||||||
accountNormal: 'credit',
|
const changeCustomerBalanceOper = CustomerRepository.changeDiffBalance(
|
||||||
note: '',
|
saleInvoice.customer_id,
|
||||||
});
|
oldSaleInvoice.customerId,
|
||||||
const costEntry = JournalEntry({
|
balance,
|
||||||
...commonJournalMeta,
|
oldSaleInvoice.balance,
|
||||||
debit: entry.total,
|
);
|
||||||
account: item.costAccountId,
|
|
||||||
accountNormal: 'debit',
|
|
||||||
note: '',
|
|
||||||
});
|
|
||||||
journal.debit(costEntry);
|
|
||||||
}
|
|
||||||
journal.credit(incomeEntry);
|
|
||||||
});
|
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
journalPoster.saveEntries(),
|
patchItemsEntriesOper,
|
||||||
journalPoster.saveBalance(),
|
changeCustomerBalanceOper,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes the given sale invoice with associated entries
|
* Deletes the given sale invoice with associated entries
|
||||||
* and journal transactions.
|
* and journal transactions.
|
||||||
* @param {Integer} saleInvoiceId
|
* @async
|
||||||
|
* @param {Number} saleInvoiceId
|
||||||
*/
|
*/
|
||||||
static async deleteSaleInvoice(saleInvoiceId) {
|
static async deleteSaleInvoice(saleInvoiceId: number) {
|
||||||
|
const oldSaleInvoice = await SaleInvoice.tenant().query().findById(saleInvoiceId);
|
||||||
|
|
||||||
await SaleInvoice.tenant().query().where('id', saleInvoiceId).delete();
|
await SaleInvoice.tenant().query().where('id', saleInvoiceId).delete();
|
||||||
await ItemEntry.tenant()
|
await ItemEntry.tenant()
|
||||||
.query()
|
.query()
|
||||||
@@ -127,6 +109,10 @@ export default class SaleInvoicesService extends ServiceItemsEntries {
|
|||||||
.where('reference_type', 'SaleInvoice')
|
.where('reference_type', 'SaleInvoice')
|
||||||
.delete();
|
.delete();
|
||||||
|
|
||||||
|
const revertCustomerBalanceOper = Customer.changeBalance(
|
||||||
|
oldSaleInvoice.customerId,
|
||||||
|
oldSaleInvoice.balance * -1,
|
||||||
|
);
|
||||||
const invoiceTransactions = await AccountTransaction.tenant()
|
const invoiceTransactions = await AccountTransaction.tenant()
|
||||||
.query()
|
.query()
|
||||||
.whereIn('reference_type', ['SaleInvoice'])
|
.whereIn('reference_type', ['SaleInvoice'])
|
||||||
@@ -139,68 +125,29 @@ export default class SaleInvoicesService extends ServiceItemsEntries {
|
|||||||
journal.loadEntries(invoiceTransactions);
|
journal.loadEntries(invoiceTransactions);
|
||||||
journal.removeEntries();
|
journal.removeEntries();
|
||||||
|
|
||||||
await Promise.all([journal.deleteEntries(), journal.saveBalance()]);
|
await Promise.all([
|
||||||
|
journal.deleteEntries(),
|
||||||
|
journal.saveBalance(),
|
||||||
|
revertCustomerBalanceOper,
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Edit the given sale invoice.
|
* Records the journal entries of sale invoice.
|
||||||
* @param {Integer} saleInvoiceId -
|
* @async
|
||||||
* @param {ISaleInvoice} saleInvoice -
|
* @param {ISaleInvoice} saleInvoice
|
||||||
|
* @return {void}
|
||||||
*/
|
*/
|
||||||
static async editSaleInvoice(saleInvoiceId, saleInvoice) {
|
async recordJournalEntries(saleInvoice: any) {
|
||||||
const updatedSaleInvoices = await SaleInvoice.tenant()
|
|
||||||
.query()
|
|
||||||
.where('id', saleInvoiceId)
|
|
||||||
.update({
|
|
||||||
...omit(saleInvoice, ['entries']),
|
|
||||||
});
|
|
||||||
const opers = [];
|
|
||||||
const entriesIds = saleInvoice.entries.filter((entry) => entry.id);
|
|
||||||
const entriesNoIds = saleInvoice.entries.filter((entry) => !entry.id);
|
|
||||||
|
|
||||||
const storedEntries = await ItemEntry.tenant()
|
|
||||||
.query()
|
|
||||||
.where('reference_id', saleInvoiceId)
|
|
||||||
.where('reference_type', 'SaleInvoice');
|
|
||||||
|
|
||||||
const entriesIdsShouldDelete = this.entriesShouldDeleted(
|
|
||||||
storedEntries,
|
|
||||||
entriesIds
|
|
||||||
);
|
|
||||||
if (entriesIdsShouldDelete.length > 0) {
|
|
||||||
const updateOper = ItemEntry.tenant()
|
|
||||||
.query()
|
|
||||||
.whereIn('id', entriesIdsShouldDelete)
|
|
||||||
.delete();
|
|
||||||
opers.push(updateOper);
|
|
||||||
}
|
|
||||||
entriesIds.forEach((entry) => {
|
|
||||||
const updateOper = ItemEntry.tenant()
|
|
||||||
.query()
|
|
||||||
.where('id', entry.id)
|
|
||||||
.update({
|
|
||||||
...omit(entry, ['id']),
|
|
||||||
});
|
|
||||||
opers.push(updateOper);
|
|
||||||
});
|
|
||||||
entriesNoIds.forEach((entry) => {
|
|
||||||
const insertOper = ItemEntry.tenant()
|
|
||||||
.query()
|
|
||||||
.insert({
|
|
||||||
reference_type: 'SaleInvoice',
|
|
||||||
reference_id: saleInvoiceId,
|
|
||||||
...omit(entry, ['id']),
|
|
||||||
});
|
|
||||||
opers.push(insertOper);
|
|
||||||
})
|
|
||||||
await Promise.all([...opers]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve sale invoice with associated entries.
|
* Retrieve sale invoice with associated entries.
|
||||||
* @param {Integer} saleInvoiceId
|
* @async
|
||||||
|
* @param {Number} saleInvoiceId
|
||||||
*/
|
*/
|
||||||
static async getSaleInvoiceWithEntries(saleInvoiceId) {
|
static async getSaleInvoiceWithEntries(saleInvoiceId: number) {
|
||||||
return SaleInvoice.tenant().query()
|
return SaleInvoice.tenant().query()
|
||||||
.where('id', saleInvoiceId)
|
.where('id', saleInvoiceId)
|
||||||
.withGraphFetched('entries')
|
.withGraphFetched('entries')
|
||||||
@@ -212,7 +159,7 @@ export default class SaleInvoicesService extends ServiceItemsEntries {
|
|||||||
* @param {Integer} saleInvoiceId
|
* @param {Integer} saleInvoiceId
|
||||||
* @return {Boolean}
|
* @return {Boolean}
|
||||||
*/
|
*/
|
||||||
static async isSaleInvoiceExists(saleInvoiceId) {
|
static async isSaleInvoiceExists(saleInvoiceId: number) {
|
||||||
const foundSaleInvoice = await SaleInvoice.tenant()
|
const foundSaleInvoice = await SaleInvoice.tenant()
|
||||||
.query()
|
.query()
|
||||||
.where('id', saleInvoiceId);
|
.where('id', saleInvoiceId);
|
||||||
@@ -221,10 +168,12 @@ export default class SaleInvoicesService extends ServiceItemsEntries {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Detarmines the sale invoice number exists on the storage.
|
* Detarmines the sale invoice number exists on the storage.
|
||||||
* @param {Integer} saleInvoiceNumber
|
* @async
|
||||||
|
* @param {Number|String} saleInvoiceNumber
|
||||||
|
* @param {Number} saleInvoiceId
|
||||||
* @return {Boolean}
|
* @return {Boolean}
|
||||||
*/
|
*/
|
||||||
static async isSaleInvoiceNumberExists(saleInvoiceNumber, saleInvoiceId) {
|
static async isSaleInvoiceNumberExists(saleInvoiceNumber: string|number, saleInvoiceId: number) {
|
||||||
const foundSaleInvoice = await SaleInvoice.tenant()
|
const foundSaleInvoice = await SaleInvoice.tenant()
|
||||||
.query()
|
.query()
|
||||||
.onBuild((query) => {
|
.onBuild((query) => {
|
||||||
@@ -243,7 +192,7 @@ export default class SaleInvoicesService extends ServiceItemsEntries {
|
|||||||
* @param {Array} invoicesIds
|
* @param {Array} invoicesIds
|
||||||
* @return {Array}
|
* @return {Array}
|
||||||
*/
|
*/
|
||||||
static async isInvoicesExist(invoicesIds) {
|
static async isInvoicesExist(invoicesIds: Array<number>) {
|
||||||
const storedInvoices = await SaleInvoice.tenant()
|
const storedInvoices = await SaleInvoice.tenant()
|
||||||
.query()
|
.query()
|
||||||
.onBuild((builder) => {
|
.onBuild((builder) => {
|
||||||
@@ -2,19 +2,20 @@ import { omit, difference, sumBy } from 'lodash';
|
|||||||
import {
|
import {
|
||||||
SaleReceipt,
|
SaleReceipt,
|
||||||
Account,
|
Account,
|
||||||
|
ItemEntry,
|
||||||
} from '@/models';
|
} from '@/models';
|
||||||
import JournalPoster from '@/services/Accounting/JournalPoster';
|
import JournalPoster from '@/services/Accounting/JournalPoster';
|
||||||
import ItemEntry from '../../models/ItemEntry';
|
|
||||||
import JournalPosterService from '@/services/Sales/JournalPosterService';
|
import JournalPosterService from '@/services/Sales/JournalPosterService';
|
||||||
|
import HasItemEntries from '@/services/Sales/HasItemsEntries';
|
||||||
|
|
||||||
export default class SalesReceipt extends JournalPosterService {
|
export default class SalesReceipt {
|
||||||
/**
|
/**
|
||||||
* Creates a new sale receipt with associated entries.
|
* Creates a new sale receipt with associated entries.
|
||||||
* @async
|
* @async
|
||||||
* @param {ISaleReceipt} saleReceipt
|
* @param {ISaleReceipt} saleReceipt
|
||||||
* @return {Object}
|
* @return {Object}
|
||||||
*/
|
*/
|
||||||
static async createSaleReceipt(saleReceipt) {
|
static async createSaleReceipt(saleReceipt: any) {
|
||||||
const amount = sumBy(saleReceipt.entries, 'amount');
|
const amount = sumBy(saleReceipt.entries, 'amount');
|
||||||
const storedSaleReceipt = await SaleReceipt.tenant()
|
const storedSaleReceipt = await SaleReceipt.tenant()
|
||||||
.query()
|
.query()
|
||||||
@@ -22,9 +23,9 @@ export default class SalesReceipt extends JournalPosterService {
|
|||||||
amount,
|
amount,
|
||||||
...omit(saleReceipt, ['entries']),
|
...omit(saleReceipt, ['entries']),
|
||||||
});
|
});
|
||||||
const storeSaleReceiptEntriesOpers = [];
|
const storeSaleReceiptEntriesOpers: Array<any> = [];
|
||||||
|
|
||||||
saleReceipt.entries.forEach((entry) => {
|
saleReceipt.entries.forEach((entry: any) => {
|
||||||
const oper = ItemEntry.tenant()
|
const oper = ItemEntry.tenant()
|
||||||
.query()
|
.query()
|
||||||
.insert({
|
.insert({
|
||||||
@@ -43,7 +44,7 @@ export default class SalesReceipt extends JournalPosterService {
|
|||||||
* @param {ISaleReceipt} saleReceipt
|
* @param {ISaleReceipt} saleReceipt
|
||||||
* @return {Promise}
|
* @return {Promise}
|
||||||
*/
|
*/
|
||||||
static async _recordJournalTransactions(saleReceipt) {
|
static async _recordJournalTransactions(saleReceipt: any) {
|
||||||
const accountsDepGraph = await Account.tenant().depGraph().query();
|
const accountsDepGraph = await Account.tenant().depGraph().query();
|
||||||
const journalPoster = new JournalPoster(accountsDepGraph);
|
const journalPoster = new JournalPoster(accountsDepGraph);
|
||||||
}
|
}
|
||||||
@@ -54,7 +55,7 @@ export default class SalesReceipt extends JournalPosterService {
|
|||||||
* @param {ISaleReceipt} saleReceipt
|
* @param {ISaleReceipt} saleReceipt
|
||||||
* @return {void}
|
* @return {void}
|
||||||
*/
|
*/
|
||||||
static async editSaleReceipt(saleReceiptId, saleReceipt) {
|
static async editSaleReceipt(saleReceiptId: number, saleReceipt: any) {
|
||||||
const amount = sumBy(saleReceipt.entries, 'amount');
|
const amount = sumBy(saleReceipt.entries, 'amount');
|
||||||
const updatedSaleReceipt = await SaleReceipt.tenant()
|
const updatedSaleReceipt = await SaleReceipt.tenant()
|
||||||
.query()
|
.query()
|
||||||
@@ -68,32 +69,11 @@ export default class SalesReceipt extends JournalPosterService {
|
|||||||
.where('reference_id', saleReceiptId)
|
.where('reference_id', saleReceiptId)
|
||||||
.where('reference_type', 'SaleReceipt');
|
.where('reference_type', 'SaleReceipt');
|
||||||
|
|
||||||
const storedSaleReceiptsIds = storedSaleReceiptEntries.map((e) => e.id);
|
// Patch sale receipt items entries.
|
||||||
const entriesHasID = saleReceipt.entries.filter((entry) => entry.id);
|
const patchItemsEntries = HasItemEntries.patchItemsEntries(
|
||||||
const entriesIds = entriesHasID.map((e) => e.id);
|
saleReceipt.entries, storedSaleReceiptEntries, 'SaleReceipt', saleReceiptId,
|
||||||
|
|
||||||
const opers = [];
|
|
||||||
const entriesIdsShouldBeDeleted = difference(
|
|
||||||
storedSaleReceiptsIds,
|
|
||||||
entriesIds
|
|
||||||
);
|
);
|
||||||
if (entriesIdsShouldBeDeleted.length > 0) {
|
return Promise.all([patchItemsEntries]);
|
||||||
const deleteOper = ItemEntry.tenant()
|
|
||||||
.query()
|
|
||||||
.whereIn('id', entriesIdsShouldBeDeleted)
|
|
||||||
.where('reference_type', 'SaleReceipt')
|
|
||||||
.delete();
|
|
||||||
opers.push(deleteOper);
|
|
||||||
}
|
|
||||||
entriesHasID.forEach((entry) => {
|
|
||||||
const updateOper = ItemEntry.tenant()
|
|
||||||
.query()
|
|
||||||
.patchAndFetchById(entry.id, {
|
|
||||||
...omit(entry, ['id']),
|
|
||||||
});
|
|
||||||
opers.push(updateOper);
|
|
||||||
});
|
|
||||||
return Promise.all([...opers]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -101,20 +81,22 @@ export default class SalesReceipt extends JournalPosterService {
|
|||||||
* @param {Integer} saleReceiptId
|
* @param {Integer} saleReceiptId
|
||||||
* @return {void}
|
* @return {void}
|
||||||
*/
|
*/
|
||||||
static async deleteSaleReceipt(saleReceiptId) {
|
static async deleteSaleReceipt(saleReceiptId: number) {
|
||||||
await SaleReceipt.tenant().query().where('id', saleReceiptId).delete();
|
const deleteSaleReceiptOper = SaleReceipt.tenant().query().where('id', saleReceiptId).delete();
|
||||||
await ItemEntry.tenant()
|
const deleteItemsEntriesOper = ItemEntry.tenant()
|
||||||
.query()
|
.query()
|
||||||
.where('reference_id', saleReceiptId)
|
.where('reference_id', saleReceiptId)
|
||||||
.where('reference_type', 'SaleReceipt')
|
.where('reference_type', 'SaleReceipt')
|
||||||
.delete();
|
.delete();
|
||||||
|
|
||||||
// Delete all associated journal transactions to payment receive transaction.
|
// Delete all associated journal transactions to payment receive transaction.
|
||||||
const deleteTransactionsOper = this.deleteJournalTransactions(
|
const deleteTransactionsOper = JournalPosterService.deleteJournalTransactions(
|
||||||
saleReceiptId,
|
saleReceiptId,
|
||||||
'SaleReceipt'
|
'SaleReceipt'
|
||||||
);
|
);
|
||||||
return Promise.all([
|
return Promise.all([
|
||||||
|
deleteItemsEntriesOper,
|
||||||
|
deleteSaleReceiptOper,
|
||||||
deleteTransactionsOper,
|
deleteTransactionsOper,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
@@ -124,7 +106,7 @@ export default class SalesReceipt extends JournalPosterService {
|
|||||||
* @param {Integer} saleReceiptId
|
* @param {Integer} saleReceiptId
|
||||||
* @returns {Boolean}
|
* @returns {Boolean}
|
||||||
*/
|
*/
|
||||||
static async isSaleReceiptExists(saleReceiptId) {
|
static async isSaleReceiptExists(saleReceiptId: number) {
|
||||||
const foundSaleReceipt = await SaleReceipt.tenant()
|
const foundSaleReceipt = await SaleReceipt.tenant()
|
||||||
.query()
|
.query()
|
||||||
.where('id', saleReceiptId);
|
.where('id', saleReceiptId);
|
||||||
@@ -136,7 +118,7 @@ export default class SalesReceipt extends JournalPosterService {
|
|||||||
* @param {Integer} saleReceiptId
|
* @param {Integer} saleReceiptId
|
||||||
* @param {ISaleReceipt} saleReceipt
|
* @param {ISaleReceipt} saleReceipt
|
||||||
*/
|
*/
|
||||||
static async isSaleReceiptEntriesIDsExists(saleReceiptId, saleReceipt) {
|
static async isSaleReceiptEntriesIDsExists(saleReceiptId: number, saleReceipt: any) {
|
||||||
const entriesIDs = saleReceipt.entries
|
const entriesIDs = saleReceipt.entries
|
||||||
.filter((e) => e.id)
|
.filter((e) => e.id)
|
||||||
.map((e) => e.id);
|
.map((e) => e.id);
|
||||||
@@ -147,7 +129,7 @@ export default class SalesReceipt extends JournalPosterService {
|
|||||||
.where('reference_id', saleReceiptId)
|
.where('reference_id', saleReceiptId)
|
||||||
.where('reference_type', 'SaleReceipt');
|
.where('reference_type', 'SaleReceipt');
|
||||||
|
|
||||||
const storedEntriesIDs = storedEntries.map((e) => e.id);
|
const storedEntriesIDs = storedEntries.map((e: any) => e.id);
|
||||||
const notFoundEntriesIDs = difference(
|
const notFoundEntriesIDs = difference(
|
||||||
entriesIDs,
|
entriesIDs,
|
||||||
storedEntriesIDs
|
storedEntriesIDs
|
||||||
@@ -159,7 +141,7 @@ export default class SalesReceipt extends JournalPosterService {
|
|||||||
* Retrieve sale receipt with associated entries.
|
* Retrieve sale receipt with associated entries.
|
||||||
* @param {Integer} saleReceiptId
|
* @param {Integer} saleReceiptId
|
||||||
*/
|
*/
|
||||||
static async getSaleReceiptWithEntries(saleReceiptId) {
|
static async getSaleReceiptWithEntries(saleReceiptId: number) {
|
||||||
const saleReceipt = await SaleReceipt.tenant().query()
|
const saleReceipt = await SaleReceipt.tenant().query()
|
||||||
.where('id', saleReceiptId)
|
.where('id', saleReceiptId)
|
||||||
.withGraphFetched('entries');
|
.withGraphFetched('entries');
|
||||||
@@ -132,6 +132,18 @@ const getTotalDeep = (items, deepProp, totalProp) =>
|
|||||||
return _.sumBy(item, totalProp) + total + acc;
|
return _.sumBy(item, totalProp) + total + acc;
|
||||||
}, 0);
|
}, 0);
|
||||||
|
|
||||||
|
function applyMixins(derivedCtor, baseCtors) {
|
||||||
|
baseCtors.forEach((baseCtor) => {
|
||||||
|
Object.getOwnPropertyNames(baseCtor.prototype).forEach((name) => {
|
||||||
|
Object.defineProperty(
|
||||||
|
derivedCtor.prototype,
|
||||||
|
name,
|
||||||
|
Object.getOwnPropertyDescriptor(baseCtor.prototype, name)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
hashPassword,
|
hashPassword,
|
||||||
origin,
|
origin,
|
||||||
@@ -143,4 +155,5 @@ export {
|
|||||||
flatToNestedArray,
|
flatToNestedArray,
|
||||||
itemsStartWith,
|
itemsStartWith,
|
||||||
getTotalDeep,
|
getTotalDeep,
|
||||||
|
applyMixins,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
"module": "commonjs",
|
"module": "commonjs",
|
||||||
"target": "es5",
|
"target": "es5",
|
||||||
"jsx": "react",
|
"jsx": "react",
|
||||||
"allowJs": true
|
"allowJs": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user