mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-15 20:30:33 +00:00
feat: issues in bills and payments made
This commit is contained in:
@@ -44,7 +44,8 @@ export default class BillsController extends BaseController {
|
||||
...this.specificBillValidationSchema,
|
||||
],
|
||||
this.validationResult,
|
||||
asyncMiddleware(this.editBill.bind(this))
|
||||
asyncMiddleware(this.editBill.bind(this)),
|
||||
this.handleServiceError,
|
||||
);
|
||||
router.get(
|
||||
'/:id', [
|
||||
@@ -101,10 +102,10 @@ export default class BillsController extends BaseController {
|
||||
*/
|
||||
get billEditValidationSchema() {
|
||||
return [
|
||||
// check('bill_number').exists().trim().escape(),
|
||||
check('bill_number').exists().trim().escape(),
|
||||
check('bill_date').exists().isISO8601(),
|
||||
check('due_date').optional().isISO8601(),
|
||||
// check('vendor_id').exists().isNumeric().toInt(),
|
||||
check('vendor_id').exists().isNumeric().toInt(),
|
||||
check('note').optional().trim().escape(),
|
||||
check('entries').isArray({ min: 1 }),
|
||||
|
||||
@@ -186,7 +187,7 @@ export default class BillsController extends BaseController {
|
||||
const { id: billId } = req.params;
|
||||
|
||||
try {
|
||||
const bill = await this.billsService.getBillWithMetadata(tenantId, billId);
|
||||
const bill = await this.billsService.getBill(tenantId, billId);
|
||||
|
||||
return res.status(200).send({ bill });
|
||||
} catch (error) {
|
||||
@@ -286,6 +287,11 @@ export default class BillsController extends BaseController {
|
||||
errors: [{ type: 'ITEMS.IDS.NOT.FOUND', code: 400 }],
|
||||
});
|
||||
}
|
||||
if (error.errorType === 'BILL_ENTRIES_IDS_NOT_FOUND') {
|
||||
return res.status(400).send({
|
||||
errors: [{ type: 'BILL_ENTRIES_IDS_NOT_FOUND', code: 900 }],
|
||||
});
|
||||
}
|
||||
}
|
||||
next(error);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { IDynamicListFilterDTO } from "./DynamicFilter";
|
||||
import { IItemEntry, IItemEntryDTO } from "./ItemEntry";
|
||||
|
||||
export interface IBillDTO {
|
||||
@@ -14,6 +15,8 @@ export interface IBillDTO {
|
||||
};
|
||||
|
||||
export interface IBillEditDTO {
|
||||
vendorId: number,
|
||||
billNumber: string,
|
||||
billDate: Date,
|
||||
dueDate: Date,
|
||||
referenceNo: string,
|
||||
@@ -42,7 +45,6 @@ export interface IBill {
|
||||
entries: IItemEntry[],
|
||||
};
|
||||
|
||||
export interface IBillsFilter {
|
||||
page: number,
|
||||
pageSize: number,
|
||||
export interface IBillsFilter extends IDynamicListFilterDTO {
|
||||
stringifiedFilterRoles?: string,
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
|
||||
|
||||
export interface IItemEntry {
|
||||
id?: number,
|
||||
|
||||
referenceType: string,
|
||||
referenceId: number,
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@ export default class Bill extends TenantModel {
|
||||
to: 'items_entries.referenceId',
|
||||
},
|
||||
filter(builder) {
|
||||
builder.where('reference_type', 'SaleReceipt');
|
||||
builder.where('reference_type', 'Bill');
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -284,6 +284,7 @@ export default class BillPaymentsService {
|
||||
* - Re-insert the journal transactions and update the diff accounts balance.
|
||||
* - Update the diff vendor balance.
|
||||
* - Update the diff bill payment amount.
|
||||
* ------
|
||||
* @param {number} tenantId - Tenant id
|
||||
* @param {Integer} billPaymentId
|
||||
* @param {BillPaymentDTO} billPayment
|
||||
@@ -313,6 +314,7 @@ export default class BillPaymentsService {
|
||||
.upsertGraph({
|
||||
id: billPaymentId,
|
||||
...omit(billPaymentObj, ['entries']),
|
||||
entries: billPaymentDTO.entries,
|
||||
});
|
||||
await this.eventDispatcher.dispatch(events.billPayments.onEdited);
|
||||
this.logger.info('[bill_payment] edited successfully.', { tenantId, billPaymentId, billPayment, oldPaymentMade });
|
||||
|
||||
@@ -133,9 +133,13 @@ export default class BillsService extends SalesInvoicesCost {
|
||||
* @param {Response} res
|
||||
* @param {Function} next
|
||||
*/
|
||||
private async validateBillNumberExists(tenantId: number, billNumber: string) {
|
||||
private async validateBillNumberExists(tenantId: number, billNumber: string, notBillId?: number) {
|
||||
const { Bill } = this.tenancy.models(tenantId);
|
||||
const foundBills = await Bill.query().where('bill_number', billNumber);
|
||||
const foundBills = await Bill.query().where('bill_number', billNumber).onBuild((builder) => {
|
||||
if (notBillId) {
|
||||
builder.whereNot('id', notBillId);
|
||||
}
|
||||
});
|
||||
|
||||
if (foundBills.length > 0) {
|
||||
throw new ServiceError(ERRORS.BILL_NUMBER_EXISTS);
|
||||
@@ -144,13 +148,15 @@ export default class BillsService extends SalesInvoicesCost {
|
||||
|
||||
/**
|
||||
* Validates the entries ids existance on the storage.
|
||||
* @param {Request} req
|
||||
* @param {Response} res
|
||||
* @param {Function} next
|
||||
* @param {number} tenantId -
|
||||
* @param {number} billId -
|
||||
* @param {IItemEntry[]} billEntries -
|
||||
*/
|
||||
async validateEntriesIdsExistance(tenantId: number, billId: number, billEntries: any) {
|
||||
private async validateEntriesIdsExistance(tenantId: number, billId: number, billEntries: IItemEntryDTO[]) {
|
||||
const { ItemEntry } = this.tenancy.models(tenantId);
|
||||
const entriesIds = billEntries.filter((e) => e.id).map((e) => e.id);
|
||||
const entriesIds = billEntries
|
||||
.filter((e: IItemEntry) => e.id)
|
||||
.map((e: IItemEntry) => e.id);
|
||||
|
||||
const storedEntries = await ItemEntry.query()
|
||||
.whereIn('reference_id', [billId])
|
||||
@@ -170,9 +176,9 @@ export default class BillsService extends SalesInvoicesCost {
|
||||
* @param {Response} res
|
||||
* @param {Function} next
|
||||
*/
|
||||
private async validateNonPurchasableEntriesItems(tenantId: number, billEntries: any) {
|
||||
private async validateNonPurchasableEntriesItems(tenantId: number, billEntries: IItemEntryDTO[]) {
|
||||
const { Item } = this.tenancy.models(tenantId);
|
||||
const itemsIds = billEntries.map((e: IItemEntry) => e.itemId);
|
||||
const itemsIds = billEntries.map((e: IItemEntryDTO) => e.itemId);
|
||||
|
||||
const purchasbleItems = await Item.query()
|
||||
.where('purchasable', true)
|
||||
@@ -194,7 +200,7 @@ export default class BillsService extends SalesInvoicesCost {
|
||||
*
|
||||
* @returns {IBill}
|
||||
*/
|
||||
private async billDTOToModel(tenantId: number, billDTO: IBillDTO, oldBill?: IBill) {
|
||||
private async billDTOToModel(tenantId: number, billDTO: IBillDTO|IBillEditDTO, oldBill?: IBill) {
|
||||
const { ItemEntry } = this.tenancy.models(tenantId);
|
||||
let invLotNumber = oldBill?.invLotNumber;
|
||||
|
||||
@@ -293,18 +299,26 @@ export default class BillsService extends SalesInvoicesCost {
|
||||
const oldBill = await this.getBillOrThrowError(tenantId, billId);
|
||||
const billObj = this.billDTOToModel(tenantId, billDTO, oldBill);
|
||||
|
||||
await this.getVendorOrThrowError(tenantId, billDTO.vendorId);
|
||||
await this.validateBillNumberExists(tenantId, billDTO.billNumber, billId);
|
||||
|
||||
await this.validateEntriesIdsExistance(tenantId, billId, billDTO.entries);
|
||||
await this.validateItemsIdsExistance(tenantId, billDTO.entries);
|
||||
await this.validateNonPurchasableEntriesItems(tenantId, billDTO.entries);
|
||||
|
||||
// Update the bill transaction.
|
||||
const bill = await Bill.query()
|
||||
.upsertGraph({
|
||||
id: billId,
|
||||
...omit(billObj, ['entries', 'invLotNumber']),
|
||||
entries: billDTO.entries.map((entry) => ({
|
||||
reference_type: 'Bill',
|
||||
...omit(entry, ['amount']),
|
||||
}))
|
||||
});
|
||||
const bill = await Bill.query().upsertGraph({
|
||||
id: billId,
|
||||
...omit(billObj, ['entries', 'invLotNumber']),
|
||||
|
||||
entries: billDTO.entries.map((entry) => ({
|
||||
reference_type: 'Bill',
|
||||
...omit(entry, ['amount']),
|
||||
}))
|
||||
});
|
||||
// Triggers event `onBillEdited`.
|
||||
await this.eventDispatcher.dispatch(events.bills.onEdited, { tenantId, billId, oldBill, bill });
|
||||
this.logger.info('[bill] bill upserted successfully.', { tenantId, billId });
|
||||
|
||||
return bill;
|
||||
}
|
||||
@@ -339,7 +353,7 @@ export default class BillsService extends SalesInvoicesCost {
|
||||
* @param {Bill} bill
|
||||
* @param {number} billId
|
||||
*/
|
||||
recordInventoryTransactions(
|
||||
public recordInventoryTransactions(
|
||||
tenantId: number,
|
||||
bill: any,
|
||||
billId: number,
|
||||
@@ -367,7 +381,7 @@ export default class BillsService extends SalesInvoicesCost {
|
||||
* @param {IBill} bill
|
||||
* @param {Integer} billId
|
||||
*/
|
||||
async recordJournalTransactions(tenantId: number, bill: IBill, billId?: number) {
|
||||
public async recordJournalTransactions(tenantId: number, bill: IBill, billId?: number) {
|
||||
const { AccountTransaction, Item, ItemEntry } = this.tenancy.models(tenantId);
|
||||
const { accountRepository } = this.tenancy.repositories(tenantId);
|
||||
|
||||
@@ -457,27 +471,21 @@ export default class BillsService extends SalesInvoicesCost {
|
||||
|
||||
/**
|
||||
* Retrieve the given bill details with associated items entries.
|
||||
* @param {Integer} billId -
|
||||
* @returns {Promise}
|
||||
* @param {Integer} billId - Specific bill.
|
||||
* @returns {Promise<IBill>}
|
||||
*/
|
||||
getBill(tenantId: number, billId: number) {
|
||||
const { Bill } = this.tenancy.models(tenantId);
|
||||
return Bill.query().findById(billId).withGraphFetched('entries');
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the given bill details with associated items entries.
|
||||
* @param {Integer} billId -
|
||||
* @returns {Promise}
|
||||
*/
|
||||
getBillWithMetadata(tenantId: number, billId: number) {
|
||||
public async getBill(tenantId: number, billId: number): Promise<IBill> {
|
||||
const { Bill } = this.tenancy.models(tenantId);
|
||||
|
||||
return Bill.query()
|
||||
.where('id', billId)
|
||||
this.logger.info('[bills] trying to fetch specific bill with metadata.', { tenantId, billId });
|
||||
const bill = await Bill.query().findById(billId)
|
||||
.withGraphFetched('vendor')
|
||||
.withGraphFetched('entries')
|
||||
.first();
|
||||
.withGraphFetched('entries');
|
||||
|
||||
if (!bill) {
|
||||
throw new ServiceError(ERRORS.BILL_NOT_FOUND);
|
||||
}
|
||||
return bill;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -486,7 +494,7 @@ export default class BillsService extends SalesInvoicesCost {
|
||||
* @param {IBill} bill -
|
||||
* @return {Promise}
|
||||
*/
|
||||
async scheduleComputeBillItemsCost(tenantId: number, bill) {
|
||||
public async scheduleComputeBillItemsCost(tenantId: number, bill) {
|
||||
const { Item } = this.tenancy.models(tenantId);
|
||||
const billItemsIds = bill.entries.map((entry) => entry.item_id);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user