Skip to main content
ARUKZ ERP keeps each fact once and points at it by ID. Every customer, vendor, contact and address is a row in one table, partners_partners; every product and variant is a row in products_products; and every business document is a header with lines that point at those rows. Each business row also carries company_id, which is how one database keeps every company’s data apart.

The master data

A sales order to a customer with a separate delivery dock points at three partner rows: the buyer (partner_id), who is billed (partner_invoice_id) and where it goes (partner_shipping_id).

Documents: header and lines

Because every line points at its order line and every order at its partner, you can walk from any invoice line back to the order, the delivery and the customer without matching names. Invoices, bills, credit notes and journal entries are all rows in accounts_account_moves, told apart by move_type.
  • Sales to stock: confirming an order creates a delivery and its stock moves, each pointing back at the order line.
  • Sales to accounts: creating an invoice writes an account move linked to the order.
  • Purchases: the same pattern, for receipts and vendor bills.
  • Manufacturing to stock: raw-material and finished-goods moves point at the manufacturing order.
  • Projects to timesheets: time is stored as analytic records with the project and task.

Company separation and shared rows

CompanyScope shows a row when its company_id is one of the user’s companies, or when it is empty. An empty company_id means shared by everyone, which is meant for reference data such as countries, currencies and units of measure. Partners and products belong to the company that creates them. Two ways a row can still end up shared by mistake:
  • It was created outside a signed-in web request (a queue job, an artisan command, a seeder), where there is no current company. Set company_id yourself in that code.
  • A visitor registered on the customer portal (/customer), which is not yet aware of companies.

Known gaps

Two partner rows for the same real company (“Zara Garments” and “ZARA GARMENTS PVT LTD”) are not caught or merged. GSTIN, email and phone are indexed but not unique, and product barcodes are not unique either. Search by GSTIN and phone before adding a customer.
Several ARUKZ columns store a name instead of a link, for example the auditor on a compliance audit, the vendor on a vendor scorecard, the job worker on a subcontract challan and the vendor on a fleet log. They work, but reports cannot join on them. New code stores the ID.
CRM leads and CRM accounts keep their own copy of a customer’s name, email and phone instead of using partners, and there is no step that turns a lead into a customer. Fixed assets overlap maintenance equipment, and procurement RFQs overlap purchase orders.
ARUKZ amounts are decimal(15,2) with no currency column; the core tables use decimal(15,4) with currency_id.
A few ARUKZ codes (asset codes, ticket numbers, document numbers and others) are unique across the whole platform rather than per company. New code takes numbers from SequenceService::next('<key>', $companyId) and makes them unique per company.

Rules for new tables

  • Store the ID (foreignId(...)->constrained()), never a copied name; read the name through the relationship when you print.
  • Put company_id on every business table and use the BelongsToCompany trait on the model.
  • Make codes unique per company: unique(['company_id', 'code']).
Build a custom plugin shows all three in a worked example.
Last modified on November 12, 2026