This page describes the leave sub-module in src/cluster_erp/modules/intranet/leave/. It keeps leave types, balances per employee, type, and year, and leave requests that move through submission and approval. Day counts are Decimal because half days are real; a submitted request reserves days as pending so that an employee cannot spend them twice (src/cluster_erp/modules/intranet/leave/services.py:1-7).
Scope and source¶
- Defined in:
src/cluster_erp/modules/intranet/models.py(IntranetLeaveType,IntranetLeaveBalance,IntranetLeaveRequest),leave/services.py,leave/routes.py,leave/schemas.py,leave/metadata.py, andleave/seeds.py. - Count: 3 tables, 15 routes in
leave/routes.py, 4ActionMetaentries inleave/metadata.py.
Fields¶
| Entity | Key fields | Source |
|---|---|---|
IntranetLeaveType |
code (unique among live rows), label, is_paid, accrual_method (annual_grant, monthly_accrual, none), default_annual_days, allows_half_day, requires_document, carryover_max_days, gender_restriction, min_notice_days, counts_calendar_days, approval_chain_code |
src/cluster_erp/modules/intranet/models.py:101, src/cluster_erp/modules/intranet/models.py:687-731 |
IntranetLeaveBalance |
party_id, leave_type_id, period_year (unique together among live rows), entitled, accrued, taken, pending, carried_over; all Numeric(7, 2) |
src/cluster_erp/modules/intranet/models.py:734-773 |
IntranetLeaveRequest |
code, party_id, leave_type_id, start_date, end_date, half_day_start, half_day_end, total_days, reason, status, cover_party_id, document_attachment_id, approval_request_id, submitted_at, decided_at, decided_by, decision_note |
src/cluster_erp/modules/intranet/models.py:776-833 |
The module seeds eight leave types on start when their codes are missing: annual, sick, unpaid, marriage, bereavement, maternity, paternity, and administrative. The seed docstring calls them country-neutral starter data that the organisation edits (src/cluster_erp/modules/intranet/leave/seeds.py:1-12, src/cluster_erp/modules/intranet/module.py:66-95). A new balance row takes default_annual_days of its type as entitled and accrued (src/cluster_erp/modules/intranet/leave/services.py:202-233).
Statuses and actions¶
A request is draft, submitted, approved, rejected, cancelled, or taken (src/cluster_erp/modules/intranet/models.py:93-100).
stateDiagram-v2 [*] --> draft draft --> submitted: submit submitted --> approved: approve submitted --> rejected: reject draft --> cancelled: cancel submitted --> cancelled: cancel approved --> cancelled: cancel
In prose: a request starts as a draft. Submit runs the checks, reserves the days, and routes the request to an approval chain when one exists. Approve moves the days from pending to taken; Reject releases them. Cancel works from draft, submitted, or approved and gives back pending or taken days (src/cluster_erp/modules/intranet/leave/services.py:55-60, src/cluster_erp/modules/intranet/leave/services.py:647-738). No transition writes taken (src/cluster_erp/modules/intranet/leave/services.py:55-60).
| Action | Label | Condition in metadata | Source |
|---|---|---|---|
submit |
Submit | status is draft |
src/cluster_erp/modules/intranet/leave/metadata.py:258-266 |
approve |
Approve | status is submitted |
src/cluster_erp/modules/intranet/leave/metadata.py:267-275 |
reject |
Reject | status is submitted |
src/cluster_erp/modules/intranet/leave/metadata.py:276-284 |
cancel |
Cancel | status is approved |
src/cluster_erp/modules/intranet/leave/metadata.py:285-293 |
The route lets a caller act only on requests in their scope; Approve and Reject also need intranet_leave_request.approve (src/cluster_erp/modules/intranet/leave/routes.py:255-280). Approve and reject notify the employee with the i18n keys intranet.notif_leave_approved and intranet.notif_leave_rejected (src/cluster_erp/modules/intranet/leave/services.py:716-735).
Day counting¶
_leave_days returns the counted days per calendar year (src/cluster_erp/modules/intranet/leave/services.py:260-334):
- A type with
counts_calendar_dayscounts every day. - Other types ask
GetCompanyDefaultTimezonefor the company party andGetOwnerWorkingDaysfor its open days, so holidays and closures are not counted. When no calendar answers, Monday to Friday count. - A half day at the start or end removes half a day from that day's year.
- A request across New Year charges each year its own share.
Submit checks¶
Submission runs these checks before any change (src/cluster_erp/modules/intranet/leave/services.py:468-551):
| Check | Error code | Source |
|---|---|---|
| No overlapping submitted, approved, or taken leave of the same person | INTRANET_LEAVE_OVERLAP |
src/cluster_erp/modules/intranet/leave/services.py:407-437 |
A gender-restricted type needs a matching recorded gender, read through GetPartyById |
INTRANET_LEAVE_GENDER_RESTRICTED |
src/cluster_erp/modules/intranet/leave/services.py:439-466 |
| Minimum notice in days | INTRANET_LEAVE_NOTICE_TOO_SHORT |
src/cluster_erp/modules/intranet/leave/services.py:486-499 |
| A required supporting document, as a direct link or an attachment on the request | INTRANET_LEAVE_DOCUMENT_REQUIRED |
src/cluster_erp/modules/intranet/leave/services.py:500-518 |
| Enough balance in each year for accruing types | INTRANET_LEAVE_INSUFFICIENT_BALANCE |
src/cluster_erp/modules/intranet/leave/services.py:521-550 |
Creating a request also checks the type, the gender restriction, and overlap, and stores half days only when the type allows them (src/cluster_erp/modules/intranet/leave/services.py:570-620).
Approval chain¶
_route_approval asks GetApprovalChainForAction for the resource intranet_leave_request and action approve. With a chain it calls SubmitForApproval and stores the approval request id. Without a chain, or on an error, the request stays submitted for a manual decision (src/cluster_erp/modules/intranet/leave/services.py:740-772). See approvals and approval chains.
Routes¶
| Router | Paths | Permission | Source |
|---|---|---|---|
leave_type_router |
/leave-types list, create, read, update, delete |
intranet_leave_type.* |
src/cluster_erp/modules/intranet/leave/routes.py:28, src/cluster_erp/modules/intranet/leave/routes.py:40-100 |
leave_balance_router |
/leave-balances list, read, create, update |
intranet_leave_balance.* |
src/cluster_erp/modules/intranet/leave/routes.py:29-31, src/cluster_erp/modules/intranet/leave/routes.py:104-166 |
leave_request_router |
/leave-requests list, create, read, update, action, delete |
intranet_leave_request.* |
src/cluster_erp/modules/intranet/leave/routes.py:32-34, src/cluster_erp/modules/intranet/leave/routes.py:170-290 |
Creating a request for another person needs intranet_leave_request.read_all, and the named party must be an active employee (src/cluster_erp/modules/intranet/leave/routes.py:204-223).
Terms introduced¶
| Term | Code identifier | Definition | Turkish term | Source |
|---|---|---|---|---|
| leave type | IntranetLeaveType |
A kind of leave with its accrual, notice, document, and restriction rules. | İzin türü | src/cluster_erp/modules/intranet/models.py:687 |
| leave balance | IntranetLeaveBalance |
The days of one leave type for one person in one year. | İzin bakiyesi | src/cluster_erp/modules/intranet/models.py:734 |
| pending days | pending |
Days reserved by submitted requests until they are decided. | Bekleyen günler | src/cluster_erp/modules/intranet/models.py:767 |
Related pages¶
Verified against commit 92f8051 on 2026-11-13.