Crons + integrations — how HR data flows out
M13 doesn't live alone. Four crons, four module integrations (M11 invoices, M16 file vault, M17 email, M20 compliance calendar). Here's the operational map.
The 4 HR-relevant crons
| Cron | Schedule | What it does |
|---|---|---|
bin/cron-m13-eosb-accrual.php | Last day of month, 23:30 Asia/Muscat | Snapshots EOSB per active employee. Idempotent on re-run. |
bin/cron-m13-leave-carry-forward.php | 1 January, 02:00 | Caps prior-year balance · materialises new-year row · ready for new accruals. |
bin/cron-m17-expiry-reminders.php | Daily, 06:00 | Walks employee_documents · employee_visa_sponsorships · client_documents · queues M17 emails at T-30/T-7/T-1. |
bin/cron-m16-retention.php | Daily, 00:00 | Audits employee-doc retention; flags past-retention items for partner review (legal-hold protected). |
Linux crontab
# M13 EOSB monthly snapshot — last day of month at 23:30 30 23 28-31 * * /usr/bin/php /var/www/acwms-v5/bin/cron-m13-eosb-accrual.php > /var/log/acwms/eosb.log 2>&1 # M13 leave year-end carry-forward — 1 January at 02:00 0 2 1 1 * /usr/bin/php /var/www/acwms-v5/bin/cron-m13-leave-carry-forward.php > /var/log/acwms/leave.log 2>&1 # M17 expiry reminders — every day at 06:00 0 6 * * * /usr/bin/php /var/www/acwms-v5/bin/cron-m17-expiry-reminders.php > /var/log/acwms/expiry.log 2>&1 # M16 retention — every day at 00:00 0 0 * * * /usr/bin/php /var/www/acwms-v5/bin/cron-m16-retention.php > /var/log/acwms/retention.log 2>&1
Module integrations
1 · M17 Communications (email)
HR triggers email send on:
- Employee doc expiring — template
compliance.expiry_reminder· cron T-30/T-7/T-1 - Leave applied — template
leave.submittedto manager · immediate - Leave decided — template
leave.decidedto applicant · immediate - Visa expiring — same expiry-reminder cron · separate audit-log channel
Each email is logged in email_log with delivery status (sent / delivered / opened / failed).
2 · M16 File Vault
HR uploads (employee documents, certifications, scans) live under storage/employees/{id}/... but surface in the unified Vault Explorer at /documents/explorer under the "Employees & HR" branch. RBAC respected — managers see only their department's employees.
3 · M11 Invoices (payroll-as-engagement)
For TPL-PAY Payroll engagements, M13 compensation feeds the WPS SIF + payslips for the client's staff. The job-level integration is one-way — M11 invoice for the firm's fee for running payroll, not for the client's salary expense.
4 · M20 Compliance Calendar
Some HR docs (work permits, MOLP labour-card renewals) appear as recurring obligations on the Compliance Calendar. The deadline-generation cron creates a forward 12-month window of upcoming renewals, surfaced on the partner's dashboard.
The audit trail
Every HR action emits an audit_logs row via AuditLogger::log():
| Action code | Triggered by |
|---|---|
m13.employee.create | EmployeeService::create |
m13.salary.revision.record | CompensationService::recordSalaryRevision |
m13.leave.apply | LeaveService::apply |
m13.leave.approve | LeaveService::approve |
m13.leave.cancel | LeaveService::cancel |
m13.eosb.snapshot | cron-m13-eosb-accrual.php |
m13.offboarding.initiate | LifecycleService::initiateOffboarding |
m13.final_settlement.approve | LifecycleService::approveSettlement |
m13.final_settlement.pay | LifecycleService::markSettlementPaid |
Health check
The /health endpoint includes HR-relevant indicators in its JSON:
db_ping— DB connection aliveemail_queue_stale— emails older than 1 hour still pending (indicator that crons are not running)storage_writable— employee photo uploads can write tostorage/employees/storage_free_bytes— capacity for new uploads
Configure your monitoring (Datadog, Pingdom, Uptime Kuma) to alert on status != ok.
Backup + restore
HR data is part of the nightly backup via bin/cron-backup.php:
db.sql.gzincludes all 33 HR tablesstorage.tar.gzincludesstorage/employees/tree (photos, documents, certs)- Off-site sync via
bin/cron-offsite-backup.shto B2 / S3 / Wasabi - Quarterly restore drill — pick a random employee · restore from off-site · verify SHA-256
Run the EOSB cron manually: php bin/cron-m13-eosb-accrual.php --dry-run. The script prints what it would do without writing. Useful before first production run to confirm settings + active-employee count.
If the EOSB cron is misconfigured (wrong php-cli path, wrong cwd) it may run silently and never write snapshots. The IAS 19 provision then drifts from the live basic_salary. Configure cron output to a log file + check it weekly.
If your dev/staging is on Windows (XAMPP), use Task Scheduler instead of crontab. Task: C:\xampp\php\php.exe D:\xampp\htdocs\acwms-v5\bin\cron-m13-eosb-accrual.php. Schedule: monthly on day 28-31, 23:30. Working directory: project root.