Перейти до змісту

Module: HRM & Payroll

Без модуля: базова зарплата відбивається у Essentials через документ «Операція» / JournalEntry — згорнутими проводками без per-employee розкладки. Деталі та повний приклад: essentials/journal-entry.md → Use-case: зарплата без модуля HRM. HRM-модуль — це розширення, що додає per-employee облік, розрахункові листи з UA 4-leg податками, табель, відпустки, payroll register та PDF.

Статус: ✅ Production-ready (2026-05-06)

Реалізовано: - Phase F-1 (2026-04-22) — Master data (Position/Employee), MVP-payroll з єдиним tax_rate_pct, AttendanceLog (S5 Gatehouse, 2026-04-28). - Phase G-HRM (2026-05-06) — UA-payroll рівня production: - F1: UA 4-leg tax engine — окремі поля та проводки для ПДФО (18%) + Військ (1.5%) + ЄСВ employee (0%) + ЄСВ employer (22% — нарахування понад gross). Знятий placeholder tax_rate_pct/tax_amount/tax_payable_account. Ставки snapshotуються на slip при compute. - F1: PayrollTaxConfig — per-tenant ставки з історією valid_from. resolve(tenant, on_date) обирає актуальний конфіг або повертає UA-defaults без save. - F2: Posting consistency hygiene — серіалізатори блокують тиху зміну posted-документа (rule document-posting.md); state у read_only_fields; perform_update → 403 на posted. - F3: TimesheetTimesheet (TransactionModel) + TimesheetLine subtable. Сервіси recompute_from_attendance (з AttendanceLog) і apply_to_payroll (push days_worked у matching slips, skip posted). - F4: Leave managementLeaveType (master), LeaveBalance (per-employee per-year), LeaveRequest з 4-state workflow (draft → submitted → approved/rejected). Approval auto-incrementує LeaveBalance.used_days, idempotent. - F5: Payroll Register reportpayroll-register через Report Framework: list per-slip з повною 4-leg розкладкою + totals row, drill-down до slip. - F6: Payslip PDFpayroll-slip через Print Framework: шапка, працівник, нарахування + 4-leg withholdings + net + ESV employer accrual + місце для підписів. - 49 backend-тестів покривають compute / 5-leg post / TaxConfig resolve / Timesheet / LeaveRequest workflow / Payroll Register / Payslip render.


Реалізована модель — детально

Models

Master Data

  • Position (MasterDataModel) — посада з base_salary + department.
  • Employee (MasterDataModel) — first_name/last_name, tax_id, контакти, position, department, hire_date, termination_date, base_salary, SCUD-поля (external_scud_id, card_uid, access_level), photo. Метод display_name() повертає "Прізвище Ім'я".
  • LeaveType (MasterDataModel) — is_paid, accrual_days_per_year, requires_doc. Default seed: Vacation (24, paid), Sick (paid), Unpaid.
  • PayrollTaxConfig (TenantAwareModel) — valid_from + 4 ставки (pdfl_rate_pct / military_rate_pct / esv_employee_rate_pct / esv_employer_rate_pct). UNIQUE (tenant, valid_from).

Transactions

  • PayrollPeriod (TransactionModel) — (year, month, standard_workdays), UNIQUE per tenant.
  • PayrollSlip (TransactionModel) — (period, employee) UNIQUE per tenant. Поля: days_worked, base_salary, gross_amount + 4 пари *_rate_pct / *_amount (PDFL / military / ESV-employee / ESV-employer) + net_amount + 7 FK на ChartOfAccounts (salary_expense, salary_payable, pdfl, military, esv_employee, esv_employer_expense, esv_employer_payable).
  • Timesheet (TransactionModel) + TimesheetLine subtable — місячна аґрегація AttendanceLog → days_worked для slip.
  • LeaveRequest (TransactionModel) — (employee, leave_type, date_from, date_to, days, leave_status). Workflow: draft → submitted → approved/rejected.

Registers / accumulated

  • AttendanceLog (TenantAwareModel, S5 Gatehouse) — daily in/out roll-up.
  • LeaveBalance (TenantAwareModel) — (employee, leave_type, year) UNIQUE; accrued_days, used_days, remaining_days (computed).

Services

Файл Функція Що робить
services/payroll.py compute_slip(slip) Pulls ставки з PayrollTaxConfig.resolve(tenant, slip.date), snapshotує на slip 4 *_rate_pct. gross = base × days/std (cap), pdfl/military/esv_emp/esv_empr = gross × rate, net = gross − withholdings.
services/payroll.py post_slip(slip) Recompute → wipe попередній PostingGroup → створити новий з 1-5 booking-pairs (gross + 0-3 withholdings + ESV employer accrual). Idempotent.
services/payroll.py unpost_slip(slip) Видаляє PostingGroup.
services/payroll.py post_period(period) Bulk-post all draft slips.
services/timesheet.py recompute_from_attendance(timesheet) Wipe lines, перебудувати з AttendanceLog за (year, month).
services/timesheet.py apply_to_payroll(timesheet, period=None) Push line.days_worked у matching PayrollSlip.days_worked (skip posted). Auto-resolve period по year+month.
services/leave.py submit_request(req) draft → submitted, auto-fill days з date range.
services/leave.py approve_request(req) submitted → approved + LeaveBalance.used_days += req.days (idempotent).
services/leave.py reject_request(req, reason) submitted → rejected.

Endpoints

/api/v1/hrm/positions/                                CRUD
/api/v1/hrm/employees/                                CRUD + upload-photo, delete-photo, form-refs
/api/v1/hrm/payroll-periods/                          CRUD + post_all
/api/v1/hrm/payroll-slips/                            CRUD + compute, post_document, unpost_document, recompute-days-worked
/api/v1/hrm/attendance-logs/                          CRUD (Sprint 5 Gatehouse)
/api/v1/hrm/tax-configs/                              CRUD (PayrollTaxConfig — ставки з історією)
/api/v1/hrm/timesheets/                               CRUD + recompute-from-attendance, apply-to-payroll, post_document, unpost_document
/api/v1/hrm/timesheet-lines/                          CRUD (subtable rows)
/api/v1/hrm/leave-types/                              CRUD
/api/v1/hrm/leave-balances/                           CRUD
/api/v1/hrm/leave-requests/                           CRUD + submit, approve, reject

Reports

Code Title Source
payroll-register Реєстр зарплати PayrollSlip per period з 4-leg breakdown + totals + drill-down до slip
Doc type Template Fields
payroll-slip hrm/print_templates/payroll-slip/base.html gross / 4 withholdings / net / ESV empr / accounts / signatures

Frontend

  • MasterDataPage для employees (custom EmployeePage з фото-табом) / positions / leaveTypes / leaveBalances / taxConfigs.
  • Generic TransactionPage для payrollPeriods / payrollSlips / timesheets (з subtable lines) / leaveRequests.
  • Custom report wrapper: PayrollRegisterReport (@/components/HRM/PayrollRegisterReport.tsx).
  • Print wired автоматично через printDocumentSafe(entityCode='payrollSlips', recordId).

Очікувані розширення (planned scope для повного модуля)

🔮 Backlog (deferred)

  • KPI Templates / KPI Records / KPI-bonuses — engine для змінної частини оплати. Trigger: sales/team-based bonus client.
  • 1ДФ year-end report — UA річна звітність з 4421/4422 проводок. Trigger: перший live tax-period.
  • Pay grades / salary bands — для HR-driven org structure.
  • Onboarding/Termination workflow — chain of personnel actions (hire date, contract, termination order). Кадрові накази.
  • Garnishments — утримання за рішенням суду (аліменти).
  • Recurring Leave accrual — auto-incrementувати LeaveBalance.accrued_days щомісяця/щороку. Зараз — manually на LeaveType зміні.

1. Master Data (Мастер-данные)

Сущность Описание Ключевые поля
Employees Персональные дела сотрудников ID, Full Name, Contact, Tax ID, Hire Date, SCUD fields
Departments Орг. структура (через Essentials) Name, Parent_ID, Manager
Positions Должности с базовым окладом Title, Base Salary, Department
LeaveType Типы отпусков Code, Name, is_paid, accrual_days_per_year
PayrollTaxConfig Ставки UA податков (з історією) valid_from, 4 rate_pct

2. Transaction Data (Транзакционные данные)

  1. Timesheet — місячний документ-аґрегатор AttendanceLog → days/hours per employee.
  2. Leave Request — заявка з 4-state workflow.
  3. Payroll Period — місячний контейнер для slips.
  4. Payroll Slip — per-employee розрахунок: gross + 4-leg taxes + net + employer ESV.

3. Journals & Ledgers (Журналы и реестры)

A. Attendance Register (S5 Gatehouse)

  • Dimensions: Employee_ID, Date, Source.
  • Resources: in_at, out_at (1 day per closed shift, 1 day per open shift).

B. Payroll Postings (через essentials.PostingGroup + PostingEntry)

  • Per slip → 1-5 booking pairs (gross + 0-3 withholdings + ESV employer accrual).
  • Drill-down via PayrollRegisterReport → row → slip.

C. Leave Balance Register

  • (employee, leave_type, year) → accrued / used / remaining.

4. Business Processes

  • Monthly Payroll Cycle:
  • Створити PayrollPeriod для місяця.
  • Створити Timesheetrecompute_from_attendance → manual edits.
  • apply_to_payroll → days_worked у slip-и.
  • Per slip: compute (auto з TaxConfig) → post_document.
  • Bulk post_all за period.
  • Звіт payroll-register для перевірки.
  • Друк PDF slip-ів.

  • Leave Cycle:

  • Створити LeaveRequest (draft).
  • Працівник submit → submitted.
  • HR/manager approve → approved + LeaveBalance.used_days +=.

5. Analytics & BI

  • Payroll Register — реалізовано (cм. Reports).
  • 🔮 Headcount Dynamics, Turnover Rate, Labor Cost Distribution — backlog.
  • 🔮 KPI Fulfillment Heatmap — після KPI engine.