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
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import { Service, Inject } from 'typedi';
|
import { Service, Inject } from 'typedi';
|
||||||
import { Request, Response, Router, NextFunction } from 'express';
|
import { Request, Response, Router, NextFunction } from 'express';
|
||||||
import asyncMiddleware from 'api/middleware/asyncMiddleware';
|
import asyncMiddleware from 'api/middleware/asyncMiddleware';
|
||||||
import BaseController from 'api/controllers/BaseController';
|
import BaseController from 'api/controllers/BaseController';
|
||||||
|
|||||||
@@ -17,33 +17,32 @@ export default class CurrenciesController extends BaseController {
|
|||||||
router() {
|
router() {
|
||||||
const router = Router();
|
const router = Router();
|
||||||
|
|
||||||
router.get('/', [
|
router.get(
|
||||||
...this.listSchema,
|
'/',
|
||||||
],
|
[...this.listSchema],
|
||||||
this.validationResult,
|
this.validationResult,
|
||||||
asyncMiddleware(this.all.bind(this))
|
asyncMiddleware(this.all.bind(this))
|
||||||
);
|
);
|
||||||
router.post('/', [
|
router.post(
|
||||||
...this.currencyDTOSchemaValidation,
|
'/',
|
||||||
],
|
[...this.currencyDTOSchemaValidation],
|
||||||
this.validationResult,
|
this.validationResult,
|
||||||
asyncMiddleware(this.newCurrency.bind(this)),
|
asyncMiddleware(this.newCurrency.bind(this)),
|
||||||
this.handlerServiceError,
|
this.handlerServiceError
|
||||||
);
|
);
|
||||||
router.post('/:id', [
|
router.post(
|
||||||
...this.currencyIdParamSchema,
|
'/:id',
|
||||||
...this.currencyEditDTOSchemaValidation
|
[...this.currencyIdParamSchema, ...this.currencyEditDTOSchemaValidation],
|
||||||
],
|
|
||||||
this.validationResult,
|
this.validationResult,
|
||||||
asyncMiddleware(this.editCurrency.bind(this)),
|
asyncMiddleware(this.editCurrency.bind(this)),
|
||||||
this.handlerServiceError,
|
this.handlerServiceError
|
||||||
);
|
);
|
||||||
router.delete('/:currency_code', [
|
router.delete(
|
||||||
...this.currencyParamSchema,
|
'/:currency_code',
|
||||||
],
|
[...this.currencyParamSchema],
|
||||||
this.validationResult,
|
this.validationResult,
|
||||||
asyncMiddleware(this.deleteCurrency.bind(this)),
|
asyncMiddleware(this.deleteCurrency.bind(this)),
|
||||||
this.handlerServiceError,
|
this.handlerServiceError
|
||||||
);
|
);
|
||||||
return router;
|
return router;
|
||||||
}
|
}
|
||||||
@@ -56,21 +55,15 @@ export default class CurrenciesController extends BaseController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get currencyEditDTOSchemaValidation(): ValidationChain[] {
|
get currencyEditDTOSchemaValidation(): ValidationChain[] {
|
||||||
return [
|
return [check('currency_name').exists().trim().escape()];
|
||||||
check('currency_name').exists().trim().escape(),
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get currencyIdParamSchema(): ValidationChain[] {
|
get currencyIdParamSchema(): ValidationChain[] {
|
||||||
return [
|
return [param('id').exists().isNumeric().toInt()];
|
||||||
param('id').exists().isNumeric().toInt(),
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get currencyParamSchema(): ValidationChain[] {
|
get currencyParamSchema(): ValidationChain[] {
|
||||||
return [
|
return [param('currency_code').exists().trim().escape()];
|
||||||
param('currency_code').exists().trim().escape(),
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get listSchema(): ValidationChain[] {
|
get listSchema(): ValidationChain[] {
|
||||||
@@ -82,16 +75,16 @@ export default class CurrenciesController extends BaseController {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve all registered currency details.
|
* Retrieve all registered currency details.
|
||||||
* @param {Request} req
|
* @param {Request} req
|
||||||
* @param {Response} res
|
* @param {Response} res
|
||||||
* @param {NextFunction} next
|
* @param {NextFunction} next
|
||||||
*/
|
*/
|
||||||
async all(req: Request, res: Response, next: NextFunction) {
|
async all(req: Request, res: Response, next: NextFunction) {
|
||||||
const { tenantId } = req;
|
const { tenantId } = req;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const currencies = await this.currenciesService.listCurrencies(tenantId);
|
const currencies = await this.currenciesService.listCurrencies(tenantId);
|
||||||
return res.status(200).send({ currencies: [ ...currencies, ] });
|
return res.status(200).send({ currencies: [...currencies] });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
next(error);
|
next(error);
|
||||||
}
|
}
|
||||||
@@ -99,9 +92,9 @@ export default class CurrenciesController extends BaseController {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new currency on the storage.
|
* Creates a new currency on the storage.
|
||||||
* @param {Request} req
|
* @param {Request} req
|
||||||
* @param {Response} res
|
* @param {Response} res
|
||||||
* @param {NextFunction} next
|
* @param {NextFunction} next
|
||||||
*/
|
*/
|
||||||
async newCurrency(req: Request, res: Response, next: Function) {
|
async newCurrency(req: Request, res: Response, next: Function) {
|
||||||
const { tenantId } = req;
|
const { tenantId } = req;
|
||||||
@@ -121,13 +114,13 @@ export default class CurrenciesController extends BaseController {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Edits details of the given currency.
|
* Edits details of the given currency.
|
||||||
* @param {Request} req
|
* @param {Request} req
|
||||||
* @param {Response} res
|
* @param {Response} res
|
||||||
* @param {NextFunction} next
|
* @param {NextFunction} next
|
||||||
*/
|
*/
|
||||||
async deleteCurrency(req: Request, res: Response, next: Function) {
|
async deleteCurrency(req: Request, res: Response, next: Function) {
|
||||||
const { tenantId } = req;
|
const { tenantId } = req;
|
||||||
const { currency_code: currencyCode } = req.params;
|
const { currency_code: currencyCode } = req.params;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await this.currenciesService.deleteCurrency(tenantId, currencyCode);
|
await this.currenciesService.deleteCurrency(tenantId, currencyCode);
|
||||||
@@ -142,9 +135,9 @@ export default class CurrenciesController extends BaseController {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes the currency.
|
* Deletes the currency.
|
||||||
* @param {Request} req
|
* @param {Request} req
|
||||||
* @param {Response} res
|
* @param {Response} res
|
||||||
* @param {NextFunction} next
|
* @param {NextFunction} next
|
||||||
*/
|
*/
|
||||||
async editCurrency(req: Request, res: Response, next: Function) {
|
async editCurrency(req: Request, res: Response, next: Function) {
|
||||||
const { tenantId } = req;
|
const { tenantId } = req;
|
||||||
@@ -152,7 +145,11 @@ export default class CurrenciesController extends BaseController {
|
|||||||
const { body: editCurrencyDTO } = req;
|
const { body: editCurrencyDTO } = req;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const currency = await this.currenciesService.editCurrency(tenantId, currencyId, editCurrencyDTO);
|
const currency = await this.currenciesService.editCurrency(
|
||||||
|
tenantId,
|
||||||
|
currencyId,
|
||||||
|
editCurrencyDTO
|
||||||
|
);
|
||||||
return res.status(200).send({
|
return res.status(200).send({
|
||||||
currency_code: currency.currencyCode,
|
currency_code: currency.currencyCode,
|
||||||
message: 'The currency has been edited successfully.',
|
message: 'The currency has been edited successfully.',
|
||||||
@@ -164,24 +161,29 @@ export default class CurrenciesController extends BaseController {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles currencies service error.
|
* Handles currencies service error.
|
||||||
* @param {Error} error
|
* @param {Error} error
|
||||||
* @param {Request} req
|
* @param {Request} req
|
||||||
* @param {Response} res
|
* @param {Response} res
|
||||||
* @param {NextFunction} next
|
* @param {NextFunction} next
|
||||||
*/
|
*/
|
||||||
handlerServiceError(error: Error, req: Request, res: Response, next: NextFunction) {
|
handlerServiceError(
|
||||||
|
error: Error,
|
||||||
|
req: Request,
|
||||||
|
res: Response,
|
||||||
|
next: NextFunction
|
||||||
|
) {
|
||||||
if (error instanceof ServiceError) {
|
if (error instanceof ServiceError) {
|
||||||
if (error.errorType === 'currency_not_found') {
|
if (error.errorType === 'currency_not_found') {
|
||||||
return res.boom.badRequest(null, {
|
return res.boom.badRequest(null, {
|
||||||
errors: [{ type: 'CURRENCY_NOT_FOUND', code: 100, }],
|
errors: [{ type: 'CURRENCY_NOT_FOUND', code: 100 }],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (error.errorType === 'currency_code_exists') {
|
if (error.errorType === 'currency_code_exists') {
|
||||||
return res.boom.badRequest(null, {
|
return res.boom.badRequest(null, {
|
||||||
errors: [{ type: 'CURRENCY_CODE_EXISTS', code: 200, }],
|
errors: [{ type: 'CURRENCY_CODE_EXISTS', code: 200 }],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
next(error);
|
next(error);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|||||||
@@ -444,6 +444,11 @@ export default class PaymentReceivesController extends BaseController {
|
|||||||
],
|
],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (error.errorType === 'PAYMENT_RECEIVE_NO_IS_REQUIRED') {
|
||||||
|
return res.boom.badRequest(null, {
|
||||||
|
errors: [{ type: 'PAYMENT_RECEIVE_NO_IS_REQUIRED', code: 1100 }],
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
next(error);
|
next(error);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ export default class SalesEstimatesController extends BaseController {
|
|||||||
check('estimate_date').exists().isISO8601(),
|
check('estimate_date').exists().isISO8601(),
|
||||||
check('expiration_date').optional().isISO8601(),
|
check('expiration_date').optional().isISO8601(),
|
||||||
check('reference').optional(),
|
check('reference').optional(),
|
||||||
check('estimate_number').exists().trim().escape(),
|
check('estimate_number').optional().trim().escape(),
|
||||||
check('delivered').default(false).isBoolean().toBoolean(),
|
check('delivered').default(false).isBoolean().toBoolean(),
|
||||||
|
|
||||||
check('entries').exists().isArray({ min: 1 }),
|
check('entries').exists().isArray({ min: 1 }),
|
||||||
@@ -401,6 +401,11 @@ export default class SalesEstimatesController extends BaseController {
|
|||||||
errors: [{ type: 'CUSTOMER_NOT_FOUND', code: 1300 }],
|
errors: [{ type: 'CUSTOMER_NOT_FOUND', code: 1300 }],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (error.errorType === 'SALE_ESTIMATE_NO_IS_REQUIRED') {
|
||||||
|
return res.boom.badRequest(null, {
|
||||||
|
errors: [{ type: 'SALE_ESTIMATE_NO_IS_REQUIRED', code: 1400 }],
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
next(error);
|
next(error);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -432,6 +432,13 @@ export default class SaleInvoicesController extends BaseController {
|
|||||||
],
|
],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (error.errorType === 'SALE_INVOICE_NO_IS_REQUIRED') {
|
||||||
|
return res.boom.badRequest(null, {
|
||||||
|
errors: [
|
||||||
|
{ type: 'SALE_INVOICE_NO_IS_REQUIRED', code: 1500 },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
next(error);
|
next(error);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ export interface ISaleEstimate {
|
|||||||
amount: number,
|
amount: number,
|
||||||
customerId: number,
|
customerId: number,
|
||||||
estimateDate: Date,
|
estimateDate: Date,
|
||||||
|
estimateNumber: string,
|
||||||
reference: string,
|
reference: string,
|
||||||
note: string,
|
note: string,
|
||||||
termsConditions: string,
|
termsConditions: string,
|
||||||
@@ -19,8 +20,8 @@ export interface ISaleEstimate {
|
|||||||
export interface ISaleEstimateDTO {
|
export interface ISaleEstimateDTO {
|
||||||
customerId: number,
|
customerId: number,
|
||||||
estimateDate?: Date,
|
estimateDate?: Date,
|
||||||
reference: string,
|
reference?: string,
|
||||||
estimateNumber: string,
|
estimateNumber?: string,
|
||||||
entries: IItemEntry[],
|
entries: IItemEntry[],
|
||||||
note: string,
|
note: string,
|
||||||
termsConditions: string,
|
termsConditions: string,
|
||||||
|
|||||||
@@ -22,7 +22,8 @@ export interface ISaleReceiptDTO {
|
|||||||
depositAccountId: number;
|
depositAccountId: number;
|
||||||
receiptDate: Date;
|
receiptDate: Date;
|
||||||
sendToEmail: string;
|
sendToEmail: string;
|
||||||
referenceNo: string;
|
referenceNo?: string;
|
||||||
|
receiptNumber?: string,
|
||||||
receiptMessage: string;
|
receiptMessage: string;
|
||||||
statement: string;
|
statement: string;
|
||||||
closed: boolean;
|
closed: boolean;
|
||||||
|
|||||||
@@ -1,13 +1,9 @@
|
|||||||
import { Model } from 'objection';
|
import { Model } from 'objection';
|
||||||
import { omit, isEmpty } from 'lodash';
|
import { omit, isEmpty } from 'lodash';
|
||||||
import {
|
import { IMetadata, IMetaQuery, IMetableStore } from 'interfaces';
|
||||||
IMetadata,
|
|
||||||
IMetaQuery,
|
|
||||||
IMetableStore,
|
|
||||||
} from 'interfaces';
|
|
||||||
import { itemsStartWith } from 'utils';
|
import { itemsStartWith } from 'utils';
|
||||||
|
|
||||||
export default class MetableStore implements IMetableStore{
|
export default class MetableStore implements IMetableStore {
|
||||||
metadata: IMetadata[];
|
metadata: IMetadata[];
|
||||||
model: Model;
|
model: Model;
|
||||||
extraColumns: string[];
|
extraColumns: string[];
|
||||||
@@ -31,18 +27,19 @@ export default class MetableStore implements IMetableStore{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Find the given metadata key.
|
* Find the given metadata key.
|
||||||
* @param {string|IMetaQuery} query -
|
* @param {string|IMetaQuery} query -
|
||||||
* @returns {IMetadata} - Metadata object.
|
* @returns {IMetadata} - Metadata object.
|
||||||
*/
|
*/
|
||||||
find(query: string|IMetaQuery): IMetadata {
|
find(query: string | IMetaQuery): IMetadata {
|
||||||
const { key, value, ...extraColumns } = this.parseQuery(query);
|
const { key, value, ...extraColumns } = this.parseQuery(query);
|
||||||
|
|
||||||
return this.metadata.find((meta: IMetadata) => {
|
return this.metadata.find((meta: IMetadata) => {
|
||||||
const isSameKey = meta.key === key;
|
const isSameKey = meta.key === key;
|
||||||
const sameExtraColumns = this.extraColumns
|
const sameExtraColumns = this.extraColumns.some(
|
||||||
.some((extraColumn: string) => extraColumns[extraColumn] === meta[extraColumn]);
|
(extraColumn: string) => extraColumns[extraColumn] === meta[extraColumn]
|
||||||
|
);
|
||||||
|
|
||||||
const isSameExtraColumns = (sameExtraColumns || isEmpty(extraColumns));
|
const isSameExtraColumns = sameExtraColumns || isEmpty(extraColumns);
|
||||||
|
|
||||||
return isSameKey && isSameExtraColumns;
|
return isSameKey && isSameExtraColumns;
|
||||||
});
|
});
|
||||||
@@ -55,10 +52,9 @@ export default class MetableStore implements IMetableStore{
|
|||||||
all(): IMetadata[] {
|
all(): IMetadata[] {
|
||||||
return this.metadata
|
return this.metadata
|
||||||
.filter((meta: IMetadata) => !meta._markAsDeleted)
|
.filter((meta: IMetadata) => !meta._markAsDeleted)
|
||||||
.map((meta: IMetadata) => omit(
|
.map((meta: IMetadata) =>
|
||||||
meta,
|
omit(meta, itemsStartWith(Object.keys(meta), '_'))
|
||||||
itemsStartWith(Object.keys(meta), '_')
|
);
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -66,16 +62,20 @@ export default class MetableStore implements IMetableStore{
|
|||||||
* @param {String} key -
|
* @param {String} key -
|
||||||
* @param {Mixied} defaultValue -
|
* @param {Mixied} defaultValue -
|
||||||
*/
|
*/
|
||||||
get(query: string|IMetaQuery, defaultValue: any): any|false {
|
get(query: string | IMetaQuery, defaultValue: any): any | false {
|
||||||
const metadata = this.find(query);
|
const metadata = this.find(query);
|
||||||
return metadata ? metadata.value : defaultValue || false;
|
return metadata
|
||||||
|
? metadata.value
|
||||||
|
: typeof defaultValue !== 'undefined'
|
||||||
|
? defaultValue
|
||||||
|
: false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Markes the metadata to should be deleted.
|
* Markes the metadata to should be deleted.
|
||||||
* @param {String} key -
|
* @param {String} key -
|
||||||
*/
|
*/
|
||||||
remove(query: string|IMetaQuery): void {
|
remove(query: string | IMetaQuery): void {
|
||||||
const metadata: IMetadata = this.find(query);
|
const metadata: IMetadata = this.find(query);
|
||||||
|
|
||||||
if (metadata) {
|
if (metadata) {
|
||||||
@@ -99,7 +99,7 @@ export default class MetableStore implements IMetableStore{
|
|||||||
* @param {String} key -
|
* @param {String} key -
|
||||||
* @param {String} value -
|
* @param {String} value -
|
||||||
*/
|
*/
|
||||||
set(query: IMetaQuery|IMetadata[]|string, metaValue?: any): void {
|
set(query: IMetaQuery | IMetadata[] | string, metaValue?: any): void {
|
||||||
if (Array.isArray(query)) {
|
if (Array.isArray(query)) {
|
||||||
const metadata = query;
|
const metadata = query;
|
||||||
|
|
||||||
@@ -127,10 +127,10 @@ export default class MetableStore implements IMetableStore{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses query query.
|
* Parses query query.
|
||||||
* @param query
|
* @param query
|
||||||
* @param value
|
* @param value
|
||||||
*/
|
*/
|
||||||
parseQuery(query: string|IMetaQuery): IMetaQuery {
|
parseQuery(query: string | IMetaQuery): IMetaQuery {
|
||||||
return typeof query !== 'object' ? { key: query } : { ...query };
|
return typeof query !== 'object' ? { key: query } : { ...query };
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,9 +141,9 @@ export default class MetableStore implements IMetableStore{
|
|||||||
* @return {string|number|boolean} -
|
* @return {string|number|boolean} -
|
||||||
*/
|
*/
|
||||||
static formatMetaValue(
|
static formatMetaValue(
|
||||||
value: string|boolean|number,
|
value: string | boolean | number,
|
||||||
valueType: string
|
valueType: string
|
||||||
) : string|number|boolean {
|
): string | number | boolean {
|
||||||
let parsedValue;
|
let parsedValue;
|
||||||
|
|
||||||
switch (valueType) {
|
switch (valueType) {
|
||||||
@@ -168,7 +168,9 @@ export default class MetableStore implements IMetableStore{
|
|||||||
* @param {Array} collection -
|
* @param {Array} collection -
|
||||||
*/
|
*/
|
||||||
mapMetadataToCollection(metadata: IMetadata[], parseType: string = 'parse') {
|
mapMetadataToCollection(metadata: IMetadata[], parseType: string = 'parse') {
|
||||||
return metadata.map((model) => this.mapMetadataToCollection(model, parseType));
|
return metadata.map((model) =>
|
||||||
|
this.mapMetadataToCollection(model, parseType)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -177,14 +179,16 @@ export default class MetableStore implements IMetableStore{
|
|||||||
*/
|
*/
|
||||||
from(meta: []) {
|
from(meta: []) {
|
||||||
if (Array.isArray(meta)) {
|
if (Array.isArray(meta)) {
|
||||||
meta.forEach((m) => { this.from(m); });
|
meta.forEach((m) => {
|
||||||
|
this.from(m);
|
||||||
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.metadata.push(meta);
|
this.metadata.push(meta);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @returns {array}
|
* @returns {array}
|
||||||
*/
|
*/
|
||||||
toArray(): IMetadata[] {
|
toArray(): IMetadata[] {
|
||||||
@@ -193,7 +197,7 @@ export default class MetableStore implements IMetableStore{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Static method to load metadata to the collection.
|
* Static method to load metadata to the collection.
|
||||||
* @param {Array} meta
|
* @param {Array} meta
|
||||||
*/
|
*/
|
||||||
static from(meta) {
|
static from(meta) {
|
||||||
const collection = new MetableCollection();
|
const collection = new MetableCollection();
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Service, Inject } from 'typedi';
|
import { Service, Inject } from 'typedi';
|
||||||
import TenancyService from 'services/Tenancy/TenancyService';
|
import TenancyService from 'services/Tenancy/TenancyService';
|
||||||
import { transactionIncrement } from 'utils';
|
import { transactionIncrement, parseBoolean } from 'utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Auto increment orders service.
|
* Auto increment orders service.
|
||||||
@@ -15,38 +15,18 @@ export default class AutoIncrementOrdersService {
|
|||||||
* @param {number} tenantId
|
* @param {number} tenantId
|
||||||
* @param {string} settingsGroup
|
* @param {string} settingsGroup
|
||||||
* @param {Function} getMaxTransactionNo
|
* @param {Function} getMaxTransactionNo
|
||||||
* @return {Promise<[string, string]>}
|
* @return {Promise<string>}
|
||||||
*/
|
*/
|
||||||
async getNextTransactionNumber(
|
getNextTransactionNumber(tenantId: number, settingsGroup: string): string {
|
||||||
tenantId: number,
|
|
||||||
settingsGroup: string,
|
|
||||||
getOrderTransaction: (prefix: string, number: string) => Promise<boolean>,
|
|
||||||
getMaxTransactionNumber: (prefix: string, number: string) => Promise<string>
|
|
||||||
): Promise<[string, string]> {
|
|
||||||
const settings = this.tenancy.settings(tenantId);
|
const settings = this.tenancy.settings(tenantId);
|
||||||
const group = settingsGroup;
|
const group = settingsGroup;
|
||||||
|
|
||||||
// Settings service transaction number and prefix.
|
// Settings service transaction number and prefix.
|
||||||
const settingNo = settings.get({ group, key: 'next_number' });
|
const autoIncrement = settings.get({ group, key: 'auto_increment' }, false);
|
||||||
const settingPrefix = settings.get({ group, key: 'number_prefix' });
|
const settingNo = settings.get({ group, key: 'next_number' }, '');
|
||||||
|
const settingPrefix = settings.get({ group, key: 'number_prefix' }, '');
|
||||||
|
|
||||||
let nextInvoiceNumber = settingNo;
|
return parseBoolean(autoIncrement, false) ? `${settingPrefix}${settingNo}` : '';
|
||||||
|
|
||||||
const orderTransaction = await getOrderTransaction(
|
|
||||||
settingPrefix,
|
|
||||||
settingNo
|
|
||||||
);
|
|
||||||
if (orderTransaction) {
|
|
||||||
// Retrieve the max invoice number in the given prefix.
|
|
||||||
const maxInvoiceNo = await getMaxTransactionNumber(
|
|
||||||
settingPrefix,
|
|
||||||
settingNo
|
|
||||||
);
|
|
||||||
if (maxInvoiceNo) {
|
|
||||||
nextInvoiceNumber = transactionIncrement(maxInvoiceNo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return [settingPrefix, nextInvoiceNumber];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -55,16 +35,17 @@ export default class AutoIncrementOrdersService {
|
|||||||
* @param {string} orderGroup - Order group.
|
* @param {string} orderGroup - Order group.
|
||||||
* @param {string} orderNumber -Order number.
|
* @param {string} orderNumber -Order number.
|
||||||
*/
|
*/
|
||||||
async incrementSettingsNextNumber(
|
async incrementSettingsNextNumber(tenantId: number, group: string) {
|
||||||
tenantId,
|
|
||||||
orderGroup: string,
|
|
||||||
orderNumber: string
|
|
||||||
) {
|
|
||||||
const settings = this.tenancy.settings(tenantId);
|
const settings = this.tenancy.settings(tenantId);
|
||||||
|
const settingNo = settings.get({ group, key: 'next_number' });
|
||||||
|
const autoIncrement = settings.get({ group, key: 'auto_increment' });
|
||||||
|
|
||||||
|
// Can't continue if the auto-increment of the service was disabled.
|
||||||
|
if (!autoIncrement) return;
|
||||||
|
|
||||||
settings.set(
|
settings.set(
|
||||||
{ group: orderGroup, key: 'next_number' },
|
{ group, key: 'next_number' },
|
||||||
transactionIncrement(orderNumber)
|
transactionIncrement(settingNo)
|
||||||
);
|
);
|
||||||
await settings.save();
|
await settings.save();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ import CustomersService from 'services/Contacts/CustomersService';
|
|||||||
import ItemsEntriesService from 'services/Items/ItemsEntriesService';
|
import ItemsEntriesService from 'services/Items/ItemsEntriesService';
|
||||||
import JournalCommands from 'services/Accounting/JournalCommands';
|
import JournalCommands from 'services/Accounting/JournalCommands';
|
||||||
import { ACCOUNT_PARENT_TYPE } from 'data/AccountTypes';
|
import { ACCOUNT_PARENT_TYPE } from 'data/AccountTypes';
|
||||||
|
import AutoIncrementOrdersService from './AutoIncrementOrdersService';
|
||||||
|
|
||||||
const ERRORS = {
|
const ERRORS = {
|
||||||
PAYMENT_RECEIVE_NO_EXISTS: 'PAYMENT_RECEIVE_NO_EXISTS',
|
PAYMENT_RECEIVE_NO_EXISTS: 'PAYMENT_RECEIVE_NO_EXISTS',
|
||||||
@@ -41,6 +42,7 @@ const ERRORS = {
|
|||||||
INVOICES_IDS_NOT_FOUND: 'INVOICES_IDS_NOT_FOUND',
|
INVOICES_IDS_NOT_FOUND: 'INVOICES_IDS_NOT_FOUND',
|
||||||
ENTRIES_IDS_NOT_EXISTS: 'ENTRIES_IDS_NOT_EXISTS',
|
ENTRIES_IDS_NOT_EXISTS: 'ENTRIES_IDS_NOT_EXISTS',
|
||||||
INVOICES_NOT_DELIVERED_YET: 'INVOICES_NOT_DELIVERED_YET',
|
INVOICES_NOT_DELIVERED_YET: 'INVOICES_NOT_DELIVERED_YET',
|
||||||
|
PAYMENT_RECEIVE_NO_IS_REQUIRED: 'PAYMENT_RECEIVE_NO_IS_REQUIRED'
|
||||||
};
|
};
|
||||||
/**
|
/**
|
||||||
* Payment receive service.
|
* Payment receive service.
|
||||||
@@ -66,6 +68,9 @@ export default class PaymentReceiveService {
|
|||||||
@Inject()
|
@Inject()
|
||||||
dynamicListService: DynamicListingService;
|
dynamicListService: DynamicListingService;
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
autoIncrementOrdersService: AutoIncrementOrdersService;
|
||||||
|
|
||||||
@Inject('logger')
|
@Inject('logger')
|
||||||
logger: any;
|
logger: any;
|
||||||
|
|
||||||
@@ -144,7 +149,8 @@ export default class PaymentReceiveService {
|
|||||||
/**
|
/**
|
||||||
* Validates the invoices IDs existance.
|
* Validates the invoices IDs existance.
|
||||||
* @param {number} tenantId -
|
* @param {number} tenantId -
|
||||||
* @param {} paymentReceiveEntries -
|
* @param {number} customerId -
|
||||||
|
* @param {IPaymentReceiveEntryDTO[]} paymentReceiveEntries -
|
||||||
*/
|
*/
|
||||||
async validateInvoicesIDsExistance(
|
async validateInvoicesIDsExistance(
|
||||||
tenantId: number,
|
tenantId: number,
|
||||||
@@ -225,6 +231,61 @@ export default class PaymentReceiveService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the next unique payment receive number.
|
||||||
|
* @param {number} tenantId - Tenant id.
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
getNextPaymentReceiveNumber(tenantId: number): string {
|
||||||
|
return this.autoIncrementOrdersService.getNextTransactionNumber(
|
||||||
|
tenantId,
|
||||||
|
'payment_receives'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increment the payment receive next number.
|
||||||
|
* @param {number} tenantId
|
||||||
|
*/
|
||||||
|
incrementNextPaymentReceiveNumber(tenantId: number) {
|
||||||
|
return this.autoIncrementOrdersService.incrementSettingsNextNumber(
|
||||||
|
tenantId,
|
||||||
|
'payment_receives'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate the payment receive number require.
|
||||||
|
* @param {IPaymentReceive} paymentReceiveObj
|
||||||
|
*/
|
||||||
|
validatePaymentReceiveNoRequire(paymentReceiveObj: IPaymentReceive) {
|
||||||
|
if (!paymentReceiveObj.paymentReceiveNo) {
|
||||||
|
throw new ServiceError(ERRORS.PAYMENT_RECEIVE_NO_IS_REQUIRED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve estimate number to object model.
|
||||||
|
* @param {number} tenantId
|
||||||
|
* @param {IPaymentReceiveCreateDTO | IPaymentReceiveEditDTO} paymentReceiveDTO - Payment receive DTO.
|
||||||
|
* @param {IPaymentReceive} oldPaymentReceive - Old payment model object.
|
||||||
|
*/
|
||||||
|
transformPaymentNumberToModel(
|
||||||
|
tenantId: number,
|
||||||
|
paymentReceiveDTO: IPaymentReceiveCreateDTO | IPaymentReceiveEditDTO,
|
||||||
|
oldPaymentReceive?: IPaymentReceive
|
||||||
|
): string {
|
||||||
|
// Retreive the next invoice number.
|
||||||
|
const autoNextNumber = this.getNextPaymentReceiveNumber(tenantId);
|
||||||
|
|
||||||
|
if (paymentReceiveDTO.paymentReceiveNo) {
|
||||||
|
return paymentReceiveDTO.paymentReceiveNo;
|
||||||
|
}
|
||||||
|
return oldPaymentReceive
|
||||||
|
? oldPaymentReceive.paymentReceiveNo
|
||||||
|
: autoNextNumber;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validate the payment receive entries IDs existance.
|
* Validate the payment receive entries IDs existance.
|
||||||
* @param {number} tenantId
|
* @param {number} tenantId
|
||||||
@@ -246,7 +307,6 @@ export default class PaymentReceiveService {
|
|||||||
'payment_receive_id',
|
'payment_receive_id',
|
||||||
paymentReceiveId
|
paymentReceiveId
|
||||||
);
|
);
|
||||||
|
|
||||||
const storedEntriesIds = storedEntries.map((entry: any) => entry.id);
|
const storedEntriesIds = storedEntries.map((entry: any) => entry.id);
|
||||||
const notFoundEntriesIds = difference(entriesIds, storedEntriesIds);
|
const notFoundEntriesIds = difference(entriesIds, storedEntriesIds);
|
||||||
|
|
||||||
@@ -255,6 +315,36 @@ export default class PaymentReceiveService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transformes the create payment receive DTO to model object.
|
||||||
|
* @param {number} tenantId
|
||||||
|
* @param {IPaymentReceiveCreateDTO} paymentReceiveDTO
|
||||||
|
*/
|
||||||
|
transformPaymentReceiveDTOToModel(
|
||||||
|
tenantId: number,
|
||||||
|
paymentReceiveDTO: IPaymentReceiveCreateDTO | IPaymentReceiveEditDTO,
|
||||||
|
oldPaymentReceive?: IPaymentReceive
|
||||||
|
): IPaymentReceive {
|
||||||
|
const paymentAmount = sumBy(paymentReceiveDTO.entries, 'paymentAmount');
|
||||||
|
|
||||||
|
// Retrieve the next payment receive number.
|
||||||
|
const paymentReceiveNo = this.transformPaymentNumberToModel(
|
||||||
|
tenantId,
|
||||||
|
paymentReceiveDTO,
|
||||||
|
oldPaymentReceive
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
amount: paymentAmount,
|
||||||
|
...formatDateFields(omit(paymentReceiveDTO, ['entries']), [
|
||||||
|
'paymentDate',
|
||||||
|
]),
|
||||||
|
...(paymentReceiveNo ? { paymentReceiveNo } : {}),
|
||||||
|
entries: paymentReceiveDTO.entries.map((entry) => ({
|
||||||
|
...omit(entry, ['id']),
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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.
|
||||||
@@ -268,34 +358,36 @@ export default class PaymentReceiveService {
|
|||||||
authorizedUser: ISystemUser
|
authorizedUser: ISystemUser
|
||||||
) {
|
) {
|
||||||
const { PaymentReceive } = this.tenancy.models(tenantId);
|
const { PaymentReceive } = this.tenancy.models(tenantId);
|
||||||
const paymentAmount = sumBy(paymentReceiveDTO.entries, 'paymentAmount');
|
|
||||||
|
// Transformes the payment receive DTO to model.
|
||||||
|
const paymentReceiveObj = this.transformPaymentReceiveDTOToModel(
|
||||||
|
tenantId,
|
||||||
|
paymentReceiveDTO
|
||||||
|
);
|
||||||
|
// Validate payment receive is required.
|
||||||
|
this.validatePaymentReceiveNoRequire(paymentReceiveObj);
|
||||||
|
|
||||||
// Validate payment receive number uniquiness.
|
// Validate payment receive number uniquiness.
|
||||||
if (paymentReceiveDTO.paymentReceiveNo) {
|
await this.validatePaymentReceiveNoExistance(
|
||||||
await this.validatePaymentReceiveNoExistance(
|
tenantId,
|
||||||
tenantId,
|
paymentReceiveObj.paymentReceiveNo
|
||||||
paymentReceiveDTO.paymentReceiveNo
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
// Validate customer existance.
|
// Validate customer existance.
|
||||||
await this.customersService.getCustomerByIdOrThrowError(
|
await this.customersService.getCustomerByIdOrThrowError(
|
||||||
tenantId,
|
tenantId,
|
||||||
paymentReceiveDTO.customerId
|
paymentReceiveDTO.customerId
|
||||||
);
|
);
|
||||||
|
|
||||||
// Validate the deposit account existance and type.
|
// Validate the deposit account existance and type.
|
||||||
await this.getDepositAccountOrThrowError(
|
await this.getDepositAccountOrThrowError(
|
||||||
tenantId,
|
tenantId,
|
||||||
paymentReceiveDTO.depositAccountId
|
paymentReceiveDTO.depositAccountId
|
||||||
);
|
);
|
||||||
|
|
||||||
// Validate payment receive invoices IDs existance.
|
// Validate payment receive invoices IDs existance.
|
||||||
await this.validateInvoicesIDsExistance(
|
await this.validateInvoicesIDsExistance(
|
||||||
tenantId,
|
tenantId,
|
||||||
paymentReceiveDTO.customerId,
|
paymentReceiveDTO.customerId,
|
||||||
paymentReceiveDTO.entries
|
paymentReceiveDTO.entries
|
||||||
);
|
);
|
||||||
|
|
||||||
// Validate invoice payment amount.
|
// Validate invoice payment amount.
|
||||||
await this.validateInvoicesPaymentsAmount(
|
await this.validateInvoicesPaymentsAmount(
|
||||||
tenantId,
|
tenantId,
|
||||||
@@ -304,15 +396,9 @@ export default class PaymentReceiveService {
|
|||||||
|
|
||||||
this.logger.info('[payment_receive] inserting to the storage.');
|
this.logger.info('[payment_receive] inserting to the storage.');
|
||||||
const paymentReceive = await PaymentReceive.query().insertGraphAndFetch({
|
const paymentReceive = await PaymentReceive.query().insertGraphAndFetch({
|
||||||
amount: paymentAmount,
|
...paymentReceiveObj,
|
||||||
...formatDateFields(omit(paymentReceiveDTO, ['entries']), [
|
|
||||||
'paymentDate',
|
|
||||||
]),
|
|
||||||
entries: paymentReceiveDTO.entries.map((entry) => ({
|
|
||||||
...omit(entry, ['id']),
|
|
||||||
})),
|
|
||||||
});
|
});
|
||||||
|
// Triggers `onPaymentReceiveCreated` event.
|
||||||
await this.eventDispatcher.dispatch(events.paymentReceive.onCreated, {
|
await this.eventDispatcher.dispatch(events.paymentReceive.onCreated, {
|
||||||
tenantId,
|
tenantId,
|
||||||
paymentReceive,
|
paymentReceive,
|
||||||
@@ -349,19 +435,26 @@ export default class PaymentReceiveService {
|
|||||||
authorizedUser: ISystemUser
|
authorizedUser: ISystemUser
|
||||||
) {
|
) {
|
||||||
const { PaymentReceive } = this.tenancy.models(tenantId);
|
const { PaymentReceive } = this.tenancy.models(tenantId);
|
||||||
const paymentAmount = sumBy(paymentReceiveDTO.entries, 'paymentAmount');
|
|
||||||
|
|
||||||
this.logger.info('[payment_receive] trying to edit payment receive.', {
|
this.logger.info('[payment_receive] trying to edit payment receive.', {
|
||||||
tenantId,
|
tenantId,
|
||||||
paymentReceiveId,
|
paymentReceiveId,
|
||||||
paymentReceiveDTO,
|
paymentReceiveDTO,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Validate the payment receive existance.
|
// Validate the payment receive existance.
|
||||||
const oldPaymentReceive = await this.getPaymentReceiveOrThrowError(
|
const oldPaymentReceive = await this.getPaymentReceiveOrThrowError(
|
||||||
tenantId,
|
tenantId,
|
||||||
paymentReceiveId
|
paymentReceiveId
|
||||||
);
|
);
|
||||||
|
// Transformes the payment receive DTO to model.
|
||||||
|
const paymentReceiveObj = this.transformPaymentReceiveDTOToModel(
|
||||||
|
tenantId,
|
||||||
|
paymentReceiveDTO,
|
||||||
|
oldPaymentReceive
|
||||||
|
);
|
||||||
|
// Validate payment receive number existance.
|
||||||
|
this.validatePaymentReceiveNoRequire(paymentReceiveObj);
|
||||||
|
|
||||||
// Validate payment receive number uniquiness.
|
// Validate payment receive number uniquiness.
|
||||||
if (paymentReceiveDTO.paymentReceiveNo) {
|
if (paymentReceiveDTO.paymentReceiveNo) {
|
||||||
await this.validatePaymentReceiveNoExistance(
|
await this.validatePaymentReceiveNoExistance(
|
||||||
@@ -375,7 +468,6 @@ export default class PaymentReceiveService {
|
|||||||
tenantId,
|
tenantId,
|
||||||
paymentReceiveDTO.depositAccountId
|
paymentReceiveDTO.depositAccountId
|
||||||
);
|
);
|
||||||
|
|
||||||
// Validate the entries ids existance on payment receive type.
|
// Validate the entries ids existance on payment receive type.
|
||||||
await this.validateEntriesIdsExistance(
|
await this.validateEntriesIdsExistance(
|
||||||
tenantId,
|
tenantId,
|
||||||
@@ -397,11 +489,7 @@ export default class PaymentReceiveService {
|
|||||||
// Update the payment receive transaction.
|
// Update the payment receive transaction.
|
||||||
const paymentReceive = await PaymentReceive.query().upsertGraphAndFetch({
|
const paymentReceive = await PaymentReceive.query().upsertGraphAndFetch({
|
||||||
id: paymentReceiveId,
|
id: paymentReceiveId,
|
||||||
amount: paymentAmount,
|
...paymentReceiveObj,
|
||||||
...formatDateFields(omit(paymentReceiveDTO, ['entries']), [
|
|
||||||
'paymentDate',
|
|
||||||
]),
|
|
||||||
entries: paymentReceiveDTO.entries,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
await this.eventDispatcher.dispatch(events.paymentReceive.onEdited, {
|
await this.eventDispatcher.dispatch(events.paymentReceive.onEdited, {
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import events from 'subscribers/events';
|
|||||||
import { ServiceError } from 'exceptions';
|
import { ServiceError } from 'exceptions';
|
||||||
import CustomersService from 'services/Contacts/CustomersService';
|
import CustomersService from 'services/Contacts/CustomersService';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
import AutoIncrementOrdersService from './AutoIncrementOrdersService';
|
||||||
|
|
||||||
const ERRORS = {
|
const ERRORS = {
|
||||||
SALE_ESTIMATE_NOT_FOUND: 'SALE_ESTIMATE_NOT_FOUND',
|
SALE_ESTIMATE_NOT_FOUND: 'SALE_ESTIMATE_NOT_FOUND',
|
||||||
@@ -30,6 +31,7 @@ const ERRORS = {
|
|||||||
SALE_ESTIMATE_ALREADY_REJECTED: 'SALE_ESTIMATE_ALREADY_REJECTED',
|
SALE_ESTIMATE_ALREADY_REJECTED: 'SALE_ESTIMATE_ALREADY_REJECTED',
|
||||||
SALE_ESTIMATE_ALREADY_APPROVED: 'SALE_ESTIMATE_ALREADY_APPROVED',
|
SALE_ESTIMATE_ALREADY_APPROVED: 'SALE_ESTIMATE_ALREADY_APPROVED',
|
||||||
SALE_ESTIMATE_NOT_DELIVERED: 'SALE_ESTIMATE_NOT_DELIVERED',
|
SALE_ESTIMATE_NOT_DELIVERED: 'SALE_ESTIMATE_NOT_DELIVERED',
|
||||||
|
SALE_ESTIMATE_NO_IS_REQUIRED: 'SALE_ESTIMATE_NO_IS_REQUIRED'
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -56,6 +58,9 @@ export default class SaleEstimateService {
|
|||||||
@EventDispatcher()
|
@EventDispatcher()
|
||||||
eventDispatcher: EventDispatcherInterface;
|
eventDispatcher: EventDispatcherInterface;
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
autoIncrementOrdersService: AutoIncrementOrdersService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve sale estimate or throw service error.
|
* Retrieve sale estimate or throw service error.
|
||||||
* @param {number} tenantId
|
* @param {number} tenantId
|
||||||
@@ -100,7 +105,7 @@ export default class SaleEstimateService {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Validates the given sale estimate not already converted to invoice.
|
* Validates the given sale estimate not already converted to invoice.
|
||||||
* @param {ISaleEstimate} saleEstimate -
|
* @param {ISaleEstimate} saleEstimate -
|
||||||
*/
|
*/
|
||||||
validateEstimateNotConverted(saleEstimate: ISaleEstimate) {
|
validateEstimateNotConverted(saleEstimate: ISaleEstimate) {
|
||||||
if (saleEstimate.isConvertedToInvoice) {
|
if (saleEstimate.isConvertedToInvoice) {
|
||||||
@@ -108,6 +113,49 @@ export default class SaleEstimateService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the next unique estimate number.
|
||||||
|
* @param {number} tenantId - Tenant id.
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
getNextEstimateNumber(tenantId: number): string {
|
||||||
|
return this.autoIncrementOrdersService.getNextTransactionNumber(
|
||||||
|
tenantId,
|
||||||
|
'sales_estimates'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increment the estimate next number.
|
||||||
|
* @param {number} tenantId -
|
||||||
|
*/
|
||||||
|
incrementNextEstimateNumber(tenantId: number) {
|
||||||
|
return this.autoIncrementOrdersService.incrementSettingsNextNumber(
|
||||||
|
tenantId,
|
||||||
|
'sales_estimates'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve estimate number to object model.
|
||||||
|
* @param {number} tenantId
|
||||||
|
* @param {ISaleEstimateDTO} saleEstimateDTO
|
||||||
|
* @param {ISaleEstimate} oldSaleEstimate
|
||||||
|
*/
|
||||||
|
transformEstimateNumberToModel(
|
||||||
|
tenantId: number,
|
||||||
|
saleEstimateDTO: ISaleEstimateDTO,
|
||||||
|
oldSaleEstimate?: ISaleEstimate
|
||||||
|
): string {
|
||||||
|
// Retreive the next invoice number.
|
||||||
|
const autoNextNumber = this.getNextEstimateNumber(tenantId);
|
||||||
|
|
||||||
|
if (saleEstimateDTO.estimateNumber) {
|
||||||
|
return saleEstimateDTO.estimateNumber;
|
||||||
|
}
|
||||||
|
return oldSaleEstimate ? oldSaleEstimate.estimateNumber : autoNextNumber;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transform DTO object ot model object.
|
* Transform DTO object ot model object.
|
||||||
* @param {number} tenantId
|
* @param {number} tenantId
|
||||||
@@ -123,17 +171,24 @@ export default class SaleEstimateService {
|
|||||||
const { ItemEntry } = this.tenancy.models(tenantId);
|
const { ItemEntry } = this.tenancy.models(tenantId);
|
||||||
const amount = sumBy(estimateDTO.entries, (e) => ItemEntry.calcAmount(e));
|
const amount = sumBy(estimateDTO.entries, (e) => ItemEntry.calcAmount(e));
|
||||||
|
|
||||||
|
// Retreive the next estimate number.
|
||||||
|
const estimateNumber = this.transformEstimateNumberToModel(
|
||||||
|
tenantId,
|
||||||
|
estimateDTO,
|
||||||
|
oldSaleEstimate
|
||||||
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
amount,
|
amount,
|
||||||
...formatDateFields(omit(estimateDTO, ['delivered', 'entries']), [
|
...formatDateFields(omit(estimateDTO, ['delivered', 'entries']), [
|
||||||
'estimateDate',
|
'estimateDate',
|
||||||
'expirationDate',
|
'expirationDate',
|
||||||
]),
|
]),
|
||||||
|
...(estimateNumber ? { estimateNumber } : {}),
|
||||||
entries: estimateDTO.entries.map((entry) => ({
|
entries: estimateDTO.entries.map((entry) => ({
|
||||||
reference_type: 'SaleEstimate',
|
reference_type: 'SaleEstimate',
|
||||||
...omit(entry, ['total', 'amount', 'id']),
|
...omit(entry, ['total', 'amount', 'id']),
|
||||||
})),
|
})),
|
||||||
|
|
||||||
// Avoid rewrite the deliver date in edit mode when already published.
|
// Avoid rewrite the deliver date in edit mode when already published.
|
||||||
...(estimateDTO.delivered &&
|
...(estimateDTO.delivered &&
|
||||||
!oldSaleEstimate?.deliveredAt && {
|
!oldSaleEstimate?.deliveredAt && {
|
||||||
@@ -141,6 +196,16 @@ export default class SaleEstimateService {
|
|||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate the sale estimate number require.
|
||||||
|
* @param {ISaleEstimate} saleInvoiceObj
|
||||||
|
*/
|
||||||
|
validateEstimateNoRequire(saleInvoiceObj: ISaleEstimate) {
|
||||||
|
if (!saleInvoiceObj.estimateNumber) {
|
||||||
|
throw new ServiceError(ERRORS.SALE_ESTIMATE_NO_IS_REQUIRED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new estimate with associated entries.
|
* Creates a new estimate with associated entries.
|
||||||
@@ -160,11 +225,14 @@ export default class SaleEstimateService {
|
|||||||
// Transform DTO object ot model object.
|
// Transform DTO object ot model object.
|
||||||
const estimateObj = this.transformDTOToModel(tenantId, estimateDTO);
|
const estimateObj = this.transformDTOToModel(tenantId, estimateDTO);
|
||||||
|
|
||||||
|
// Validate the sale estimate number require.
|
||||||
|
this.validateEstimateNoRequire(estimateObj);
|
||||||
|
|
||||||
// Validate estimate number uniquiness on the storage.
|
// Validate estimate number uniquiness on the storage.
|
||||||
if (estimateDTO.estimateNumber) {
|
if (estimateObj.estimateNumber) {
|
||||||
await this.validateEstimateNumberExistance(
|
await this.validateEstimateNumberExistance(
|
||||||
tenantId,
|
tenantId,
|
||||||
estimateDTO.estimateNumber
|
estimateObj.estimateNumber
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
// Retrieve the given customer or throw not found service error.
|
// Retrieve the given customer or throw not found service error.
|
||||||
@@ -221,6 +289,9 @@ export default class SaleEstimateService {
|
|||||||
estimateDTO,
|
estimateDTO,
|
||||||
oldSaleEstimate
|
oldSaleEstimate
|
||||||
);
|
);
|
||||||
|
// Validate the sale estimate number require.
|
||||||
|
this.validateEstimateNoRequire(estimateObj);
|
||||||
|
|
||||||
// Validate estimate number uniquiness on the storage.
|
// Validate estimate number uniquiness on the storage.
|
||||||
if (estimateDTO.estimateNumber) {
|
if (estimateDTO.estimateNumber) {
|
||||||
await this.validateEstimateNumberExistance(
|
await this.validateEstimateNumberExistance(
|
||||||
|
|||||||
@@ -162,28 +162,44 @@ export default class SaleInvoicesService {
|
|||||||
* @param {number} tenantId - Tenant id.
|
* @param {number} tenantId - Tenant id.
|
||||||
* @return {string}
|
* @return {string}
|
||||||
*/
|
*/
|
||||||
async getNextInvoiceNumber(tenantId: number): Promise<[string, string]> {
|
getNextInvoiceNumber(tenantId: number): string {
|
||||||
const { SaleInvoice } = this.tenancy.models(tenantId);
|
|
||||||
|
|
||||||
// Retrieve the max invoice number in the given prefix.
|
|
||||||
const getMaxInvoicesNo = (prefix, number) => {
|
|
||||||
return SaleInvoice.query()
|
|
||||||
.modify('maxInvoiceNo', prefix, number)
|
|
||||||
.then((res) => res?.invNumber);
|
|
||||||
};
|
|
||||||
// Retrieve the order transaction number by number.
|
|
||||||
const getTransactionNumber = (prefix, number) => {
|
|
||||||
return SaleInvoice.query().modify('byPrefixAndNumber', prefix, number);
|
|
||||||
};
|
|
||||||
|
|
||||||
return this.autoIncrementOrdersService.getNextTransactionNumber(
|
return this.autoIncrementOrdersService.getNextTransactionNumber(
|
||||||
tenantId,
|
tenantId,
|
||||||
'sales_invoices',
|
'sales_invoices'
|
||||||
getTransactionNumber,
|
|
||||||
getMaxInvoicesNo
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increment the invoice next number.
|
||||||
|
* @param {number} tenantId -
|
||||||
|
*/
|
||||||
|
incrementNextInvoiceNumber(tenantId: number) {
|
||||||
|
return this.autoIncrementOrdersService.incrementSettingsNextNumber(
|
||||||
|
tenantId,
|
||||||
|
'sales_invoices'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve invoice number to object model.
|
||||||
|
* @param tenantId
|
||||||
|
* @param saleInvoiceDTO
|
||||||
|
* @param oldSaleInvoice
|
||||||
|
*/
|
||||||
|
transformInvoiceNumberToModel(
|
||||||
|
tenantId: number,
|
||||||
|
saleInvoiceDTO: ISaleInvoiceCreateDTO | ISaleInvoiceEditDTO,
|
||||||
|
oldSaleInvoice?: ISaleInvoice
|
||||||
|
): string {
|
||||||
|
// Retreive the next invoice number.
|
||||||
|
const autoNextNumber = this.getNextInvoiceNumber(tenantId);
|
||||||
|
|
||||||
|
if (saleInvoiceDTO.invoiceNo) {
|
||||||
|
return saleInvoiceDTO.invoiceNo;
|
||||||
|
}
|
||||||
|
return oldSaleInvoice ? oldSaleInvoice.invoiceNo : autoNextNumber;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transform DTO object to model object.
|
* Transform DTO object to model object.
|
||||||
* @param {number} tenantId - Tenant id.
|
* @param {number} tenantId - Tenant id.
|
||||||
@@ -192,33 +208,37 @@ export default class SaleInvoicesService {
|
|||||||
transformDTOToModel(
|
transformDTOToModel(
|
||||||
tenantId: number,
|
tenantId: number,
|
||||||
saleInvoiceDTO: ISaleInvoiceCreateDTO | ISaleInvoiceEditDTO,
|
saleInvoiceDTO: ISaleInvoiceCreateDTO | ISaleInvoiceEditDTO,
|
||||||
oldSaleInvoice?: ISaleInvoice,
|
oldSaleInvoice?: ISaleInvoice
|
||||||
autoNextNumber?: [string, string] // prefix, number
|
|
||||||
): ISaleInvoice {
|
): ISaleInvoice {
|
||||||
const { ItemEntry } = this.tenancy.models(tenantId);
|
const { ItemEntry } = this.tenancy.models(tenantId);
|
||||||
|
|
||||||
const balance = sumBy(saleInvoiceDTO.entries, (e) =>
|
const balance = sumBy(saleInvoiceDTO.entries, (e) =>
|
||||||
ItemEntry.calcAmount(e)
|
ItemEntry.calcAmount(e)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const invoiceNo = this.transformInvoiceNumberToModel(
|
||||||
|
tenantId,
|
||||||
|
saleInvoiceDTO,
|
||||||
|
oldSaleInvoice
|
||||||
|
);
|
||||||
return {
|
return {
|
||||||
...formatDateFields(
|
...formatDateFields(
|
||||||
omit(saleInvoiceDTO, ['delivered', 'entries', 'fromEstimateId']),
|
omit(saleInvoiceDTO, ['delivered', 'entries', 'fromEstimateId']),
|
||||||
['invoiceDate', 'dueDate']
|
['invoiceDate', 'dueDate']
|
||||||
),
|
),
|
||||||
// Avoid rewrite the deliver date in edit mode when already published.
|
// Avoid rewrite the deliver date in edit mode when already published.
|
||||||
|
balance,
|
||||||
...(saleInvoiceDTO.delivered &&
|
...(saleInvoiceDTO.delivered &&
|
||||||
!oldSaleInvoice?.deliveredAt && {
|
!oldSaleInvoice?.deliveredAt && {
|
||||||
deliveredAt: moment().toMySqlDateTime(),
|
deliveredAt: moment().toMySqlDateTime(),
|
||||||
}),
|
}),
|
||||||
balance,
|
// Avoid add payment amount in edit mode.
|
||||||
paymentAmount: 0,
|
...(!oldSaleInvoice
|
||||||
...(saleInvoiceDTO.invoiceNo || autoNextNumber
|
|
||||||
? {
|
? {
|
||||||
invoiceNo: saleInvoiceDTO.invoiceNo
|
paymentAmount: 0,
|
||||||
? saleInvoiceDTO.invoiceNo
|
|
||||||
: join(autoNextNumber, ''),
|
|
||||||
}
|
}
|
||||||
: {}),
|
: {}),
|
||||||
|
...(invoiceNo ? { invoiceNo } : {}),
|
||||||
entries: saleInvoiceDTO.entries.map((entry) => ({
|
entries: saleInvoiceDTO.entries.map((entry) => ({
|
||||||
referenceType: 'SaleInvoice',
|
referenceType: 'SaleInvoice',
|
||||||
...omit(entry, ['amount', 'id']),
|
...omit(entry, ['amount', 'id']),
|
||||||
@@ -226,6 +246,16 @@ export default class SaleInvoicesService {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate the invoice number require.
|
||||||
|
* @param {ISaleInvoice} saleInvoiceObj
|
||||||
|
*/
|
||||||
|
validateInvoiceNoRequire(saleInvoiceObj: ISaleInvoice) {
|
||||||
|
if (!saleInvoiceObj.invoiceNo) {
|
||||||
|
throw new ServiceError(ERRORS.SALE_INVOICE_NO_IS_REQUIRED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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.
|
||||||
@@ -241,28 +271,25 @@ export default class SaleInvoicesService {
|
|||||||
): Promise<ISaleInvoice> {
|
): Promise<ISaleInvoice> {
|
||||||
const { saleInvoiceRepository } = this.tenancy.repositories(tenantId);
|
const { saleInvoiceRepository } = this.tenancy.repositories(tenantId);
|
||||||
|
|
||||||
// The next invoice number automattically or manually.
|
|
||||||
const autoNextNumber = !saleInvoiceDTO.invoiceNo
|
|
||||||
? await this.getNextInvoiceNumber(tenantId)
|
|
||||||
: null;
|
|
||||||
|
|
||||||
// Transform DTO object to model object.
|
// Transform DTO object to model object.
|
||||||
const saleInvoiceObj = this.transformDTOToModel(
|
const saleInvoiceObj = this.transformDTOToModel(
|
||||||
tenantId,
|
tenantId,
|
||||||
saleInvoiceDTO,
|
saleInvoiceDTO,
|
||||||
null,
|
null
|
||||||
autoNextNumber
|
|
||||||
);
|
);
|
||||||
|
this.validateInvoiceNoRequire(saleInvoiceObj);
|
||||||
|
|
||||||
// Validate customer existance.
|
// Validate customer existance.
|
||||||
await this.customersService.getCustomerByIdOrThrowError(
|
await this.customersService.getCustomerByIdOrThrowError(
|
||||||
tenantId,
|
tenantId,
|
||||||
saleInvoiceDTO.customerId
|
saleInvoiceDTO.customerId
|
||||||
);
|
);
|
||||||
|
|
||||||
// Validate sale invoice number uniquiness.
|
// Validate sale invoice number uniquiness.
|
||||||
if (saleInvoiceDTO.invoiceNo) {
|
if (saleInvoiceObj.invoiceNo) {
|
||||||
await this.validateInvoiceNumberUnique(
|
await this.validateInvoiceNumberUnique(
|
||||||
tenantId,
|
tenantId,
|
||||||
saleInvoiceDTO.invoiceNo
|
saleInvoiceObj.invoiceNo
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
// Validate the from estimate id exists on the storage.
|
// Validate the from estimate id exists on the storage.
|
||||||
@@ -296,7 +323,6 @@ export default class SaleInvoicesService {
|
|||||||
saleInvoiceDTO,
|
saleInvoiceDTO,
|
||||||
saleInvoiceId: saleInvoice.id,
|
saleInvoiceId: saleInvoice.id,
|
||||||
authorizedUser,
|
authorizedUser,
|
||||||
autoNextNumber,
|
|
||||||
});
|
});
|
||||||
this.logger.info('[sale_invoice] successfully inserted.', {
|
this.logger.info('[sale_invoice] successfully inserted.', {
|
||||||
tenantId,
|
tenantId,
|
||||||
@@ -317,11 +343,12 @@ export default class SaleInvoicesService {
|
|||||||
public async editSaleInvoice(
|
public async editSaleInvoice(
|
||||||
tenantId: number,
|
tenantId: number,
|
||||||
saleInvoiceId: number,
|
saleInvoiceId: number,
|
||||||
saleInvoiceDTO: any,
|
saleInvoiceDTO: ISaleInvoiceEditDTO,
|
||||||
authorizedUser: ISystemUser
|
authorizedUser: ISystemUser
|
||||||
): Promise<ISaleInvoice> {
|
): Promise<ISaleInvoice> {
|
||||||
const { saleInvoiceRepository } = this.tenancy.repositories(tenantId);
|
const { saleInvoiceRepository } = this.tenancy.repositories(tenantId);
|
||||||
|
|
||||||
|
// Retrieve the sale invoice or throw not found service error.
|
||||||
const oldSaleInvoice = await this.getInvoiceOrThrowError(
|
const oldSaleInvoice = await this.getInvoiceOrThrowError(
|
||||||
tenantId,
|
tenantId,
|
||||||
saleInvoiceId
|
saleInvoiceId
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import ItemsEntriesService from 'services/Items/ItemsEntriesService';
|
|||||||
import { ItemEntry } from 'models';
|
import { ItemEntry } from 'models';
|
||||||
import InventoryService from 'services/Inventory/Inventory';
|
import InventoryService from 'services/Inventory/Inventory';
|
||||||
import { ACCOUNT_PARENT_TYPE } from 'data/AccountTypes';
|
import { ACCOUNT_PARENT_TYPE } from 'data/AccountTypes';
|
||||||
|
import AutoIncrementOrdersService from './AutoIncrementOrdersService';
|
||||||
|
|
||||||
const ERRORS = {
|
const ERRORS = {
|
||||||
SALE_RECEIPT_NOT_FOUND: 'SALE_RECEIPT_NOT_FOUND',
|
SALE_RECEIPT_NOT_FOUND: 'SALE_RECEIPT_NOT_FOUND',
|
||||||
@@ -26,6 +27,7 @@ const ERRORS = {
|
|||||||
DEPOSIT_ACCOUNT_NOT_CURRENT_ASSET: 'DEPOSIT_ACCOUNT_NOT_CURRENT_ASSET',
|
DEPOSIT_ACCOUNT_NOT_CURRENT_ASSET: 'DEPOSIT_ACCOUNT_NOT_CURRENT_ASSET',
|
||||||
SALE_RECEIPT_NUMBER_NOT_UNIQUE: 'SALE_RECEIPT_NUMBER_NOT_UNIQUE',
|
SALE_RECEIPT_NUMBER_NOT_UNIQUE: 'SALE_RECEIPT_NUMBER_NOT_UNIQUE',
|
||||||
SALE_RECEIPT_IS_ALREADY_CLOSED: 'SALE_RECEIPT_IS_ALREADY_CLOSED',
|
SALE_RECEIPT_IS_ALREADY_CLOSED: 'SALE_RECEIPT_IS_ALREADY_CLOSED',
|
||||||
|
SALE_RECEIPT_NO_IS_REQUIRED: 'SALE_RECEIPT_NO_IS_REQUIRED'
|
||||||
};
|
};
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
@@ -51,6 +53,9 @@ export default class SalesReceiptService {
|
|||||||
@Inject('logger')
|
@Inject('logger')
|
||||||
logger: any;
|
logger: any;
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
autoIncrementOrdersService: AutoIncrementOrdersService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validate whether sale receipt exists on the storage.
|
* Validate whether sale receipt exists on the storage.
|
||||||
* @param {number} tenantId -
|
* @param {number} tenantId -
|
||||||
@@ -130,6 +135,59 @@ export default class SalesReceiptService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate the sale receipt number require.
|
||||||
|
* @param {ISaleReceipt} saleReceipt
|
||||||
|
*/
|
||||||
|
validateReceiptNoRequire(saleReceipt: ISaleReceipt) {
|
||||||
|
if (!saleReceipt.receiptNumber) {
|
||||||
|
throw new ServiceError(ERRORS.SALE_RECEIPT_NO_IS_REQUIRED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the next unique receipt number.
|
||||||
|
* @param {number} tenantId - Tenant id.
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
getNextReceiptNumber(tenantId: number): string {
|
||||||
|
return this.autoIncrementOrdersService.getNextTransactionNumber(
|
||||||
|
tenantId,
|
||||||
|
'sales_receipts'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increment the receipt next number.
|
||||||
|
* @param {number} tenantId -
|
||||||
|
*/
|
||||||
|
incrementNextReceiptNumber(tenantId: number) {
|
||||||
|
return this.autoIncrementOrdersService.incrementSettingsNextNumber(
|
||||||
|
tenantId,
|
||||||
|
'sales_receipts'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve estimate number to object model.
|
||||||
|
* @param {number} tenantId
|
||||||
|
* @param {ISaleReceiptDTO} saleReceiptDTO - Sale receipt DTO.
|
||||||
|
* @param {ISaleReceipt} oldSaleReceipt - Old receipt model object.
|
||||||
|
*/
|
||||||
|
transformReceiptNumberToModel(
|
||||||
|
tenantId: number,
|
||||||
|
saleReceiptDTO: ISaleReceiptDTO,
|
||||||
|
oldSaleReceipt?: ISaleReceipt
|
||||||
|
): string {
|
||||||
|
// Retreive the next invoice number.
|
||||||
|
const autoNextNumber = this.getNextReceiptNumber(tenantId);
|
||||||
|
|
||||||
|
if (saleReceiptDTO.receiptNumber) {
|
||||||
|
return saleReceiptDTO.receiptNumber;
|
||||||
|
}
|
||||||
|
return oldSaleReceipt ? oldSaleReceipt.receiptNumber : autoNextNumber;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transform DTO object to model object.
|
* Transform DTO object to model object.
|
||||||
* @param {ISaleReceiptDTO} saleReceiptDTO -
|
* @param {ISaleReceiptDTO} saleReceiptDTO -
|
||||||
@@ -137,18 +195,26 @@ export default class SalesReceiptService {
|
|||||||
* @returns {ISaleReceipt}
|
* @returns {ISaleReceipt}
|
||||||
*/
|
*/
|
||||||
transformObjectDTOToModel(
|
transformObjectDTOToModel(
|
||||||
|
tenantId: number,
|
||||||
saleReceiptDTO: ISaleReceiptDTO,
|
saleReceiptDTO: ISaleReceiptDTO,
|
||||||
oldSaleReceipt?: ISaleReceipt
|
oldSaleReceipt?: ISaleReceipt
|
||||||
): ISaleReceipt {
|
): ISaleReceipt {
|
||||||
const amount = sumBy(saleReceiptDTO.entries, (e) =>
|
const amount = sumBy(saleReceiptDTO.entries, (e) =>
|
||||||
ItemEntry.calcAmount(e)
|
ItemEntry.calcAmount(e)
|
||||||
);
|
);
|
||||||
|
// Retreive the receipt number.
|
||||||
|
const receiptNumber = this.transformReceiptNumberToModel(
|
||||||
|
tenantId,
|
||||||
|
saleReceiptDTO,
|
||||||
|
oldSaleReceipt
|
||||||
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
amount,
|
amount,
|
||||||
...formatDateFields(omit(saleReceiptDTO, ['closed', 'entries']), [
|
...formatDateFields(omit(saleReceiptDTO, ['closed', 'entries']), [
|
||||||
'receiptDate',
|
'receiptDate',
|
||||||
]),
|
]),
|
||||||
|
...(receiptNumber ? { receiptNumber } : {}),
|
||||||
// Avoid rewrite the deliver date in edit mode when already published.
|
// Avoid rewrite the deliver date in edit mode when already published.
|
||||||
...(saleReceiptDTO.closed &&
|
...(saleReceiptDTO.closed &&
|
||||||
!oldSaleReceipt?.closedAt && {
|
!oldSaleReceipt?.closedAt && {
|
||||||
@@ -174,7 +240,12 @@ export default class SalesReceiptService {
|
|||||||
const { SaleReceipt } = this.tenancy.models(tenantId);
|
const { SaleReceipt } = this.tenancy.models(tenantId);
|
||||||
|
|
||||||
// Transform sale receipt DTO to model.
|
// Transform sale receipt DTO to model.
|
||||||
const saleReceiptObj = this.transformObjectDTOToModel(saleReceiptDTO);
|
const saleReceiptObj = this.transformObjectDTOToModel(
|
||||||
|
tenantId,
|
||||||
|
saleReceiptDTO
|
||||||
|
);
|
||||||
|
// Validate receipt number is required.
|
||||||
|
this.validateReceiptNoRequire(saleReceiptObj);
|
||||||
|
|
||||||
// Validate receipt deposit account existance and type.
|
// Validate receipt deposit account existance and type.
|
||||||
await this.validateReceiptDepositAccountExistance(
|
await this.validateReceiptDepositAccountExistance(
|
||||||
@@ -238,9 +309,13 @@ export default class SalesReceiptService {
|
|||||||
);
|
);
|
||||||
// Transform sale receipt DTO to model.
|
// Transform sale receipt DTO to model.
|
||||||
const saleReceiptObj = this.transformObjectDTOToModel(
|
const saleReceiptObj = this.transformObjectDTOToModel(
|
||||||
|
tenantId,
|
||||||
saleReceiptDTO,
|
saleReceiptDTO,
|
||||||
oldSaleReceipt
|
oldSaleReceipt
|
||||||
);
|
);
|
||||||
|
// Validate receipt number is required.
|
||||||
|
this.validateReceiptNoRequire(saleReceiptObj);
|
||||||
|
|
||||||
// Validate receipt deposit account existance and type.
|
// Validate receipt deposit account existance and type.
|
||||||
await this.validateReceiptDepositAccountExistance(
|
await this.validateReceiptDepositAccountExistance(
|
||||||
tenantId,
|
tenantId,
|
||||||
@@ -309,7 +384,7 @@ export default class SalesReceiptService {
|
|||||||
await this.eventDispatcher.dispatch(events.saleReceipt.onDeleted, {
|
await this.eventDispatcher.dispatch(events.saleReceipt.onDeleted, {
|
||||||
tenantId,
|
tenantId,
|
||||||
saleReceiptId,
|
saleReceiptId,
|
||||||
oldSaleReceipt
|
oldSaleReceipt,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -463,7 +538,7 @@ export default class SalesReceiptService {
|
|||||||
'SaleReceipt',
|
'SaleReceipt',
|
||||||
saleReceipt.receiptDate,
|
saleReceipt.receiptDate,
|
||||||
'OUT',
|
'OUT',
|
||||||
override,
|
override
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,4 +9,5 @@ export const ERRORS = {
|
|||||||
'INVOICE_AMOUNT_SMALLER_THAN_PAYMENT_AMOUNT',
|
'INVOICE_AMOUNT_SMALLER_THAN_PAYMENT_AMOUNT',
|
||||||
INVOICE_HAS_ASSOCIATED_PAYMENT_ENTRIES:
|
INVOICE_HAS_ASSOCIATED_PAYMENT_ENTRIES:
|
||||||
'INVOICE_HAS_ASSOCIATED_PAYMENT_ENTRIES',
|
'INVOICE_HAS_ASSOCIATED_PAYMENT_ENTRIES',
|
||||||
|
SALE_INVOICE_NO_IS_REQUIRED: 'SALE_INVOICE_NO_IS_REQUIRED'
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -50,17 +50,9 @@ export default class SaleInvoiceSubscriber {
|
|||||||
@On(events.saleInvoice.onCreated)
|
@On(events.saleInvoice.onCreated)
|
||||||
public async handleInvoiceNextNumberIncrement({
|
public async handleInvoiceNextNumberIncrement({
|
||||||
tenantId,
|
tenantId,
|
||||||
saleInvoiceId,
|
|
||||||
saleInvoice,
|
|
||||||
saleInvoiceDTO,
|
|
||||||
autoNextNumber,
|
|
||||||
}) {
|
}) {
|
||||||
if (saleInvoiceDTO.invoiceNo || !autoNextNumber) return;
|
await this.saleInvoicesService.incrementNextInvoiceNumber(
|
||||||
|
|
||||||
await this.saleInvoicesService.autoIncrementOrdersService.incrementSettingsNextNumber(
|
|
||||||
tenantId,
|
tenantId,
|
||||||
'sales_invoices',
|
|
||||||
autoNextNumber[1]
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -130,9 +130,6 @@ export default class PaymentReceivesSubscriber {
|
|||||||
tenantId,
|
tenantId,
|
||||||
paymentReceiveId,
|
paymentReceiveId,
|
||||||
}) {
|
}) {
|
||||||
await this.settingsService.incrementNextNumber(tenantId, {
|
await this.paymentReceivesService.incrementNextPaymentReceiveNumber(tenantId);
|
||||||
key: 'next_number',
|
|
||||||
group: 'payment_receives',
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -289,6 +289,30 @@ const transformToMap = (objects, key) => {
|
|||||||
|
|
||||||
const transactionIncrement = (s) => s.replace(/([0-8]|\d?9+)?$/, (e) => ++e);
|
const transactionIncrement = (s) => s.replace(/([0-8]|\d?9+)?$/, (e) => ++e);
|
||||||
|
|
||||||
|
const booleanValuesRepresentingTrue: string[] = [
|
||||||
|
'true',
|
||||||
|
'1',
|
||||||
|
];
|
||||||
|
const booleanValuesRepresentingFalse: string[] = [
|
||||||
|
'false',
|
||||||
|
'0',
|
||||||
|
];
|
||||||
|
|
||||||
|
const normalizeValue = (value: any): string => value.toString().trim().toLowerCase();
|
||||||
|
|
||||||
|
const booleanValues: string[] = [
|
||||||
|
...booleanValuesRepresentingTrue,
|
||||||
|
...booleanValuesRepresentingFalse,
|
||||||
|
].map((value) => normalizeValue(value));
|
||||||
|
|
||||||
|
export const parseBoolean = <T>(value: any, defaultValue: T): T | boolean => {
|
||||||
|
const normalizedValue = normalizeValue(value);
|
||||||
|
if (booleanValues.indexOf(normalizedValue) === -1) {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
return booleanValuesRepresentingTrue.indexOf(normalizedValue) !== -1;
|
||||||
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
hashPassword,
|
hashPassword,
|
||||||
origin,
|
origin,
|
||||||
Reference in New Issue
Block a user