Logos (PNG, JPEG, WebP) are decoded, trimmed to their ink box, downscaled to 1200 px and re-encoded as a content-addressed print PNG plus a white knockout variant when the logo has alpha; aspect, ink density, mean colour and kind (wordmark, mark, tall) are stored with the settings and frozen in the issue snapshot. Legacy logos are derived at startup. The Arun P logo PDF shrinks from 334 KB to 92 KB. Settings gains a Branding section with white and dark previews and a business-name toggle (migration M5).
233 lines
6.4 KiB
TypeScript
233 lines
6.4 KiB
TypeScript
export type TaxType = "none" | "cgst_sgst" | "igst";
|
|
export type LineMode = "fixed" | "rate";
|
|
export type LineUnit = "second" | "minute" | "hour" | "session" | "unit";
|
|
|
|
export interface Settings {
|
|
vendorName: string;
|
|
vendorAddress: string;
|
|
vendorEmail: string;
|
|
vendorPhone: string;
|
|
vendorPan: string;
|
|
vendorGstin: string;
|
|
vendorStateCode: string;
|
|
logoPath: string | null;
|
|
signaturePath: string | null;
|
|
defaultBankId: number | null;
|
|
defaultTaxRate: number;
|
|
defaultTaxType: TaxType;
|
|
paymentTermsDays: number;
|
|
currency: string;
|
|
onboarded: boolean;
|
|
theme: string;
|
|
gstRegistration: GstRegistration;
|
|
defaultHsnSac: string;
|
|
signatoryName: string;
|
|
signatoryDesignation: string;
|
|
/** The user's default page setup (RenderPrefsV1 JSON); empty means the built-in defaults. */
|
|
renderPrefs: string;
|
|
/** Folder of the last export; kept by the backend (saving settings does not change it). */
|
|
lastExportDir?: string;
|
|
/** The untouched logo file the derived images came from. */
|
|
logoOriginalPath: string | null;
|
|
/** White-ink variant for dark surfaces; only for logos with transparency. */
|
|
logoKnockoutPath: string | null;
|
|
/** LogoMeta JSON from the import pipeline; empty until the logo has been through it. */
|
|
logoMeta: string;
|
|
/** Whether the logo already contains the business name. Automatic means a wordmark does. */
|
|
logoIncludesName: "auto" | "yes" | "no";
|
|
}
|
|
|
|
export interface BankAccount {
|
|
id: number | null;
|
|
label: string;
|
|
bankName: string;
|
|
accountName: string;
|
|
accountNo: string;
|
|
branch: string;
|
|
ifsc: string;
|
|
isDefault: boolean;
|
|
}
|
|
|
|
export interface InvoiceSeries {
|
|
id: number;
|
|
prefix: string;
|
|
padding: number;
|
|
nextNumber: number;
|
|
isActive: boolean;
|
|
createdAt: string;
|
|
nextInvoiceNumber: string;
|
|
}
|
|
|
|
export interface Client {
|
|
id: number | null;
|
|
name: string;
|
|
address: string;
|
|
gstin: string;
|
|
stateCode: string;
|
|
poNumber: string;
|
|
createdAt: string;
|
|
}
|
|
|
|
export interface InvoiceItem {
|
|
id?: number | null;
|
|
description: string;
|
|
mode: LineMode;
|
|
rate: number;
|
|
unit: LineUnit;
|
|
quantity: number;
|
|
amount: number;
|
|
sortOrder: number;
|
|
/** Optional so older callers that build items by hand keep compiling; stored as "" when absent. */
|
|
hsnSac?: string;
|
|
}
|
|
|
|
export type GstRegistration = "unregistered" | "regular";
|
|
|
|
/** What the webview sends to issue an invoice; totals, tax and words are derived in Rust. */
|
|
export interface InvoiceInput {
|
|
invoiceDate: string;
|
|
dueDate: string;
|
|
clientId: number | null;
|
|
clientName: string;
|
|
clientAddress: string;
|
|
clientGstin: string;
|
|
poNumber: string;
|
|
placeOfSupplyStateCode: string;
|
|
discount: number;
|
|
taxType: TaxType;
|
|
taxRate: number;
|
|
reverseCharge: boolean;
|
|
bankAccountId: number | null;
|
|
signaturePath: string | null;
|
|
notes: string;
|
|
saveClient: boolean;
|
|
draftId: number | null;
|
|
items: InvoiceItem[];
|
|
}
|
|
|
|
export type InvoiceStatus = "draft" | "issued" | "cancelled";
|
|
|
|
/** An invoice as stored: all amounts are derived on the Rust side. */
|
|
export interface Invoice {
|
|
id: number;
|
|
number: string;
|
|
seriesId: number | null;
|
|
invoiceDate: string;
|
|
dueDate: string;
|
|
clientId: number | null;
|
|
clientName: string;
|
|
clientAddress: string;
|
|
clientGstin: string;
|
|
poNumber: string;
|
|
placeOfSupplyStateCode: string;
|
|
subtotal: number;
|
|
discount: number;
|
|
taxType: TaxType;
|
|
taxRate: number;
|
|
cgstAmount: number;
|
|
sgstAmount: number;
|
|
igstAmount: number;
|
|
total: number;
|
|
amountInWords: string;
|
|
bankAccountId: number | null;
|
|
bankSnapshot: string;
|
|
signaturePath: string | null;
|
|
notes: string;
|
|
status: InvoiceStatus;
|
|
createdAt: string;
|
|
updatedAt: string;
|
|
docType: "invoice" | "tax_invoice";
|
|
reverseCharge: boolean;
|
|
/** JSON of the supplier details at issue time; empty when unknown. */
|
|
vendorSnapshot: string;
|
|
snapshotOrigin: string;
|
|
cancelledAt: string | null;
|
|
cancelReason: string;
|
|
archivedPdfSha256: string | null;
|
|
/** RenderPrefsV1 JSON frozen at issue; empty when none was stored. */
|
|
renderPrefs: string;
|
|
/** Layout fingerprint of the archived PDF; null when nothing is archived. */
|
|
archivedFingerprint?: string | null;
|
|
archivedAt?: string | null;
|
|
items: InvoiceItem[];
|
|
}
|
|
|
|
export interface DraftSummary {
|
|
id: number;
|
|
updatedAt: string;
|
|
clientName: string | null;
|
|
total: number | null;
|
|
}
|
|
|
|
export interface InvoiceSummary {
|
|
id: number;
|
|
number: string;
|
|
invoiceDate: string;
|
|
dueDate: string;
|
|
clientName: string;
|
|
total: number;
|
|
status: InvoiceStatus;
|
|
createdAt: string;
|
|
}
|
|
|
|
export const EMPTY_ITEM: InvoiceItem = {
|
|
description: "",
|
|
mode: "fixed",
|
|
rate: 0,
|
|
unit: "unit",
|
|
quantity: 1,
|
|
amount: 0,
|
|
sortOrder: 0,
|
|
hsnSac: "",
|
|
};
|
|
|
|
/** GST state codes, same list as STATES in src-tauri/src/gst.rs (from India Compliance). */
|
|
export const INDIAN_STATES: { code: string; name: string }[] = [
|
|
{ code: "01", name: "Jammu and Kashmir" },
|
|
{ code: "02", name: "Himachal Pradesh" },
|
|
{ code: "03", name: "Punjab" },
|
|
{ code: "04", name: "Chandigarh" },
|
|
{ code: "05", name: "Uttarakhand" },
|
|
{ code: "06", name: "Haryana" },
|
|
{ code: "07", name: "Delhi" },
|
|
{ code: "08", name: "Rajasthan" },
|
|
{ code: "09", name: "Uttar Pradesh" },
|
|
{ code: "10", name: "Bihar" },
|
|
{ code: "11", name: "Sikkim" },
|
|
{ code: "12", name: "Arunachal Pradesh" },
|
|
{ code: "13", name: "Nagaland" },
|
|
{ code: "14", name: "Manipur" },
|
|
{ code: "15", name: "Mizoram" },
|
|
{ code: "16", name: "Tripura" },
|
|
{ code: "17", name: "Meghalaya" },
|
|
{ code: "18", name: "Assam" },
|
|
{ code: "19", name: "West Bengal" },
|
|
{ code: "20", name: "Jharkhand" },
|
|
{ code: "21", name: "Odisha" },
|
|
{ code: "22", name: "Chhattisgarh" },
|
|
{ code: "23", name: "Madhya Pradesh" },
|
|
{ code: "24", name: "Gujarat" },
|
|
{ code: "26", name: "Dadra and Nagar Haveli and Daman and Diu" },
|
|
{ code: "27", name: "Maharashtra" },
|
|
{ code: "29", name: "Karnataka" },
|
|
{ code: "30", name: "Goa" },
|
|
{ code: "31", name: "Lakshadweep Islands" },
|
|
{ code: "32", name: "Kerala" },
|
|
{ code: "33", name: "Tamil Nadu" },
|
|
{ code: "34", name: "Puducherry" },
|
|
{ code: "35", name: "Andaman and Nicobar Islands" },
|
|
{ code: "36", name: "Telangana" },
|
|
{ code: "37", name: "Andhra Pradesh" },
|
|
{ code: "38", name: "Ladakh" },
|
|
{ code: "96", name: "Other Countries" },
|
|
{ code: "97", name: "Other Territory" },
|
|
];
|
|
|
|
export const UNIT_LABELS: Record<LineUnit, string> = {
|
|
second: "per second",
|
|
minute: "per minute",
|
|
hour: "per hour",
|
|
session: "per session",
|
|
unit: "per unit",
|
|
};
|