Data Model
Warka stores nothing in a bespoke schema. Every record is a standard Frappe, ERPNext, or HRMS doctype, and the custom app adds only a handful of custom fields, some seeded master data, and one document-event hook. This means the entire ERPNext and HRMS data model, its reports, its permission system, and its integrity guarantees are available unchanged. This document lists the doctypes each module uses, the fields Warka adds, the master data it seeds, the document hook it registers, and the submittable-document-with-a-ledger model that underpins finance and payroll. The endpoints that read and write these doctypes are in the API Reference.
Doctypes by module
HR and Payroll (ERPNext + HRMS)
| Doctype | Purpose |
|---|---|
| Employee | The person record; the anchor for HR, payroll, and lifecycle |
| Leave Application | A leave request, approved and submitted by an HR Manager |
| Leave Allocation | Grants a leave balance to an employee |
| Attendance | A submitted daily attendance record |
| Employee Checkin | A raw clock IN / OUT punch |
| Salary Structure | A reusable definition of earnings and deductions |
| Salary Structure Assignment | Binds a structure and base salary to an employee |
| Salary Slip | A generated payslip for one employee for one period |
| Payroll Entry | A payroll run that generates and submits slips for a period |
| Expense Claim | An employee expense reimbursement request |
| Expense Claim Type | The category and account an expense posts to |
| Job Opening | A role, optionally published to the public careers site |
| Job Applicant | A candidate in the recruitment pipeline |
| Job Offer | An offer extended to an applicant |
| Employee Onboarding / Employee Separation | The lifecycle checklists for joining and leaving |
| Employee Onboarding Template / Employee Separation Template | Reusable checklist definitions |
| Employee Boarding Activity | A single checklist line (child table) |
| Appraisal, Appraisal Cycle, Appraisal Template | Performance review records |
| Shift Type, Shift Assignment | Attendance-by-shift configuration |
| Department, Designation, Branch, Employee Grade, Leave Type, Holiday List | HR master data |
Finance (ERPNext Accounts)
| Doctype | Purpose |
|---|---|
| Sales Invoice | A customer bill; posts to the ledger on submit |
| Purchase Invoice | A supplier bill; posts to the ledger on submit |
| Payment Entry | Records a payment against an invoice |
| Journal Entry | A direct two-line (or more) ledger posting |
| Account | A node in the chart of accounts |
| GL Entry | An immutable general-ledger line (created by submitted documents) |
| Fiscal Year | The accounting year a posting date falls in |
| Cost Center | A dimension for cost attribution |
| Mode of Payment | Cash, bank, and the accounts they post to |
Selling (ERPNext CRM and Selling)
| Doctype | Purpose |
|---|---|
| Customer | A party you sell to |
| Lead | An unqualified prospect |
| Opportunity | A qualified sales opportunity |
| Quotation | A price quote for a customer or lead |
| Sales Order | A confirmed customer order |
| Contact, Issue, Customer Group, Territory | CRM master and support data |
Buying (ERPNext Buying)
| Doctype | Purpose |
|---|---|
| Supplier | A party you buy from |
| Material Request | An internal purchase requisition |
| Purchase Order | A confirmed order to a supplier |
| Supplier Group | Supplier categorization |
Stock (ERPNext Stock)
| Doctype | Purpose |
|---|---|
| Item | A product or service |
| Item Group | The item category tree |
| Warehouse | A stock location |
| Bin | Per-item, per-warehouse quantity and valuation |
| UOM | Unit of measure |
| Price List | Selling and buying price lists |
Projects (ERPNext Projects)
| Doctype | Purpose |
|---|---|
| Project | A project record |
| Task | A unit of work within a project |
| Timesheet | Logged time against tasks or projects |
Core (Frappe)
| Doctype | Purpose |
|---|---|
| User | A login account |
| Role, Has Role | The RBAC role and its assignment to a user |
| Company | The company the whole system is scoped to |
| File | An uploaded document or attachment |
| DocShare | A per-user share grant on a document |
| Global Defaults, System Settings, Selling Settings, Buying Settings | Site and app configuration singletons |
Custom fields Warka adds
Warka adds custom fields idempotently through Frappe's custom-field system, wired
to the after_install and after_migrate hooks so the schema is reproducible on
any site. It never forks a standard doctype.
Employee (ensure_employee_custom_fields in api.py)
A "National Identity and Residence" section with an Ethiopian context, inserted after the blood-group field:
| Fieldname | Label | Type |
|---|---|---|
fayda_id | Fayda ID (National ID) | Data |
tin_number | TIN Number | Data |
nationality | Nationality | Data (default Ethiopian) |
region | Region / City | Data |
sub_city | Sub-City / Zone | Data |
woreda | Woreda | Data |
kebele | Kebele | Data |
house_number | House Number | Data |
Company (ensure_careers_fields in careers.py)
A collapsible "Careers Page" section that lets HR brand the public careers site from inside the ERP:
| Fieldname | Label | Type |
|---|---|---|
careers_headline | Careers Headline | Data |
careers_tagline | Careers Tagline | Small Text |
careers_about | About Working Here | Text Editor |
Employee Boarding Activity (ensure_boarding_field in api.py)
| Fieldname | Label | Type |
|---|---|---|
cz_completed | Completed | Check |
The cz_completed flag tracks per-activity checklist progress directly, which
sidesteps the fragile standard submit/Task machinery so the lifecycle flow always
works. The app also self-heals this column on demand (_ensure_boarding_field_once)
if a site was updated in place without running the migrate hook.
Master data seeded by setup_defaults.py
ensure_operational_defaults() is idempotent and runs on every migrate. It fills
the gaps a bare bench new-site leaves, so no transactional endpoint fails on a
missing link. If any of these is deleted by hand, the next migrate recreates it.
| Step | What it guarantees |
|---|---|
_ensure_fiscal_year | A Fiscal Year covering today |
_ensure_item_groups | All Item Groups, plus Services and Products leaves |
_ensure_uoms | Nos, Unit, Hour, Day, Kg, Box |
_ensure_price_lists | Standard Selling and Standard Buying in the company currency |
_ensure_party_groups | Customer, supplier, and territory groups, and the Selling/Buying default group settings |
_ensure_genders | Male, Female, Other |
_ensure_hr_masters | Leave types, expense claim types, a day shift, and designations (only when HRMS is present and empty) |
_ensure_company_defaults | Company default accounts, a bank account, a Cash mode of payment, a tax account, expense-claim and salary-component accounts, a holiday list, and a default salary structure |
complete_setup_wizard() is the separate one-time routine that runs the real
ERPNext setup wizard to provision the Company and chart of accounts from the
COMPANY_* configuration. See
Configuration and Customization for the
values it consumes and why this makes Warka company-agnostic.
The document event hook
The app registers one doc_events hook in hooks.py:
doc_events = {
"Expense Claim": {
"validate": "cyber_zeb_erp.doc_hooks.expense_claim_defaults",
},
}
expense_claim_defaults (in doc_hooks.py) runs on every write path (frontend
REST, the whitelisted API, and imports). Cost center is mandatory on every
expense row but users rarely set it, so the hook defaults the header and each row
to the company cost center when blank, turning a hard validation error into a
sensible default. This is the pattern to follow when adding your own hooks; see
Extending and Customizing.
The submittable-document-with-a-ledger model
ERPNext transactions are submittable documents, and this is the key model to
understand. A document has a docstatus:
| docstatus | State | Meaning |
|---|---|---|
| 0 | Draft | Editable, no ledger impact |
| 1 | Submitted | Locked; has posted its effects to the ledger |
| 2 | Cancelled | Reversed; ledger effects backed out |
When a Sales Invoice, Purchase Invoice, Payment Entry, Journal Entry, or Salary
Slip is submitted, ERPNext writes immutable GL Entry rows to the general
ledger. Reports such as the Profit and Loss statement, the Balance Sheet, and the
aging reports read those GL Entries, never the source documents, so the financial
statements are always a faithful projection of what was actually posted. Warka's
create endpoints insert a draft and then attempt to submit it inside a savepoint,
so a submit that fails validation leaves a recoverable draft rather than losing
the record (_submit_or_draft in api.py). Stock movements work the same way:
submitting a stock document updates the per-item, per-warehouse Bin, which the
inventory dashboard reads for valuation and low-stock detection.
Multi-company
Every transactional doctype carries a company field, and the ledger, cost
centers, warehouses, and default accounts are all company-scoped. The API
resolves the active company from the user default, then the Global Defaults
singleton, then the first Company on the site (_default_company). The cached
dashboards are keyed per company so one company's numbers are never served to
another. A single Warka instance can therefore run several companies, though a
typical deployment provisions one. Company setup and the chart of accounts are
covered in the Implementation Guide.