issue_invoice allocates the number, freezes vendor and bank details and stores server-computed totals in one transaction. Issued invoices are cancelled, not deleted. Tax heads derive from supplier state and place of supply (a disagreeing choice is rejected); unregistered suppliers issue a plain Invoice. Adds GSTIN checksum validation, canonical India Compliance state list, server-side drafts, series validation, relative and magic-byte-checked asset paths, and GST settings. PDF re-exports use the frozen vendor snapshot.
221 lines
5.8 KiB
Rust
221 lines
5.8 KiB
Rust
use serde::{Deserialize, Serialize};
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct Settings {
|
|
pub vendor_name: String,
|
|
pub vendor_address: String,
|
|
pub vendor_email: String,
|
|
pub vendor_phone: String,
|
|
pub vendor_pan: String,
|
|
pub vendor_gstin: String,
|
|
pub vendor_state_code: String,
|
|
pub logo_path: Option<String>,
|
|
pub signature_path: Option<String>,
|
|
pub default_bank_id: Option<i64>,
|
|
pub default_tax_rate: f64,
|
|
pub default_tax_type: String,
|
|
pub payment_terms_days: i64,
|
|
pub currency: String,
|
|
pub onboarded: bool,
|
|
pub theme: String,
|
|
pub gst_registration: String,
|
|
pub default_hsn_sac: String,
|
|
pub signatory_name: String,
|
|
pub signatory_designation: String,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct BankAccount {
|
|
pub id: Option<i64>,
|
|
#[serde(default)]
|
|
pub label: String,
|
|
#[serde(default)]
|
|
pub bank_name: String,
|
|
#[serde(default)]
|
|
pub account_name: String,
|
|
#[serde(default)]
|
|
pub account_no: String,
|
|
#[serde(default)]
|
|
pub branch: String,
|
|
#[serde(default)]
|
|
pub ifsc: String,
|
|
#[serde(default)]
|
|
pub is_default: bool,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct InvoiceSeries {
|
|
pub id: i64,
|
|
pub prefix: String,
|
|
pub padding: i64,
|
|
pub next_number: i64,
|
|
pub is_active: bool,
|
|
pub created_at: String,
|
|
/// The number the next invoice created under this series would receive.
|
|
pub next_invoice_number: String,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct Client {
|
|
pub id: Option<i64>,
|
|
pub name: String,
|
|
#[serde(default)]
|
|
pub address: String,
|
|
#[serde(default)]
|
|
pub gstin: String,
|
|
#[serde(default)]
|
|
pub state_code: String,
|
|
#[serde(default)]
|
|
pub po_number: String,
|
|
#[serde(default)]
|
|
pub created_at: String,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct InvoiceItem {
|
|
#[serde(default)]
|
|
pub id: Option<i64>,
|
|
#[serde(default)]
|
|
pub description: String,
|
|
/// "fixed" = a single amount; "rate" = rate x quantity.
|
|
#[serde(default = "default_mode")]
|
|
pub mode: String,
|
|
#[serde(default)]
|
|
pub rate: f64,
|
|
/// second | minute | hour | session | unit
|
|
#[serde(default = "default_unit")]
|
|
pub unit: String,
|
|
#[serde(default)]
|
|
pub quantity: f64,
|
|
#[serde(default)]
|
|
pub amount: f64,
|
|
#[serde(default)]
|
|
pub sort_order: i64,
|
|
#[serde(default)]
|
|
pub hsn_sac: String,
|
|
}
|
|
|
|
fn default_mode() -> String {
|
|
"fixed".to_string()
|
|
}
|
|
|
|
fn default_unit() -> String {
|
|
"unit".to_string()
|
|
}
|
|
|
|
/// What the webview may send when issuing an invoice. Money totals, tax amounts,
|
|
/// the amount in words and the vendor/bank snapshots are derived on the Rust side.
|
|
#[derive(Debug, Clone, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct InvoiceInput {
|
|
pub invoice_date: String,
|
|
#[serde(default)]
|
|
pub due_date: String,
|
|
#[serde(default)]
|
|
pub client_id: Option<i64>,
|
|
#[serde(default)]
|
|
pub client_name: String,
|
|
#[serde(default)]
|
|
pub client_address: String,
|
|
#[serde(default)]
|
|
pub client_gstin: String,
|
|
#[serde(default)]
|
|
pub po_number: String,
|
|
#[serde(default)]
|
|
pub place_of_supply_state_code: String,
|
|
#[serde(default)]
|
|
pub discount: f64,
|
|
/// The tax treatment the user chose; it must match the derived one.
|
|
#[serde(default = "default_tax_type")]
|
|
pub tax_type: String,
|
|
#[serde(default)]
|
|
pub tax_rate: f64,
|
|
#[serde(default)]
|
|
pub reverse_charge: bool,
|
|
#[serde(default)]
|
|
pub bank_account_id: Option<i64>,
|
|
#[serde(default)]
|
|
pub signature_path: Option<String>,
|
|
#[serde(default)]
|
|
pub notes: String,
|
|
#[serde(default)]
|
|
pub save_client: bool,
|
|
#[serde(default)]
|
|
pub draft_id: Option<i64>,
|
|
#[serde(default)]
|
|
pub items: Vec<InvoiceItem>,
|
|
}
|
|
|
|
fn default_tax_type() -> String {
|
|
"none".to_string()
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct Invoice {
|
|
pub id: i64,
|
|
pub number: String,
|
|
pub series_id: Option<i64>,
|
|
pub invoice_date: String,
|
|
pub due_date: String,
|
|
pub client_id: Option<i64>,
|
|
pub client_name: String,
|
|
pub client_address: String,
|
|
pub client_gstin: String,
|
|
pub po_number: String,
|
|
pub place_of_supply_state_code: String,
|
|
pub subtotal: f64,
|
|
pub discount: f64,
|
|
pub tax_type: String,
|
|
pub tax_rate: f64,
|
|
pub cgst_amount: f64,
|
|
pub sgst_amount: f64,
|
|
pub igst_amount: f64,
|
|
pub total: f64,
|
|
pub amount_in_words: String,
|
|
pub bank_account_id: Option<i64>,
|
|
pub bank_snapshot: String,
|
|
pub signature_path: Option<String>,
|
|
pub notes: String,
|
|
/// draft | issued | cancelled
|
|
pub status: String,
|
|
pub created_at: String,
|
|
pub updated_at: String,
|
|
pub doc_type: String,
|
|
pub reverse_charge: bool,
|
|
/// JSON of the supplier details as they were when the invoice was issued; empty if unknown.
|
|
pub vendor_snapshot: String,
|
|
pub snapshot_origin: String,
|
|
pub cancelled_at: Option<String>,
|
|
pub cancel_reason: String,
|
|
pub archived_pdf_sha256: Option<String>,
|
|
pub items: Vec<InvoiceItem>,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct InvoiceSummary {
|
|
pub id: i64,
|
|
pub number: String,
|
|
pub invoice_date: String,
|
|
pub due_date: String,
|
|
pub client_name: String,
|
|
pub total: f64,
|
|
pub status: String,
|
|
pub created_at: String,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct DraftSummary {
|
|
pub id: i64,
|
|
pub updated_at: String,
|
|
pub client_name: Option<String>,
|
|
pub total: Option<f64>,
|
|
}
|