Initial commit: Voiced invoice desktop app
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>
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
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`;
|
||||
}
|
||||
Reference in New Issue
Block a user