PPMP Management

PPMP Management combines a department/year selector with create, edit, lookup, soft-delete, and display handlers. The form carries ppmp_year, ppmp_name, ppmp_id, and expence_account[]; duplicate checks run before the tbl_ppmp write. The list is role-dependent, while direct identifier lookups and deletion do not show source-proven record-ownership checks.

Management boundary

flowchart TD
    form["manage-ppmp.php<br/>PPMP form"] --> list["ppmp-list.php<br/>department and year selector"]
    list -->|"PPMP ID/name options"| form
    form -->|"ppmp_id"| lookup["get-ppmp.php<br/>lookup and account options"]
    form -->|"submit"| duplicate["ppmp-submit.php<br/>duplicate check"]
    duplicate -->|"duplicate check passes"| save["tbl_ppmp<br/>batch_update_insert"]
    form -->|"delete"| remove["delete-ppmp.php<br/>soft deletion"]
    view["view-ppmp.php<br/>metadata"] --> items["ppmp-view.php<br/>items, status, and total"]

Component.php resolves the matching custom include path, custom/'.$type.'.php, and includes the selected handler. The management form and view templates consume the resulting data in separate stages.

Select and load a PPMP

The management template in imspr/novusoft/include/ppmp-management/view/manage-ppmp.php declares these controls:

Control Source-defined role
ppmp_year Selects the PPMP year.
ppmp_name Supplies the PPMP name.
ppmp_id Selects the PPMP record for an edit or lookup.
expence_account[] Multiple-value expense-account selection.

The selector handler in imspr/novusoft/include/ppmp-management/custom/ppmp-list.php uses the posted department and year. If ppmp_year is empty, it sets Please set PPMP year but does not exit; it continues into the role-dependent query and reaches the JSON exit only at the end. Its predicates differ by session role:

Session condition Selector predicate
user_role_id != 1 dept = ?, deleted = 0, approved_1 = 0, and year = ?
user_role_id == 1 dept = ?, deleted = 0, and year = ?

The resulting PPMP IDs and names populate ppmp_id. For an existing record, imspr/novusoft/include/ppmp-management/custom/get-ppmp.php reads tbl_ppmp by the submitted ppmp_id, returns its year and name, splits the stored expence_account value, marks matching account codes as selected, and emits the response through the JSON helper.

[!WARNING] The selector’s department/year filtering does not establish ownership enforcement for direct identifier operations. The get-by-ID, view-by-ID, and delete handlers use submitted identifiers without a source-proven owner or department predicate. The edit duplicate check also uses the session department, while the create check and persistence payload use the submitted department.

Save path

The submission handler in imspr/novusoft/include/ppmp-management/custom/ppmp-submit.php preserves this order:

1. Choose create or edit | An empty ppmp_id selects the create branch; a non-empty ppmp_id selects the edit branch.
2. Check for an existing PPMP | Both branches count non-deleted records with status = 1 matching the submitted year and name. Create uses the submitted department; edit excludes the submitted ppmp_id and uses the session department.
3. Reject a positive duplicate count | The handler sets success to false, returns PPMP already exist, and exits through the JSON helper before the write.
4. Build the persistence payload | The handler writes the identifier, year, uppercased name, submitted department, pipe-joined expense accounts, session audit fields, and timestamps into a tbl_ppmp payload.
5. Persist and report the result | batch_update_insert writes through tbl_ppmp, and the response success value is derived from its result.

The duplicate predicates require status = 1, but the management persistence payload does not assign status or approved_1. The approval labels shown by the view therefore do not prove that the management save enforces or transitions server-side approval state. No successful save execution record was observed.

Delete path

[!CAUTION] imspr/novusoft/include/ppmp-management/custom/delete-ppmp.php performs a soft-delete sequence. It takes ppmp_id from posted data, sets tbl_ppmp.deleted to 1 with latest-editor audit fields, and submits that update through batch_update_insert. It then sets deleted = 1 in tbl_ppmp_catalog and tbl_ppmp_consolidate rows whose dept field equals the posted PPMP ID. No owner, department, or locking guard is shown, and the related-row comparison uses dept as the PPMP-ID match field.

The response message is Delete Successfull; its success value is derived from the main persistence result. This source behavior does not establish that deletion completed successfully at runtime.

Display and status boundaries

[
    {
        "title": "Metadata and approval controls",
        "body": "imspr/novusoft/include/view-ppmp/custom/view-ppmp.php reads tbl_ppmp by the submitted identifier and projects approved_1, transfer, gpms_dept, an encoded PPMP ID, and a BAC flag derived from session user_role_id == 1. The view template exposes APPROVE? controls only when the record is unapproved and BAC-visible. Outside the !\\$approved && \\$bac branch, when \\$bac is truthy, it maps approval values to APPROVED, PENDING, or DISAPPROVED labels. The Unapproved control is nested in that BAC branch and appears when \\$approved is truthy, rather than only when it equals 1."
    },
    {
        "title": "Items, status labels, and totals",
        "body": "imspr/novusoft/include/view-ppmp/custom/ppmp-view.php retrieves item rows through tbl_ppmp_catalog_item, tbl_ppmp_consolidate, and tbl_ppmp joins, constrained by the supplied PPMP ID and b.deleted = 0. It derives APPROVED, DISAPPROVED, or PENDING from approved_1, groups items by the uppercase first character of item_code and then account_desc, accumulates final_total, and exposes the grouped items with a formatted total."
    },
    {
        "title": "Transfer and print availability",
        "body": "Only the BAC-visible approved branch, where \\$bac is truthy and \\$approved == 1, reaches the transfer block. In that branch, an empty gpms_dept reports Detpartment Mapped is missing; a non-empty gpms_dept renders the Transfer control disabled. Non-BAC or unapproved records do not reach that mapping and Transfer block. Direct Print and Print Preview are rendered disabled. No successful lookup, deletion, transfer, or print execution record was observed."
    }
]

Updated