mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-24 00:29:49 +00:00
feat: discount sale and purchase transactions
This commit is contained in:
@@ -183,6 +183,13 @@ export default class VendorCreditController extends BaseController {
|
|||||||
|
|
||||||
check('attachments').isArray().optional(),
|
check('attachments').isArray().optional(),
|
||||||
check('attachments.*.key').exists().isString(),
|
check('attachments.*.key').exists().isString(),
|
||||||
|
|
||||||
|
// Discount.
|
||||||
|
check('discount').optional({ nullable: true }).isNumeric().toFloat(),
|
||||||
|
check('discount_type').optional({ nullable: true }).isString().trim(),
|
||||||
|
|
||||||
|
// Adjustment.
|
||||||
|
check('adjustment').optional({ nullable: true }).isNumeric().toFloat(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -244,11 +244,19 @@ export default class PaymentReceivesController extends BaseController {
|
|||||||
.isNumeric()
|
.isNumeric()
|
||||||
.toInt(),
|
.toInt(),
|
||||||
|
|
||||||
|
// Attachments.
|
||||||
check('attachments').isArray().optional(),
|
check('attachments').isArray().optional(),
|
||||||
check('attachments.*.key').exists().isString(),
|
check('attachments.*.key').exists().isString(),
|
||||||
|
|
||||||
// Pdf template id.
|
// Pdf template id.
|
||||||
check('pdf_template_id').optional({ nullable: true }).isNumeric().toInt(),
|
check('pdf_template_id').optional({ nullable: true }).isNumeric().toInt(),
|
||||||
|
|
||||||
|
// Discount.
|
||||||
|
check('discount').optional({ nullable: true }).isNumeric().toFloat(),
|
||||||
|
check('discount_type').optional({ nullable: true }).isString().trim(),
|
||||||
|
|
||||||
|
// Adjustment.
|
||||||
|
check('adjustment').optional({ nullable: true }).isNumeric().toFloat(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { body, check, param, query } from 'express-validator';
|
|||||||
import { Inject, Service } from 'typedi';
|
import { Inject, Service } from 'typedi';
|
||||||
import {
|
import {
|
||||||
AbilitySubject,
|
AbilitySubject,
|
||||||
|
DiscountType,
|
||||||
ISaleEstimateDTO,
|
ISaleEstimateDTO,
|
||||||
SaleEstimateAction,
|
SaleEstimateAction,
|
||||||
SaleEstimateMailOptionsDTO,
|
SaleEstimateMailOptionsDTO,
|
||||||
@@ -195,11 +196,21 @@ export default class SalesEstimatesController extends BaseController {
|
|||||||
check('terms_conditions').optional().trim(),
|
check('terms_conditions').optional().trim(),
|
||||||
check('send_to_email').optional().trim(),
|
check('send_to_email').optional().trim(),
|
||||||
|
|
||||||
|
// # Attachments
|
||||||
check('attachments').isArray().optional(),
|
check('attachments').isArray().optional(),
|
||||||
check('attachments.*.key').exists().isString(),
|
check('attachments.*.key').exists().isString(),
|
||||||
|
|
||||||
// Pdf template id.
|
// # Pdf template id.
|
||||||
check('pdf_template_id').optional({ nullable: true }).isNumeric().toInt(),
|
check('pdf_template_id').optional({ nullable: true }).isNumeric().toInt(),
|
||||||
|
|
||||||
|
// # Discount
|
||||||
|
check('discount').optional().isNumeric().toFloat(),
|
||||||
|
check('discount_type')
|
||||||
|
.default(DiscountType.Amount)
|
||||||
|
.isIn([DiscountType.Amount, DiscountType.Percentage]),
|
||||||
|
|
||||||
|
// # Adjustment
|
||||||
|
check('adjustment').optional().isNumeric().toFloat(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
/**
|
||||||
|
* @param { import("knex").Knex } knex
|
||||||
|
* @returns { Promise<void> }
|
||||||
|
*/
|
||||||
|
exports.up = function(knex) {
|
||||||
|
return knex.schema.alterTable('sales_estimates', (table) => {
|
||||||
|
table.decimal('discount', 10, 2).nullable().after('credited_amount');
|
||||||
|
table.string('discount_type').nullable().after('discount');
|
||||||
|
|
||||||
|
table.decimal('adjustment', 10, 2).nullable().after('discount_type');
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param { import("knex").Knex } knex
|
||||||
|
* @returns { Promise<void> }
|
||||||
|
*/
|
||||||
|
exports.down = function(knex) {
|
||||||
|
return knex.schema.alterTable('sales_estimates', (table) => {
|
||||||
|
table.dropColumn('discount');
|
||||||
|
table.dropColumn('discount_type');
|
||||||
|
table.dropColumn('adjustment');
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
/**
|
||||||
|
* @param { import("knex").Knex } knex
|
||||||
|
* @returns { Promise<void> }
|
||||||
|
*/
|
||||||
|
exports.up = function(knex) {
|
||||||
|
return knex.schema.alterTable('sales_receipts', (table) => {
|
||||||
|
table.decimal('discount', 10, 2).nullable().after('amount');
|
||||||
|
table.string('discount_type').nullable().after('discount');
|
||||||
|
|
||||||
|
table.decimal('adjustment', 10, 2).nullable().after('discount_type');
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param { import("knex").Knex } knex
|
||||||
|
* @returns { Promise<void> }
|
||||||
|
*/
|
||||||
|
exports.down = function(knex) {
|
||||||
|
return knex.schema.alterTable('sales_receipts', (table) => {
|
||||||
|
table.dropColumn('discount');
|
||||||
|
table.dropColumn('discount_type');
|
||||||
|
table.dropColumn('adjustment');
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
/**
|
||||||
|
* @param { import("knex").Knex } knex
|
||||||
|
* @returns { Promise<void> }
|
||||||
|
*/
|
||||||
|
exports.up = function(knex) {
|
||||||
|
return knex.schema.alterTable('bills', (table) => {
|
||||||
|
// Discount.
|
||||||
|
table.decimal('discount', 10, 2).nullable().after('amount');
|
||||||
|
table.string('discount_type').nullable().after('discount');
|
||||||
|
|
||||||
|
// Adjustment.
|
||||||
|
table.decimal('adjustment', 10, 2).nullable().after('discount_type');
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param { import("knex").Knex } knex
|
||||||
|
* @returns { Promise<void> }
|
||||||
|
*/
|
||||||
|
exports.down = function(knex) {
|
||||||
|
return knex.schema.alterTable('bills', (table) => {
|
||||||
|
table.dropColumn('discount');
|
||||||
|
table.dropColumn('discount_type');
|
||||||
|
table.dropColumn('adjustment');
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
/**
|
||||||
|
* @param { import("knex").Knex } knex
|
||||||
|
* @returns { Promise<void> }
|
||||||
|
*/
|
||||||
|
exports.up = function(knex) {
|
||||||
|
return knex.schema.alterTable('credit_notes', (table) => {
|
||||||
|
table.decimal('discount', 10, 2).nullable().after('credited_amount');
|
||||||
|
table.string('discount_type').nullable().after('discount');
|
||||||
|
table.decimal('adjustment', 10, 2).nullable().after('discount_type');
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param { import("knex").Knex } knex
|
||||||
|
* @returns { Promise<void> }
|
||||||
|
*/
|
||||||
|
exports.down = function(knex) {
|
||||||
|
return knex.schema.alterTable('credit_notes', (table) => {
|
||||||
|
table.dropColumn('discount');
|
||||||
|
table.dropColumn('discount_type');
|
||||||
|
table.dropColumn('adjustment');
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -3,6 +3,7 @@ import { IDynamicListFilterDTO } from './DynamicFilter';
|
|||||||
import { IItemEntry, IItemEntryDTO } from './ItemEntry';
|
import { IItemEntry, IItemEntryDTO } from './ItemEntry';
|
||||||
import { IBillLandedCost } from './LandedCost';
|
import { IBillLandedCost } from './LandedCost';
|
||||||
import { AttachmentLinkDTO } from './Attachments';
|
import { AttachmentLinkDTO } from './Attachments';
|
||||||
|
import { DiscountType } from './SaleInvoice';
|
||||||
|
|
||||||
export interface IBillDTO {
|
export interface IBillDTO {
|
||||||
vendorId: number;
|
vendorId: number;
|
||||||
@@ -22,6 +23,13 @@ export interface IBillDTO {
|
|||||||
projectId?: number;
|
projectId?: number;
|
||||||
isInclusiveTax?: boolean;
|
isInclusiveTax?: boolean;
|
||||||
attachments?: AttachmentLinkDTO[];
|
attachments?: AttachmentLinkDTO[];
|
||||||
|
|
||||||
|
// # Discount
|
||||||
|
discount?: number;
|
||||||
|
discountType?: DiscountType;
|
||||||
|
|
||||||
|
// # Adjustment
|
||||||
|
adjustment?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IBillEditDTO {
|
export interface IBillEditDTO {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Knex } from 'knex';
|
import { Knex } from 'knex';
|
||||||
import { IDynamicListFilter, IItemEntry } from '@/interfaces';
|
import { DiscountType, IDynamicListFilter, IItemEntry } from '@/interfaces';
|
||||||
import { ILedgerEntry } from './Ledger';
|
import { ILedgerEntry } from './Ledger';
|
||||||
import { AttachmentLinkDTO } from './Attachments';
|
import { AttachmentLinkDTO } from './Attachments';
|
||||||
|
|
||||||
@@ -23,6 +23,9 @@ export interface ICreditNoteNewDTO {
|
|||||||
branchId?: number;
|
branchId?: number;
|
||||||
warehouseId?: number;
|
warehouseId?: number;
|
||||||
attachments?: AttachmentLinkDTO[];
|
attachments?: AttachmentLinkDTO[];
|
||||||
|
discount?: number;
|
||||||
|
discountType?: DiscountType;
|
||||||
|
adjustment?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ICreditNoteEditDTO {
|
export interface ICreditNoteEditDTO {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { IItemEntry, IItemEntryDTO } from './ItemEntry';
|
|||||||
import { IDynamicListFilterDTO } from '@/interfaces/DynamicFilter';
|
import { IDynamicListFilterDTO } from '@/interfaces/DynamicFilter';
|
||||||
import { CommonMailOptions, CommonMailOptionsDTO } from './Mailable';
|
import { CommonMailOptions, CommonMailOptionsDTO } from './Mailable';
|
||||||
import { AttachmentLinkDTO } from './Attachments';
|
import { AttachmentLinkDTO } from './Attachments';
|
||||||
|
import { DiscountType } from './SaleInvoice';
|
||||||
|
|
||||||
export interface ISaleEstimate {
|
export interface ISaleEstimate {
|
||||||
id?: number;
|
id?: number;
|
||||||
@@ -40,6 +41,13 @@ export interface ISaleEstimateDTO {
|
|||||||
branchId?: number;
|
branchId?: number;
|
||||||
warehouseId?: number;
|
warehouseId?: number;
|
||||||
attachments?: AttachmentLinkDTO[];
|
attachments?: AttachmentLinkDTO[];
|
||||||
|
|
||||||
|
// # Discount
|
||||||
|
discount?: number;
|
||||||
|
discountType?: DiscountType;
|
||||||
|
|
||||||
|
// # Adjustment
|
||||||
|
adjustment?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ISalesEstimatesFilter extends IDynamicListFilterDTO {
|
export interface ISalesEstimatesFilter extends IDynamicListFilterDTO {
|
||||||
|
|||||||
@@ -82,6 +82,11 @@ export interface ISaleInvoice {
|
|||||||
paymentMethods?: Array<PaymentIntegrationTransactionLink>;
|
paymentMethods?: Array<PaymentIntegrationTransactionLink>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum DiscountType {
|
||||||
|
Percentage = 'Percentage',
|
||||||
|
Amount = 'Amount',
|
||||||
|
}
|
||||||
|
|
||||||
export interface ISaleInvoiceDTO {
|
export interface ISaleInvoiceDTO {
|
||||||
invoiceDate: Date;
|
invoiceDate: Date;
|
||||||
dueDate: Date;
|
dueDate: Date;
|
||||||
@@ -105,7 +110,7 @@ export interface ISaleInvoiceDTO {
|
|||||||
|
|
||||||
// # Discount
|
// # Discount
|
||||||
discount?: number;
|
discount?: number;
|
||||||
discountType?: string;
|
discountType?: DiscountType;
|
||||||
|
|
||||||
// # Adjustments
|
// # Adjustments
|
||||||
adjustments?: string;
|
adjustments?: string;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { Knex } from 'knex';
|
|||||||
import { IItemEntry } from './ItemEntry';
|
import { IItemEntry } from './ItemEntry';
|
||||||
import { CommonMailOptions, CommonMailOptionsDTO } from './Mailable';
|
import { CommonMailOptions, CommonMailOptionsDTO } from './Mailable';
|
||||||
import { AttachmentLinkDTO } from './Attachments';
|
import { AttachmentLinkDTO } from './Attachments';
|
||||||
|
import { DiscountType } from './SaleInvoice';
|
||||||
|
|
||||||
export interface ISaleReceipt {
|
export interface ISaleReceipt {
|
||||||
id?: number;
|
id?: number;
|
||||||
@@ -47,6 +48,11 @@ export interface ISaleReceiptDTO {
|
|||||||
entries: any[];
|
entries: any[];
|
||||||
branchId?: number;
|
branchId?: number;
|
||||||
attachments?: AttachmentLinkDTO[];
|
attachments?: AttachmentLinkDTO[];
|
||||||
|
|
||||||
|
discount?: number;
|
||||||
|
discountType?: DiscountType;
|
||||||
|
|
||||||
|
adjustment?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ISalesReceiptsService {
|
export interface ISalesReceiptsService {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { IDynamicListFilter, IItemEntry, IItemEntryDTO } from '@/interfaces';
|
import { DiscountType, IDynamicListFilter, IItemEntry, IItemEntryDTO } from '@/interfaces';
|
||||||
import { Knex } from 'knex';
|
import { Knex } from 'knex';
|
||||||
import { AttachmentLinkDTO } from './Attachments';
|
import { AttachmentLinkDTO } from './Attachments';
|
||||||
|
|
||||||
@@ -63,6 +63,11 @@ export interface IVendorCreditDTO {
|
|||||||
branchId?: number;
|
branchId?: number;
|
||||||
warehouseId?: number;
|
warehouseId?: number;
|
||||||
attachments?: AttachmentLinkDTO[];
|
attachments?: AttachmentLinkDTO[];
|
||||||
|
|
||||||
|
discount?: number;
|
||||||
|
discountType?: DiscountType;
|
||||||
|
|
||||||
|
adjustment?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IVendorCreditCreateDTO extends IVendorCreditDTO {}
|
export interface IVendorCreditCreateDTO extends IVendorCreditDTO {}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Model, raw, mixin } from 'objection';
|
import { Model, raw, mixin } from 'objection';
|
||||||
import { castArray, difference } from 'lodash';
|
import { castArray, defaultTo, difference } from 'lodash';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import TenantModel from 'models/TenantModel';
|
import TenantModel from 'models/TenantModel';
|
||||||
import BillSettings from './Bill.Settings';
|
import BillSettings from './Bill.Settings';
|
||||||
@@ -7,6 +7,7 @@ import ModelSetting from './ModelSetting';
|
|||||||
import CustomViewBaseModel from './CustomViewBaseModel';
|
import CustomViewBaseModel from './CustomViewBaseModel';
|
||||||
import { DEFAULT_VIEWS } from '@/services/Purchases/Bills/constants';
|
import { DEFAULT_VIEWS } from '@/services/Purchases/Bills/constants';
|
||||||
import ModelSearchable from './ModelSearchable';
|
import ModelSearchable from './ModelSearchable';
|
||||||
|
import { DiscountType } from '@/interfaces';
|
||||||
|
|
||||||
export default class Bill extends mixin(TenantModel, [
|
export default class Bill extends mixin(TenantModel, [
|
||||||
ModelSetting,
|
ModelSetting,
|
||||||
@@ -21,6 +22,11 @@ export default class Bill extends mixin(TenantModel, [
|
|||||||
public taxAmountWithheld: number;
|
public taxAmountWithheld: number;
|
||||||
public exchangeRate: number;
|
public exchangeRate: number;
|
||||||
|
|
||||||
|
public discount: number;
|
||||||
|
public discountType: DiscountType;
|
||||||
|
|
||||||
|
public adjustment: number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Timestamps columns.
|
* Timestamps columns.
|
||||||
*/
|
*/
|
||||||
@@ -103,9 +109,15 @@ export default class Bill extends mixin(TenantModel, [
|
|||||||
* @returns {number}
|
* @returns {number}
|
||||||
*/
|
*/
|
||||||
get total() {
|
get total() {
|
||||||
|
const discountAmount = this.discountType === DiscountType.Amount
|
||||||
|
? this.discount
|
||||||
|
: this.subtotal * (this.discount / 100);
|
||||||
|
|
||||||
|
const adjustmentAmount = defaultTo(this.adjustment, 0);
|
||||||
|
|
||||||
return this.isInclusiveTax
|
return this.isInclusiveTax
|
||||||
? this.subtotal
|
? this.subtotal - discountAmount - adjustmentAmount
|
||||||
: this.subtotal + this.taxAmountWithheld;
|
: this.subtotal + this.taxAmountWithheld - discountAmount - adjustmentAmount;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -5,12 +5,20 @@ import CustomViewBaseModel from './CustomViewBaseModel';
|
|||||||
import { DEFAULT_VIEWS } from '@/services/CreditNotes/constants';
|
import { DEFAULT_VIEWS } from '@/services/CreditNotes/constants';
|
||||||
import ModelSearchable from './ModelSearchable';
|
import ModelSearchable from './ModelSearchable';
|
||||||
import CreditNoteMeta from './CreditNote.Meta';
|
import CreditNoteMeta from './CreditNote.Meta';
|
||||||
|
import { DiscountType } from '@/interfaces';
|
||||||
|
|
||||||
export default class CreditNote extends mixin(TenantModel, [
|
export default class CreditNote extends mixin(TenantModel, [
|
||||||
ModelSetting,
|
ModelSetting,
|
||||||
CustomViewBaseModel,
|
CustomViewBaseModel,
|
||||||
ModelSearchable,
|
ModelSearchable,
|
||||||
]) {
|
]) {
|
||||||
|
public amount: number;
|
||||||
|
public exchangeRate: number;
|
||||||
|
public openedAt: Date;
|
||||||
|
public discount: number;
|
||||||
|
public discountType: DiscountType;
|
||||||
|
public adjustment: number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Table name
|
* Table name
|
||||||
*/
|
*/
|
||||||
@@ -48,6 +56,42 @@ export default class CreditNote extends mixin(TenantModel, [
|
|||||||
return this.amount * this.exchangeRate;
|
return this.amount * this.exchangeRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Credit note subtotal.
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
get subtotal() {
|
||||||
|
return this.amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Credit note subtotal in local currency.
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
get subtotalLocal() {
|
||||||
|
return this.subtotal * this.exchangeRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Credit note total.
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
get total() {
|
||||||
|
const discountAmount = this.discountType === DiscountType.Amount
|
||||||
|
? this.discount
|
||||||
|
: this.subtotal * (this.discount / 100);
|
||||||
|
|
||||||
|
return this.subtotal - discountAmount - this.adjustment;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Credit note total in local currency.
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
get totalLocal() {
|
||||||
|
return this.total * this.exchangeRate;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Detarmines whether the credit note is draft.
|
* Detarmines whether the credit note is draft.
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
|
|||||||
@@ -7,12 +7,22 @@ import ModelSetting from './ModelSetting';
|
|||||||
import CustomViewBaseModel from './CustomViewBaseModel';
|
import CustomViewBaseModel from './CustomViewBaseModel';
|
||||||
import { DEFAULT_VIEWS } from '@/services/Sales/Estimates/constants';
|
import { DEFAULT_VIEWS } from '@/services/Sales/Estimates/constants';
|
||||||
import ModelSearchable from './ModelSearchable';
|
import ModelSearchable from './ModelSearchable';
|
||||||
|
import { DiscountType } from '@/interfaces';
|
||||||
|
import { defaultTo } from 'lodash';
|
||||||
|
|
||||||
export default class SaleEstimate extends mixin(TenantModel, [
|
export default class SaleEstimate extends mixin(TenantModel, [
|
||||||
ModelSetting,
|
ModelSetting,
|
||||||
CustomViewBaseModel,
|
CustomViewBaseModel,
|
||||||
ModelSearchable,
|
ModelSearchable,
|
||||||
]) {
|
]) {
|
||||||
|
public amount: number;
|
||||||
|
public exchangeRate: number;
|
||||||
|
|
||||||
|
public discount: number;
|
||||||
|
public discountType: DiscountType;
|
||||||
|
|
||||||
|
public adjustment: number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Table name
|
* Table name
|
||||||
*/
|
*/
|
||||||
@@ -49,6 +59,44 @@ export default class SaleEstimate extends mixin(TenantModel, [
|
|||||||
return this.amount * this.exchangeRate;
|
return this.amount * this.exchangeRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Estimate subtotal.
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
get subtotal() {
|
||||||
|
return this.amount;;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Estimate subtotal in local currency.
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
get subtotalLocal() {
|
||||||
|
return this.localAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Estimate total.
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
get total() {
|
||||||
|
const discountAmount = this.discountType === DiscountType.Amount
|
||||||
|
? this.discount
|
||||||
|
: this.subtotal * (this.discount / 100);
|
||||||
|
|
||||||
|
const adjustmentAmount = defaultTo(this.adjustment, 0);
|
||||||
|
|
||||||
|
return this.subtotal - discountAmount - adjustmentAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Estimate total in local currency.
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
get totalLocal() {
|
||||||
|
return this.total * this.exchangeRate;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Detarmines whether the sale estimate converted to sale invoice.
|
* Detarmines whether the sale estimate converted to sale invoice.
|
||||||
* @return {boolean}
|
* @return {boolean}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { mixin, Model, raw } from 'objection';
|
import { mixin, Model, raw } from 'objection';
|
||||||
import { castArray, takeWhile } from 'lodash';
|
import { castArray, defaultTo, takeWhile } from 'lodash';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import TenantModel from 'models/TenantModel';
|
import TenantModel from 'models/TenantModel';
|
||||||
import ModelSetting from './ModelSetting';
|
import ModelSetting from './ModelSetting';
|
||||||
@@ -7,6 +7,7 @@ import SaleInvoiceMeta from './SaleInvoice.Settings';
|
|||||||
import CustomViewBaseModel from './CustomViewBaseModel';
|
import CustomViewBaseModel from './CustomViewBaseModel';
|
||||||
import { DEFAULT_VIEWS } from '@/services/Sales/Invoices/constants';
|
import { DEFAULT_VIEWS } from '@/services/Sales/Invoices/constants';
|
||||||
import ModelSearchable from './ModelSearchable';
|
import ModelSearchable from './ModelSearchable';
|
||||||
|
import { DiscountType } from '@/interfaces';
|
||||||
|
|
||||||
export default class SaleInvoice extends mixin(TenantModel, [
|
export default class SaleInvoice extends mixin(TenantModel, [
|
||||||
ModelSetting,
|
ModelSetting,
|
||||||
@@ -23,6 +24,10 @@ export default class SaleInvoice extends mixin(TenantModel, [
|
|||||||
public writtenoffAt: Date;
|
public writtenoffAt: Date;
|
||||||
public dueDate: Date;
|
public dueDate: Date;
|
||||||
public deliveredAt: Date;
|
public deliveredAt: Date;
|
||||||
|
public discount: number;
|
||||||
|
public discountType: DiscountType;
|
||||||
|
public adjustments: number;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Table name
|
* Table name
|
||||||
@@ -130,9 +135,16 @@ export default class SaleInvoice extends mixin(TenantModel, [
|
|||||||
* @returns {number}
|
* @returns {number}
|
||||||
*/
|
*/
|
||||||
get total() {
|
get total() {
|
||||||
|
const discountAmount = this.discountType === DiscountType.Amount
|
||||||
|
? this.discount
|
||||||
|
: this.subtotal * (this.discount / 100);
|
||||||
|
|
||||||
|
const adjustmentAmount = defaultTo(this.adjustments, 0);
|
||||||
|
const differencies = discountAmount + adjustmentAmount;
|
||||||
|
|
||||||
return this.isInclusiveTax
|
return this.isInclusiveTax
|
||||||
? this.subtotal
|
? this.subtotal - differencies
|
||||||
: this.subtotal + this.taxAmountWithheld;
|
: this.subtotal + this.taxAmountWithheld - differencies;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -5,12 +5,23 @@ import SaleReceiptSettings from './SaleReceipt.Settings';
|
|||||||
import CustomViewBaseModel from './CustomViewBaseModel';
|
import CustomViewBaseModel from './CustomViewBaseModel';
|
||||||
import { DEFAULT_VIEWS } from '@/services/Sales/Receipts/constants';
|
import { DEFAULT_VIEWS } from '@/services/Sales/Receipts/constants';
|
||||||
import ModelSearchable from './ModelSearchable';
|
import ModelSearchable from './ModelSearchable';
|
||||||
|
import { DiscountType } from '@/interfaces';
|
||||||
|
import { defaultTo } from 'lodash';
|
||||||
|
|
||||||
export default class SaleReceipt extends mixin(TenantModel, [
|
export default class SaleReceipt extends mixin(TenantModel, [
|
||||||
ModelSetting,
|
ModelSetting,
|
||||||
CustomViewBaseModel,
|
CustomViewBaseModel,
|
||||||
ModelSearchable,
|
ModelSearchable,
|
||||||
]) {
|
]) {
|
||||||
|
public amount: number;
|
||||||
|
public exchangeRate: number;
|
||||||
|
public closedAt: Date;
|
||||||
|
|
||||||
|
public discount: number;
|
||||||
|
public discountType: DiscountType;
|
||||||
|
|
||||||
|
public adjustment: number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Table name
|
* Table name
|
||||||
*/
|
*/
|
||||||
@@ -40,6 +51,44 @@ export default class SaleReceipt extends mixin(TenantModel, [
|
|||||||
return this.amount * this.exchangeRate;
|
return this.amount * this.exchangeRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Receipt subtotal.
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
get subtotal() {
|
||||||
|
return this.amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Receipt subtotal in local currency.
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
get subtotalLocal() {
|
||||||
|
return this.localAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Receipt total.
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
get total() {
|
||||||
|
const discountAmount = this.discountType === DiscountType.Amount
|
||||||
|
? this.discount
|
||||||
|
: this.subtotal * (this.discount / 100);
|
||||||
|
|
||||||
|
const adjustmentAmount = defaultTo(this.adjustment, 0);
|
||||||
|
|
||||||
|
return this.subtotal - discountAmount - adjustmentAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Receipt total in local currency.
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
get totalLocal() {
|
||||||
|
return this.total * this.exchangeRate;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Detarmine whether the sale receipt closed.
|
* Detarmine whether the sale receipt closed.
|
||||||
* @return {boolean}
|
* @return {boolean}
|
||||||
|
|||||||
@@ -6,12 +6,20 @@ import CustomViewBaseModel from './CustomViewBaseModel';
|
|||||||
import { DEFAULT_VIEWS } from '@/services/Purchases/VendorCredits/constants';
|
import { DEFAULT_VIEWS } from '@/services/Purchases/VendorCredits/constants';
|
||||||
import ModelSearchable from './ModelSearchable';
|
import ModelSearchable from './ModelSearchable';
|
||||||
import VendorCreditMeta from './VendorCredit.Meta';
|
import VendorCreditMeta from './VendorCredit.Meta';
|
||||||
|
import { DiscountType } from '@/interfaces';
|
||||||
|
|
||||||
export default class VendorCredit extends mixin(TenantModel, [
|
export default class VendorCredit extends mixin(TenantModel, [
|
||||||
ModelSetting,
|
ModelSetting,
|
||||||
CustomViewBaseModel,
|
CustomViewBaseModel,
|
||||||
ModelSearchable,
|
ModelSearchable,
|
||||||
]) {
|
]) {
|
||||||
|
public amount: number;
|
||||||
|
public exchangeRate: number;
|
||||||
|
public openedAt: Date;
|
||||||
|
public discount: number;
|
||||||
|
public discountType: DiscountType;
|
||||||
|
public adjustment: number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Table name
|
* Table name
|
||||||
*/
|
*/
|
||||||
@@ -34,6 +42,42 @@ export default class VendorCredit extends mixin(TenantModel, [
|
|||||||
return this.amount * this.exchangeRate;
|
return this.amount * this.exchangeRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vendor credit subtotal.
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
get subtotal() {
|
||||||
|
return this.amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vendor credit subtotal in local currency.
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
get subtotalLocal() {
|
||||||
|
return this.subtotal * this.exchangeRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vendor credit total.
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
get total() {
|
||||||
|
const discountAmount = this.discountType === DiscountType.Amount
|
||||||
|
? this.discount
|
||||||
|
: this.subtotal * (this.discount / 100);
|
||||||
|
|
||||||
|
return this.subtotal - discountAmount - this.adjustment;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vendor credit total in local currency.
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
get totalLocal() {
|
||||||
|
return this.total * this.exchangeRate;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Model modifiers.
|
* Model modifiers.
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user