Master Data
Read Conventions first.
items
The item master. Very wide - pricing, planning, production, delivery attributes, and its own 24-account G/L set.
id,business_id,code- UNIQUE (business_id, code)nameNOT NULL;description,foreign_description,model,remarksDEFAULT ‘’item_typeDEFAULT ‘inventory’item_group_id→ item_groups;item_category_id→ item_categories;item_subcategory_id→ item_subcategoriesbrand_id→ brandscountry_of_origin,hs_code,commodity_codedefault_uom_id→ uomslifecycle_statusDEFAULT ‘active’;is_activeboolean DEFAULT trueimage_urlparent_item_id→ items CASCADE - variant parentproduct_typeDEFAULT ‘simple’ - CHECK IN (‘simple’,‘variable’)managed_byDEFAULT ‘none’ - CHECK IN (‘none’,‘batch’,‘serial’)track_expiryboolean DEFAULT falsedefault_purchase_price,default_selling_pricenumeric(12,2) DEFAULT 0tax_liableboolean,tax_ratenumeric(5,2),tax_component_id→ tax_components - item’s default tax code;tax_rateauto-synced from itmin_inventory,max_inventory,required_inventory_levelnumeric(14,3) DEFAULT 0 - general (default) levelsweightnumeric(12,3),weight_unitCHECK IN (‘kg’,‘g’,‘lb’,‘oz’);length/width/heightnumeric(12,3),dimension_unitCHECK IN (‘cm’,‘m’,‘in’,‘ft’)packing_material_charge_percent- CHECK 0..100warranty_period_id→ warranty_periodsis_gift_voucherboolean DEFAULT falseloyalty_points_excludedboolean DEFAULT falseis_pos_quick_pickboolean DEFAULT false - max 5 per business, enforced in application code not SQL; partial index(business_id) WHERE is_pos_quick_pickallow_oversellboolean NULL - item-level override, wins outright over branch/business- Planning Data:
planning_methodCHECK IN (‘none’,‘mrp’);procurement_methodCHECK IN (‘buy’,‘make’) - this is the “is a production item” switch;order_interval,order_multiple/minimum_order_qtynumeric(14,3),checking_rule,lead_time_daysint,tolerance_daysint - Production Data:
is_phantom_itemboolean;default_issue_methodCHECK IN (‘manual’,‘backflush’) gl_accounts_byDEFAULT ‘item_group’ - CHECK IN (‘item_group’,‘warehouse’,‘item_level’) - three mutually exclusive sources, not a cascade- 24 nullable
uuid → gl_accountscolumns (used only whengl_accounts_by = 'item_level') - same names asgl_account_determination_defaults created_at,updated_at
item_groups
Top level of the item hierarchy, and the primary G/L Account Determination source.
id,business_id,name,created_atinventory_account_id→ gl_accounts- 23 more nullable
→ gl_accounts:expense_account_id,revenue_account_id,cogs_account_id,allocation_account_id,variance_account_id,price_difference_account_id,negative_inventory_adjustment_account_id,inventory_offset_decrease_account_id,inventory_offset_increase_account_id,sales_returns_account_id,exchange_rate_difference_account_id,goods_clearing_account_id,gl_decrease_account_id,gl_increase_account_id,wip_inventory_account_id,wip_inventory_variance_account_id,wip_offset_account_id,inventory_offset_pl_account_id,expense_clearing_account_id,stock_in_transit_account_id,shipped_goods_account_id,sales_credit_account_id,purchase_credit_account_id
item_categories / item_subcategories
2nd and 3rd levels of the item hierarchy.
- item_categories -
id,business_id,item_group_id→ item_groups NOT NULL,name,created_at - item_subcategories -
id,business_id,item_category_id→ item_categories NOT NULL,name,created_at
brands
id, business_id, name, created_at - UNIQUE (business_id, name)
uoms / uom_groups
Units of measure, with conversion to a base UoM.
- uoms -
id,business_id,code,name- UNIQUE (business_id, code);allow_decimalboolean DEFAULT true;base_uom_id→ uoms NULL (self-reference);conversion_factornumeric(18,6) DEFAULT 1;uom_group_id→ uom_groups NOT NULL;created_at - uom_groups -
id,business_id,name- UNIQUE (business_id, name);allow_weight_loss_calcboolean DEFAULT false;created_at- seeded “Weight” (calc-enabled) and “Each / Count” per business
price_lists / item_prices
- price_lists -
id,business_id,name- UNIQUE (business_id, name);currency_id→ currencies NOT NULL;created_at - item_prices -
id,item_idCASCADE,price_list_id→ price_lists;selling_pricenumeric(12,2) DEFAULT 0;cost_pricenumeric DEFAULT 0;created_at- UNIQUE (item_id, price_list_id)
item_barcodes / item_suppliers
- item_barcodes -
id,item_idCASCADE,barcodetext UNIQUE globally,is_active,created_at - item_suppliers - supplier catalogue per item, also reused as the targeting table for supplier-based promotions.
id,item_idCASCADE,supplier_id→ business_partners,supplier_item_code,supplier_barcode,lead_time_daysint,moqnumeric(12,2),is_preferredboolean,created_at- UNIQUE (item_id, supplier_id)
item_default_bins
Per-item-per-warehouse settings row. NULL on a level column means “inherit the item’s general level”, not zero.
item_id,warehouse_id- composite PKbin_id→ bin_locations ON DELETE SET NULLlocked,enforce_default_binboolean DEFAULT falsemin_inventory,max_inventory,required_inventory_levelnumeric(14,3) NULL
branch_items
Which items are enabled at which branch.
branch_idCASCADE,item_idCASCADE - composite PK;created_at
Variances (item variants)
- variances - variant dimension (e.g. “Colour”).
id,business_id,name,created_at- UNIQUE (business_id, name) - variance_values -
id,variance_idCASCADE,value,image_url,created_at- UNIQUE (variance_id, value) - item_variance_values - which variance values a (parent) item offers.
item_idCASCADE,variance_idCASCADE,value_id→ variance_values CASCADE - PK (item_id, value_id) - item_variant_selections - the specific value a child/variant item resolves to per dimension.
item_idCASCADE,variance_idCASCADE,value_idCASCADE - PK (item_id, variance_id)
warranty_periods / warranty_records
- warranty_periods -
id,business_id,name- UNIQUE (business_id, name);duration_daysint NOT NULL CHECK > 0;is_active,created_at - warranty_records - one row per warranted A/R invoice line.
id,business_id,ar_invoice_id,ar_invoice_line_id,item_id,customer_id→ business_partners,branch_id,warranty_period_id(all NOT NULL),quantityNOT NULL,start_date/expiry_dateNOT NULL,created_at; indexes on customer_id, item_id, ar_invoice_id
business_partners
Customers, suppliers and vendors in one table.
id,business_id,nameNOT NULLcode- text NOT NULL DEFAULT ‘’ - partial UNIQUE index(business_id, code) WHERE code <> ''is_customer,is_supplier,is_vendorboolean - CHECK (is_customer OR is_supplier OR is_vendor)contact_person,phone,mobile,email,address,notes,tax_id,partner_groupDEFAULT ‘’credit_limitnumeric(12,2),payment_terms_daysint,opening_balancenumeric(12,2)payment_term_id→ payment_terms;default_tax_group_id→ tax_groups;default_price_list_id→ price_listssscl_liableboolean DEFAULT falsedate_of_birthdate - birthday promotionsis_loyalty_memberboolean,loyalty_member_notext NULL,loyalty_enrolled_at,loyalty_points_balancenumeric(14,2) CHECK >= 0 - UNIQUE (business_id, loyalty_member_no); NULLs never collidechange_money_balancenumeric(12,2) CHECK >= 0 - decrementing balancesubject_to_withholding_taxboolean DEFAULT false - must be true before any WHT code appliesdefault_withholding_tax_code_id→ withholding_tax_codesis_active,created_at- Every business has a standing ‘Walk-in Customer’ partner
partner_ledger_entries
id,partner_id→ business_partners CASCADEentry_date,descriptiondebit,creditnumeric(12,2) - CHECK (debit >= 0 AND credit >= 0 AND (debit > 0 OR credit > 0))created_by→ users nullable (auto-posted POS entries have no human creator),created_at
payment_terms
id, business_id, name - UNIQUE (business_id, name); term_type CHECK IN (‘credit’,‘down_payment’); credit_days int NULL; down_payment_percent numeric(5,2) NULL; is_active, created_at
Tax tables
- tax_components - an individual tax (VAT, SSCL, …).
id,business_id,code- UNIQUE (business_id, code);name;ratenumeric(6,3) NOT NULL;gl_account_id→ gl_accounts;is_ssclboolean DEFAULT false (designates the SSCL surcharge; excluded from per-line tax pickers, consumed specially by the totals engine);is_active,created_at - tax_groups -
id,business_id,nameUNIQUE (business_id, name);code- UNIQUE (business_id, code);is_active,created_at - tax_group_components - ordered components within a group.
id,tax_group_idCASCADE,tax_component_id,sequenceint NOT NULL - UNIQUE (tax_group_id, sequence);calculation_basisCHECK IN (‘item_price’,‘running_total’);is_mandatoryboolean DEFAULT false;purchase_calc_type/sale_calc_typeDEFAULT ‘percentage’ CHECK IN (‘percentage’,‘fixed’);purchase_value/sale_valuenumeric DEFAULT 100 - “X% of the Total Value the component’s own rate applies to” (e.g. SSCL = 2.5% of 85% of total); 100 means the full value, no reduction
convenience_fees
Reusable business-level fee, applied per document.
id,business_id,name- UNIQUE (business_id, name)fee_typeCHECK IN (‘percentage’,‘fixed’);valuenumeric(14,2)applies_toDEFAULT ‘purchase’ - CHECK IN (‘purchase’,‘sale’)is_taxableboolean DEFAULT false;tax_group_id/tax_component_id- CHECK: not both setis_active,created_at
warehouses / bin_locations
- warehouses -
id,business_id,branch_id→ branches NULL,code- UNIQUE (business_id, code);name,address,is_active,created_at; 24 nullableuuid → gl_accountscolumns (the “By Warehouse” G/L determination source, symmetric to item_groups) - bin_locations - hierarchical bins within a warehouse; informational for now, stock quantity is still tracked at warehouse level.
id,warehouse_idCASCADE,parent_id→ bin_locations NULL,code- UNIQUE (warehouse_id, code);name,bin_typeDEFAULT ‘standard’;capacity_qty/capacity_weight/capacity_volumenumeric(14,3) NULL;is_active,created_at
Delivery partner tables
- delivery_partners -
id,business_id,name- UNIQUE (business_id, name);code,contact_person,phone,email,address;is_active,created_at - delivery_partner_rate_cards -
id,delivery_partner_idCASCADE,city- UNIQUE (delivery_partner_id, city);district,shipping_zone;first_kg_rate,additional_kg_ratenumeric CHECK >= 0;created_at - delivery_partner_waybills - pre-issued waybill stock, allocated to an invoice when used.
id,delivery_partner_idCASCADE,waybill_no- UNIQUE (delivery_partner_id, waybill_no);statusDEFAULT ‘available’ CHECK IN (‘available’,‘allocated’);allocated_to_ar_invoice_id→ ar_invoices NULL,allocated_at,created_at