Module: Newspaper Branch GL Actuals — CSV Upload

UAT Notes / Quick Documentation

Frontend + Backend Duplicate protection via normalized hash POST upload: csv

What this module is for

This is the upload screen + backend processor used to load Newspaper Branch GL actuals into the database from a CSV.

The front-end page is only the UI. The backend does the validation, duplicate checks, inserts, and logging.

Files in this module

Frontend (UI only)
/admin/newspaper/newspaper_branch_gl_upload.php
Shows the upload form, handles the progress bar, calls the backend via AJAX, and prints the result message (success/warning/error).
Backend (upload + processing)
/admin/newspaper/newspaper_branch_gl_upload_backend.php
Accepts the CSV, checks if the same data was uploaded before, reads each row, validates it, inserts into DB, and logs the upload batch.

Data flow (end to end)

1
User selects a .csv file on the upload page.
2
User clicks Upload & Process.
3
UI sends the file to:
admin/newspaper/newspaper_branch_gl_upload_backend.php
Method: POST (multipart/form-data)
4
Backend responds with JSON:
  • success → upload processed and inserted (with counts)
  • info → upload blocked because the same data was already uploaded
  • error → something went wrong (missing file, invalid CSV, etc.)
5
UI displays the result in an alert box.

Frontend details (what UAT will see)

Screen behavior

  • File selector: “Choose CSV File”
  • Fullscreen loader overlay while uploading
  • Progress bar during browser upload
  • Final status message once backend replies

Validation (UI side)

If no file is selected and the user submits, the field is marked invalid and the message is shown: “Please choose a CSV file.”

Backend response handling (UI)

The UI expects JSON but reads the response as text first, then runs:

JSON.parse(resp.trim())

If parsing fails (for example BOM/whitespace or a PHP warning), it shows the raw response as an error message.

Backend details (what happens to the CSV)

Database tables used

  • Main data table: tbl_admin_actual_branch_gl_newspaper
  • Upload log table: tbl_admin_actual_branch_gl_newspaper_upload_log

Endpoint requirements

  • Only accepts POST
  • File field name must be: csv
  • Response is always JSON (success/info/error)

Duplicate upload protection important

The backend prevents uploading the same information twice by using two hashes:

  • file_hash = sha256 of the raw uploaded file
  • normalized_hash = sha256 of a normalized version of the content

The duplicate check uses normalized_hash, not file_hash. That means it still blocks duplicates even if: row order changes, extra spaces exist, or debit formatting changes (like 1,000 vs 1000.00).

If a duplicate is found

  • status: info
  • message: “This same information has already been uploaded. Upload blocked.”
  • also returns: previous batch_id, uploaded_at, and original_filename

Batch ID

Each upload creates a batch id like: BYYYYMMDDHHMMSS_xxxxxxxx
Example: B20260128101530_a1b2c3d4

CSV format expectations

Header handling (flexible)

The backend reads the first row as headers and maps columns by name (case/space insensitive). It also uses fallback indexes if headers don’t match exactly.

GL CODE Header “GL CODE” or fallback index 0
ENTERD_BRN Header “ENTERD_BRN” or fallback index 2
DATEOFTRAN Header “DATEOFTRAN” or fallback index 5

Note for UAT

If someone uploads a CSV with missing/renamed headers, it may still process using fallback indexes, as long as the column order matches what the code expects.


Required fields per row

  • GL CODE
  • ENTERD_BRN
  • DATEOFTRAN

If any of these are empty, the row is skipped and counted as invalid.

Date parsing supported

  • YYYY-MM-DD
  • DD/MM/YYYY
  • Anything else PHP DateTime can understand (best effort)

If the date can’t be parsed, the row is skipped as invalid.

GL Description override forced

Even if the CSV contains a description, the backend forces: gl_description = "NEWSPAPER".

Month field creation

  • dateoftran stored as Y-m-d
  • applicable_month stored as F Y (example: January 2026)

Debit cleanup

DEBITS is cleaned (commas/spaces removed) and cast to float. For the normalized hash, debits are normalized to 2 decimals so duplicates are detected reliably.

Insert behaviour + counters

The backend tracks:

  • total_rows = number of data rows read (excluding header)
  • inserted = successful inserts
  • invalid = skipped due to missing required fields / bad date
  • failed = row had required fields but DB insert failed

At the end it writes a record into tbl_admin_actual_branch_gl_newspaper_upload_log including the batch id, hashes, filename, file size, and totals.

Example JSON response

{
  "status": "success",
  "batch_id": "...",
  "total_rows": 123,
  "inserted": 120,
  "invalid": 2,
  "failed": 1
}

Status can also be info (duplicate blocked) or error (upload/validation issue).

What UAT should test (recommended)

  • Happy path: upload a valid CSV → status success → confirm rows in tbl_admin_actual_branch_gl_newspaper
  • Duplicate upload block: upload same CSV again → status info → confirm previous batch details displayed
  • Same data, different order: shuffle rows and upload → should still be blocked as duplicate
  • Invalid rows: missing GL CODE / ENTERD_BRN / DATEOFTRAN → invalid count increases, rows not inserted
  • Date formats: try 2026-01-28 and 28/01/2026 → both should work
  • DB insert fail scenario (if possible): any row violating a DB constraint should count under failed

Small operational notes

  • This endpoint only accepts POST with file field name csv
  • Response is always JSON (success/info/error)
  • The UI is separate, so backend errors won’t break the page layout — they show as alerts