Back to Help | Back to login

SYSTEM UPDATES

Central Business Platform (CBP)

Access: The CBP platform is available at https://cbp.africacdc.org/staff/apm. You must have a valid account to sign in.
No matching content found. Try different keywords.

APM System Updates

This document lists notable features, improvements, and changes to the APM (Approvals Management) system.


Budget execution dashboard (2026-06-02)

Summary

  • New Budget execution dashboard under Dashboard → Budget execution (also linked from Reports): quarterly and annual views by division.
  • Initiated = approved matrix activities, single memos, special memos, and non-travel memos with budget.
  • Executed = approved Service Request + ARF amounts linked to each initiative.
  • 100% executed when SR/ARF totals reach the initiative’s approved budget.
  • Access: all divisions (admin / permission 88), directorate directors (their divisions), staff (own division).

Documentation

Routes

  • GET /budget-execution — dashboard UI
  • GET /budget-execution/data — JSON API (Redis-cached via ApmPageCache, scope budget_execution, 5 min TTL; busted on SR/ARF/memo writes)

Fix (2026-06-02)

  • Fixed data API 500: removed invalid division_name column from matrix eager load.
  • Data endpoint now uses dedicated Redis page cache scope with retry / nocache support on the UI.
  • UI: division-first layout (loop all matching divisions), wrapped titles, fund-code balances per initiative, Excel/PDF export.
  • Pagination: 10 divisions per page with prev/next controls; summary KPIs cover all filtered data.
  • Division cards show budget remaining, fund working balance, execution ring, and status chips (100% / partial / not started).
  • Admins default to All divisions in the filter.

Fund code working balance (2026-06-02)

Summary

  • Working balance on budget forms: approved budget − committed spend (draft, pending, and approved documents).
  • Real-time checks on matrix activities, special memos, non-travel memos, and change requests (increases only).
  • Fund code dropdown shows available balance; red Budget exceeded! warning and disabled submit when over limit.
  • Balances refresh automatically (~15s) while the form is open; server-side validation on save.
  • Redis-backed cache when CACHE_STORE=redis (version-busted on budget writes).

Documentation

Deploy

  • Deploy APM application code and public/js/apm-working-balance.js.
  • Ensure fund codes have Approved budget set (Fund Codes → Edit).
  • Recommended: CACHE_STORE=redis in production .env.

Supplementary service requests (2026-05-20)

Summary

  • Supplementary service requests (UI label; parent_service_request_id in DB) let creators request the remaining memo balance after a parent SR’s total requested funds are below the original memo budget.
  • One direct child per SR (nested children allowed while balance remains); linked by service_requests.parent_service_request_id.
  • System setting allow_child_service_requests (group service_requests, default on) in App Settings.
  • UI banner, badges, parent document number on detail/PDF; server and client validation against the cap.

Documentation

Deploy

php artisan migrate
php artisan db:seed --class=SystemSettingsSeeder

Weekly brief — documentation (2026-05-09)


Average time per document — timing trail, report, and background jobs (2026-05-01)

Purpose

  • Per-action audit trail of how long each approver took from “received at this workflow step” to approve/reject, aligned with the receipt rules used by the Approver Dashboard average-time metric (see ApproverDashboardHelper::getAverageApprovalTimeAll() and ApprovalReceiptTimeCalculator).
  • Other Memo approvals use the same idea via other_memos_approval_trails (submission / resubmit at order 0, then prior approved steps).

Database

  • Table approver_document_timing_records (migration 2026_05_01_000001_create_approver_document_timing_records_table.php).
  • One row per unified approval_trails action in approved / rejected (non-archived, with workflow + order), and per Other Memo approved row (sequence ≥ 1).
  • Stores approver staff_id and name snapshot, received_at, acted_at, hours_elapsed, document type label, title, document number, division (id + name snapshot), workflow name / role where applicable, and nullable links approval_trail_id / other_memo_approval_trail_id (unique, short index names for MySQL). Rows include Laravel created_at / updated_at for when the snapshot row was written or last touched.

Real-time capture

  • RecordApproverDocumentTimingJob: dispatched afterCommit from ApprovalService::processApproval when the action is approved or rejected.
  • RecordOtherMemoApproverDocumentTimingJob: dispatched from Other Memo web approve and OtherMemoApiApprovalService::approve.
  • Requires a running queue worker (queue:work / systemd worker). If the queue is not processed, rows are not written until jobs run.

Historical backfill

  • Command: php artisan apm:backfill-approver-document-timings

Options: --chunk=, --approval-only, --other-memo-only.

Idempotent: skips rows that already exist (unique source trail ids).

  • Also exposed on Jobs maintenance UI (apm:backfill-approver-document-timings).

Report and navigation (access control)

  • Reports → Average time per document: GET /reports/average-time-per-document (and /export for CSV).
  • Full access (any approver filter): user_session('role') === 10 (APM admin), or permission 87, or permission 88 — same convention as cross-division dashboard / admin UI elsewhere (approver_timing_report_can_view_all() in CustomHelper.php).
  • Self-service: any logged-in user with staff_id may view only their own rows; staff_id query param must match session or be omitted (scoped automatically). Other combinations return 403.
  • Approver Dashboard: average-time badge links when user has full access or the row’s staff_id matches the current user.
  • Pending Approvals: detail button when full access, when viewing your own queue, or when staff_id in the URL matches you.

Code reference

  • Model: App\Models\ApproverDocumentTimingRecord
  • Services: App\Services\ApprovalReceiptTimeCalculator, App\Services\ApproverDocumentTimingService
  • Report: App\Http\Controllers\ApproverDocumentTimingReportController

Routing after Head of Operations (order 7), matrices & activities UX, memo PDF budgets (2026-04-29)

Next approver (division category)

  • ApprovalService::getNextApprover() after approval_level 7 no longer picks the next row as “first approval_order > 7” (which always selected 8 — Programs).
  • Next step is now explicit: Operations → order 9 (DDG); Programs8 (Head of Programs, with category-aware lookup); Other / unknown / missing division → 9 (DDG, with sensible fallbacks).
  • Full behaviour is documented in APPROVAL_WORKFLOW_NEXT_APPROVER.md (high-level flow, item 8).

Matrices

  • Archive / unarchive at matrix level (admin), plus matrix list filter for active / archived / all (status query param on matrices index).
  • config/approval_states.php: added archived (and rejected) so matrix metadata badges do not error when overall_status is archived.
  • Migration 2026_04_27_144500_add_previous_overall_status_to_memo_tables.php also adds previous_overall_status on matrices for unarchive restore (run migrations if not already applied).

Activities index

  • Status filter on /apm/activities (draft, pending, approved, rejected, returned, archived, or all), included in AJAX tab reloads.

Activity memo PDF (multi fund code)

  • activities/memo-pdf-simple.php: budget line items are grouped per fund code from budget_breakdown (same idea as the activity show page), instead of flattening into one table when multiple fund codes are used.

APM API (v1) and Swagger documentation

Added: REST API for the APM module with JWT authentication and OpenAPI/Swagger documentation.

What’s new

  • APM API v1 (base path: /api/apm/v1):

- Auth: Login (email + password, Argon2i-compatible), refresh token, logout, me. Login and refresh return JWT plus user data (user_id, auth_staff_id, email, name, division_id, role, status).

- Pending approvals: GET pending-approvals and GET pending-approvals/summary — same data and rules as the web pending-approvals page; processed items excluded.

- Documents: GET documents/{type}/{id} — document by type (special_memo, matrix, activity, non_travel_memo, service_request, arf, change_request) with approval_trails (same structure as matrices/37 and special-memo/19).

- Actions: POST actions — approve, reject, return, or cancel (cancel = return when HOD for special memo). Body: type, id, action, optional comment and available_budget.

- Approved by me: GET approved-by-me and GET approved-by-me/average-time — list of documents approved/rejected by the current user and average approval time (same as dashboard).

- Matrices: GET matrices/{matrixId} (detail with activities and passed/pending metadata), POST matrices/{matrixId} (approve or return).

- Activities: GET matrices/{matrixId}/activities/{activityId} (activity or single-memo detail), POST (passed, returned, convert_to_single_memo).

- Memo list: GET memo-list/pending and GET memo-list/approved — memos for the authenticated user’s division only, with filters: year, quarter, memo_type (QM, SM, SPM, NT, CR, SR, ARF), title, document_number, per_page, page.

  • API users: Synced from the staff app user table (same structure: user_id, auth_staff_id, password, name, role, status, etc.). Sync command php artisan users:sync runs hourly. API login uses email (from staff work_email) and password (Argon2i hashes supported).
  • Swagger / OpenAPI:

- OpenAPI 3.0 spec: documentation/APM_API_OPENAPI.yaml — full description of all endpoints, request/response schemas, and JWT security.

- Swagger UI: Visit /docs (e.g. http://localhost/staff/apm/docs) to explore and try the API with the interactive UI. Use Authorize to set the JWT after login.

Documentation

  • OpenAPI spec: APM_API_OPENAPI.yaml.
  • In-app docs: open /docs in the browser when the APM app is running.

Signature verification and document validation

Added: Validate APM Document Signature Hashes feature.

What’s new

  • Signature verification page (nav: Memos → Validate APM Document Signature Hashes):

- Validate uploaded document: Upload an APM PDF; the system extracts document number(s) and signature hashes, validates them against the database, and does not store the file. Supports multiple document numbers (e.g. ARF + parent memo).

- Look up document & signatory hashes: Enter document number and year to see the document and all signatories with their verification hashes.

- Verify a signature hash: Enter a hash and document number to see which signatory and action the hash corresponds to.

  • All three methods use AJAX with a progress bar and show results in a single centered modal with a Print option.
  • Document number–based lookup: Document numbers (e.g. AU/CDC/SDI/IM/SM/011) are parsed so the correct base table (activities, special_memos, non_travel_memos, request_arfs, change_request, service_requests) is queried.
  • Activity / matrix documents: Signatories are built from both approval_trails (morph) and activity_approval_trails, so hashes from the main signature section and budget section of PDFs can be validated.
  • Multiple document numbers: When a PDF contains more than one document number (e.g. ARF and parent memo), all are resolved and signatories are merged; validation succeeds if a hash matches any of those documents.
  • Metadata in results: Document metadata includes creator, division, date created, and activity title (when available).
  • PDF dependency: Upload validation uses smalot/pdfparser for text extraction; install with composer require smalot/pdfparser if needed.

Documentation


Add new entries above this line, with a clear heading and date or version if applicable.

Help Center Back to login