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)

DoctypePurpose
EmployeeThe person record; the anchor for HR, payroll, and lifecycle
Leave ApplicationA leave request, approved and submitted by an HR Manager
Leave AllocationGrants a leave balance to an employee
AttendanceA submitted daily attendance record
Employee CheckinA raw clock IN / OUT punch
Salary StructureA reusable definition of earnings and deductions
Salary Structure AssignmentBinds a structure and base salary to an employee
Salary SlipA generated payslip for one employee for one period
Payroll EntryA payroll run that generates and submits slips for a period
Expense ClaimAn employee expense reimbursement request
Expense Claim TypeThe category and account an expense posts to
Job OpeningA role, optionally published to the public careers site
Job ApplicantA candidate in the recruitment pipeline
Job OfferAn offer extended to an applicant
Employee Onboarding / Employee SeparationThe lifecycle checklists for joining and leaving
Employee Onboarding Template / Employee Separation TemplateReusable checklist definitions
Employee Boarding ActivityA single checklist line (child table)
Appraisal, Appraisal Cycle, Appraisal TemplatePerformance review records
Shift Type, Shift AssignmentAttendance-by-shift configuration
Department, Designation, Branch, Employee Grade, Leave Type, Holiday ListHR master data

Finance (ERPNext Accounts)

DoctypePurpose
Sales InvoiceA customer bill; posts to the ledger on submit
Purchase InvoiceA supplier bill; posts to the ledger on submit
Payment EntryRecords a payment against an invoice
Journal EntryA direct two-line (or more) ledger posting
AccountA node in the chart of accounts
GL EntryAn immutable general-ledger line (created by submitted documents)
Fiscal YearThe accounting year a posting date falls in
Cost CenterA dimension for cost attribution
Mode of PaymentCash, bank, and the accounts they post to

Selling (ERPNext CRM and Selling)

DoctypePurpose
CustomerA party you sell to
LeadAn unqualified prospect
OpportunityA qualified sales opportunity
QuotationA price quote for a customer or lead
Sales OrderA confirmed customer order
Contact, Issue, Customer Group, TerritoryCRM master and support data

Buying (ERPNext Buying)

DoctypePurpose
SupplierA party you buy from
Material RequestAn internal purchase requisition
Purchase OrderA confirmed order to a supplier
Supplier GroupSupplier categorization

Stock (ERPNext Stock)

DoctypePurpose
ItemA product or service
Item GroupThe item category tree
WarehouseA stock location
BinPer-item, per-warehouse quantity and valuation
UOMUnit of measure
Price ListSelling and buying price lists

Projects (ERPNext Projects)

DoctypePurpose
ProjectA project record
TaskA unit of work within a project
TimesheetLogged time against tasks or projects

Core (Frappe)

DoctypePurpose
UserA login account
Role, Has RoleThe RBAC role and its assignment to a user
CompanyThe company the whole system is scoped to
FileAn uploaded document or attachment
DocShareA per-user share grant on a document
Global Defaults, System Settings, Selling Settings, Buying SettingsSite 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:

FieldnameLabelType
fayda_idFayda ID (National ID)Data
tin_numberTIN NumberData
nationalityNationalityData (default Ethiopian)
regionRegion / CityData
sub_citySub-City / ZoneData
woredaWoredaData
kebeleKebeleData
house_numberHouse NumberData

Company (ensure_careers_fields in careers.py)

A collapsible "Careers Page" section that lets HR brand the public careers site from inside the ERP:

FieldnameLabelType
careers_headlineCareers HeadlineData
careers_taglineCareers TaglineSmall Text
careers_aboutAbout Working HereText Editor

Employee Boarding Activity (ensure_boarding_field in api.py)

FieldnameLabelType
cz_completedCompletedCheck

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.

StepWhat it guarantees
_ensure_fiscal_yearA Fiscal Year covering today
_ensure_item_groupsAll Item Groups, plus Services and Products leaves
_ensure_uomsNos, Unit, Hour, Day, Kg, Box
_ensure_price_listsStandard Selling and Standard Buying in the company currency
_ensure_party_groupsCustomer, supplier, and territory groups, and the Selling/Buying default group settings
_ensure_gendersMale, Female, Other
_ensure_hr_mastersLeave types, expense claim types, a day shift, and designations (only when HRMS is present and empty)
_ensure_company_defaultsCompany 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:

docstatusStateMeaning
0DraftEditable, no ledger impact
1SubmittedLocked; has posted its effects to the ledger
2CancelledReversed; 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.