mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-17 21:30:31 +00:00
feat: add discount functionality to sales and purchase transactions
- Introduced discount_type and discount fields in Bills and SalesReceipts controllers. - Updated database migrations to include discount and discount_type in estimates and credit notes tables. - Enhanced SaleReceipt and SaleEstimate models to support discount attributes. - Implemented formatting for discount amounts in transformers and PDF templates. - Updated email templates to display discount information. This commit enhances the handling of discounts across various transaction types, improving the overall functionality and user experience.
This commit is contained in:
@@ -4,6 +4,7 @@ import { check, param, query } from 'express-validator';
|
|||||||
import {
|
import {
|
||||||
AbilitySubject,
|
AbilitySubject,
|
||||||
BillAction,
|
BillAction,
|
||||||
|
DiscountType,
|
||||||
IBillDTO,
|
IBillDTO,
|
||||||
IBillEditDTO,
|
IBillEditDTO,
|
||||||
} from '@/interfaces';
|
} from '@/interfaces';
|
||||||
@@ -144,8 +145,15 @@ export default class BillsController 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(),
|
||||||
|
|
||||||
|
// # Discount
|
||||||
|
check('discount_type')
|
||||||
|
.default(DiscountType.Amount)
|
||||||
|
.isIn([DiscountType.Amount, DiscountType.Percentage]),
|
||||||
|
check('discount').optional().isDecimal().toFloat(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import {
|
|||||||
import { ServiceError } from '@/exceptions';
|
import { ServiceError } from '@/exceptions';
|
||||||
import DynamicListingService from '@/services/DynamicListing/DynamicListService';
|
import DynamicListingService from '@/services/DynamicListing/DynamicListService';
|
||||||
import CheckPolicies from '@/api/middleware/CheckPolicies';
|
import CheckPolicies from '@/api/middleware/CheckPolicies';
|
||||||
import { AbilitySubject, SaleReceiptAction } from '@/interfaces';
|
import { AbilitySubject, DiscountType, SaleReceiptAction } from '@/interfaces';
|
||||||
import { SaleReceiptApplication } from '@/services/Sales/Receipts/SaleReceiptApplication';
|
import { SaleReceiptApplication } from '@/services/Sales/Receipts/SaleReceiptApplication';
|
||||||
import { ACCEPT_TYPE } from '@/interfaces/Http';
|
import { ACCEPT_TYPE } from '@/interfaces/Http';
|
||||||
|
|
||||||
@@ -178,6 +178,12 @@ export default class SalesReceiptsController extends BaseController {
|
|||||||
|
|
||||||
// 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 })
|
||||||
|
.isIn([DiscountType.Percentage, DiscountType.Amount]),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
*/
|
*/
|
||||||
exports.up = function(knex) {
|
exports.up = function(knex) {
|
||||||
return knex.schema.alterTable('sales_estimates', (table) => {
|
return knex.schema.alterTable('sales_estimates', (table) => {
|
||||||
table.decimal('discount', 10, 2).nullable().after('credited_amount');
|
table.decimal('discount', 10, 2).nullable().after('amount');
|
||||||
table.string('discount_type').nullable().after('discount');
|
table.string('discount_type').nullable().after('discount');
|
||||||
|
|
||||||
table.decimal('adjustment', 10, 2).nullable().after('discount_type');
|
table.decimal('adjustment', 10, 2).nullable().after('discount_type');
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
*/
|
*/
|
||||||
exports.up = function(knex) {
|
exports.up = function(knex) {
|
||||||
return knex.schema.alterTable('credit_notes', (table) => {
|
return knex.schema.alterTable('credit_notes', (table) => {
|
||||||
table.decimal('discount', 10, 2).nullable().after('credited_amount');
|
table.decimal('discount', 10, 2).nullable().after('exchange_rate');
|
||||||
table.string('discount_type').nullable().after('discount');
|
table.string('discount_type').nullable().after('discount');
|
||||||
table.decimal('adjustment', 10, 2).nullable().after('discount_type');
|
table.decimal('adjustment', 10, 2).nullable().after('discount_type');
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -29,6 +29,12 @@ export interface ISaleReceipt {
|
|||||||
localAmount?: number;
|
localAmount?: number;
|
||||||
entries?: IItemEntry[];
|
entries?: IItemEntry[];
|
||||||
|
|
||||||
|
subtotal?: number;
|
||||||
|
subtotalLocal?: number;
|
||||||
|
|
||||||
|
total?: number;
|
||||||
|
totalLocal?: number;
|
||||||
|
|
||||||
discountAmount: number;
|
discountAmount: number;
|
||||||
discountPercentage?: number | null;
|
discountPercentage?: number | null;
|
||||||
|
|
||||||
|
|||||||
@@ -43,8 +43,18 @@ export default class CreditNote extends mixin(TenantModel, [
|
|||||||
'isPublished',
|
'isPublished',
|
||||||
'isOpen',
|
'isOpen',
|
||||||
'isClosed',
|
'isClosed',
|
||||||
|
|
||||||
'creditsRemaining',
|
'creditsRemaining',
|
||||||
'creditsUsed',
|
'creditsUsed',
|
||||||
|
|
||||||
|
'subtotal',
|
||||||
|
'subtotalLocal',
|
||||||
|
|
||||||
|
'discountAmount',
|
||||||
|
'discountPercentage',
|
||||||
|
|
||||||
|
'total',
|
||||||
|
'totalLocal',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,10 @@ export default class PaymentReceive extends mixin(TenantModel, [
|
|||||||
CustomViewBaseModel,
|
CustomViewBaseModel,
|
||||||
ModelSearchable,
|
ModelSearchable,
|
||||||
]) {
|
]) {
|
||||||
|
amount!: number;
|
||||||
|
paymentAmount!: number;
|
||||||
|
exchangeRate!: number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Table name.
|
* Table name.
|
||||||
*/
|
*/
|
||||||
@@ -40,6 +44,10 @@ export default class PaymentReceive extends mixin(TenantModel, [
|
|||||||
return this.amount * this.exchangeRate;
|
return this.amount * this.exchangeRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Payment receive total.
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
get total() {
|
get total() {
|
||||||
return this.paymentAmount;
|
return this.paymentAmount;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,6 +43,8 @@ export default class SaleEstimate extends mixin(TenantModel, [
|
|||||||
static get virtualAttributes() {
|
static get virtualAttributes() {
|
||||||
return [
|
return [
|
||||||
'localAmount',
|
'localAmount',
|
||||||
|
'discountAmount',
|
||||||
|
'discountPercentage',
|
||||||
'isDelivered',
|
'isDelivered',
|
||||||
'isExpired',
|
'isExpired',
|
||||||
'isConvertedToInvoice',
|
'isConvertedToInvoice',
|
||||||
|
|||||||
@@ -72,6 +72,7 @@ export default class SaleInvoice extends mixin(TenantModel, [
|
|||||||
|
|
||||||
'taxAmountWithheldLocal',
|
'taxAmountWithheldLocal',
|
||||||
'discountAmount',
|
'discountAmount',
|
||||||
|
'discountPercentage',
|
||||||
|
|
||||||
'total',
|
'total',
|
||||||
'totalLocal',
|
'totalLocal',
|
||||||
|
|||||||
@@ -40,7 +40,21 @@ export default class SaleReceipt extends mixin(TenantModel, [
|
|||||||
* Virtual attributes.
|
* Virtual attributes.
|
||||||
*/
|
*/
|
||||||
static get virtualAttributes() {
|
static get virtualAttributes() {
|
||||||
return ['localAmount', 'isClosed', 'isDraft'];
|
return [
|
||||||
|
'localAmount',
|
||||||
|
|
||||||
|
'subtotal',
|
||||||
|
'subtotalLocal',
|
||||||
|
|
||||||
|
'total',
|
||||||
|
'totalLocal',
|
||||||
|
|
||||||
|
'discountAmount',
|
||||||
|
'discountPercentage',
|
||||||
|
|
||||||
|
'isClosed',
|
||||||
|
'isDraft',
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ export class CreditNoteTransformer extends Transformer {
|
|||||||
'discountAmountFormatted',
|
'discountAmountFormatted',
|
||||||
'discountPercentageFormatted',
|
'discountPercentageFormatted',
|
||||||
'adjustmentFormatted',
|
'adjustmentFormatted',
|
||||||
|
'totalFormatted',
|
||||||
|
'totalLocalFormatted',
|
||||||
'entries',
|
'entries',
|
||||||
'attachments',
|
'attachments',
|
||||||
];
|
];
|
||||||
@@ -86,7 +88,6 @@ export class CreditNoteTransformer extends Transformer {
|
|||||||
return formatNumber(credit.amount, { money: false });
|
return formatNumber(credit.amount, { money: false });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves formatted discount amount.
|
* Retrieves formatted discount amount.
|
||||||
* @param credit
|
* @param credit
|
||||||
@@ -120,6 +121,28 @@ export class CreditNoteTransformer extends Transformer {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the formatted total.
|
||||||
|
* @param credit
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
protected totalFormatted = (credit): string => {
|
||||||
|
return formatNumber(credit.total, {
|
||||||
|
currencyCode: credit.currencyCode,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the formatted total in local currency.
|
||||||
|
* @param credit
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
protected totalLocalFormatted = (credit): string => {
|
||||||
|
return formatNumber(credit.totalLocal, {
|
||||||
|
currencyCode: credit.currencyCode,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the entries of the credit note.
|
* Retrieves the entries of the credit note.
|
||||||
* @param {ICreditNote} credit
|
* @param {ICreditNote} credit
|
||||||
|
|||||||
@@ -254,18 +254,27 @@ export interface EstimatePdfBrandingAttributes {
|
|||||||
companyAddress: string;
|
companyAddress: string;
|
||||||
billedToLabel: string;
|
billedToLabel: string;
|
||||||
|
|
||||||
|
// # Total
|
||||||
total: string;
|
total: string;
|
||||||
totalLabel: string;
|
totalLabel: string;
|
||||||
showTotal: boolean;
|
showTotal: boolean;
|
||||||
|
|
||||||
|
// # Discount
|
||||||
|
discount: string;
|
||||||
|
showDiscount: boolean;
|
||||||
|
discountLabel: string;
|
||||||
|
|
||||||
|
// # Subtotal
|
||||||
subtotal: string;
|
subtotal: string;
|
||||||
subtotalLabel: string;
|
subtotalLabel: string;
|
||||||
showSubtotal: boolean;
|
showSubtotal: boolean;
|
||||||
|
|
||||||
|
// # Customer Note
|
||||||
showCustomerNote: boolean;
|
showCustomerNote: boolean;
|
||||||
customerNote: string;
|
customerNote: string;
|
||||||
customerNoteLabel: string;
|
customerNoteLabel: string;
|
||||||
|
|
||||||
|
// # Terms & Conditions
|
||||||
showTermsConditions: boolean;
|
showTermsConditions: boolean;
|
||||||
termsConditions: string;
|
termsConditions: string;
|
||||||
termsConditionsLabel: string;
|
termsConditionsLabel: string;
|
||||||
|
|||||||
@@ -20,6 +20,10 @@ export const transformEstimateToPdfTemplate = (
|
|||||||
customerNote: estimate.note,
|
customerNote: estimate.note,
|
||||||
termsConditions: estimate.termsConditions,
|
termsConditions: estimate.termsConditions,
|
||||||
customerAddress: contactAddressTextFormat(estimate.customer),
|
customerAddress: contactAddressTextFormat(estimate.customer),
|
||||||
|
discount: estimate.discountAmountFormatted,
|
||||||
|
discountLabel: estimate.discountPercentageFormatted
|
||||||
|
? `Discount [${estimate.discountPercentageFormatted}]`
|
||||||
|
: 'Discount',
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { Inject, Service } from 'typedi';
|
import { Inject, Service } from 'typedi';
|
||||||
import { renderInvoicePaperTemplateHtml } from '@bigcapital/pdf-templates';
|
import { renderInvoicePaperTemplateHtml } from '@bigcapital/pdf-templates';
|
||||||
import { ChromiumlyTenancy } from '@/services/ChromiumlyTenancy/ChromiumlyTenancy';
|
import { ChromiumlyTenancy } from '@/services/ChromiumlyTenancy/ChromiumlyTenancy';
|
||||||
import { TemplateInjectable } from '@/services/TemplateInjectable/TemplateInjectable';
|
|
||||||
import { GetSaleInvoice } from './GetSaleInvoice';
|
import { GetSaleInvoice } from './GetSaleInvoice';
|
||||||
import HasTenancyService from '@/services/Tenancy/TenancyService';
|
import HasTenancyService from '@/services/Tenancy/TenancyService';
|
||||||
import { transformInvoiceToPdfTemplate } from './utils';
|
import { transformInvoiceToPdfTemplate } from './utils';
|
||||||
@@ -9,7 +8,6 @@ import { InvoicePdfTemplateAttributes } from '@/interfaces';
|
|||||||
import { SaleInvoicePdfTemplate } from './SaleInvoicePdfTemplate';
|
import { SaleInvoicePdfTemplate } from './SaleInvoicePdfTemplate';
|
||||||
import { EventPublisher } from '@/lib/EventPublisher/EventPublisher';
|
import { EventPublisher } from '@/lib/EventPublisher/EventPublisher';
|
||||||
import events from '@/subscribers/events';
|
import events from '@/subscribers/events';
|
||||||
import { renderInvoicePaymentEmail } from '@bigcapital/email-components';
|
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export class SaleInvoicePdf {
|
export class SaleInvoicePdf {
|
||||||
|
|||||||
@@ -28,6 +28,10 @@ export const transformInvoiceToPdfTemplate = (
|
|||||||
subtotal: invoice.subtotalFormatted,
|
subtotal: invoice.subtotalFormatted,
|
||||||
paymentMade: invoice.paymentAmountFormatted,
|
paymentMade: invoice.paymentAmountFormatted,
|
||||||
dueAmount: invoice.dueAmountFormatted,
|
dueAmount: invoice.dueAmountFormatted,
|
||||||
|
discount: invoice.discountAmountFormatted,
|
||||||
|
discountLabel: invoice.discountPercentageFormatted
|
||||||
|
? `Discount [${invoice.discountPercentageFormatted}]`
|
||||||
|
: 'Discount',
|
||||||
|
|
||||||
termsConditions: invoice.termsConditions,
|
termsConditions: invoice.termsConditions,
|
||||||
statement: invoice.invoiceMessage,
|
statement: invoice.invoiceMessage,
|
||||||
|
|||||||
@@ -13,9 +13,12 @@ export class SaleReceiptTransformer extends Transformer {
|
|||||||
*/
|
*/
|
||||||
public includeAttributes = (): string[] => {
|
public includeAttributes = (): string[] => {
|
||||||
return [
|
return [
|
||||||
'formattedSubtotal',
|
|
||||||
'discountAmountFormatted',
|
'discountAmountFormatted',
|
||||||
'discountPercentageFormatted',
|
'discountPercentageFormatted',
|
||||||
|
'subtotalFormatted',
|
||||||
|
'subtotalLocalFormatted',
|
||||||
|
'totalFormatted',
|
||||||
|
'totalLocalFormatted',
|
||||||
'adjustmentFormatted',
|
'adjustmentFormatted',
|
||||||
'formattedAmount',
|
'formattedAmount',
|
||||||
'formattedReceiptDate',
|
'formattedReceiptDate',
|
||||||
@@ -58,8 +61,37 @@ export class SaleReceiptTransformer extends Transformer {
|
|||||||
* @param {ISaleReceipt} receipt
|
* @param {ISaleReceipt} receipt
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
protected formattedSubtotal = (receipt: ISaleReceipt): string => {
|
protected subtotalFormatted = (receipt: ISaleReceipt): string => {
|
||||||
return formatNumber(receipt.amount, { money: false });
|
return formatNumber(receipt.subtotal, { money: false });
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the estimate formatted subtotal in local currency.
|
||||||
|
* @param {ISaleReceipt} receipt
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
protected subtotalLocalFormatted = (receipt: ISaleReceipt): string => {
|
||||||
|
return formatNumber(receipt.subtotalLocal, {
|
||||||
|
currencyCode: receipt.currencyCode,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the receipt formatted total.
|
||||||
|
* @param receipt
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
protected totalFormatted = (receipt: ISaleReceipt): string => {
|
||||||
|
return formatNumber(receipt.total, { money: false });
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the receipt formatted total in local currency.
|
||||||
|
* @param receipt
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
protected totalLocalFormatted = (receipt: ISaleReceipt): string => {
|
||||||
|
return formatNumber(receipt.totalLocal, { money: false });
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -67,7 +99,7 @@ export class SaleReceiptTransformer extends Transformer {
|
|||||||
* @param {ISaleReceipt} estimate
|
* @param {ISaleReceipt} estimate
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
protected formattedAmount = (receipt: ISaleReceipt): string => {
|
protected amountFormatted = (receipt: ISaleReceipt): string => {
|
||||||
return formatNumber(receipt.amount, {
|
return formatNumber(receipt.amount, {
|
||||||
currencyCode: receipt.currencyCode,
|
currencyCode: receipt.currencyCode,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { Inject, Service } from 'typedi';
|
import { Inject, Service } from 'typedi';
|
||||||
import { TemplateInjectable } from '@/services/TemplateInjectable/TemplateInjectable';
|
|
||||||
import { ChromiumlyTenancy } from '@/services/ChromiumlyTenancy/ChromiumlyTenancy';
|
import { ChromiumlyTenancy } from '@/services/ChromiumlyTenancy/ChromiumlyTenancy';
|
||||||
import { GetSaleReceipt } from './GetSaleReceipt';
|
import { GetSaleReceipt } from './GetSaleReceipt';
|
||||||
import HasTenancyService from '@/services/Tenancy/TenancyService';
|
import HasTenancyService from '@/services/Tenancy/TenancyService';
|
||||||
@@ -18,9 +17,6 @@ export class SaleReceiptsPdf {
|
|||||||
@Inject()
|
@Inject()
|
||||||
private chromiumlyTenancy: ChromiumlyTenancy;
|
private chromiumlyTenancy: ChromiumlyTenancy;
|
||||||
|
|
||||||
@Inject()
|
|
||||||
private templateInjectable: TemplateInjectable;
|
|
||||||
|
|
||||||
@Inject()
|
@Inject()
|
||||||
private getSaleReceiptService: GetSaleReceipt;
|
private getSaleReceiptService: GetSaleReceipt;
|
||||||
|
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ export const transformReceiptToBrandingTemplateAttributes = (
|
|||||||
saleReceipt: ISaleReceipt
|
saleReceipt: ISaleReceipt
|
||||||
): Partial<ISaleReceiptBrandingTemplateAttributes> => {
|
): Partial<ISaleReceiptBrandingTemplateAttributes> => {
|
||||||
return {
|
return {
|
||||||
total: saleReceipt.formattedAmount,
|
total: saleReceipt.totalFormatted,
|
||||||
subtotal: saleReceipt.formattedSubtotal,
|
subtotal: saleReceipt.subtotalFormatted,
|
||||||
lines: saleReceipt.entries?.map((entry) => ({
|
lines: saleReceipt.entries?.map((entry) => ({
|
||||||
item: entry.item.name,
|
item: entry.item.name,
|
||||||
description: entry.description,
|
description: entry.description,
|
||||||
@@ -19,6 +19,10 @@ export const transformReceiptToBrandingTemplateAttributes = (
|
|||||||
})),
|
})),
|
||||||
receiptNumber: saleReceipt.receiptNumber,
|
receiptNumber: saleReceipt.receiptNumber,
|
||||||
receiptDate: saleReceipt.formattedReceiptDate,
|
receiptDate: saleReceipt.formattedReceiptDate,
|
||||||
|
discount: saleReceipt.discountAmountFormatted,
|
||||||
|
discountLabel: saleReceipt.discountPercentageFormatted
|
||||||
|
? `Discount [${saleReceipt.discountPercentageFormatted}]`
|
||||||
|
: 'Discount',
|
||||||
customerAddress: contactAddressTextFormat(saleReceipt.customer),
|
customerAddress: contactAddressTextFormat(saleReceipt.customer),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -21,10 +21,6 @@ export interface ReceiptEmailTemplateProps {
|
|||||||
// # Colors
|
// # Colors
|
||||||
primaryColor?: string;
|
primaryColor?: string;
|
||||||
|
|
||||||
// # Invoice total
|
|
||||||
total: string;
|
|
||||||
totalLabel?: string;
|
|
||||||
|
|
||||||
// # Receipt #
|
// # Receipt #
|
||||||
receiptNumber?: string;
|
receiptNumber?: string;
|
||||||
receiptNumberLabel?: string;
|
receiptNumberLabel?: string;
|
||||||
@@ -32,6 +28,14 @@ export interface ReceiptEmailTemplateProps {
|
|||||||
// # Items
|
// # Items
|
||||||
items: Array<{ label: string; quantity: string; rate: string }>;
|
items: Array<{ label: string; quantity: string; rate: string }>;
|
||||||
|
|
||||||
|
// # Invoice total
|
||||||
|
total: string;
|
||||||
|
totalLabel?: string;
|
||||||
|
|
||||||
|
// # Discount
|
||||||
|
discount?: string;
|
||||||
|
discountLabel?: string;
|
||||||
|
|
||||||
// # Subtotal
|
// # Subtotal
|
||||||
subtotal?: string;
|
subtotal?: string;
|
||||||
subtotalLabel?: string;
|
subtotalLabel?: string;
|
||||||
@@ -117,7 +121,7 @@ export const ReceiptEmailTemplate: React.FC<
|
|||||||
<Text style={dueAmountLineItemAmountStyle}>{subtotal}</Text>
|
<Text style={dueAmountLineItemAmountStyle}>{subtotal}</Text>
|
||||||
</Column>
|
</Column>
|
||||||
</Row>
|
</Row>
|
||||||
|
|
||||||
<Row style={totalLineRowStyle}>
|
<Row style={totalLineRowStyle}>
|
||||||
<Column width={'50%'}>
|
<Column width={'50%'}>
|
||||||
<Text style={totalLineItemLabelStyle}>{totalLabel}</Text>
|
<Text style={totalLineItemLabelStyle}>{totalLabel}</Text>
|
||||||
|
|||||||
@@ -48,6 +48,12 @@ export interface EstimatePaperTemplateProps extends PaperTemplateProps {
|
|||||||
showTotal?: boolean;
|
showTotal?: boolean;
|
||||||
totalLabel?: string;
|
totalLabel?: string;
|
||||||
|
|
||||||
|
// # Discount
|
||||||
|
discount?: string;
|
||||||
|
showDiscount?: boolean;
|
||||||
|
discountLabel?: string;
|
||||||
|
|
||||||
|
// # Subtotal
|
||||||
subtotal?: string;
|
subtotal?: string;
|
||||||
showSubtotal?: boolean;
|
showSubtotal?: boolean;
|
||||||
subtotalLabel?: string;
|
subtotalLabel?: string;
|
||||||
@@ -101,6 +107,11 @@ export function EstimatePaperTemplate({
|
|||||||
totalLabel = 'Total',
|
totalLabel = 'Total',
|
||||||
showTotal = true,
|
showTotal = true,
|
||||||
|
|
||||||
|
// # Discount
|
||||||
|
discount = '0.00',
|
||||||
|
discountLabel = 'Discount',
|
||||||
|
showDiscount = true,
|
||||||
|
|
||||||
// # Subtotal
|
// # Subtotal
|
||||||
subtotal = '1000/00',
|
subtotal = '1000/00',
|
||||||
subtotalLabel = 'Subtotal',
|
subtotalLabel = 'Subtotal',
|
||||||
@@ -202,8 +213,8 @@ export function EstimatePaperTemplate({
|
|||||||
<Text>{data.item}</Text>
|
<Text>{data.item}</Text>
|
||||||
<Text
|
<Text
|
||||||
fontSize={'12px'}
|
fontSize={'12px'}
|
||||||
// className={Classes.TEXT_MUTED}
|
// className={Classes.TEXT_MUTED}
|
||||||
// style={{ fontSize: 12 }}
|
// style={{ fontSize: 12 }}
|
||||||
>
|
>
|
||||||
{data.description}
|
{data.description}
|
||||||
</Text>
|
</Text>
|
||||||
@@ -223,6 +234,12 @@ export function EstimatePaperTemplate({
|
|||||||
amount={subtotal}
|
amount={subtotal}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
{showDiscount && discount && (
|
||||||
|
<PaperTemplate.TotalLine
|
||||||
|
label={discountLabel}
|
||||||
|
amount={discount}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
{showTotal && (
|
{showTotal && (
|
||||||
<PaperTemplate.TotalLine label={totalLabel} amount={total} />
|
<PaperTemplate.TotalLine label={totalLabel} amount={total} />
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -2,10 +2,7 @@ import { Box } from '../lib/layout/Box';
|
|||||||
import { Text } from '../lib/text/Text';
|
import { Text } from '../lib/text/Text';
|
||||||
import { Stack } from '../lib/layout/Stack';
|
import { Stack } from '../lib/layout/Stack';
|
||||||
import { Group } from '../lib/layout/Group';
|
import { Group } from '../lib/layout/Group';
|
||||||
import {
|
import { PaperTemplate, PaperTemplateProps } from './PaperTemplate';
|
||||||
PaperTemplate,
|
|
||||||
PaperTemplateProps,
|
|
||||||
} from './PaperTemplate';
|
|
||||||
import {
|
import {
|
||||||
DefaultPdfTemplateTerms,
|
DefaultPdfTemplateTerms,
|
||||||
DefaultPdfTemplateItemDescription,
|
DefaultPdfTemplateItemDescription,
|
||||||
@@ -32,16 +29,21 @@ export interface ReceiptPaperTemplateProps extends PaperTemplateProps {
|
|||||||
|
|
||||||
billedToLabel?: string;
|
billedToLabel?: string;
|
||||||
|
|
||||||
|
// # Subtotal
|
||||||
|
subtotal?: string;
|
||||||
|
showSubtotal?: boolean;
|
||||||
|
subtotalLabel?: string;
|
||||||
|
|
||||||
|
// # Discount
|
||||||
|
discount?: string;
|
||||||
|
showDiscount?: boolean;
|
||||||
|
discountLabel?: string;
|
||||||
|
|
||||||
// Total
|
// Total
|
||||||
total?: string;
|
total?: string;
|
||||||
showTotal?: boolean;
|
showTotal?: boolean;
|
||||||
totalLabel?: string;
|
totalLabel?: string;
|
||||||
|
|
||||||
// Subtotal
|
|
||||||
subtotal?: string;
|
|
||||||
showSubtotal?: boolean;
|
|
||||||
subtotalLabel?: string;
|
|
||||||
|
|
||||||
// Customer Note
|
// Customer Note
|
||||||
showCustomerNote?: boolean;
|
showCustomerNote?: boolean;
|
||||||
customerNote?: string;
|
customerNote?: string;
|
||||||
@@ -99,10 +101,17 @@ export function ReceiptPaperTemplate({
|
|||||||
|
|
||||||
billedToLabel = 'Billed To',
|
billedToLabel = 'Billed To',
|
||||||
|
|
||||||
|
// # Total
|
||||||
total = '$1000.00',
|
total = '$1000.00',
|
||||||
totalLabel = 'Total',
|
totalLabel = 'Total',
|
||||||
showTotal = true,
|
showTotal = true,
|
||||||
|
|
||||||
|
// # Discount
|
||||||
|
discount = '',
|
||||||
|
discountLabel = 'Discount',
|
||||||
|
showDiscount = true,
|
||||||
|
|
||||||
|
// # Subtotal
|
||||||
subtotal = '1000/00',
|
subtotal = '1000/00',
|
||||||
subtotalLabel = 'Subtotal',
|
subtotalLabel = 'Subtotal',
|
||||||
showSubtotal = true,
|
showSubtotal = true,
|
||||||
@@ -192,8 +201,8 @@ export function ReceiptPaperTemplate({
|
|||||||
<Text>{data.item}</Text>
|
<Text>{data.item}</Text>
|
||||||
<Text
|
<Text
|
||||||
fontSize={'12px'}
|
fontSize={'12px'}
|
||||||
// className={Classes.TEXT_MUTED}
|
// className={Classes.TEXT_MUTED}
|
||||||
// style={{ fontSize: 12 }}
|
// style={{ fontSize: 12 }}
|
||||||
>
|
>
|
||||||
{data.description}
|
{data.description}
|
||||||
</Text>
|
</Text>
|
||||||
@@ -213,6 +222,12 @@ export function ReceiptPaperTemplate({
|
|||||||
amount={subtotal}
|
amount={subtotal}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
{showDiscount && discount && (
|
||||||
|
<PaperTemplate.TotalLine
|
||||||
|
label={discountLabel}
|
||||||
|
amount={discount}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
{showTotal && (
|
{showTotal && (
|
||||||
<PaperTemplate.TotalLine label={totalLabel} amount={total} />
|
<PaperTemplate.TotalLine label={totalLabel} amount={total} />
|
||||||
)}
|
)}
|
||||||
|
|||||||
Reference in New Issue
Block a user