Offline-first invoicing app for Arun P, built by Bongbetic. - Tauri v2 (Rust) + React/TypeScript + IBM Carbon Design System UI - SQLite (rusqlite) storage with a persistent invoice-number series - Guided first-run setup, pre-filled vendor/bank details - Fixed-amount or rate x quantity line items (per sec/min/hour/session/unit) - GST as CGST+SGST or IGST, Indian amount-in-words - Optional signature, with a computer-generated note as fallback - Print-ready PDF export via @react-pdf/renderer - Windows cross-compile via cargo-xwin (NSIS installer) Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
76 lines
1.9 KiB
TypeScript
76 lines
1.9 KiB
TypeScript
const ONES = [
|
|
"",
|
|
"One",
|
|
"Two",
|
|
"Three",
|
|
"Four",
|
|
"Five",
|
|
"Six",
|
|
"Seven",
|
|
"Eight",
|
|
"Nine",
|
|
"Ten",
|
|
"Eleven",
|
|
"Twelve",
|
|
"Thirteen",
|
|
"Fourteen",
|
|
"Fifteen",
|
|
"Sixteen",
|
|
"Seventeen",
|
|
"Eighteen",
|
|
"Nineteen",
|
|
];
|
|
|
|
const TENS = ["", "", "Twenty", "Thirty", "Forty", "Fifty", "Sixty", "Seventy", "Eighty", "Ninety"];
|
|
|
|
function twoDigits(n: number): string {
|
|
if (n < 20) return ONES[n];
|
|
const tens = Math.floor(n / 10);
|
|
const ones = n % 10;
|
|
return TENS[tens] + (ones ? " " + ONES[ones] : "");
|
|
}
|
|
|
|
function threeDigits(n: number): string {
|
|
const hundreds = Math.floor(n / 100);
|
|
const rest = n % 100;
|
|
let out = "";
|
|
if (hundreds > 0) out += ONES[hundreds] + " Hundred";
|
|
if (rest > 0) out += (out ? " " : "") + twoDigits(rest);
|
|
return out;
|
|
}
|
|
|
|
/** Whole-number to words using the Indian numbering system (thousand, lakh, crore). */
|
|
function wholeToWords(n: number): string {
|
|
if (n === 0) return "Zero";
|
|
const parts: string[] = [];
|
|
|
|
const crore = Math.floor(n / 10000000);
|
|
let rest = n % 10000000;
|
|
if (crore > 0) parts.push(`${wholeToWords(crore)} Crore`);
|
|
|
|
const lakh = Math.floor(rest / 100000);
|
|
rest %= 100000;
|
|
if (lakh > 0) parts.push(`${twoDigits(lakh)} Lakh`);
|
|
|
|
const thousand = Math.floor(rest / 1000);
|
|
rest %= 1000;
|
|
if (thousand > 0) parts.push(`${twoDigits(thousand)} Thousand`);
|
|
|
|
if (rest > 0) parts.push(threeDigits(rest));
|
|
|
|
return parts.join(" ");
|
|
}
|
|
|
|
/** e.g. 25000 -> "Indian Rupees Twenty Five Thousand Only" */
|
|
export function amountInWords(amount: number, currency = "Indian Rupees"): string {
|
|
const value = Number.isFinite(amount) ? Math.abs(amount) : 0;
|
|
const rupees = Math.floor(value);
|
|
const paise = Math.round((value - rupees) * 100);
|
|
|
|
let out = "";
|
|
if (currency) out += `${currency} `;
|
|
out += wholeToWords(rupees);
|
|
if (paise > 0) out += ` and ${twoDigits(paise)} Paise`;
|
|
return `${out} Only`;
|
|
}
|