feat(sales): currency code associated from invoice customer.

feat(purchases): currency code associated from vendor customer.
This commit is contained in:
a.bouhuolia
2021-03-08 09:47:04 +02:00
parent 6ec4ee4f0f
commit 3a3d881f67
26 changed files with 292 additions and 196 deletions

View File

@@ -27,6 +27,7 @@ import DynamicListingService from 'services/DynamicListing/DynamicListService';
import { entriesAmountDiff, formatDateFields } from 'utils';
import { ServiceError } from 'exceptions';
import { ACCOUNT_PARENT_TYPE } from 'data/AccountTypes';
import VendorsService from 'services/Contacts/VendorsService';
const ERRORS = {
BILL_VENDOR_NOT_FOUND: 'VENDOR_NOT_FOUND',
@@ -38,6 +39,7 @@ const ERRORS = {
BILL_ENTRIES_IDS_NOT_FOUND: 'BILL_ENTRIES_IDS_NOT_FOUND',
BILL_PAYMENT_ENTRIES_NOT_FOUND: 'BILL_PAYMENT_ENTRIES_NOT_FOUND',
INVALID_BILL_PAYMENT_AMOUNT: 'INVALID_BILL_PAYMENT_AMOUNT',
PAYMENT_NUMBER_SHOULD_NOT_MODIFY: 'PAYMENT_NUMBER_SHOULD_NOT_MODIFY',
};
/**
@@ -58,6 +60,9 @@ export default class BillPaymentsService {
@Inject()
dynamicListService: DynamicListingService;
@Inject()
vendorsService: VendorsService;
@EventDispatcher()
eventDispatcher: EventDispatcherInterface;
@@ -118,7 +123,6 @@ export default class BillPaymentsService {
const paymentAccount = await accountRepository.findOneById(
paymentAccountId
);
if (!paymentAccount) {
throw new ServiceError(ERRORS.PAYMENT_ACCOUNT_NOT_FOUND);
}
@@ -263,6 +267,45 @@ export default class BillPaymentsService {
}
}
/**
* * Validate the payment vendor whether modified.
* @param {string} billPaymentNo
*/
validateVendorNotModified(
billPaymentDTO: IBillPaymentDTO,
oldBillPayment: IBillPayment
) {
if (billPaymentDTO.vendorId !== oldBillPayment.vendorId) {
throw new ServiceError(ERRORS.PAYMENT_NUMBER_SHOULD_NOT_MODIFY);
}
}
/**
* Transforms create/edit DTO to model.
* @param {number} tenantId
* @param {IBillPaymentDTO} billPaymentDTO - Bill payment.
* @param {IBillPayment} oldBillPayment - Old bill payment.
* @return {Promise<IBillPayment>}
*/
async transformDTOToModel(
tenantId: number,
billPaymentDTO: IBillPaymentDTO,
oldBillPayment?: IBillPayment
): Promise<IBillPayment> {
// Retrieve vendor details by the given vendor id.
const vendor = await this.vendorsService.getVendorByIdOrThrowError(
tenantId,
billPaymentDTO.vendorId
);
return {
amount: sumBy(billPaymentDTO.entries, 'paymentAmount'),
currencyCode: vendor.currencyCode,
...formatDateFields(billPaymentDTO, ['paymentDate']),
entries: billPaymentDTO.entries,
};
}
/**
* Creates a new bill payment transcations and store it to the storage
* with associated bills entries and journal transactions.
@@ -288,11 +331,11 @@ export default class BillPaymentsService {
});
const { BillPayment } = this.tenancy.models(tenantId);
const billPaymentObj = {
amount: sumBy(billPaymentDTO.entries, 'paymentAmount'),
...formatDateFields(billPaymentDTO, ['paymentDate']),
};
// Transform create DTO to model object.
const billPaymentObj = await this.transformDTOToModel(
tenantId,
billPaymentDTO
);
// Validate vendor existance on the storage.
await this.getVendorOrThrowError(tenantId, billPaymentObj.vendorId);
@@ -301,7 +344,6 @@ export default class BillPaymentsService {
tenantId,
billPaymentObj.paymentAccountId
);
// Validate the payment number uniquiness.
if (billPaymentObj.paymentNumber) {
await this.validatePaymentNumber(tenantId, billPaymentObj.paymentNumber);
@@ -312,15 +354,13 @@ export default class BillPaymentsService {
billPaymentObj.entries,
billPaymentDTO.vendorId
);
// Validates the bills due payment amount.
await this.validateBillsDueAmount(tenantId, billPaymentObj.entries);
const billPayment = await BillPayment.query().insertGraphAndFetch({
...omit(billPaymentObj, ['entries']),
entries: billPaymentDTO.entries,
...billPaymentObj,
});
// Triggers `onBillPaymentCreated` event.
await this.eventDispatcher.dispatch(events.billPayment.onCreated, {
tenantId,
billPayment,
@@ -363,11 +403,14 @@ export default class BillPaymentsService {
tenantId,
billPaymentId
);
const billPaymentObj = {
amount: sumBy(billPaymentDTO.entries, 'paymentAmount'),
...formatDateFields(billPaymentDTO, ['paymentDate']),
};
// Transform bill payment DTO to model object.
const billPaymentObj = await this.transformDTOToModel(
tenantId,
billPaymentDTO,
oldBillPayment
);
// Validate vendor not modified.
this.validateVendorNotModified(billPaymentDTO, oldBillPayment);
// Validate vendor existance on the storage.
await this.getVendorOrThrowError(tenantId, billPaymentObj.vendorId);
@@ -377,28 +420,24 @@ export default class BillPaymentsService {
tenantId,
billPaymentObj.paymentAccountId
);
// Validate the items entries IDs existance on the storage.
await this.validateEntriesIdsExistance(
tenantId,
billPaymentId,
billPaymentObj.entries
);
// Validate the bills existance and associated to the given vendor.
await this.validateBillsExistance(
tenantId,
billPaymentObj.entries,
billPaymentDTO.vendorId
);
// Validates the bills due payment amount.
await this.validateBillsDueAmount(
tenantId,
billPaymentObj.entries,
oldBillPayment.entries
);
// Validate the payment number uniquiness.
if (billPaymentObj.paymentNumber) {
await this.validatePaymentNumber(
@@ -409,8 +448,7 @@ export default class BillPaymentsService {
}
const billPayment = await BillPayment.query().upsertGraphAndFetch({
id: billPaymentId,
...omit(billPaymentObj, ['entries']),
entries: billPaymentDTO.entries,
...billPaymentObj,
});
await this.eventDispatcher.dispatch(events.billPayment.onEdited, {
tenantId,

View File

@@ -27,6 +27,7 @@ import ItemsService from 'services/Items/ItemsService';
import ItemsEntriesService from 'services/Items/ItemsEntriesService';
import JournalCommands from 'services/Accounting/JournalCommands';
import JournalPosterService from 'services/Sales/JournalPosterService';
import VendorsService from 'services/Contacts/VendorsService';
import { ERRORS } from './constants';
/**
@@ -46,7 +47,7 @@ export default class BillsService extends SalesInvoicesCost {
@Inject()
tenancy: TenancyService;
@EventDispatcher()
eventDispatcher: EventDispatcherInterface;
@@ -62,6 +63,9 @@ export default class BillsService extends SalesInvoicesCost {
@Inject()
journalPosterService: JournalPosterService;
@Inject()
vendorsService: VendorsService;
/**
* Validates whether the vendor is exist.
* @async
@@ -136,16 +140,25 @@ export default class BillsService extends SalesInvoicesCost {
}
/**
* Converts bill DTO to model.
* Validate the bill number require.
* @param {string} billNo -
*/
validateBillNoRequire(billNo: string) {
if (!billNo) {
throw new ServiceError(ERRORS.BILL_NO_IS_REQUIRED);
}
}
/**
* Converts create bill DTO to model.
* @param {number} tenantId
* @param {IBillDTO} billDTO
* @param {IBill} oldBill
*
* @returns {IBill}
*/
private async billDTOToModel(
tenantId: number,
billDTO: IBillDTO | IBillEditDTO,
billDTO: IBillDTO,
authorizedUser: ISystemUser,
oldBill?: IBill
) {
@@ -157,15 +170,25 @@ export default class BillsService extends SalesInvoicesCost {
}));
const amount = sumBy(entries, 'amount');
// Bill number from DTO or from auto-increment.
const billNumber = billDTO.billNumber || oldBill?.billNumber;
// Retrieve vendor details by the given vendor id.
const vendor = await this.vendorsService.getVendorByIdOrThrowError(
tenantId,
billDTO.vendorId
);
return {
...formatDateFields(omit(billDTO, ['open', 'entries']), [
'billDate',
'dueDate',
]),
amount,
currencyCode: vendor.currencyCode,
billNumber,
entries: entries.map((entry) => ({
reference_type: 'Bill',
...omit(entry, ['amount', 'id']),
...omit(entry, ['amount']),
})),
// Avoid rewrite the open date in edit mode when already opened.
...(billDTO.open &&
@@ -205,16 +228,14 @@ export default class BillsService extends SalesInvoicesCost {
const billObj = await this.billDTOToModel(
tenantId,
billDTO,
authorizedUser,
null
authorizedUser
);
// Retrieve vendor or throw not found service error.
await this.getVendorOrThrowError(tenantId, billDTO.vendorId);
// Validate the bill number uniqiness on the storage.
if (billDTO.billNumber) {
await this.validateBillNumberExists(tenantId, billDTO.billNumber);
}
await this.validateBillNumberExists(tenantId, billDTO.billNumber);
// Validate items IDs existance.
await this.itemsEntriesService.validateItemsIdsExistance(
tenantId,
@@ -277,7 +298,6 @@ export default class BillsService extends SalesInvoicesCost {
authorizedUser,
oldBill
);
// Retrieve vendor details or throw not found service error.
await this.getVendorOrThrowError(tenantId, billDTO.vendorId);
@@ -292,7 +312,6 @@ export default class BillsService extends SalesInvoicesCost {
'Bill',
billDTO.entries
);
// Validate the items ids existance on the storage.
await this.itemsEntriesService.validateItemsIdsExistance(
tenantId,

View File

@@ -7,4 +7,5 @@ export const ERRORS = {
BILL_ENTRIES_IDS_NOT_FOUND: 'BILL_ENTRIES_IDS_NOT_FOUND',
NOT_PURCHASE_ABLE_ITEMS: 'NOT_PURCHASE_ABLE_ITEMS',
BILL_ALREADY_OPEN: 'BILL_ALREADY_OPEN',
BILL_NO_IS_REQUIRED: 'BILL_NO_IS_REQUIRED'
};