mirror of
https://github.com/frappe/books.git
synced 2024-11-12 16:36:27 +00:00
Merge pull request #974 from AbleKSaju/feat-grandtotal-in-words
feat: display grand total amount in words
This commit is contained in:
commit
cb48742d63
@ -11,5 +11,6 @@ export class PrintSettings extends Doc {
|
||||
color?: string;
|
||||
font?: string;
|
||||
displayLogo?: boolean;
|
||||
amountInWords?: boolean;
|
||||
override hidden: HiddenMap = {};
|
||||
}
|
||||
|
@ -114,6 +114,12 @@
|
||||
"label": "Display Logo in Invoice",
|
||||
"fieldtype": "Check",
|
||||
"section": "Customizations"
|
||||
},
|
||||
{
|
||||
"fieldname": "amountInWords",
|
||||
"label": "Display Amount In Words",
|
||||
"fieldtype": "Check",
|
||||
"section": "Customizations"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ import {
|
||||
getSavePath,
|
||||
showExportInFolder,
|
||||
} from './ui';
|
||||
import { Money } from 'pesa';
|
||||
|
||||
export type PrintTemplateHint = {
|
||||
[key: string]: string | PrintTemplateHint | PrintTemplateHint[];
|
||||
@ -28,6 +29,7 @@ const printSettingsFields = [
|
||||
'phone',
|
||||
'address',
|
||||
'companyName',
|
||||
'amountInWords',
|
||||
];
|
||||
const accountingSettingsFields = ['gstin', 'taxId'];
|
||||
|
||||
@ -63,6 +65,10 @@ export async function getPrintTemplatePropValues(
|
||||
(values.doc as PrintTemplateData).showHSN = showHSN(doc);
|
||||
}
|
||||
|
||||
(values.doc as PrintTemplateData).grandTotalInWords = getGrandTotalInWords(
|
||||
(doc.grandTotal as Money).float
|
||||
);
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
@ -95,6 +101,112 @@ export function getPrintTemplatePropHints(schemaName: string, fyo: Fyo) {
|
||||
return hints;
|
||||
}
|
||||
|
||||
function getGrandTotalInWords(total: number) {
|
||||
const formattedTotal = total.toFixed(2);
|
||||
|
||||
const [integerPart, decimalPart] = formattedTotal.split('.');
|
||||
|
||||
const ones = [
|
||||
'',
|
||||
t`One`,
|
||||
t`Two`,
|
||||
t`Three`,
|
||||
t`Four`,
|
||||
t`Five`,
|
||||
t`Six`,
|
||||
t`Seven`,
|
||||
t`Eight`,
|
||||
t`Nine`,
|
||||
];
|
||||
|
||||
const teens = [
|
||||
t`Ten`,
|
||||
t`Eleven`,
|
||||
t`Twelve`,
|
||||
t`Thirteen`,
|
||||
t`Fourteen`,
|
||||
t`Fifteen`,
|
||||
t`Sixteen`,
|
||||
t`Seventeen`,
|
||||
t`Eighteen`,
|
||||
t`Nineteen`,
|
||||
];
|
||||
|
||||
const tens = [
|
||||
'',
|
||||
'',
|
||||
t`Twenty`,
|
||||
t`Thirty`,
|
||||
t`Forty`,
|
||||
t`Fifty`,
|
||||
t`Sixty`,
|
||||
t`Seventy`,
|
||||
t`Eighty`,
|
||||
t`Ninety`,
|
||||
];
|
||||
|
||||
const scales = ['', t`Thousand`, t`Million`, t`Billion`];
|
||||
|
||||
function convertThreeDigitNumber(num: number) {
|
||||
let result = '';
|
||||
|
||||
const hundredDigit = Math.floor(num / 100);
|
||||
const remainder = num % 100;
|
||||
|
||||
if (hundredDigit > 0) {
|
||||
result += ones[hundredDigit] + ` ${t`Hundred`}`;
|
||||
}
|
||||
|
||||
if (remainder > 0) {
|
||||
if (hundredDigit > 0) {
|
||||
result += ` ${t`And`} `;
|
||||
}
|
||||
|
||||
if (remainder < 10) {
|
||||
result += ones[remainder];
|
||||
} else if (remainder < 20) {
|
||||
result += teens[remainder - 10];
|
||||
} else {
|
||||
const tensDigit = Math.floor(remainder / 10);
|
||||
const onesDigit = remainder % 10;
|
||||
result += tens[tensDigit];
|
||||
if (onesDigit > 0) {
|
||||
result += ' ' + ones[onesDigit];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
let spelledOutInteger = '';
|
||||
const integerGroups = integerPart.match(/(\d{1,3})(?=(\d{3})*$)/g) || [];
|
||||
const groupCount = integerGroups.length;
|
||||
|
||||
integerGroups.forEach((group, index) => {
|
||||
const groupValue = parseInt(group);
|
||||
|
||||
if (groupValue > 0) {
|
||||
const groupText = convertThreeDigitNumber(groupValue);
|
||||
const groupSuffix = scales[groupCount - index - 1];
|
||||
spelledOutInteger +=
|
||||
groupText + (groupSuffix ? ' ' + groupSuffix : '') + ' ';
|
||||
}
|
||||
});
|
||||
|
||||
spelledOutInteger = spelledOutInteger.trim() || t`Zero`;
|
||||
|
||||
let spelledOutDecimal = '';
|
||||
const decimalCents = parseInt(decimalPart);
|
||||
|
||||
if (decimalCents !== 0) {
|
||||
spelledOutDecimal =
|
||||
` ${t`and`} ` + convertThreeDigitNumber(decimalCents) + ` ${t`Paisa`}`;
|
||||
}
|
||||
|
||||
return `${spelledOutInteger}${spelledOutDecimal} ${t`only`}`;
|
||||
}
|
||||
|
||||
function showHSN(doc: Doc): boolean {
|
||||
const items = doc.items;
|
||||
if (!Array.isArray(items)) {
|
||||
|
@ -126,5 +126,9 @@
|
||||
<h3 class="text-lg font-semibold">Notes</h3>
|
||||
<p class="mt-4 text-lg whitespace-pre-line">{{ doc.terms }}</p>
|
||||
</section>
|
||||
<div v-if="print.amountInWords" class="flex justify-end mt-10">
|
||||
<h3 class="text-lg font-semibold mr-2">Grand Total In Words:</h3>
|
||||
<p>{{doc.grandTotalInWords}}</p>
|
||||
</div>
|
||||
</footer>
|
||||
</main>
|
||||
|
Loading…
Reference in New Issue
Block a user