<?php
class class_GlobalEvents extends GlobalEventsBase
{
	function init() {
		$this->events = array(
	'pageEvents' => array(
		'ModifyMenuItem' => true,
		'AfterSuccessfulLogin' => true,
		'BeforeShowMenu' => true,
		'OnPageLoad' => true,
		'AfterAppInit' => true 
	),
	'onScreenEvents' => array(
		'2530' => true,
		'2532' => true,
		'2536' => true,
		'2548' => true,
		'2552' => true,
		'2556' => true,
		'2562' => true,
		'2570' => true,
		'2572' => true,
		'2574' => true,
		'2576' => true,
		'2582' => true,
		'2586' => true,
		'2588' => true,
		'2590' => true,
		'2594' => true,
		'2596' => true,
		'2600' => true,
		'2604' => true,
		'2606' => true,
		'2614' => true,
		'2620' => true,
		'2622' => true,
		'2628' => true,
		'2638' => true,
		'2642' => true,
		'2648' => true,
		'63373' => true,
		'63473' => true,
		'63487' => true,
		'63987' => true,
		'64289' => true,
		'64515' => true,
		'64877' => true,
		'64883' => true,
		'64914' => true,
		'64917' => true,
		'64922' => true,
		'66058' => true,
		'66064' => true,
		'66154' => true,
		'66715' => true 
	),
	'dashboardEvents' => array(
		'2568' => true 
	),
	'buttons' => array(
		'2534' => true,
		'2538' => true,
		'2540' => true,
		'2542' => true,
		'2546' => true,
		'2550' => true,
		'2554' => true,
		'2558' => true,
		'2560' => true,
		'2564' => true,
		'2566' => true,
		'2578' => true,
		'2580' => true,
		'2592' => true,
		'2598' => true,
		'2602' => true,
		'2608' => true,
		'2610' => true,
		'2612' => true,
		'2616' => true,
		'2618' => true,
		'2624' => true,
		'2626' => true,
		'2630' => true,
		'2632' => true,
		'2636' => true,
		'2640' => true,
		'2644' => true,
		'2646' => true,
		'64850' => true,
		'64853' => true,
		'64856' => true,
		'66720' => true 
	),
	'maps' => array(
		 
	),
	'tablePermissions' => array(
		 
	),
	'recordEditable' => array(
		 
	) 
);
	}

		function ModifyMenuItem( &$menuItem ) {
		// Place event code here.
// Use "Add Action" button to add code snippets.
// Place event code here.
// Use "Add Action" button to add code snippets.

$title = $menuItem->getTitle();

if ($title=="Hide")
{return false;
}
else
{

return true;

}

		;
		return true;
	}

	function AfterSuccessfulLogin( $username, $password, &$data, $pageObject ) {
		// Place event code here.
// Use "Add Action" button to add code snippets.

function addApprovalNotif($title, $message, $icon, $table, $keyField, $keyValue)
{
    $keys = array();
    $keys[$keyField] = $keyValue;

    addNotification(
        $message,
        $title,
        $icon,
        makePageLink($table, "edit", $keys)
    );
}

// Avoid duplicate notifications every page refresh
if (!isset($_SESSION["approval_notifications_loaded"])) {

    $_SESSION["approval_notifications_loaded"] = true;

    // 1. Item
    $sql = "
        SELECT id, item_code
        FROM item
        WHERE status = 'Pending'
        ORDER BY id DESC
        LIMIT 20
    ";
    $rs = DB::Query($sql);
    if ($rs) {
        while ($row = $rs->fetchAssoc()) {
            addApprovalNotif(
                "For Approval",
                "Item pending approval: " . $row["item_code"],
                "fa-cube",
                "item",
                "id",
                $row["id"]
            );
        }
    }

    // 2. Supplier
    $sql = "
        SELECT supplier_id, supplier_name
        FROM supplier
        WHERE status = 'Pending'
        ORDER BY supplier_id DESC
        LIMIT 20
    ";
    $rs = DB::Query($sql);
    if ($rs) {
        while ($row = $rs->fetchAssoc()) {
            addApprovalNotif(
                "For Approval",
                "Supplier pending approval: " . $row["supplier_name"],
                "fa-truck",
                "supplier",
                "supplier_id",
                $row["supplier_id"]
            );
        }
    }

    // 3. Augmentation Portal Request
    $sql = "
        SELECT portal_request_id, portal_request_no
        FROM augmentation_portal_request
        WHERE status = 'FOR_APPROVAL'
        ORDER BY portal_request_id DESC
        LIMIT 20
    ";
    $rs = DB::Query($sql);
    if ($rs) {
        while ($row = $rs->fetchAssoc()) {
            addApprovalNotif(
                "For Approval",
                "Augmentation Request for approval: " . $row["portal_request_no"],
                "fa-envelope",
                "augmentation_portal_request",
                "portal_request_id",
                $row["portal_request_id"]
            );
        }
    }

    // 4. Disposal Form
    $sql = "
        SELECT id, disposal_no
        FROM disposal_form
        WHERE status = 'Pending'
        ORDER BY id DESC
        LIMIT 20
    ";
    $rs = DB::Query($sql);
    if ($rs) {
        while ($row = $rs->fetchAssoc()) {
            addApprovalNotif(
                "For Approval",
                "Disposal Form pending approval: " . $row["disposal_no"],
                "fa-trash",
                "disposal_form",
                "id",
                $row["id"]
            );
        }
    }

    // 5. Divert
    $sql = "
        SELECT id, divert_no
        FROM divert
        WHERE status = 'Pending'
           OR approval_status = 'Pending'
        ORDER BY id DESC
        LIMIT 20
    ";
    $rs = DB::Query($sql);
    if ($rs) {
        while ($row = $rs->fetchAssoc()) {
            addApprovalNotif(
                "For Approval",
                "Divert request pending approval: " . $row["divert_no"],
                "fa-random",
                "divert",
                "id",
                $row["id"]
            );
        }
    }

    // 6. Production Plan
    $sql = "
        SELECT id, plan_no
        FROM production_plan
        WHERE status = 'Pending'
        ORDER BY id DESC
        LIMIT 20
    ";
    $rs = DB::Query($sql);
    if ($rs) {
        while ($row = $rs->fetchAssoc()) {
            addApprovalNotif(
                "For Approval",
                "Production Plan pending approval: " . $row["plan_no"],
                "fa-calendar",
                "production_plan",
                "id",
                $row["id"]
            );
        }
    }

    // 7. Production Work Order
    $sql = "
        SELECT id, work_order_no
        FROM production_work_order
        WHERE status = 'Pending'
        ORDER BY id DESC
        LIMIT 20
    ";
    $rs = DB::Query($sql);
    if ($rs) {
        while ($row = $rs->fetchAssoc()) {
            addApprovalNotif(
                "For Approval",
                "Production Work Order pending approval: " . $row["work_order_no"],
                "fa-cogs",
                "production_work_order",
                "id",
                $row["id"]
            );
        }
    }

    // 8. Purchase Order
    $sql = "
        SELECT id, reference_number
        FROM purchaseorder
        WHERE status = 'Pending'
        ORDER BY id DESC
        LIMIT 20
    ";
    $rs = DB::Query($sql);
    if ($rs) {
        while ($row = $rs->fetchAssoc()) {
            addApprovalNotif(
                "For Approval",
                "Purchase Order pending approval: " . $row["reference_number"],
                "fa-shopping-cart",
                "purchaseorder",
                "id",
                $row["id"]
            );
        }
    }

    // 9. Raw Material Issuance
    $sql = "
        SELECT id, issuance_no
        FROM raw_material_issuance
        WHERE status = 'Pending'
        ORDER BY id DESC
        LIMIT 20
    ";
    $rs = DB::Query($sql);
    if ($rs) {
        while ($row = $rs->fetchAssoc()) {
            addApprovalNotif(
                "For Approval",
                "Raw Material Issuance pending approval: " . $row["issuance_no"],
                "fa-sign-out",
                "raw_material_issuance",
                "id",
                $row["id"]
            );
        }
    }

    // 10. Raw Material Request / RISP
    $sql = "
        SELECT id, risp_no
        FROM raw_material_request
        WHERE status = 'Pending'
        ORDER BY id DESC
        LIMIT 20
    ";
    $rs = DB::Query($sql);
    if ($rs) {
        while ($row = $rs->fetchAssoc()) {
            addApprovalNotif(
                "For Approval",
                "RISP pending approval: " . $row["risp_no"],
                "fa-file-text",
                "raw_material_request",
                "id",
                $row["id"]
            );
        }
    }

    // 11. Stock Transfer Form
    $sql = "
        SELECT transfer_form_id, transfer_form_no
        FROM stock_transfer_form
        WHERE status = 'Pending'
        ORDER BY transfer_form_id DESC
        LIMIT 20
    ";
    $rs = DB::Query($sql);
    if ($rs) {
        while ($row = $rs->fetchAssoc()) {
            addApprovalNotif(
                "For Approval",
                "Stock Transfer Form pending approval: " . $row["transfer_form_no"],
                "fa-exchange",
                "stock_transfer_form",
                "transfer_form_id",
                $row["transfer_form_id"]
            );
        }
    }
}

// Load logged-in user details into session
// ======================================================
// LOAD LOGGED-IN USER LOCATION INTO SESSION
// ======================================================

$sqlUser = DB::PrepareSQL("
    SELECT
        ID,
        warehouse,
        warehouse_id,
        mother_facility_id
    FROM users
    WHERE username = '?s'
    LIMIT 1
", $username);

$rsUser = DB::Query($sqlUser);

if ($rsUser) {

    $userData = $rsUser->fetchAssoc();

    if ($userData) {

        $warehouseId = isset($userData["warehouse_id"])
            ? (int)$userData["warehouse_id"]
            : 0;

        // Use the legacy warehouse column when warehouse_id is empty
        if (
            $warehouseId <= 0 &&
            !empty($userData["warehouse"])
        ) {
            $warehouseId = (int)$userData["warehouse"];
        }

        $_SESSION["user_id"] =
            (int)$userData["ID"];

        $_SESSION["warehouse"] =
            $warehouseId;

        $_SESSION["warehouse_id"] =
            $warehouseId;

        $_SESSION["mother_facility_id"] =
            isset($userData["mother_facility_id"])
                ? (int)$userData["mother_facility_id"]
                : 0;
    }
}

header("Location: Dashboard_dashboard.php");
exit();
		;
		
	}

	function BeforeShowMenu( &$xt, &$templatefile, $pageObject ) {
		$sql = "
SELECT
(
    (SELECT COUNT(*) FROM augmentation_portal_request WHERE status='FOR_APPROVAL')
    +
    (SELECT COUNT(*) FROM purchaseorder WHERE status='Pending')
    +
    (SELECT COUNT(*) FROM production_plan WHERE status='Pending')
    +
    (SELECT COUNT(*) FROM production_work_order WHERE status='Pending')
    +
    (SELECT COUNT(*) FROM disposal_form WHERE status='Pending')
) total_pending
";

$rs = DB::Query($sql);
$data = $rs->fetchAssoc();

$_SESSION["approval_count"] = $data["total_pending"];

header("Location: Dashboard_dashboard.php");
exit();



		;
		
	}
	
	// custom buttons 
		// custom button - Button1
	function buttonHandler_2534( $_params )
	{
		$result = array();

		$button = $this->prepareButtonContext( $_params );
		$ajax = $button; 
		$keys = $button->getKeys();

		// .NET naming
		$parameters = $_params;
		$params = &$_params;

		// Put your code here.

$result["txt"] = $params["txt"]." world!";;

		RunnerContext::pop();
		echo runner_json_encode( $result);
		$button->deleteTempFiles();
	}

		// custom button - donation_to_qa
	function buttonHandler_2538( $_params )
	{
		$result = array();

		$button = $this->prepareButtonContext( $_params );
		$ajax = $button; 
		$keys = $button->getKeys();

		// .NET naming
		$parameters = $_params;
		$params = &$_params;

		// ==========================================================
// DONATION RECEIVING TO QA INCOMING GOODS
// PHPRunner Custom Button - Server Event
// ==========================================================
//
// Required client parameter:
// $params["donation_receiving_detail_id"]
//
// Donation Receiving transaction number is stored in:
// qa_incoming_goods.dr_no
//
// PHPRunner may display this field as:
// value_dr_no_1
// ==========================================================


// ----------------------------------------------------------
// 1. GET DONATION RECEIVING DETAIL ID
// ----------------------------------------------------------

$donationReceivingDetailId =
    isset($params["donation_receiving_detail_id"])
        ? (int)$params["donation_receiving_detail_id"]
        : 0;

if ($donationReceivingDetailId <= 0) {

    $result["success"] = false;
    $result["message"] =
        "Invalid Donation Receiving detail ID.";

    return;
}


// ----------------------------------------------------------
// DATABASE ERROR HELPER
// ----------------------------------------------------------

if (!function_exists("getLastDbErrorDonationQA")) {

    function getLastDbErrorDonationQA()
    {
        if (method_exists("DB", "LastError")) {

            $error = DB::LastError();

            if ($error != "") {
                return $error;
            }
        }

        if (function_exists("db_error")) {

            $error = db_error();

            if ($error != "") {
                return $error;
            }
        }

        return "Unknown database error.";
    }
}


// ----------------------------------------------------------
// EXECUTE SQL OR THROW ERROR
// ----------------------------------------------------------

if (!function_exists("execOrFailDonationQA")) {

    function execOrFailDonationQA(
        $sql,
        $label
    ) {
        $success = DB::Exec($sql);

        if ($success === false) {

            throw new Exception(
                $label . " failed: " .
                getLastDbErrorDonationQA()
            );
        }

        return $success;
    }
}


// ----------------------------------------------------------
// GENERATE TRANSACTION NUMBER
// Must be called inside the transaction
// ----------------------------------------------------------

if (!function_exists("getTransactionNumberDonationQA")) {

    function getTransactionNumberDonationQA(
        $transactionCode
    ) {
        $transactionCode =
            trim($transactionCode);

        $sqlNumbering = "
            SELECT
                id,
                prefix,
                digit_length,
                next_no
            FROM transaction_numbering
            WHERE transaction_code = '" .
                db_addslashes($transactionCode) . "'
              AND is_active = 1
            LIMIT 1
            FOR UPDATE
        ";

        $rsNumbering =
            DB::Query($sqlNumbering);

        $numberingData =
            $rsNumbering
                ? $rsNumbering->fetchAssoc()
                : null;

        if (!$numberingData) {

            throw new Exception(
                "No active transaction numbering setup " .
                "was found for " .
                $transactionCode . "."
            );
        }

        $generatedNumber =
            $numberingData["prefix"] .
            str_pad(
                (int)$numberingData["next_no"],
                (int)$numberingData["digit_length"],
                "0",
                STR_PAD_LEFT
            );

        execOrFailDonationQA(
            "
                UPDATE transaction_numbering
                SET next_no = next_no + 1
                WHERE id = " .
                    (int)$numberingData["id"] . "
            ",
            "Update " .
                $transactionCode .
                " transaction numbering"
        );

        return $generatedNumber;
    }
}


// ----------------------------------------------------------
// START TRANSACTION
// ----------------------------------------------------------

DB::Exec("START TRANSACTION");

try {

    // ======================================================
    // 2. GET DONATION RECEIVING DETAIL
    // ======================================================

    $sqlDonation = "
        SELECT
            drd.id
                AS donation_receiving_detail_id,

            dr.id
                AS donation_receiving_id,

            dr.donation_receiving_no,
            dr.donation_date,

            dr.donor_id,

            COALESCE(
                NULLIF(TRIM(d.donor_name), ''),
                NULLIF(TRIM(dr.donor_name), ''),
                ''
            ) AS donor_name,

            dr.warehouse
                AS donation_warehouse_id,

            dr.mother_facility_id
                AS donation_mother_facility_id,

            drd.item_id,

            COALESCE(
                NULLIF(i.parent_item_id, 0),
                0
            ) AS parent_item_id,

            i.sku,

            COALESCE(
                NULLIF(TRIM(i.description), ''),
                NULLIF(TRIM(drd.item_description), ''),
                NULLIF(TRIM(i.name), ''),
                ''
            ) AS item_name,

            COALESCE(
                NULLIF(TRIM(i.name), ''),
                NULLIF(TRIM(drd.article), ''),
                NULLIF(TRIM(i.description), ''),
                NULLIF(TRIM(drd.item_description), ''),
                ''
            ) AS item_kind,

            i.brand_id,

            COALESCE(
                NULLIF(TRIM(ib.brand_name), ''),
                NULLIF(TRIM(i.brand), ''),
                ''
            ) AS brand_name,

            COALESCE(
                NULLIF(
                    CAST(drd.unit AS UNSIGNED),
                    0
                ),
                NULLIF(i.unit_id, 0)
            ) AS unit_id,

            COALESCE(
                NULLIF(TRIM(iu.name), ''),
                NULLIF(TRIM(drd.unit), ''),
                ''
            ) AS unit_name,

            drd.quantity
                AS delivered_quantity,

            drd.unit_value,
            drd.total_value,

            drd.batch_no
                AS donation_batch_no,

            drd.serial_no,
            drd.expiry_date,
            drd.warranty_date,

            drd.remarks
                AS donation_detail_remarks

        FROM donation_receiving_detail drd

        INNER JOIN donation_receiving dr
            ON dr.id =
                drd.donation_receiving_id

        LEFT JOIN donor d
            ON d.id = dr.donor_id

        LEFT JOIN item i
            ON i.id = drd.item_id

        LEFT JOIN itembrand ib
            ON ib.id = i.brand_id

        LEFT JOIN itemunit iu
            ON iu.id = COALESCE(
                NULLIF(
                    CAST(drd.unit AS UNSIGNED),
                    0
                ),
                NULLIF(i.unit_id, 0)
            )

        WHERE drd.id = " .
            $donationReceivingDetailId . "

        LIMIT 1
    ";

    $rsDonation =
        DB::Query($sqlDonation);

    $donation =
        $rsDonation
            ? $rsDonation->fetchAssoc()
            : null;

    if (!$donation) {

        throw new Exception(
            "The selected Donation Receiving " .
            "detail was not found."
        );
    }


    // ======================================================
    // 3. VALIDATE DONATION RECEIVING DATA
    // ======================================================

    $donationReceivingId =
        (int)$donation[
            "donation_receiving_id"
        ];

    $donationReceivingDetailId =
        (int)$donation[
            "donation_receiving_detail_id"
        ];

    $donationReceivingNo =
        isset($donation[
            "donation_receiving_no"
        ])
            ? trim(
                $donation[
                    "donation_receiving_no"
                ]
            )
            : "";

    $itemId =
        (int)$donation["item_id"];

    $parentItemId =
        (int)$donation["parent_item_id"];

    $donorId =
        (int)$donation["donor_id"];

    $donorName =
        isset($donation["donor_name"])
            ? trim($donation["donor_name"])
            : "";

    $itemName =
        isset($donation["item_name"])
            ? trim($donation["item_name"])
            : "";

    $itemKind =
        isset($donation["item_kind"])
            ? trim($donation["item_kind"])
            : "";

    $brandName =
        isset($donation["brand_name"])
            ? trim($donation["brand_name"])
            : "";

    $unitName =
        isset($donation["unit_name"])
            ? trim($donation["unit_name"])
            : "";

    $deliveredQuantity =
        (float)$donation[
            "delivered_quantity"
        ];


    if ($donationReceivingId <= 0) {

        throw new Exception(
            "The Donation Receiving header is missing."
        );
    }

    if ($donationReceivingNo == "") {

        throw new Exception(
            "The Donation Receiving transaction number " .
            "is missing."
        );
    }

    if ($itemId <= 0) {

        throw new Exception(
            "The Donation Receiving detail does not " .
            "have a valid Item."
        );
    }

    if ($itemName == "") {

        throw new Exception(
            "The Item Description is missing from the " .
            "Donation Receiving detail and Item Master."
        );
    }

    if ($donorName == "") {

        throw new Exception(
            "The Donor Name is missing from the " .
            "Donation Receiving record."
        );
    }

    if ($deliveredQuantity <= 0) {

        throw new Exception(
            "The donated quantity must be greater " .
            "than zero."
        );
    }


    // ======================================================
    // 4. PREVENT DUPLICATE QA CREATION
    // ======================================================

    $sqlExistingQa = "
        SELECT
            id,
            qa_no,
            dr_no
        FROM qa_incoming_goods
        WHERE source_transaction_type =
              'DONATION_RECEIVING'

          AND source_transaction_id =
              " . $donationReceivingId . "

          AND source_detail_id =
              " . $donationReceivingDetailId . "

        LIMIT 1
        FOR UPDATE
    ";

    $rsExistingQa =
        DB::Query($sqlExistingQa);

    $existingQa =
        $rsExistingQa
            ? $rsExistingQa->fetchAssoc()
            : null;

    if ($existingQa) {

        DB::Exec("COMMIT");

        $result["success"] = true;
        $result["already_exists"] = true;

        $result["qa_id"] =
            (int)$existingQa["id"];

        $result["qa_no"] =
            $existingQa["qa_no"];

        $result["dr_no"] =
            $existingQa["dr_no"];

        $result["value_dr_no_1"] =
            $existingQa["dr_no"];

        $result["message"] =
            "QA Incoming Goods already exists. " .
            "QA No.: " .
            $existingQa["qa_no"];

        return;
    }


    // ======================================================
    // 5. GET CURRENT LOGGED-IN USER
    // Uses PHPRunner built-in UserID session
    // ======================================================

    $userName =
        isset($_SESSION["UserID"])
            ? trim($_SESSION["UserID"])
            : "";

    if ($userName == "") {

        throw new Exception(
            "The current PHPRunner user session " .
            "was not found."
        );
    }

    $sqlUser = "
        SELECT
            u.ID AS user_id,
            u.username,

            u.mother_facility_id
                AS user_mother_facility_id,

            CASE
                WHEN u.warehouse_id IS NOT NULL
                     AND u.warehouse_id > 0
                THEN u.warehouse_id
                ELSE u.warehouse
            END AS user_warehouse_id

        FROM users u

        WHERE u.username = '" .
            db_addslashes($userName) . "'

        LIMIT 1
    ";

    $rsUser =
        DB::Query($sqlUser);

    $userData =
        $rsUser
            ? $rsUser->fetchAssoc()
            : null;

    if (!$userData) {

        throw new Exception(
            "The current logged-in User record " .
            "was not found."
        );
    }

    $createdById =
        (int)$userData["user_id"];

    $userWarehouseId =
        (int)$userData["user_warehouse_id"];

    $userMotherFacilityId =
        (int)$userData[
            "user_mother_facility_id"
        ];

    if ($createdById <= 0) {

        throw new Exception(
            "The logged-in User has an invalid ID."
        );
    }


    // Refresh custom session values
    $_SESSION["user_id"] =
        $createdById;

    $_SESSION["warehouse"] =
        $userWarehouseId;

    $_SESSION["warehouse_id"] =
        $userWarehouseId;

    $_SESSION["mother_facility_id"] =
        $userMotherFacilityId;


    // ======================================================
    // 6. RESOLVE RECEIVING WAREHOUSE
    // Priority:
    // 1. Donation Receiving Warehouse
    // 2. Logged-in User Warehouse
    // ======================================================

    $donationWarehouseId =
        (int)$donation[
            "donation_warehouse_id"
        ];

    $donationMotherFacilityId =
        (int)$donation[
            "donation_mother_facility_id"
        ];

    $warehouseCandidates = array();

    if ($donationWarehouseId > 0) {

        $warehouseCandidates[] =
            $donationWarehouseId;
    }

    if (
        $userWarehouseId > 0 &&
        $userWarehouseId !=
            $donationWarehouseId
    ) {
        $warehouseCandidates[] =
            $userWarehouseId;
    }

    if (count($warehouseCandidates) <= 0) {

        throw new Exception(
            "No Warehouse is assigned in the " .
            "Donation Receiving record or the " .
            "logged-in User profile."
        );
    }

    $fallbackMotherFacilityId = 0;

    if ($donationMotherFacilityId > 0) {

        $fallbackMotherFacilityId =
            $donationMotherFacilityId;

    } elseif ($userMotherFacilityId > 0) {

        $fallbackMotherFacilityId =
            $userMotherFacilityId;
    }

    $fallbackMotherFacilitySql =
        $fallbackMotherFacilityId > 0
            ? (string)$fallbackMotherFacilityId
            : "NULL";

    $warehouseData = null;
    $warehouseSource = "";

    foreach (
        $warehouseCandidates
        as $candidateWarehouseId
    ) {
        $candidateWarehouseId =
            (int)$candidateWarehouseId;

        $sqlWarehouse = "
            SELECT
                w.id AS warehouse_id,
                w.warehouse_code,
                w.name AS warehouse_name,

                COALESCE(
                    NULLIF(
                        w.mother_facility_id,
                        0
                    ),
                    " .
                    $fallbackMotherFacilitySql . "
                ) AS mother_facility_id,

                mf.facility_code,
                mf.facility_name

            FROM warehouse w

            LEFT JOIN mother_facility mf
                ON mf.id = COALESCE(
                    NULLIF(
                        w.mother_facility_id,
                        0
                    ),
                    " .
                    $fallbackMotherFacilitySql . "
                )

            WHERE w.id = " .
                $candidateWarehouseId . "

            LIMIT 1
        ";

        $rsWarehouse =
            DB::Query($sqlWarehouse);

        $candidateWarehouse =
            $rsWarehouse
                ? $rsWarehouse->fetchAssoc()
                : null;

        if ($candidateWarehouse) {

            $warehouseData =
                $candidateWarehouse;

            $warehouseSource =
                $candidateWarehouseId ==
                $donationWarehouseId
                    ? "DONATION_RECEIVING"
                    : "USER_PROFILE";

            break;
        }
    }

    if (!$warehouseData) {

        throw new Exception(
            "The receiving Warehouse record " .
            "was not found."
        );
    }

    if (
        (int)$warehouseData[
            "mother_facility_id"
        ] <= 0
    ) {
        throw new Exception(
            "The receiving Warehouse does not have " .
            "a Mother Facility assignment."
        );
    }

    if (
        trim(
            $warehouseData["warehouse_code"]
        ) == ""
    ) {
        throw new Exception(
            "The receiving Warehouse Code is missing."
        );
    }

    if (
        trim(
            $warehouseData["facility_code"]
        ) == ""
    ) {
        throw new Exception(
            "The Mother Facility Code is missing."
        );
    }


    // ======================================================
    // 7. GENERATE QA NO., BATCH NO., AND VBN
    // ======================================================

    $qaNo =
        getTransactionNumberDonationQA(
            "QA"
        );

    $batchNo =
        getTransactionNumberDonationQA(
            "BATCH"
        );

    $vbnSequence =
        getTransactionNumberDonationQA(
            "VBN"
        );

    $vbnSequenceOnly =
        preg_replace(
            "/[^0-9]/",
            "",
            $vbnSequence
        );

    if ($vbnSequenceOnly == "") {

        throw new Exception(
            "The generated VBN sequence is invalid."
        );
    }

    $vbn =
        trim(
            $warehouseData["facility_code"]
        ) .
        "-" .
        trim(
            $warehouseData["warehouse_code"]
        ) .
        "-" .
        date("Y") .
        "-" .
        $vbnSequenceOnly;


    // ======================================================
    // 8. CALCULATE 2% SAMPLE QUANTITY
    // ======================================================

    $totalSampleInspected =
        ceil(
            $deliveredQuantity * 0.02
        );

    if (
        $totalSampleInspected >
        $deliveredQuantity
    ) {
        $totalSampleInspected =
            $deliveredQuantity;
    }

    if (
        $deliveredQuantity > 0 &&
        $totalSampleInspected <= 0
    ) {
        $totalSampleInspected = 1;
    }

    $deliveredQuantitySql =
        number_format(
            $deliveredQuantity,
            4,
            ".",
            ""
        );

    $totalSampleInspectedSql =
        number_format(
            $totalSampleInspected,
            4,
            ".",
            ""
        );


    // ======================================================
    // 9. PREPARE SQL VALUES
    // ======================================================

    $donorSql =
        $donorId > 0
            ? (string)$donorId
            : "NULL";

    $expiryDateSql =
        !empty($donation["expiry_date"])
            ? "'" .
                db_addslashes(
                    $donation["expiry_date"]
                ) .
                "'"
            : "NULL";

    $warrantyDateSql =
        !empty($donation["warranty_date"])
            ? "'" .
                db_addslashes(
                    $donation["warranty_date"]
                ) .
                "'"
            : "NULL";


    // ======================================================
    // 10. INSERT QA INCOMING GOODS HEADER
    //
    // IMPORTANT:
    // dr_no receives donation_receiving_no.
    // PHPRunner control value_dr_no_1 displays this value.
    // ======================================================

    $insertQa = "
        INSERT INTO qa_incoming_goods
        (
            qa_no,
            receiving_report_no,

            source_transaction_type,
            source_transaction_id,
            source_detail_id,

            po_no,
            dr_no,
            ar_no,

            supplier_donor,

            po_receiving_id,
            po_receiving_detail_id,

            delivery_receipt_id,
            delivery_receipt_detail_id,

            inspection_date,

            receiving_warehouse_id,
            receiving_warehouse_name,
            warehouse_code,

            no_of_inspectors,

            item_id,
            item_name,
            kind,
            brand,
            unit,

            source,

            delivered_quantity,
            inspected_quantity,
            accepted_quantity,
            returned_quantity,
            for_disposal_quantity,
            rejected_quantity,
            on_hold_quantity,

            total_sample_inspected,

            average_acceptance_rate,
            average_rejection_rate,

            final_action_taken,
            receiving_status,
            approval_status,

            batch_no,
            vbn,

            mother_facility_id,
            mother_facility_code,
            mother_facility_name,

            supplier,
            donor,

            expiry_date,
            waranty_date,

            created_by,
            createdAt,
            updatedAt
        )
        VALUES
        (
            '" .
                db_addslashes($qaNo) .
            "',

            '" .
                db_addslashes($qaNo) .
            "',

            'DONATION_RECEIVING',

            " . $donationReceivingId . ",

            " .
                $donationReceivingDetailId .
            ",

            NULL,

            '" .
                db_addslashes(
                    $donationReceivingNo
                ) .
            "',

            NULL,

            '" .
                db_addslashes($donorName) .
            "',

            NULL,
            NULL,

            NULL,
            NULL,

            CURDATE(),

            " .
                (int)$warehouseData[
                    "warehouse_id"
                ] .
            ",

            '" .
                db_addslashes(
                    $warehouseData[
                        "warehouse_name"
                    ]
                ) .
            "',

            '" .
                db_addslashes(
                    $warehouseData[
                        "warehouse_code"
                    ]
                ) .
            "',

            1,

            " . $itemId . ",

            '" .
                db_addslashes($itemName) .
            "',

            '" .
                db_addslashes($itemKind) .
            "',

            '" .
                db_addslashes($brandName) .
            "',

            '" .
                db_addslashes($unitName) .
            "',

            'DONATION_RECEIVING',

            " . $deliveredQuantitySql . ",

            0,
            0,
            0,
            0,
            0,
            0,

            " .
                $totalSampleInspectedSql .
            ",

            0,
            0,

            'FOR_FURTHER_INSPECTION',
            'FOR_QA',
            'DRAFT',

            '" .
                db_addslashes($batchNo) .
            "',

            '" .
                db_addslashes($vbn) .
            "',

            " .
                (int)$warehouseData[
                    "mother_facility_id"
                ] .
            ",

            '" .
                db_addslashes(
                    $warehouseData[
                        "facility_code"
                    ]
                ) .
            "',

            '" .
                db_addslashes(
                    $warehouseData[
                        "facility_name"
                    ]
                ) .
            "',

            NULL,

            " . $donorSql . ",

            " . $expiryDateSql . ",

            " . $warrantyDateSql . ",

            " . $createdById . ",

            NOW(),
            NOW()
        )
    ";

    execOrFailDonationQA(
        $insertQa,
        "Insert Donation QA Incoming Goods"
    );


    // ======================================================
    // 11. GET GENERATED QA ID
    // ======================================================

    $qaId =
        (int)DB::LastId();

    if ($qaId <= 0) {

        $sqlQaId = "
            SELECT id
            FROM qa_incoming_goods
            WHERE qa_no = '" .
                db_addslashes($qaNo) . "'
            ORDER BY id DESC
            LIMIT 1
        ";

        $rsQaId =
            DB::Query($sqlQaId);

        $qaIdRow =
            $rsQaId
                ? $rsQaId->fetchAssoc()
                : null;

        if ($qaIdRow) {

            $qaId =
                (int)$qaIdRow["id"];
        }
    }

    if ($qaId <= 0) {

        throw new Exception(
            "The QA header was inserted, but the " .
            "generated QA ID could not be retrieved."
        );
    }


    // ======================================================
    // 12. DETERMINE QA CRITERIA SOURCE
    //
    // Priority:
    // 1. Item criteria
    // 2. Parent Item criteria
    // ======================================================

    $criteriaItemId =
        $itemId;

    $criteriaSource =
        "ITEM";

    $sqlItemCriteriaCount = "
        SELECT
            COUNT(*) AS criteria_count
        FROM qa_item_criteria
        WHERE item_id = " . $itemId . "
          AND qa_module = 'INCOMING_GOODS'
          AND status = 'ACTIVE'
    ";

    $rsItemCriteriaCount =
        DB::Query($sqlItemCriteriaCount);

    $itemCriteriaCountRow =
        $rsItemCriteriaCount
            ? $rsItemCriteriaCount->fetchAssoc()
            : null;

    $itemCriteriaCount =
        $itemCriteriaCountRow
            ? (int)$itemCriteriaCountRow[
                "criteria_count"
            ]
            : 0;

    if (
        $itemCriteriaCount <= 0 &&
        $parentItemId > 0
    ) {
        $criteriaItemId =
            $parentItemId;

        $criteriaSource =
            "PARENT_ITEM";
    }


    // ======================================================
    // 13. GET ACTIVE QA CRITERIA
    // ======================================================

    $sqlCriteria = "
        SELECT
            id,
            criteria_code,
            criteria_description,
            expected_result,
            inspection_method,
            sort_order
        FROM qa_item_criteria
        WHERE item_id = " .
            (int)$criteriaItemId . "
          AND qa_module = 'INCOMING_GOODS'
          AND status = 'ACTIVE'
        ORDER BY
            sort_order,
            id
    ";

    $rsCriteria =
        DB::Query($sqlCriteria);

    $insertedCriteria = 0;


    // ======================================================
    // 14. INSERT QA CRITERIA DETAILS
    // ======================================================

    while (
        $rsCriteria &&
        (
            $criteria =
                $rsCriteria->fetchAssoc()
        )
    ) {
        $criteriaCode =
            isset($criteria["criteria_code"])
                ? trim(
                    $criteria["criteria_code"]
                )
                : "";

        $criteriaDescription =
            isset(
                $criteria[
                    "criteria_description"
                ]
            )
                ? $criteria[
                    "criteria_description"
                ]
                : "";

        $expectedResult =
            isset($criteria["expected_result"])
                ? $criteria["expected_result"]
                : "";

        $inspectionMethod =
            isset(
                $criteria[
                    "inspection_method"
                ]
            )
                ? trim(
                    $criteria[
                        "inspection_method"
                    ]
                )
                : "";

        if ($inspectionMethod == "") {

            $inspectionMethod = "VISUAL";
        }

        $sortOrder =
            isset($criteria["sort_order"])
                ? (int)$criteria["sort_order"]
                : 0;

        if ($sortOrder <= 0) {

            $sortOrder =
                $insertedCriteria + 1;
        }

        $insertDetail = "
            INSERT INTO qa_incoming_goods_detail
            (
                qa_incoming_goods_id,

                item_id,
                item_name,

                criteria_id,
                criteria_code,

                sample_quantity,
                sample_unit,

                criteria_description,
                expected_result,
                inspection_method,
                inspection_result,

                sort_order,

                createdAt,
                updatedAt
            )
            VALUES
            (
                " . $qaId . ",

                " . $itemId . ",

                '" .
                    db_addslashes($itemName) .
                "',

                " .
                    (int)$criteria["id"] .
                ",

                '" .
                    db_addslashes(
                        $criteriaCode
                    ) .
                "',

                " .
                    $totalSampleInspectedSql .
                ",

                '" .
                    db_addslashes($unitName) .
                "',

                '" .
                    db_addslashes(
                        $criteriaDescription
                    ) .
                "',

                '" .
                    db_addslashes(
                        $expectedResult
                    ) .
                "',

                '" .
                    db_addslashes(
                        $inspectionMethod
                    ) .
                "',

                'PASSED',

                " . $sortOrder . ",

                NOW(),
                NOW()
            )
        ";

        execOrFailDonationQA(
            $insertDetail,
            "Insert Donation QA criterion"
        );

        $insertedCriteria++;
    }

    if ($insertedCriteria <= 0) {

        $criteriaSource =
            "NO_ACTIVE_CRITERIA";
    }


    // ======================================================
    // 15. COMMIT TRANSACTION
    // ======================================================

    DB::Exec("COMMIT");


    // ======================================================
    // 16. RETURN RESULT TO CLIENT
    // ======================================================

    $result["success"] = true;
    $result["already_exists"] = false;

    $result["message"] =
        "QA Incoming Goods created successfully " .
        "from Donation Receiving. QA No.: " .
        $qaNo;

    $result["qa_id"] =
        $qaId;

    $result["qa_no"] =
        $qaNo;

    $result["batch_no"] =
        $batchNo;

    $result["vbn"] =
        $vbn;

    $result["source_transaction_type"] =
        "DONATION_RECEIVING";

    $result["source_transaction_id"] =
        $donationReceivingId;

    $result["source_detail_id"] =
        $donationReceivingDetailId;

    $result["donation_receiving_id"] =
        $donationReceivingId;

    $result["donation_receiving_detail_id"] =
        $donationReceivingDetailId;

    $result["donation_receiving_no"] =
        $donationReceivingNo;


    // Actual database field
    $result["dr_no"] =
        $donationReceivingNo;


    // PHPRunner control/alias
    $result["value_dr_no_1"] =
        $donationReceivingNo;


    $result["supplier_id"] =
        null;

    $result["supplier_name"] =
        null;

    $result["donor_id"] =
        $donorId;

    $result["donor_name"] =
        $donorName;

    $result["item_id"] =
        $itemId;

    $result["parent_item_id"] =
        $parentItemId;

    $result["sku"] =
        $donation["sku"];

    $result["item_name"] =
        $itemName;

    $result["kind"] =
        $itemKind;

    $result["brand_name"] =
        $brandName;

    $result["unit_name"] =
        $unitName;

    $result["delivered_quantity"] =
        $deliveredQuantity;

    $result["total_sample_inspected"] =
        $totalSampleInspected;

    $result["sample_rate"] =
        2;

    $result["expiry_date"] =
        $donation["expiry_date"];

    $result["warranty_date"] =
        $donation["warranty_date"];

    $result["warehouse_id"] =
        (int)$warehouseData[
            "warehouse_id"
        ];

    $result["warehouse_name"] =
        $warehouseData[
            "warehouse_name"
        ];

    $result["warehouse_code"] =
        $warehouseData[
            "warehouse_code"
        ];

    $result["warehouse_source"] =
        $warehouseSource;

    $result["mother_facility_id"] =
        (int)$warehouseData[
            "mother_facility_id"
        ];

    $result["mother_facility_code"] =
        $warehouseData[
            "facility_code"
        ];

    $result["mother_facility_name"] =
        $warehouseData[
            "facility_name"
        ];

    $result["created_by"] =
        $createdById;

    $result["criteria_count"] =
        $insertedCriteria;

    $result["criteria_source"] =
        $criteriaSource;

    $result["criteria_item_id"] =
        $criteriaItemId;


// ==========================================================
// ERROR HANDLING
// ==========================================================

} catch (Exception $e) {

    DB::Exec("ROLLBACK");

    $result["success"] = false;
    $result["message"] =
        $e->getMessage();
};

		RunnerContext::pop();
		echo runner_json_encode( $result);
		$button->deleteTempFiles();
	}

		// custom button - Create Dispatch Plan
	function buttonHandler_2546( $_params )
	{
		$result = array();

		$button = $this->prepareButtonContext( $_params );
		$ajax = $button; 
		$keys = $button->getKeys();

		// .NET naming
		$parameters = $_params;
		$params = &$_params;

		// ======================================================
// CREATE ONE DISPATCH PLAN FROM MULTIPLE AUGMENTATION RIS
// ======================================================

$selected = array();

while ($record = $button->getNextSelectedRecord()) {
    $selected[] = $record;
}

// ------------------------------------------------------
// Must select at least one RIS
// ------------------------------------------------------

if (count($selected) == 0) {

    $result["success"] = false;
    $result["txt"] =
        "Please select at least one RIS.";

    return;
}


// ------------------------------------------------------
// First selected RIS
// ------------------------------------------------------

$first = $selected[0];

$originWarehouseId =
    intval($first["origin_warehouse_id"]);

$originWarehouseCode =
    trim($first["origin_warehouse_code"]);

$originWarehouseName =
    trim($first["origin_warehouse_name"]);

$destination =
    trim($first["destination"]);


// ------------------------------------------------------
// Validate selected RIS
//
// One DR has one origin and one destination.
// Therefore selected RIS must belong to the same
// dispatch movement.
// ------------------------------------------------------

foreach ($selected as $row) {

    if (intval($row["warehouse_count"]) != 1) {

        $result["success"] = false;

        $result["txt"] =
            "RIS " .
            $row["ris_no"] .
            " contains allocations from more than one warehouse.";

        return;
    }

    if (
        intval($row["origin_warehouse_id"])
        != $originWarehouseId
    ) {

        $result["success"] = false;

        $result["txt"] =
            "Selected RIS must have the same origin warehouse.";

        return;
    }

    if (
        strtoupper(trim($row["destination"]))
        != strtoupper($destination)
    ) {

        $result["success"] = false;

        $result["txt"] =
            "Selected RIS must have the same destination.";

        return;
    }
}


// ------------------------------------------------------
// Create Dispatch Plan header
// ------------------------------------------------------

$data = array();

$data["source_reference_type"] = "RIS";

/*
Multiple RIS are stored in request_dispatch_plan_source.
Do not force one RIS ID into the header.
*/
$data["source_reference_id"] = null;

if (count($selected) == 1) {

    $data["source_reference_no"] =
        $selected[0]["ris_no"];

} else {

    $data["source_reference_no"] =
        "MULTIPLE RIS";
}

$data["dispatch_sequence"] = 1;

$data["dispatch_date"] =
    date("Y-m-d");

$data["origin_warehouse_id"] =
    $originWarehouseId;

$data["origin_warehouse_code"] =
    $originWarehouseCode;

$data["origin_warehouse_name"] =
    $originWarehouseName;

$data["destination_type"] =
    "OTHER";

$data["destination_name"] =
    $destination;

$data["destination_address"] =
    $destination;

$data["contact_person"] =
    $first["contact_person"];

$data["contact_no"] =
    $first["contact_number"];

$data["dispatch_status"] =
    "PLANNED";

$data["created_by"] =
    $_SESSION["uid"] ?? null;


DB::Insert(
    "request_dispatch_plan",
    $data
);

$dispatchPlanId =
    DB::LastId();


// ------------------------------------------------------
// Dispatch Plan Number
//
// Matches the slide's YYYY-MM-0001 style.
// ------------------------------------------------------

$dispatchPlanNo =
    date("Y-m") .
    "-" .
    str_pad(
        $dispatchPlanId,
        4,
        "0",
        STR_PAD_LEFT
    );

$sql = DB::PrepareSQL(
    "UPDATE request_dispatch_plan
     SET dispatch_plan_no=':1'
     WHERE id=:2",
    $dispatchPlanNo,
    $dispatchPlanId
);

DB::Exec($sql);


// ------------------------------------------------------
// Add every selected RIS to source table
// ------------------------------------------------------

$sequence = 1;

foreach ($selected as $row) {

    $risId =
        intval($row["ris_id"]);

    $risNo =
        trim($row["ris_no"]);


    $sourceData = array();

    $sourceData["request_dispatch_plan_id"] =
        $dispatchPlanId;

    $sourceData["augmentation_request_id"] =
        $risId;

    $sourceData["ris_no"] =
        $risNo;

    $sourceData["source_sequence"] =
        $sequence;

    DB::Insert(
        "request_dispatch_plan_source",
        $sourceData
    );

    $sequence++;


    // --------------------------------------------------
    // Copy APPROVED allocations into Dispatch Plan items
    // --------------------------------------------------

    $sqlItems = DB::PrepareSQL(
        "
        SELECT
            ara.allocation_id,
            ara.augmentation_request_item_id,
            ara.augmentation_request_id,
            ara.item_id,
            ara.sku,
            ara.item_description,
            ara.batch_no,
            ara.expiry_date,
            ara.unit,
            ara.allocated_qty

        FROM augmentation_request_allocation ara

        WHERE ara.augmentation_request_id = :1

          AND ara.allocation_status = 'APPROVED'

          AND ara.allocated_qty > 0

        ORDER BY
            ara.line_no,
            ara.allocation_id
        ",
        $risId
    );

    $rsItems =
        DB::Query($sqlItems);

    while (
        $item =
        $rsItems->fetchAssoc()
    ) {

        if (
            intval($item["item_id"]) <= 0
        ) {
            continue;
        }

        $qty =
            floatval(
                $item["allocated_qty"]
            );

        $itemData = array();

        $itemData["request_dispatch_plan_id"] =
            $dispatchPlanId;

        $itemData["augmentation_request_id"] =
            $risId;

        $itemData["augmentation_request_item_id"] =
            $item[
                "augmentation_request_item_id"
            ];

        $itemData[
            "augmentation_request_allocation_id"
        ] =
            $item["allocation_id"];

        $itemData["source_detail_id"] =
            $item["allocation_id"];

        $itemData["item_id"] =
            $item["item_id"];

        $itemData["item_code"] =
            $item["sku"];

        $itemData["item_description"] =
            $item["item_description"];

        $itemData["batch_no"] =
            $item["batch_no"];

        $itemData["expiry_date"] =
            $item["expiry_date"];

        $itemData["uom"] =
            $item["unit"];

        $itemData["requested_quantity"] =
            $qty;

        $itemData["planned_dispatch_quantity"] =
            $qty;

        $itemData["actual_dispatched_quantity"] =
            0;

        $itemData["received_quantity"] =
            0;

        $itemData["balance_quantity"] =
            $qty;

        $itemData["item_status"] =
            "PLANNED";

        DB::Insert(
            "request_dispatch_plan_item",
            $itemData
        );
    }
}


// ------------------------------------------------------
// Return result to browser
// ------------------------------------------------------

$result["success"] = true;

$result["dispatch_plan_id"] =
    $dispatchPlanId;

$result["dispatch_plan_no"] =
    $dispatchPlanNo;

$result["txt"] =
    "Dispatch Plan " .
    $dispatchPlanNo .
    " was created from " .
    count($selected) .
    " RIS record(s).";;

		RunnerContext::pop();
		echo runner_json_encode( $result);
		$button->deleteTempFiles();
	}

		// custom button - forecast
	function buttonHandler_2550( $_params )
	{
		$result = array();

		$button = $this->prepareButtonContext( $_params );
		$ajax = $button; 
		$keys = $button->getKeys();

		// .NET naming
		$parameters = $_params;
		$params = &$_params;

		$motherFacilityId = isset($params["mother_facility_id"])
    ? (int)$params["mother_facility_id"]
    : 0;

$motherFacilityCode = isset($params["mother_facility_code"])
    ? trim($params["mother_facility_code"])
    : "";

if ($motherFacilityId <= 0 && $motherFacilityCode == "") {
    $result["success"] = false;
    $result["message"] = "Missing mother facility ID or facility code.";
    return;
}

$transactionStarted = false;

try {

    // ------------------------------------------------------
    // Get mother facility
    // ------------------------------------------------------
    if ($motherFacilityId > 0) {
        $rsFacility = DB::Query("
            SELECT
                id,
                facility_code,
                facility_name,
                status
            FROM mother_facility
            WHERE id = ".$motherFacilityId."
            LIMIT 1
        ");
    } else {
        $rsFacility = DB::Query("
            SELECT
                id,
                facility_code,
                facility_name,
                status
            FROM mother_facility
            WHERE facility_code = '".db_addslashes($motherFacilityCode)."'
            LIMIT 1
        ");
    }

    $facility = $rsFacility->fetchAssoc();

    if (!$facility) {
        $result["success"] = false;
        $result["message"] = "Mother facility not found.";
        return;
    }

    if (strtoupper((string)$facility["status"]) != "ACTIVE") {
        $result["success"] = false;
        $result["message"] = "The selected mother facility is inactive.";
        return;
    }

    $motherFacilityId = (int)$facility["id"];

    // ------------------------------------------------------
    // Confirm that the facility has at least one active warehouse
    // ------------------------------------------------------
    $rsWarehouseCount = DB::Query("
        SELECT COUNT(*) AS cnt
        FROM warehouse
        WHERE mother_facility_id = ".$motherFacilityId."
          AND IFNULL(inactive, 0) = 0
    ");

    $warehouseCountRow = $rsWarehouseCount->fetchAssoc();
    $warehouseCount = (int)$warehouseCountRow["cnt"];

    if ($warehouseCount <= 0) {
        $result["success"] = false;
        $result["message"] = "No active warehouse is assigned to this mother facility.";
        return;
    }

    // ------------------------------------------------------
    // Check facility-level Food Pack forecast records
    // ------------------------------------------------------
    $rsCheck = DB::Query("
        SELECT COUNT(*) AS cnt
        FROM vw_foodpack_forecast_ranking_facility
        WHERE mother_facility_id = ".$motherFacilityId."
    ");

    $check = $rsCheck->fetchAssoc();

    if ((int)$check["cnt"] <= 0) {
        $result["success"] = false;
        $result["message"] =
            "No Food Pack forecast records were found for this facility. " .
            "Please check the Food Pack subcategory, BOM components, warehouse assignment, " .
            "batch number, and expiry date of inventory transactions.";
        return;
    }

    // ------------------------------------------------------
    // Start transaction and lock PSF numbering
    // production_suggestion_run/detail must be InnoDB.
    // ------------------------------------------------------
    DB::Exec("START TRANSACTION");
    $transactionStarted = true;

    DB::Exec("
        INSERT IGNORE INTO transaction_numbering
        (
            transaction_code,
            transaction_name,
            prefix,
            digit_length,
            start_no,
            next_no,
            is_active
        )
        VALUES
        (
            'PSF',
            'Production Suggestion Forecast',
            'PSF',
            5,
            1,
            1,
            1
        )
    ");

    $rsNum = DB::Query("
        SELECT
            id,
            prefix,
            digit_length,
            next_no
        FROM transaction_numbering
        WHERE transaction_code = 'PSF'
          AND is_active = 1
        LIMIT 1
        FOR UPDATE
    ");

    $num = $rsNum->fetchAssoc();

    if (!$num) {
        throw new Exception("No active transaction numbering for PSF.");
    }

    $runNo = $num["prefix"] . str_pad(
        (int)$num["next_no"],
        (int)$num["digit_length"],
        "0",
        STR_PAD_LEFT
    );

    // ------------------------------------------------------
    // Create facility-level forecast run
    // Warehouse fields remain NULL until the actual production
    // warehouse is selected during scheduling.
    // ------------------------------------------------------
    DB::Exec("
        INSERT INTO production_suggestion_run
        (
            run_no,
            run_date,
            mother_facility_id,
            mother_facility_code,
            mother_facility_name,
            warehouse_id,
            warehouse_code,
            warehouse_name,
            status,
            remarks,
            created_at
        )
        VALUES
        (
            '".db_addslashes($runNo)."',
            NOW(),
            ".$motherFacilityId.",
            '".db_addslashes($facility["facility_code"])."',
            '".db_addslashes($facility["facility_name"])."',
            NULL,
            NULL,
            NULL,
            'GENERATED',
            'Facility-level forecast using the combined inventory of ".$warehouseCount." active warehouse(s). Forecast expiry uses the earliest available raw-material expiry date.',
            NOW()
        )
    ");

    $runId = (int)DB::LastId();

    if ($runId <= 0) {
        throw new Exception("Forecast run was not created.");
    }

    // ------------------------------------------------------
    // Insert ALL Food Packs, including zero-producible records
    // ------------------------------------------------------
    DB::Exec("
        INSERT INTO production_suggestion_detail
        (
            run_id,
            mother_facility_id,
            mother_facility_code,
            mother_facility_name,
            warehouse_id,
            warehouse_code,
            warehouse_name,
            finished_good_id,
            finished_good_sku,
            finished_good_name,
            finished_good_description,
            component_count,
            insufficient_component_count,
            max_possible_qty,
            suggested_qty,
            target_qty,
            forecasted_expiry_date,
            forecasted_expiry_status,
            component_breakdown,
            selected_for_schedule,
            status,
            created_at
        )
        SELECT
            ".$runId.",
            mother_facility_id,
            mother_facility_code,
            mother_facility_name,
            NULL,
            NULL,
            NULL,
            finished_good_id,
            finished_good_sku,
            finished_good_description,
            finished_good_description,
            component_count,
            insufficient_component_count,
            IFNULL(max_possible_qty, 0),
            IFNULL(max_possible_qty, 0),
            0,
            forecasted_expiry_date,
            forecasted_expiry_status,
            component_breakdown,
            0,
            CASE
                WHEN IFNULL(max_possible_qty, 0) > 0 THEN 'SUGGESTED'
                ELSE 'NO_STOCK'
            END,
            NOW()
        FROM vw_foodpack_forecast_ranking_facility
        WHERE mother_facility_id = ".$motherFacilityId."
        ORDER BY
            IFNULL(priority, 999) ASC,
            IFNULL(max_possible_qty, 0) DESC,
            finished_good_description ASC
    ");

    $rsInserted = DB::Query("
        SELECT COUNT(*) AS cnt
        FROM production_suggestion_detail
        WHERE run_id = ".$runId."
    ");

    $inserted = $rsInserted->fetchAssoc();

    if ((int)$inserted["cnt"] <= 0) {
        throw new Exception("No forecast detail was generated.");
    }

    // ------------------------------------------------------
    // Consume numbering only after the run and details exist
    // ------------------------------------------------------
    DB::Exec("
        UPDATE transaction_numbering
        SET next_no = next_no + 1
        WHERE id = ".(int)$num["id"]."
    ");

    DB::Exec("COMMIT");
    $transactionStarted = false;

    $result["success"] = true;
    $result["message"] =
        "Production forecast generated successfully for " .
        $facility["facility_name"] . ": " . $runNo;
    $result["run_id"] = $runId;
    $result["run_no"] = $runNo;
    $result["mother_facility_id"] = $motherFacilityId;
    $result["warehouse_count"] = $warehouseCount;

} catch (Exception $e) {

    if ($transactionStarted) {
        DB::Exec("ROLLBACK");
    }

    $result["success"] = false;
    $result["message"] = $e->getMessage();
};

		RunnerContext::pop();
		echo runner_json_encode( $result);
		$button->deleteTempFiles();
	}

		// custom button - PortaltoRIS
	function buttonHandler_2560( $_params )
	{
		$result = array();

		$button = $this->prepareButtonContext( $_params );
		$ajax = $button; 
		$keys = $button->getKeys();

		// .NET naming
		$parameters = $_params;
		$params = &$_params;

		$portalRequestId = (int)$params["portal_request_id"];

DB::Exec("START TRANSACTION");

try {

    if ($portalRequestId <= 0) {
        throw new Exception("Invalid Portal Request ID.");
    }

    // =====================================================
    // GET PORTAL REQUEST HEADER
    // =====================================================

    $sqlHeader = "
        SELECT *
        FROM augmentation_portal_request
        WHERE portal_request_id = ".$portalRequestId."
        LIMIT 1
    ";

    $rsHeader = DB::Query($sqlHeader);
    $header = $rsHeader ? $rsHeader->fetchAssoc() : null;

    if (!$header) {
        throw new Exception("Portal request not found.");
    }

    if ($header["status"] != "APPROVED") {
        throw new Exception("Only APPROVED portal requests can be imported.");
    }

    if (!empty($header["imported_augmentation_request_id"])) {
        DB::Exec("COMMIT");

        $result["success"] = true;
        $result["message"] = "Augmentation Request already exists.";
        $result["augmentation_request_id"] = $header["imported_augmentation_request_id"];
        return;
    }

    // =====================================================
    // CHECK ALLOCATION
    // =====================================================

    $sqlCheck = "
        SELECT COUNT(*) AS total_count
        FROM augmentation_portal_request_allocation
        WHERE portal_request_id = ".$portalRequestId."
          AND imported_augmentation_request_id IS NULL
          AND allocated_qty > 0
    ";

    $rsCheck = DB::Query($sqlCheck);
    $check = $rsCheck ? $rsCheck->fetchAssoc() : null;

    if (!$check || (int)$check["total_count"] <= 0) {
        throw new Exception("No valid allocation found for this portal request.");
    }

    // =====================================================
    // GET NUMBERING
    // =====================================================

    $transactionCode = "AR";

    $sqlNumber = "
        SELECT
            id,
            prefix,
            digit_length,
            next_no
        FROM transaction_numbering
        WHERE transaction_code = '".db_addslashes($transactionCode)."'
          AND is_active = 1
        LIMIT 1
        FOR UPDATE
    ";

    $rsNumber = DB::Query($sqlNumber);
    $num = $rsNumber ? $rsNumber->fetchAssoc() : null;

    if (!$num) {
        throw new Exception("No active transaction numbering setup found for AR.");
    }

    $numberingId = (int)$num["id"];
    $prefix = $num["prefix"];
    $digitLength = (int)$num["digit_length"];
    $nextNo = (int)$num["next_no"];

    $requestNo = $prefix . str_pad($nextNo, $digitLength, "0", STR_PAD_LEFT);

    // =====================================================
    // INSERT AUGMENTATION REQUEST HEADER
    // =====================================================

    $createdBy = Security::getUserName();

    $sqlInsertHeader = "
        INSERT INTO augmentation_request
        (
            request_no,
            request_type_id,
            request_date,
            request_channel,
            portal_user_id,
            requesting_office,
            requestor_name,
            requestor_contact_no,
            delivery_site,
            address,
            contact_person,
            contact_number,
            purpose,
            remarks,
            status_id,
            created_by,
            created_at,
            updated_by,
            updated_at
        )
        VALUES
        (
            '".db_addslashes($requestNo)."',
            1,
            CURDATE(),
            'portal',
            ".(int)$header["portal_user_id"].",
            '".db_addslashes($header["requesting_office_lgu"])."',
            '".db_addslashes($header["contact_person"])."',
            '".db_addslashes($header["contact_number"])."',
            '".db_addslashes($header["delivery_address"])."',
            '".db_addslashes($header["delivery_address"])."',
            '".db_addslashes($header["contact_person"])."',
            '".db_addslashes($header["contact_number"])."',
            '".db_addslashes($header["purpose"])."',
            '".db_addslashes($header["remarks"])."',
            1,
            '".db_addslashes($createdBy)."',
            NOW(),
            '".db_addslashes($createdBy)."',
            NOW()
        )
    ";

    DB::Exec($sqlInsertHeader);

    $augmentationRequestId = DB::LastId();

    // =====================================================
    // INSERT AUGMENTATION REQUEST ITEMS FROM ALLOCATION
    // One allocation line = one augmentation_request_item line
    // =====================================================

    $sqlAlloc = "
        SELECT
            a.allocation_id,
            a.portal_request_id,
            a.portal_request_detail_id,
            a.line_no,
            a.item_id,
            a.sku,
            a.item_description,
            a.warehouse_id,
            a.warehouse_code,
            a.warehouse_name,
            a.allocated_qty,
            a.unit,
            a.remarks
        FROM augmentation_portal_request_allocation a
        WHERE a.portal_request_id = ".$portalRequestId."
          AND a.imported_augmentation_request_id IS NULL
          AND a.allocated_qty > 0
        ORDER BY a.portal_request_detail_id, a.line_no, a.allocation_id
    ";

    $rsAlloc = DB::Query($sqlAlloc);

    $lineNo = 1;
    $insertedItems = 0;

    while ($alloc = $rsAlloc->fetchAssoc()) {

        $itemId = (int)$alloc["item_id"];

        if ($itemId <= 0) {
            throw new Exception("Allocation line has no valid item.");
        }

        $warehouseIdSql = "NULL";
        if (!empty($alloc["warehouse_id"])) {
            $warehouseIdSql = (int)$alloc["warehouse_id"];
        }

        $sqlInsertItem = "
            INSERT INTO augmentation_request_item
            (
                augmentation_request_id,
                line_no,
                item_id,
                warehouse_id,
                warehouse_code,
                warehouse_name,
                stock_no,
                item_code,
                item_description,
                unit,
                requested_qty,
                stock_available_status,
                stock_available_qty,
                approved_qty,
                issued_qty,
                received_qty,
                cancelled_qty,
                returned_qty,
                item_status,
                remarks,
                created_at
            )
            VALUES
            (
                ".$augmentationRequestId.",
                ".$lineNo.",
                ".$itemId.",
                ".$warehouseIdSql.",
                '".db_addslashes($alloc["warehouse_code"])."',
                '".db_addslashes($alloc["warehouse_name"])."',
                '".db_addslashes($alloc["sku"])."',
                '".db_addslashes($alloc["sku"])."',
                '".db_addslashes($alloc["item_description"])."',
                '".db_addslashes($alloc["unit"])."',
                ".(float)$alloc["allocated_qty"].",
                'YES',
                ".(float)$alloc["allocated_qty"].",
                ".(float)$alloc["allocated_qty"].",
                0,
                0,
                0,
                0,
                'AVAILABLE',
                '".db_addslashes($alloc["remarks"])."',
                NOW()
            )
        ";

        DB::Exec($sqlInsertItem);

        DB::Exec("
            UPDATE augmentation_portal_request_allocation
            SET
                imported_augmentation_request_id = ".$augmentationRequestId.",
                imported_at = NOW(),
                imported_by = '".db_addslashes($createdBy)."'
            WHERE allocation_id = ".(int)$alloc["allocation_id"]."
        ");

        $lineNo++;
        $insertedItems++;
    }

    if ($insertedItems <= 0) {
        throw new Exception("No allocation items were imported.");
    }

    // =====================================================
    // UPDATE PORTAL REQUEST AS IMPORTED
    // =====================================================

    DB::Exec("
        UPDATE augmentation_portal_request
        SET
            imported_augmentation_request_id = ".$augmentationRequestId.",
            imported_at = NOW(),
            imported_by = '".db_addslashes($createdBy)."'
        WHERE portal_request_id = ".$portalRequestId."
    ");

    // =====================================================
    // UPDATE TRANSACTION NUMBERING
    // =====================================================

    DB::Exec("
        UPDATE transaction_numbering
        SET next_no = next_no + 1
        WHERE id = ".$numberingId."
    ");

    DB::Exec("COMMIT");

    $result["success"] = true;
    $result["message"] = "Augmentation Request created successfully.";
    $result["augmentation_request_id"] = $augmentationRequestId;
    $result["request_no"] = $requestNo;
    $result["item_count"] = $insertedItems;

} catch (Exception $e) {

    DB::Exec("ROLLBACK");

    $result["success"] = false;
    $result["message"] = $e->getMessage();
};

		RunnerContext::pop();
		echo runner_json_encode( $result);
		$button->deleteTempFiles();
	}

		// custom button - Create Trip Ticket
	function buttonHandler_2564( $_params )
	{
		$result = array();

		$button = $this->prepareButtonContext( $_params );
		$ajax = $button; 
		$keys = $button->getKeys();

		// .NET naming
		$parameters = $_params;
		$params = &$_params;

		// ======================================================
// CREATE TRIP TICKET FROM DELIVERY RECEIPT
// ======================================================

$drId =
    isset($params["delivery_receipt_id"])
        ? (int)$params["delivery_receipt_id"]
        : 0;

if ($drId <= 0) {
    $result["success"] = false;
    $result["message"] =
        "Invalid Delivery Receipt ID.";
    return;
}

$transactionCode = "TT";
$transactionStarted = false;
$stage = "Starting Trip Ticket creation";

// ------------------------------------------------------
// SQL helpers
// ------------------------------------------------------
$sqlText = function ($value) {

    if ($value === null || trim((string)$value) === "") {
        return "NULL";
    }

    return "'" .
        db_addslashes((string)$value) .
        "'";
};

$sqlInt = function ($value) {

    if (
        $value === null ||
        $value === "" ||
        (int)$value <= 0
    ) {
        return "NULL";
    }

    return (string)(int)$value;
};

$sqlDecimal = function ($value) {

    if ($value === null || $value === "") {
        return "NULL";
    }

    return number_format(
        (float)$value,
        7,
        ".",
        ""
    );
};

$firstNonEmpty = function (
    $values,
    $defaultValue
) {

    foreach ($values as $value) {

        if (
            $value !== null &&
            trim((string)$value) !== ""
        ) {
            return trim((string)$value);
        }
    }

    return $defaultValue;
};

try {

    DB::Exec("START TRANSACTION");
    $transactionStarted = true;

    // --------------------------------------------------
    // Load and lock Delivery Receipt
    // --------------------------------------------------
    $stage = "Reading Delivery Receipt";

    $rsDR = DB::Query("
        SELECT *
        FROM delivery_receipt
        WHERE id = ".$drId."
        LIMIT 1
        FOR UPDATE
    ");

    $dr = $rsDR
        ? $rsDR->fetchAssoc()
        : null;

    if (!$dr) {
        throw new Exception(
            "Delivery Receipt not found."
        );
    }

    if (
        isset($dr["dispatch_status"]) &&
        strtoupper(trim($dr["dispatch_status"]))
            == "CANCELLED"
    ) {
        throw new Exception(
            "A Trip Ticket cannot be created from a cancelled Delivery Receipt."
        );
    }

    // --------------------------------------------------
    // Return existing Trip Ticket
    // --------------------------------------------------
    if (
        !empty($dr["trip_ticket_id"]) &&
        (int)$dr["trip_ticket_id"] > 0
    ) {

        $existingId =
            (int)$dr["trip_ticket_id"];

        $rsExisting = DB::Query("
            SELECT
                id,
                trip_ticket_no,
                trip_status
            FROM trip_ticket
            WHERE id = ".$existingId."
            LIMIT 1
        ");

        $existing = $rsExisting
            ? $rsExisting->fetchAssoc()
            : null;

        if (
            $existing &&
            strtoupper(
                trim($existing["trip_status"])
            ) != "CANCELLED"
        ) {

            DB::Exec("COMMIT");

            $result["success"] = true;
            $result["message"] =
                "Trip Ticket already exists: " .
                $existing["trip_ticket_no"];

            $result["trip_ticket_id"] =
                (int)$existing["id"];

            $result["trip_ticket_no"] =
                $existing["trip_ticket_no"];

            return;
        }
    }

    $rsExisting = DB::Query("
        SELECT
            id,
            trip_ticket_no
        FROM trip_ticket
        WHERE delivery_receipt_id = ".$drId."
          AND trip_status <> 'CANCELLED'
        ORDER BY id DESC
        LIMIT 1
    ");

    $existing = $rsExisting
        ? $rsExisting->fetchAssoc()
        : null;

    if ($existing) {

        DB::Exec("
            UPDATE delivery_receipt
            SET
                trip_ticket_id =
                    ".(int)$existing["id"].",
                updated_at = NOW()
            WHERE id = ".$drId."
        ");

        DB::Exec("COMMIT");

        $result["success"] = true;
        $result["message"] =
            "Trip Ticket already exists: " .
            $existing["trip_ticket_no"];

        $result["trip_ticket_id"] =
            (int)$existing["id"];

        $result["trip_ticket_no"] =
            $existing["trip_ticket_no"];

        return;
    }

    // --------------------------------------------------
    // Load source Augmentation Request, when applicable
    // --------------------------------------------------
    $stage = "Resolving destination";

    $sourceRequest = null;

    if (
        isset($dr["source_reference_type"]) &&
        strtoupper(
            trim($dr["source_reference_type"])
        ) == "RIS" &&
        isset($dr["source_reference_id"]) &&
        (int)$dr["source_reference_id"] > 0
    ) {

        $sourceRequestId =
            (int)$dr["source_reference_id"];

        $rsSourceRequest = DB::Query("
            SELECT
                augmentation_request_id,
                request_no,
                ris_no,
                requesting_office,
                office_bureau,
                division_unit,
                requestor_name,
                requestor_contact_no,
                delivery_site,
                address,
                delivery_instructions,
                contact_person,
                contact_number,
                area_of_operation,
                requested_by_name,
                purpose
            FROM augmentation_request
            WHERE augmentation_request_id =
                ".$sourceRequestId."
            LIMIT 1
        ");

        $sourceRequest =
            $rsSourceRequest
                ? $rsSourceRequest->fetchAssoc()
                : null;
    }

    // --------------------------------------------------
    // Resolve destination and recipient
    // --------------------------------------------------
    $resolvedDestinationName =
        $firstNonEmpty(
            array(
                isset($dr["destination_name"])
                    ? $dr["destination_name"]
                    : "",

                isset($dr["destination_warehouse_name"])
                    ? $dr["destination_warehouse_name"]
                    : "",

                $sourceRequest &&
                isset($sourceRequest["delivery_site"])
                    ? $sourceRequest["delivery_site"]
                    : "",

                $sourceRequest &&
                isset($sourceRequest["requesting_office"])
                    ? $sourceRequest["requesting_office"]
                    : "",

                $sourceRequest &&
                isset($sourceRequest["office_bureau"])
                    ? $sourceRequest["office_bureau"]
                    : "",

                $sourceRequest &&
                isset($sourceRequest["area_of_operation"])
                    ? $sourceRequest["area_of_operation"]
                    : "",

                isset($dr["recipient_office"])
                    ? $dr["recipient_office"]
                    : "",

                isset($dr["recipient_name"])
                    ? $dr["recipient_name"]
                    : ""
            ),
            "Destination for " .
            (
                !empty($dr["source_reference_no"])
                    ? $dr["source_reference_no"]
                    : $dr["delivery_receipt_no"]
            )
        );

    $resolvedDestinationAddress =
        $firstNonEmpty(
            array(
                isset($dr["destination_address"])
                    ? $dr["destination_address"]
                    : "",

                $sourceRequest &&
                isset($sourceRequest["address"])
                    ? $sourceRequest["address"]
                    : "",

                $sourceRequest &&
                isset($sourceRequest["delivery_instructions"])
                    ? $sourceRequest["delivery_instructions"]
                    : "",

                $sourceRequest &&
                isset($sourceRequest["area_of_operation"])
                    ? $sourceRequest["area_of_operation"]
                    : ""
            ),
            ""
        );

    $resolvedRecipientName =
        $firstNonEmpty(
            array(
                isset($dr["recipient_name"])
                    ? $dr["recipient_name"]
                    : "",

                isset($dr["recipient_contact_person"])
                    ? $dr["recipient_contact_person"]
                    : "",

                $sourceRequest &&
                isset($sourceRequest["contact_person"])
                    ? $sourceRequest["contact_person"]
                    : "",

                $sourceRequest &&
                isset($sourceRequest["requestor_name"])
                    ? $sourceRequest["requestor_name"]
                    : "",

                $sourceRequest &&
                isset($sourceRequest["requested_by_name"])
                    ? $sourceRequest["requested_by_name"]
                    : ""
            ),
            "Authorized Recipient"
        );

    $resolvedRecipientContact =
        $firstNonEmpty(
            array(
                isset($dr["recipient_contact_no"])
                    ? $dr["recipient_contact_no"]
                    : "",

                isset(
                    $dr[
                        "recipient_information_contact_no"
                    ]
                )
                    ? $dr[
                        "recipient_information_contact_no"
                      ]
                    : "",

                $sourceRequest &&
                isset($sourceRequest["contact_number"])
                    ? $sourceRequest["contact_number"]
                    : "",

                $sourceRequest &&
                isset(
                    $sourceRequest[
                        "requestor_contact_no"
                    ]
                )
                    ? $sourceRequest[
                        "requestor_contact_no"
                      ]
                    : ""
            ),
            ""
        );

    $dr["destination_name"] =
        $resolvedDestinationName;

    $dr["destination_address"] =
        $resolvedDestinationAddress;

    $dr["recipient_name"] =
        $resolvedRecipientName;

    $dr["recipient_contact_no"] =
        $resolvedRecipientContact;

    // Save resolved values to the DR
    DB::Exec("
        UPDATE delivery_receipt
        SET
            destination_name =
                ".$sqlText(
                    $resolvedDestinationName
                ).",

            destination_address =
                ".$sqlText(
                    $resolvedDestinationAddress
                ).",

            recipient_name =
                ".$sqlText(
                    $resolvedRecipientName
                ).",

            recipient_contact_no =
                ".$sqlText(
                    $resolvedRecipientContact
                ).",

            updated_at = NOW()

        WHERE id = ".$drId."
    ");

    // --------------------------------------------------
    // Load DR cargo details and source warehouses
    // --------------------------------------------------
    $stage = "Reading Delivery Receipt details";

    $rsDetails = DB::Query("
        SELECT
            d.id,
            d.line_no,
            d.item_code,
            d.item_description,
            d.qty_for_dispatch,
            d.actual_dispatched_quantity,
            d.uom,
            d.batch_no,
            d.warehouse_id,

            COALESCE(
                NULLIF(d.warehouse_code, ''),
                w.warehouse_code
            ) AS warehouse_code,

            COALESCE(
                NULLIF(d.warehouse_name, ''),
                w.name
            ) AS warehouse_name,

            w.complete_address,
            w.lat,
            w.`long` AS lng

        FROM delivery_receipt_detail d

        LEFT JOIN warehouse w
            ON w.id = d.warehouse_id

        WHERE d.delivery_receipt_id =
              ".$drId."

          AND d.detail_status <> 'CANCELLED'

        ORDER BY
            d.line_no,
            d.id
    ");

    if (!$rsDetails) {
        throw new Exception(
            "Unable to read Delivery Receipt details."
        );
    }

    $cargoLines = array();
    $sourceWarehouses = array();
    $seenWarehouseIds = array();
    $cargoTotalQty = 0;

    while ($detail = $rsDetails->fetchAssoc()) {

        $qty =
            (float)$detail[
                "actual_dispatched_quantity"
            ] > 0
                ? (float)$detail[
                    "actual_dispatched_quantity"
                  ]
                : (float)$detail[
                    "qty_for_dispatch"
                  ];

        if ($qty <= 0) {
            continue;
        }

        $cargoLine =
            $detail["line_no"] .
            ". ";

        if (!empty($detail["item_code"])) {
            $cargoLine .=
                "[" .
                $detail["item_code"] .
                "] ";
        }

        $cargoLine .=
            $detail["item_description"] .
            " - " .
            number_format(
                $qty,
                2,
                ".",
                ""
            );

        if (!empty($detail["uom"])) {
            $cargoLine .=
                " " .
                $detail["uom"];
        }

        if (!empty($detail["warehouse_name"])) {
            $cargoLine .=
                " | Source: " .
                $detail["warehouse_name"];
        }

        if (!empty($detail["batch_no"])) {
            $cargoLine .=
                " | Batch: " .
                $detail["batch_no"];
        }

        $cargoLines[] = $cargoLine;
        $cargoTotalQty += $qty;

        $warehouseId =
            (int)$detail["warehouse_id"];

        if (
            $warehouseId > 0 &&
            !isset($seenWarehouseIds[$warehouseId])
        ) {

            $seenWarehouseIds[$warehouseId] = true;

            $sourceWarehouses[] = array(
                "source_type" =>
                    "WAREHOUSE",

                "warehouse_id" =>
                    $warehouseId,

                "saved_location_id" =>
                    null,

                "warehouse_code" =>
                    $detail["warehouse_code"],

                "name" =>
                    $detail["warehouse_name"],

                "address" =>
                    $detail["complete_address"],

                "lat" =>
                    $detail["lat"],

                "lng" =>
                    $detail["lng"]
            );
        }
    }

    if (count($cargoLines) <= 0) {
        throw new Exception(
            "The Delivery Receipt has no valid cargo details."
        );
    }

    $cargoDescription =
        implode("\n", $cargoLines);

    // --------------------------------------------------
    // Fallback source warehouse from DR header
    // --------------------------------------------------
    if (count($sourceWarehouses) <= 0) {

        $sourceWarehouseId =
            !empty($dr["warehouse_id"])
                ? (int)$dr["warehouse_id"]
                : (
                    !empty($dr["source_location_id"])
                        ? (int)$dr["source_location_id"]
                        : 0
                );

        if ($sourceWarehouseId > 0) {

            $rsSourceWarehouse = DB::Query("
                SELECT
                    id,
                    warehouse_code,
                    name,
                    complete_address,
                    lat,
                    `long` AS lng
                FROM warehouse
                WHERE id = ".$sourceWarehouseId."
                LIMIT 1
            ");

            $sourceWarehouse =
                $rsSourceWarehouse
                    ? $rsSourceWarehouse->fetchAssoc()
                    : null;

            if ($sourceWarehouse) {

                $sourceWarehouses[] = array(
                    "source_type" =>
                        "WAREHOUSE",

                    "warehouse_id" =>
                        (int)$sourceWarehouse["id"],

                    "saved_location_id" =>
                        null,

                    "warehouse_code" =>
                        $sourceWarehouse[
                            "warehouse_code"
                        ],

                    "name" =>
                        $sourceWarehouse["name"],

                    "address" =>
                        $sourceWarehouse[
                            "complete_address"
                        ],

                    "lat" =>
                        $sourceWarehouse["lat"],

                    "lng" =>
                        $sourceWarehouse["lng"]
                );
            }
        }
    }

    if (count($sourceWarehouses) <= 0) {
        throw new Exception(
            "No source warehouse was found in the Delivery Receipt details."
        );
    }

    $primaryOrigin =
        $sourceWarehouses[0];

    // --------------------------------------------------
    // Resolve destination warehouse or saved location
    // --------------------------------------------------
    $destination = array(
        "source_type" =>
            "SAVED_LOCATION",

        "warehouse_id" =>
            null,

        "saved_location_id" =>
            null,

        "name" =>
            $resolvedDestinationName,

        "address" =>
            $resolvedDestinationAddress,

        "lat" =>
            null,

        "lng" =>
            null
    );

    $destinationType =
        isset($dr["destination_type"])
            ? strtoupper(
                trim($dr["destination_type"])
              )
            : "OTHER";

    if ($destinationType == "WAREHOUSE") {

        $destinationWarehouse = null;

        $destinationWarehouseId =
            !empty($dr["destination_location_id"])
                ? (int)$dr[
                    "destination_location_id"
                  ]
                : 0;

        if ($destinationWarehouseId > 0) {

            $rsDestinationWarehouse =
                DB::Query("
                    SELECT
                        id,
                        warehouse_code,
                        name,
                        complete_address,
                        lat,
                        `long` AS lng
                    FROM warehouse
                    WHERE id =
                        ".$destinationWarehouseId."
                    LIMIT 1
                ");

            $destinationWarehouse =
                $rsDestinationWarehouse
                    ? $rsDestinationWarehouse
                        ->fetchAssoc()
                    : null;
        }

        if (
            !$destinationWarehouse &&
            !empty(
                $dr[
                    "destination_warehouse_code"
                ]
            )
        ) {

            $destinationCode =
                $dr[
                    "destination_warehouse_code"
                ];

            $rsDestinationWarehouse =
                DB::Query("
                    SELECT
                        id,
                        warehouse_code,
                        name,
                        complete_address,
                        lat,
                        `long` AS lng
                    FROM warehouse
                    WHERE warehouse_code = '" .
                        db_addslashes(
                            $destinationCode
                        ) .
                    "'
                    LIMIT 1
                ");

            $destinationWarehouse =
                $rsDestinationWarehouse
                    ? $rsDestinationWarehouse
                        ->fetchAssoc()
                    : null;
        }

        if ($destinationWarehouse) {

            $destination = array(
                "source_type" =>
                    "WAREHOUSE",

                "warehouse_id" =>
                    (int)$destinationWarehouse["id"],

                "saved_location_id" =>
                    null,

                "name" =>
                    $destinationWarehouse["name"],

                "address" =>
                    $destinationWarehouse[
                        "complete_address"
                    ],

                "lat" =>
                    $destinationWarehouse["lat"],

                "lng" =>
                    $destinationWarehouse["lng"]
            );
        } else {

            /*
               Destination type may have been left at its
               default WAREHOUSE value. Use the resolved
               text destination instead of failing.
            */
            $destination["source_type"] =
                "SAVED_LOCATION";
        }
    } elseif (
        !empty($dr["destination_location_id"])
    ) {

        $savedLocationId =
            (int)$dr["destination_location_id"];

        $rsSavedLocation = DB::Query("
            SELECT
                id,
                location_name,
                address,
                lat,
                lng
            FROM saved_location
            WHERE id = ".$savedLocationId."
            LIMIT 1
        ");

        $savedLocation =
            $rsSavedLocation
                ? $rsSavedLocation->fetchAssoc()
                : null;

        if ($savedLocation) {

            $destination = array(
                "source_type" =>
                    "SAVED_LOCATION",

                "warehouse_id" =>
                    null,

                "saved_location_id" =>
                    (int)$savedLocation["id"],

                "name" =>
                    $firstNonEmpty(
                        array(
                            $savedLocation[
                                "location_name"
                            ],
                            $resolvedDestinationName
                        ),
                        $resolvedDestinationName
                    ),

                "address" =>
                    $firstNonEmpty(
                        array(
                            $savedLocation["address"],
                            $resolvedDestinationAddress
                        ),
                        ""
                    ),

                "lat" =>
                    $savedLocation["lat"],

                "lng" =>
                    $savedLocation["lng"]
            );
        }
    }

    // --------------------------------------------------
    // Generate Trip Ticket number
    // --------------------------------------------------
    $stage = "Generating Trip Ticket number";

    $rsNumbering = DB::Query("
        SELECT
            id,
            prefix,
            digit_length,
            next_no
        FROM transaction_numbering
        WHERE transaction_code = '" .
            db_addslashes(
                $transactionCode
            ) .
        "'
          AND is_active = 1
        LIMIT 1
        FOR UPDATE
    ");

    $numbering =
        $rsNumbering
            ? $rsNumbering->fetchAssoc()
            : null;

    if (!$numbering) {
        throw new Exception(
            "No active transaction numbering setup was found for TT."
        );
    }

    $numberingId =
        (int)$numbering["id"];

    $prefix =
        trim($numbering["prefix"]);

    $digitLength =
        (int)$numbering["digit_length"];

    $nextNo =
        (int)$numbering["next_no"];

    if ($prefix == "") {
        $prefix = "TT";
    }

    if ($digitLength <= 0) {
        $digitLength = 5;
    }

    if ($nextNo <= 0) {
        $nextNo = 1;
    }

    $tripTicketNo =
        $prefix .
        str_pad(
            $nextNo,
            $digitLength,
            "0",
            STR_PAD_LEFT
        );

    $rsDuplicateNumber = DB::Query("
        SELECT id
        FROM trip_ticket
        WHERE trip_ticket_no = '" .
            db_addslashes(
                $tripTicketNo
            ) .
        "'
        LIMIT 1
    ");

    if (
        $rsDuplicateNumber &&
        $rsDuplicateNumber->fetchAssoc()
    ) {
        throw new Exception(
            "Trip Ticket number " .
            $tripTicketNo .
            " already exists. Check transaction numbering."
        );
    }

    // --------------------------------------------------
    // Dates and route
    // --------------------------------------------------
    $issueDate =
        !empty($dr["issue_date"])
            ? $dr["issue_date"]
            : date("Y-m-d");

    $dispatchDate =
        !empty($dr["dispatch_date"])
            ? $dr["dispatch_date"]
            : $issueDate;

    $dispatchDatetime =
        $dispatchDate .
        " 08:00:00";

    $routeNames = array();

    foreach (
        $sourceWarehouses
        as $sourceWarehouse
    ) {
        $routeNames[] =
            $sourceWarehouse["name"];
    }

    $routeNames[] =
        $destination["name"];

    $routeDescription =
        implode(
            " to ",
            $routeNames
        );

    $destinationText =
        $destination["name"];

    if (
        !empty($destination["address"])
    ) {
        $destinationText .=
            "\n" .
            $destination["address"];
    }

    $transporterType =
        !empty($dr["transporter_type"])
            ? strtoupper(
                trim($dr["transporter_type"])
              )
            : "DSWD_FLEET";

    $validTransporterTypes = array(
        "DSWD_FLEET",
        "SERVICE_PROVIDER",
        "GOVERNMENT_ASSET",
        "PARTNER_WFP_TRANSPORT"
    );

    if (
        !in_array(
            $transporterType,
            $validTransporterTypes
        )
    ) {
        $transporterType =
            "DSWD_FLEET";
    }

    $createdBy =
        isset($_SESSION["UserID"])
            ? (int)$_SESSION["UserID"]
            : 0;

    // --------------------------------------------------
    // Create Trip Ticket header
    // --------------------------------------------------
    $stage = "Creating Trip Ticket header";

    $insertTripTicketSql = "
        INSERT INTO trip_ticket
        (
            control_no,
            trip_ticket_no,
            form_type,

            logistics_job_id,
            delivery_receipt_id,
            request_dispatch_plan_id,

            request_date,
            trip_date_from,
            trip_date_to,
            issue_date,
            dispatch_datetime,

            driver_name,
            driver_contact_no,
            helper_name,
            helper_contact_no,

            vehicle_id,
            primary_plate_no,
            plate_no,
            vehicle_type,

            transporter_type,
            third_party_provider_id,
            provider_id,

            route_from_location_id,
            route_to_location_id,

            origin_source_type,
            origin_saved_location_id,

            destination_source_type,
            destination_saved_location_id,

            origin_location_name,
            origin_address,
            origin_lat,
            origin_lng,

            destination_location_name,
            destination_address,
            destination_lat,
            destination_lng,

            expected_departure_datetime,
            current_lat,
            current_lng,
            eta_text,

            route_description,
            destination_text,

            purpose,
            cargo_description,

            receiver_name,
            receiver_contact_no,

            trip_status,
            delivery_status,
            app_trip_status,
            status,

            remarks,

            created_by,
            created_at,
            updated_by,
            updated_at
        )
        VALUES
        (
            ".$sqlText(
                $dr["delivery_receipt_no"]
            ).",

            ".$sqlText(
                $tripTicketNo
            ).",

            'FORM_A',

            ".$sqlInt(
                isset($dr["logistics_job_id"])
                    ? $dr["logistics_job_id"]
                    : null
            ).",

            ".$drId.",

            ".$sqlInt(
                isset(
                    $dr[
                        "request_dispatch_plan_id"
                    ]
                )
                    ? $dr[
                        "request_dispatch_plan_id"
                      ]
                    : null
            ).",

            ".$sqlText($issueDate).",
            ".$sqlText($dispatchDate).",
            ".$sqlText($dispatchDate).",
            ".$sqlText($issueDate).",
            ".$sqlText($dispatchDatetime).",

            ".$sqlText(
                isset($dr["driver_name"])
                    ? $dr["driver_name"]
                    : null
            ).",

            ".$sqlText(
                isset($dr["driver_contact_no"])
                    ? $dr["driver_contact_no"]
                    : null
            ).",

            ".$sqlText(
                isset($dr["helper_name"])
                    ? $dr["helper_name"]
                    : null
            ).",

            ".$sqlText(
                isset($dr["helper_contact_no"])
                    ? $dr["helper_contact_no"]
                    : null
            ).",

            ".$sqlInt(
                isset($dr["vehicle_id"])
                    ? $dr["vehicle_id"]
                    : null
            ).",

            ".$sqlText(
                isset($dr["vehicle_plate_no"])
                    ? $dr["vehicle_plate_no"]
                    : null
            ).",

            ".$sqlText(
                isset($dr["vehicle_plate_no"])
                    ? $dr["vehicle_plate_no"]
                    : null
            ).",

            ".$sqlText(
                isset($dr["vehicle_type"])
                    ? $dr["vehicle_type"]
                    : null
            ).",

            ".$sqlText(
                $transporterType
            ).",

            ".$sqlInt(
                isset(
                    $dr[
                        "third_party_provider_id"
                    ]
                )
                    ? $dr[
                        "third_party_provider_id"
                      ]
                    : null
            ).",

            ".$sqlInt(
                isset($dr["provider_id"])
                    ? $dr["provider_id"]
                    : null
            ).",

            ".$sqlInt(
                $primaryOrigin["warehouse_id"]
            ).",

            ".$sqlInt(
                $destination["warehouse_id"]
            ).",

            'WAREHOUSE',
            NULL,

            ".$sqlText(
                $destination["source_type"]
            ).",

            ".$sqlInt(
                $destination[
                    "saved_location_id"
                ]
            ).",

            ".$sqlText(
                $primaryOrigin["name"]
            ).",

            ".$sqlText(
                $primaryOrigin["address"]
            ).",

            ".$sqlDecimal(
                $primaryOrigin["lat"]
            ).",

            ".$sqlDecimal(
                $primaryOrigin["lng"]
            ).",

            ".$sqlText(
                $destination["name"]
            ).",

            ".$sqlText(
                $destination["address"]
            ).",

            ".$sqlDecimal(
                $destination["lat"]
            ).",

            ".$sqlDecimal(
                $destination["lng"]
            ).",

            ".$sqlText(
                $dispatchDatetime
            ).",

            ".$sqlDecimal(
                $primaryOrigin["lat"]
            ).",

            ".$sqlDecimal(
                $primaryOrigin["lng"]
            ).",

            'Trip not started',

            ".$sqlText(
                $routeDescription
            ).",

            ".$sqlText(
                $destinationText
            ).",

            ".$sqlText(
                isset($dr["purpose"])
                    ? substr(
                        $dr["purpose"],
                        0,
                        255
                    )
                    : null
            ).",

            ".$sqlText(
                $cargoDescription
            ).",

            ".$sqlText(
                $resolvedRecipientName
            ).",

            ".$sqlText(
                $resolvedRecipientContact
            ).",

            'DRAFT',
            'PLANNED',
            'NOT_STARTED',
            'Pending',

            ".$sqlText(
                "Auto-created from Delivery Receipt " .
                $dr["delivery_receipt_no"]
            ).",

            ".$sqlInt($createdBy).",
            NOW(),
            ".$sqlInt($createdBy).",
            NOW()
        )
    ";

    DB::Exec($insertTripTicketSql);

    $rsCreatedId = DB::Query("
        SELECT LAST_INSERT_ID() AS id
    ");

    $createdIdRow =
        $rsCreatedId
            ? $rsCreatedId->fetchAssoc()
            : null;

    $tripTicketId =
        $createdIdRow
            ? (int)$createdIdRow["id"]
            : 0;

    if ($tripTicketId <= 0) {
        throw new Exception(
            "Trip Ticket header was not created."
        );
    }

    // --------------------------------------------------
    // Create Trip Ticket route legs
    // --------------------------------------------------
    $stage = "Creating Trip Ticket route details";

    $routeStops =
        $sourceWarehouses;

    $routeStops[] =
        $destination;

    $routeLegCount = 0;

    for (
        $index = 0;
        $index < count($routeStops) - 1;
        $index++
    ) {

        $departure =
            $routeStops[$index];

        $arrival =
            $routeStops[$index + 1];

        $lineNo =
            $index + 1;

        $departureWarehouseId =
            $departure["source_type"] ==
                "WAREHOUSE"
                ? $departure["warehouse_id"]
                : null;

        $departureSavedLocationId =
            $departure["source_type"] ==
                "SAVED_LOCATION"
                ? $departure[
                    "saved_location_id"
                  ]
                : null;

        $arrivalWarehouseId =
            $arrival["source_type"] ==
                "WAREHOUSE"
                ? $arrival["warehouse_id"]
                : null;

        $arrivalSavedLocationId =
            $arrival["source_type"] ==
                "SAVED_LOCATION"
                ? $arrival[
                    "saved_location_id"
                  ]
                : null;

        DB::Exec("
            INSERT INTO trip_ticket_detail
            (
                trip_ticket_id,
                line_no,
                trip_date,
                passenger_name,

                departure_source_type,
                departure_warehouse_id,
                departure_saved_location_id,
                departure_location_name,
                departure_address,
                departure_lat,
                departure_lng,
                place_of_departure,
                departure_time,

                arrival_source_type,
                arrival_warehouse_id,
                arrival_saved_location_id,
                arrival_location_name,
                arrival_address,
                arrival_lat,
                arrival_lng,
                place_of_arrival,

                alternate_plate_no,
                app_detail_status,
                remarks,
                created_at
            )
            VALUES
            (
                ".$tripTicketId.",
                ".$lineNo.",
                ".$sqlText($dispatchDate).",
                ".$sqlText(
                    $resolvedRecipientName
                ).",

                ".$sqlText(
                    $departure["source_type"]
                ).",

                ".$sqlInt(
                    $departureWarehouseId
                ).",

                ".$sqlInt(
                    $departureSavedLocationId
                ).",

                ".$sqlText(
                    $departure["name"]
                ).",

                ".$sqlText(
                    $departure["address"]
                ).",

                ".$sqlDecimal(
                    $departure["lat"]
                ).",

                ".$sqlDecimal(
                    $departure["lng"]
                ).",

                ".$sqlText(
                    $departure["name"]
                ).",

                " .
                (
                    $index == 0
                        ? "'08:00:00'"
                        : "NULL"
                ) .
                ",

                ".$sqlText(
                    $arrival["source_type"]
                ).",

                ".$sqlInt(
                    $arrivalWarehouseId
                ).",

                ".$sqlInt(
                    $arrivalSavedLocationId
                ).",

                ".$sqlText(
                    $arrival["name"]
                ).",

                ".$sqlText(
                    $arrival["address"]
                ).",

                ".$sqlDecimal(
                    $arrival["lat"]
                ).",

                ".$sqlDecimal(
                    $arrival["lng"]
                ).",

                ".$sqlText(
                    $arrival["name"]
                ).",

                ".$sqlText(
                    isset($dr["vehicle_plate_no"])
                        ? $dr["vehicle_plate_no"]
                        : null
                ).",

                'NOT_STARTED',

                ".$sqlText(
                    "Auto-created from Delivery Receipt " .
                    $dr["delivery_receipt_no"]
                ).",

                NOW()
            )
        ");

        $routeLegCount++;
    }

    if ($routeLegCount <= 0) {
        throw new Exception(
            "No Trip Ticket route detail was created."
        );
    }

    // --------------------------------------------------
    // Link DR and increment numbering
    // --------------------------------------------------
    $stage = "Finalizing Trip Ticket";

    DB::Exec("
        UPDATE delivery_receipt
        SET
            trip_ticket_id =
                ".$tripTicketId.",

            warehouse_id =
                ".$sqlInt(
                    $primaryOrigin[
                        "warehouse_id"
                    ]
                ).",

            source_location_id =
                ".$sqlInt(
                    $primaryOrigin[
                        "warehouse_id"
                    ]
                ).",

            origin_warehouse_code =
                ".$sqlText(
                    $primaryOrigin[
                        "warehouse_code"
                    ]
                ).",

            origin_warehouse_name =
                ".$sqlText(
                    $primaryOrigin["name"]
                ).",

            updated_at = NOW()

        WHERE id = ".$drId."
    ");

    DB::Exec("
        UPDATE transaction_numbering
        SET
            next_no = next_no + 1,
            updated_at = NOW()
        WHERE id = ".$numberingId."
    ");

    DB::Exec("COMMIT");

    $result["success"] = true;

    $result["message"] =
        "Trip Ticket " .
        $tripTicketNo .
        " created successfully.";

    $result["trip_ticket_id"] =
        $tripTicketId;

    $result["trip_ticket_no"] =
        $tripTicketNo;

    $result["route_leg_count"] =
        $routeLegCount;

    $result["cargo_total_qty"] =
        $cargoTotalQty;

} catch (\Throwable $e) {

    if ($transactionStarted) {

        try {
            DB::Exec("ROLLBACK");
        } catch (\Throwable $rollbackError) {
            // Keep the original error.
        }
    }

    $result["success"] = false;

    $result["message"] =
        "Create Trip Ticket failed during " .
        $stage .
        ": " .
        $e->getMessage();

    $result["error_type"] =
        get_class($e);
};

		RunnerContext::pop();
		echo runner_json_encode( $result);
		$button->deleteTempFiles();
	}

		// custom button - Production Schedule
	function buttonHandler_2566( $_params )
	{
		$result = array();

		$button = $this->prepareButtonContext( $_params );
		$ajax = $button; 
		$keys = $button->getKeys();

		// .NET naming
		$parameters = $_params;
		$params = &$_params;

		// ======================================================
// SERVER - CREATE PRODUCTION SCHEDULE
// Top/List Button from production_suggestion_detail
// Uses run_id from URL masterkey1
// IMPORTANT: No early return; use break so PHPRunner can return JSON.
// ======================================================

$result["success"] = false;
$result["message"] = "";
$result["production_plan_id"] = 0;
$result["plan_no"] = "";

$run_id = isset($params["run_id"]) ? intval($params["run_id"]) : 0;

// Simple escape helper
$esc = function($value) {
    if ($value === null) {
        return "NULL";
    }
    return "'" . str_replace("'", "''", $value) . "'";
};

do {

    // ------------------------------------------------------
    // 0. Validate run id
    // ------------------------------------------------------
    if ($run_id <= 0) {
        $result["message"] = "Invalid Production Suggestion Run ID.";
        break;
    }

    // ------------------------------------------------------
    // 1. Get production suggestion run
    // ------------------------------------------------------
    $rsRun = DB::Query("
        SELECT
            id,
            run_no,
            warehouse_id,
            warehouse_code,
            warehouse_name,
            status
        FROM production_suggestion_run
        WHERE id = ".$run_id."
        LIMIT 1
    ");

    $run = $rsRun ? $rsRun->fetchAssoc() : null;

    if (!$run) {
        $result["message"] = "Production Suggestion Run not found.";
        break;
    }

    if (strtoupper(trim($run["status"])) == "SCHEDULED") {
        $result["message"] = "This suggestion run is already scheduled.";
        break;
    }

    // Shared quantity expression
    $qtyExpr = "
        CASE
            WHEN IFNULL(target_qty, 0) > 0 THEN target_qty
            ELSE suggested_qty
        END
    ";

    // ------------------------------------------------------
    // 2. Check valid rows
    // ------------------------------------------------------
    $rsValid = DB::Query("
        SELECT COUNT(*) AS cnt
        FROM production_suggestion_detail
        WHERE run_id = ".$run_id."
          AND IFNULL(max_possible_qty, 0) > 0
          AND IFNULL(CAST(status AS CHAR), '') <> 'SCHEDULED'
          AND (".$qtyExpr.") > 0
    ");

    $valid = $rsValid ? $rsValid->fetchAssoc() : null;
    $validCount = $valid ? intval($valid["cnt"]) : 0;

    if ($validCount <= 0) {
        $result["message"] = "No valid suggested finished goods found. Only rows with max possible quantity greater than zero can be scheduled.";
        break;
    }

    // ------------------------------------------------------
    // 3. Validate target qty should not exceed max possible qty
    // ------------------------------------------------------
    $rsInvalid = DB::Query("
        SELECT COUNT(*) AS cnt
        FROM production_suggestion_detail
        WHERE run_id = ".$run_id."
          AND IFNULL(max_possible_qty, 0) > 0
          AND IFNULL(CAST(status AS CHAR), '') <> 'SCHEDULED'
          AND (".$qtyExpr.") > max_possible_qty
    ");

    $invalid = $rsInvalid ? $rsInvalid->fetchAssoc() : null;
    $invalidCount = $invalid ? intval($invalid["cnt"]) : 0;

    if ($invalidCount > 0) {
        $result["message"] = "Some target quantities exceed the max possible quantity. Please adjust them first.";
        break;
    }

    // ------------------------------------------------------
    // 4. Get transaction numbering for Production Plan
    // ------------------------------------------------------
    $rsNum = DB::Query("
        SELECT
            id,
            prefix,
            digit_length,
            next_no
        FROM transaction_numbering
        WHERE transaction_code = 'PP'
          AND is_active = 1
        LIMIT 1
    ");

    $num = $rsNum ? $rsNum->fetchAssoc() : null;

    if (!$num) {
        $result["message"] = "Transaction numbering for PP / Production Plan was not found.";
        break;
    }

    $numbering_id = intval($num["id"]);
    $prefix = $num["prefix"];
    $digit_length = intval($num["digit_length"]);
    $next_no = intval($num["next_no"]);

    $plan_no = $prefix . str_pad($next_no, $digit_length, "0", STR_PAD_LEFT);

    // Avoid duplicate production plan number
    $rsDup = DB::Query("
        SELECT COUNT(*) AS cnt
        FROM production_plan
        WHERE plan_no = ".$esc($plan_no)."
    ");

    $dup = $rsDup ? $rsDup->fetchAssoc() : null;
    $dupCount = $dup ? intval($dup["cnt"]) : 0;

    if ($dupCount > 0) {
        $result["message"] = "Production Plan No. ".$plan_no." already exists. Please check PP transaction numbering next_no.";
        break;
    }

    $warehouse_id_sql = "NULL";

    if (isset($run["warehouse_id"]) && $run["warehouse_id"] !== "" && $run["warehouse_id"] !== null) {
        $warehouse_id_sql = intval($run["warehouse_id"]);
    }

    $remarks = "Created from Production Suggestion Run: ".$run["run_no"]." / Run ID: ".$run_id;

    // ------------------------------------------------------
    // 5. Insert production_plan header
    // ------------------------------------------------------
    $sqlHeader = "
        INSERT INTO production_plan (
            plan_no,
            plan_date,
            period_from,
            period_to,
            warehouse_id,
            production_area,
            shift_code,
            status,
            prepared_by,
            approved_by,
            approved_date,
            remarks,
            created_at,
            updated_at
        ) VALUES (
            ".$esc($plan_no).",
            CURDATE(),
            CURDATE(),
            CURDATE(),
            ".$warehouse_id_sql.",
            NULL,
            NULL,
            'Pending',
            NULL,
            NULL,
            NULL,
            ".$esc($remarks).",
            NOW(),
            NOW()
        )
    ";

    $okHeader = DB::Exec($sqlHeader);

    if ($okHeader === false) {
        $result["message"] = "Failed to create Production Plan header.";
        break;
    }

    $rsNew = DB::Query("SELECT LAST_INSERT_ID() AS production_plan_id");
    $newData = $rsNew ? $rsNew->fetchAssoc() : null;
    $production_plan_id = $newData ? intval($newData["production_plan_id"]) : 0;

    if ($production_plan_id <= 0) {
        $result["message"] = "Failed to get newly created Production Plan ID.";
        break;
    }

    // ------------------------------------------------------
    // 6. Insert production_plan_details
    // Item description and UOM are taken from item table
    // ------------------------------------------------------
    $sqlDetails = "
        INSERT INTO production_plan_details (
            production_plan_id,
            schedule_date,
            finished_good_id,
            work_description,
            production_line,
            target_qty,
            uom,
            priority_no,
            notes,
            created_at
        )
        SELECT
            ".$production_plan_id.",
            CURDATE(),
            psd.finished_good_id,
            LEFT(
                COALESCE(
                    NULLIF(i.description, ''),
                    NULLIF(psd.finished_good_description, ''),
                    NULLIF(psd.finished_good_name, ''),
                    NULLIF(psd.finished_good_sku, '')
                ),
                150
            ) AS work_description,
            NULL,
            CASE
                WHEN IFNULL(psd.target_qty, 0) > 0 THEN psd.target_qty
                ELSE psd.suggested_qty
            END AS target_qty,
            iu.name AS uom,
            psd.id AS priority_no,
            CONCAT(
                'From Production Suggestion Detail ID: ', psd.id,
                ' | SKU: ', COALESCE(psd.finished_good_sku, ''),
                ' | Max Possible Qty: ', COALESCE(psd.max_possible_qty, 0),
                ' | Components: ', COALESCE(psd.component_breakdown, '')
            ) AS notes,
            NOW()
        FROM production_suggestion_detail psd
        LEFT JOIN item i
            ON i.id = psd.finished_good_id
        LEFT JOIN itemunit iu
            ON iu.id = i.unit_id
        WHERE psd.run_id = ".$run_id."
          AND IFNULL(psd.max_possible_qty, 0) > 0
          AND IFNULL(CAST(psd.status AS CHAR), '') <> 'SCHEDULED'
          AND (
                CASE
                    WHEN IFNULL(psd.target_qty, 0) > 0 THEN psd.target_qty
                    ELSE psd.suggested_qty
                END
              ) > 0
          AND (
                CASE
                    WHEN IFNULL(psd.target_qty, 0) > 0 THEN psd.target_qty
                    ELSE psd.suggested_qty
                END
              ) <= psd.max_possible_qty
    ";

    $okDetails = DB::Exec($sqlDetails);

    if ($okDetails === false) {
        DB::Exec("DELETE FROM production_plan WHERE id = ".$production_plan_id);

        $result["message"] = "Failed to create Production Plan details. Header was removed.";
        break;
    }

    // ------------------------------------------------------
    // 7. Count inserted details
    // ------------------------------------------------------
    $rsInserted = DB::Query("
        SELECT COUNT(*) AS cnt
        FROM production_plan_details
        WHERE production_plan_id = ".$production_plan_id."
    ");

    $inserted = $rsInserted ? $rsInserted->fetchAssoc() : null;
    $insertedCount = $inserted ? intval($inserted["cnt"]) : 0;

    if ($insertedCount <= 0) {
        DB::Exec("DELETE FROM production_plan WHERE id = ".$production_plan_id);

        $result["message"] = "Production Plan header was created but no detail was inserted. Header was removed.";
        break;
    }

    // ------------------------------------------------------
    // 8. Update production suggestion detail
    // ------------------------------------------------------
    DB::Exec("
        UPDATE production_suggestion_detail
        SET
            status = 'SCHEDULED',
            selected_for_schedule = 1
        WHERE run_id = ".$run_id."
          AND IFNULL(max_possible_qty, 0) > 0
          AND IFNULL(CAST(status AS CHAR), '') <> 'SCHEDULED'
          AND (
                CASE
                    WHEN IFNULL(target_qty, 0) > 0 THEN target_qty
                    ELSE suggested_qty
                END
              ) > 0
          AND (
                CASE
                    WHEN IFNULL(target_qty, 0) > 0 THEN target_qty
                    ELSE suggested_qty
                END
              ) <= max_possible_qty
    ");

    // ------------------------------------------------------
    // 9. Update production suggestion run
    // ------------------------------------------------------
    DB::Exec("
        UPDATE production_suggestion_run
        SET status = 'SCHEDULED'
        WHERE id = ".$run_id."
    ");

    // ------------------------------------------------------
    // 10. Increment transaction numbering
    // ------------------------------------------------------
    DB::Exec("
        UPDATE transaction_numbering
        SET next_no = next_no + 1
        WHERE id = ".$numbering_id."
    ");

    // ------------------------------------------------------
    // 11. Return response
    // ------------------------------------------------------
    $result["success"] = true;
    $result["message"] = "Production Schedule created successfully. Plan No: ".$plan_no." with ".$insertedCount." item(s).";
    $result["production_plan_id"] = $production_plan_id;
    $result["plan_no"] = $plan_no;

} while (false);;

		RunnerContext::pop();
		echo runner_json_encode( $result);
		$button->deleteTempFiles();
	}

		// custom button - Submit Allocation
	function buttonHandler_2578( $_params )
	{
		$result = array();

		$button = $this->prepareButtonContext( $_params );
		$ajax = $button; 
		$keys = $button->getKeys();

		// .NET naming
		$parameters = $_params;
		$params = &$_params;

		$result["success"] = false;
$result["message"] = "";

$requestId =
    intval(
        $params["augmentation_request_id"]
    );


if ($requestId <= 0) {

    $result["message"] =
        "Invalid augmentation request.";

    return;
}


/* ============================================================
   CHECK HEADER
   ============================================================ */

$sql = DB::PrepareSQL(
    "
    SELECT allocation_status

    FROM augmentation_request

    WHERE augmentation_request_id = :1
    ",
    $requestId
);

$currentStatus =
    DB::DBLookup($sql);


if ($currentStatus != "FOR_ALLOCATION") {

    $result["message"] =
        "This request is not currently FOR_ALLOCATION.";

    return;
}


/* ============================================================
   CHECK FOR OVER-ALLOCATED REQUEST ITEMS
   ============================================================ */

$sql = DB::PrepareSQL(
    "
    SELECT COUNT(*)

    FROM
    (
        SELECT
            ari.augmentation_request_item_id,

            COALESCE(
                ari.dromic_original_quantity,
                ari.requested_qty
            ) AS requested_qty,

            COALESCE(
                SUM(
                    CASE

                        WHEN ara.allocation_status
                             IN ('PENDING','APPROVED')

                        THEN ara.allocated_qty

                        ELSE 0

                    END
                ),
                0
            ) AS allocated_qty

        FROM augmentation_request_item ari

        LEFT JOIN augmentation_request_allocation ara

            ON ara.augmentation_request_item_id =
               ari.augmentation_request_item_id

        WHERE ari.augmentation_request_id = :1

          AND ari.item_status NOT IN (
              'CANCELLED',
              'RETURNED'
          )

        GROUP BY
            ari.augmentation_request_item_id,
            ari.dromic_original_quantity,
            ari.requested_qty

        HAVING allocated_qty > requested_qty

    ) x
    ",
    $requestId
);

$overAllocated =
    intval(DB::DBLookup($sql));


if ($overAllocated > 0) {

    $result["message"] =
        "Submission stopped. One or more requested items are over-allocated.";

    return;
}


/* ============================================================
   CHECK THAT AT LEAST ONE ALLOCATION EXISTS
   ============================================================ */

$sql = DB::PrepareSQL(
    "
    SELECT COUNT(*)

    FROM augmentation_request_allocation

    WHERE augmentation_request_id = :1

      AND allocation_status = 'PENDING'

      AND allocated_qty > 0
    ",
    $requestId
);

$allocationCount =
    intval(DB::DBLookup($sql));


if ($allocationCount <= 0) {

    $result["message"] =
        "Please allocate inventory before submitting this request.";

    return;
}


/* ============================================================
   USER
   ============================================================ */

$userData =
    Security::currentUserData();

$userId = 0;

if (
    is_array($userData) &&
    isset($userData["ID"])
) {
    $userId =
        intval($userData["ID"]);
}


/* ============================================================
   MOVE TO DROMIC CONFIRMATION
   ============================================================ */

$sql = DB::PrepareSQL(
    "
    UPDATE augmentation_request

    SET
        allocation_status =
            'WAITING_DROMIC_CONFIRMATION',

        current_step =
            'WAITING_DROMIC_CONFIRMATION',

        date_allocated =
            COALESCE(
                date_allocated,
                CURDATE()
            ),

        dromic_allocation_go_signal_status =
            'PENDING',

        dromic_sync_status =
            'PENDING_WRITEBACK',

        updated_by = :1,

        updated_at = NOW()

    WHERE augmentation_request_id = :2
    ",
    $userId,
    $requestId
);

DB::Exec($sql);


if (DB::LastError()) {

    $result["message"] =
        "Unable to submit allocation: "
        . DB::LastError();

    return;
}


$result["success"] = true;

$result["message"] =
    "Allocation submitted for DROMIC confirmation.";;

		RunnerContext::pop();
		echo runner_json_encode( $result);
		$button->deleteTempFiles();
	}

		// custom button - Approve_Selected_Suppliers
	function buttonHandler_2580( $_params )
	{
		$result = array();

		$button = $this->prepareButtonContext( $_params );
		$ajax = $button; 
		$keys = $button->getKeys();

		// .NET naming
		$parameters = $_params;
		$params = &$_params;

		$result["success"] = false;
$result["txt"] = "";

$approvedCount = 0;
$skippedCount = 0;

/*
 * Get the currently logged-in PHPRunner user.
 */
$userData = Security::currentUserData();

$approvedBy = 0;

if (isset($userData["ID"])) {
    $approvedBy = (int)$userData["ID"];
} elseif (isset($userData["id"])) {
    $approvedBy = (int)$userData["id"];
}

$approvedBySQL = $approvedBy > 0
    ? (string)$approvedBy
    : "NULL";

DB::Exec("START TRANSACTION");

$dbError = DB::LastError();

if ($dbError != "") {
    $result["txt"] =
        "Unable to start supplier approval transaction: " .
        $dbError;
    return;
}

/*
 * Process all checked supplier records.
 */
while ($record = $button->getNextSelectedRecord()) {

    $supplierId = isset($record["id"])
        ? (int)$record["id"]
        : 0;

    if ($supplierId <= 0) {
        $skippedCount++;
        continue;
    }

    /*
     * Lock and validate the supplier record.
     */
    $rsSupplier = DB::Query("
        SELECT
            id,
            status
        FROM supplier
        WHERE id = " . $supplierId . "
        FOR UPDATE
    ");

    $dbError = DB::LastError();

    if ($dbError != "") {
        DB::Exec("ROLLBACK");

        $result["txt"] =
            "Approval failed while checking Supplier ID " .
            $supplierId . ": " . $dbError;

        return;
    }

    $supplierData = $rsSupplier
        ? $rsSupplier->fetchAssoc()
        : null;

    /*
     * Skip suppliers that no longer exist or were already processed.
     */
    if (
        !$supplierData ||
        $supplierData["status"] !== "Pending"
    ) {
        $skippedCount++;
        continue;
    }

    $approvalRemarks = db_addslashes(
        "Approved through the Approval Dashboard"
    );

    $sqlUpdate = "
        UPDATE supplier
        SET
            status = 'Approved',
            approved_by = " . $approvedBySQL . ",
            approved_date = NOW(),
            approval_remarks = '" . $approvalRemarks . "',
            updatedAt = NOW()
        WHERE id = " . $supplierId . "
          AND status = 'Pending'
    ";

    DB::Exec($sqlUpdate);

    $dbError = DB::LastError();

    if ($dbError != "") {
        DB::Exec("ROLLBACK");

        $result["txt"] =
            "Approval failed for Supplier ID " .
            $supplierId . ": " . $dbError;

        return;
    }

    $approvedCount++;
}

DB::Exec("COMMIT");

$dbError = DB::LastError();

if ($dbError != "") {
    DB::Exec("ROLLBACK");

    $result["txt"] =
        "Unable to complete the supplier approval: " .
        $dbError;

    return;
}

$result["success"] = true;

if ($approvedCount > 0) {
    $result["txt"] =
        $approvedCount .
        ($approvedCount === 1
            ? " supplier was approved successfully."
            : " suppliers were approved successfully.");
} else {
    $result["txt"] =
        "No pending suppliers were approved.";
}

if ($skippedCount > 0) {
    $result["txt"] .=
        " " . $skippedCount .
        ($skippedCount === 1
            ? " record was skipped because it was already processed."
            : " records were skipped because they were already processed.");
};

		RunnerContext::pop();
		echo runner_json_encode( $result);
		$button->deleteTempFiles();
	}

		// custom button - Create PO
	function buttonHandler_2592( $_params )
	{
		$result = array();

		$button = $this->prepareButtonContext( $_params );
		$ajax = $button; 
		$keys = $button->getKeys();

		// .NET naming
		$parameters = $_params;
		$params = &$_params;

		// ======================================================
// SERVER - CREATE PO FROM PURCHASE REQUEST
// PHPRunner Custom Button Server Event
//
// PR item_id          -> PO parent_item_id
// PO item_id          -> NULL
// PO description      -> NULL
// Mother Facility     -> carried forward
// UOM                 -> item.unit_id of parent item
// ======================================================

$result = array(
    "success" => false,
    "message" => "Unable to create Purchase Order."
);

DB::Exec("START TRANSACTION");

try {

    // --------------------------------------------------
    // Get PR ID
    // --------------------------------------------------
    $pr_id = 0;

    if (isset($params["keys"]["id"])) {
        $pr_id = (int)$params["keys"]["id"];
    } elseif (isset($params["keys"][0])) {
        $pr_id = (int)$params["keys"][0];
    } elseif (isset($keys["id"])) {
        $pr_id = (int)$keys["id"];
    } elseif (isset($keys[0])) {
        $pr_id = (int)$keys[0];
    }

    if ($pr_id <= 0) {
        throw new Exception(
            "No Purchase Request ID was received from the selected row."
        );
    }

    // --------------------------------------------------
    // Confirm required PO detail column exists
    // --------------------------------------------------
    $sqlColumnCheck = "
        SELECT COUNT(*) AS cnt
        FROM information_schema.COLUMNS
        WHERE TABLE_SCHEMA = DATABASE()
          AND TABLE_NAME = 'purchaseorderdetail'
          AND COLUMN_NAME = 'mother_facility_id'
    ";

    $rsColumnCheck = DB::Query($sqlColumnCheck);
    $columnCheck = $rsColumnCheck
        ? $rsColumnCheck->fetchAssoc()
        : null;

    if (
        !$columnCheck ||
        (int)$columnCheck["cnt"] === 0
    ) {
        throw new Exception(
            "The field purchaseorderdetail.mother_facility_id does not exist. Run the required ALTER TABLE script first."
        );
    }

    // --------------------------------------------------
    // Check PR and existing PO
    // --------------------------------------------------
    $sqlCheck = "
        SELECT
            pr.id,
            pr.reference_number,
            pr.`date`,
            pr.purpose,
            pr.fund_cluster_id,
            po.id AS existing_po_id,
            po.reference_number AS existing_po_reference_number
        FROM purchaserequest pr
        LEFT JOIN purchaseorder po
            ON po.pr_id = pr.id
        WHERE pr.id = " . $pr_id . "
        FOR UPDATE
    ";

    $rsCheck = DB::Query($sqlCheck);
    $pr = $rsCheck
        ? $rsCheck->fetchAssoc()
        : null;

    if (!$pr) {
        throw new Exception("Purchase Request not found.");
    }

    if (!empty($pr["existing_po_id"])) {
        throw new Exception(
            "This Purchase Request already has a Purchase Order: " .
            $pr["existing_po_reference_number"]
        );
    }

    // --------------------------------------------------
    // Check PR detail records
    // --------------------------------------------------
    $sqlCount = "
        SELECT COUNT(*) AS cnt
        FROM purchaserequestdetail
        WHERE pr_id = " . $pr_id . "
    ";

    $rsCount = DB::Query($sqlCount);
    $rowCount = $rsCount
        ? $rsCount->fetchAssoc()
        : null;

    if (
        !$rowCount ||
        (int)$rowCount["cnt"] === 0
    ) {
        throw new Exception(
            "Cannot create PO. This Purchase Request has no detail items."
        );
    }

    // --------------------------------------------------
    // Check PR details for missing Mother Facility
    // --------------------------------------------------
    $sqlMissingFacility = "
        SELECT COUNT(*) AS cnt
        FROM purchaserequestdetail
        WHERE pr_id = " . $pr_id . "
          AND mother_facility_id IS NULL
    ";

    $rsMissingFacility = DB::Query($sqlMissingFacility);
    $missingFacility = $rsMissingFacility
        ? $rsMissingFacility->fetchAssoc()
        : null;

    if (
        $missingFacility &&
        (int)$missingFacility["cnt"] > 0
    ) {
        throw new Exception(
            "One or more Purchase Request detail records have no Mother Facility."
        );
    }

    // --------------------------------------------------
    // Generate PO Number
    // --------------------------------------------------
    $transactionCode = "PO";

    $sqlNumbering = "
        SELECT
            id,
            prefix,
            digit_length,
            next_no
        FROM transaction_numbering
        WHERE transaction_code = '" .
            db_addslashes($transactionCode) . "'
          AND is_active = 1
        FOR UPDATE
    ";

    $rsNumbering = DB::Query($sqlNumbering);
    $numData = $rsNumbering
        ? $rsNumbering->fetchAssoc()
        : null;

    if (!$numData) {
        throw new Exception(
            "No active transaction numbering setup found for PO."
        );
    }

    $numberingId = (int)$numData["id"];
    $prefix = $numData["prefix"];
    $digitLength = (int)$numData["digit_length"];
    $nextNo = (int)$numData["next_no"];

    $po_ref =
        $prefix .
        str_pad(
            $nextNo,
            $digitLength,
            "0",
            STR_PAD_LEFT
        );

    DB::Exec("
        UPDATE transaction_numbering
        SET next_no = next_no + 1
        WHERE id = " . $numberingId . "
    ");

    // --------------------------------------------------
    // Fund cluster
    // --------------------------------------------------
    $fund_cluster_id_sql = "NULL";

    if (
        $pr["fund_cluster_id"] !== null &&
        $pr["fund_cluster_id"] !== ""
    ) {
        $fund_cluster_id_sql =
            (int)$pr["fund_cluster_id"];
    }

    // --------------------------------------------------
    // Insert PO Header
    // --------------------------------------------------
    $sqlInsertPO = "
        INSERT INTO purchaseorder
        (
            reference_number,
            delivery_date,
            delivery_term,
            payment_term,
            ord_number,
            ord_date,
            po_type,
            gross_purchase,
            discount_amount,
            net_amount,
            vat_amount,
            net_pay,
            createdAt,
            updatedAt,
            pr_id,
            fund_cluster_id,
            `date`,
            `status`
        )
        VALUES
        (
            " . db_prepare_string($po_ref) . ",
            NOW(),
            'FOR ENCODING',
            'FOR ENCODING',
            " . db_prepare_string($po_ref) . ",
            NOW(),
            'REGULAR',
            0,
            0,
            0,
            0,
            0,
            NOW(),
            NOW(),
            " . $pr_id . ",
            " . $fund_cluster_id_sql . ",
            CURDATE(),
            'Pending'
        )
    ";

    DB::Exec($sqlInsertPO);

    $po_id = DB::LastId();

    if (!$po_id) {
        throw new Exception("PO header was not created.");
    }

    // --------------------------------------------------
    // Insert PO Details
    // --------------------------------------------------
    $sqlInsertDetails = "
        INSERT INTO purchaseorderdetail
        (
            quantity,
            unit_cost,
            remarks,
            createdAt,
            updatedAt,
            purchase_order_id,
            item_id,
            parent_item_id,
            amount,
            item_description,
            uom,
            warehouse,
            mother_facility_id,
            pr_detail_id
        )
        SELECT
            prd.quantity,
            0 AS unit_cost,
            prd.remarks,
            NOW(),
            NOW(),
            " . $po_id . ",
            NULL AS item_id,
            prd.item_id AS parent_item_id,
            0 AS amount,
            NULL AS item_description,
            i.unit_id AS uom,
            prd.warehouse,
            prd.mother_facility_id,
            prd.id AS pr_detail_id
        FROM purchaserequestdetail prd
        LEFT JOIN item i
            ON i.id = prd.item_id
        WHERE prd.pr_id = " . $pr_id . "
    ";

    DB::Exec($sqlInsertDetails);

    // --------------------------------------------------
    // Validate detail insertion
    // --------------------------------------------------
    $sqlInsertedCount = "
        SELECT COUNT(*) AS cnt
        FROM purchaseorderdetail
        WHERE purchase_order_id = " . $po_id . "
    ";

    $rsInsertedCount = DB::Query($sqlInsertedCount);
    $insertedCount = $rsInsertedCount
        ? $rsInsertedCount->fetchAssoc()
        : null;

    if (
        !$insertedCount ||
        (int)$insertedCount["cnt"] === 0
    ) {
        throw new Exception(
            "PO details were not created. Verify that purchaseorderdetail contains mother_facility_id."
        );
    }

    // --------------------------------------------------
    // Update PR
    // --------------------------------------------------
    DB::Exec("
        UPDATE purchaserequest
        SET
            po_status = 'CONVERTED_TO_PO',
            po_created_at = NOW(),
            updatedAt = NOW()
        WHERE id = " . $pr_id . "
    ");

    DB::Exec("COMMIT");

    $result["success"] = true;
    $result["message"] =
        "Purchase Order created successfully.";

    $result["po_id"] = $po_id;
    $result["po_reference_number"] = $po_ref;
    $result["pr_reference_number"] =
        $pr["reference_number"];

} catch (Exception $e) {

    DB::Exec("ROLLBACK");

    $result["success"] = false;
    $result["message"] = $e->getMessage();
};

		RunnerContext::pop();
		echo runner_json_encode( $result);
		$button->deleteTempFiles();
	}

		// custom button - ProdtoRISP
	function buttonHandler_2602( $_params )
	{
		$result = array();

		$button = $this->prepareButtonContext( $_params );
		$ajax = $button; 
		$keys = $button->getKeys();

		// .NET naming
		$parameters = $_params;
		$params = &$_params;

		$result["success"] = false;
$result["message"] = "";
$result["raw_material_request_id"] = null;

try {

    $wo_id = 0;

    if (isset($params["production_work_order_id"])) {
        $wo_id = intval($params["production_work_order_id"]);
    }

    if ($wo_id <= 0) {
        $result["message"] = "Invalid Production Work Order ID.";
        return;
    }

    // ======================================================
    // GET PRODUCTION WORK ORDER HEADER
    // ======================================================

    $sqlWO = "
        SELECT
            id,
            work_order_no,
            work_order_date,
            production_plan_id,
            production_area,
            status,
            created_by
        FROM production_work_order
        WHERE id = " . $wo_id . "
        LIMIT 1
    ";

    $rsWO = DB::Query($sqlWO);
    $wo = $rsWO->fetchAssoc();

    if (!$wo) {
        $result["message"] = "Production Work Order not found.";
        return;
    }

    // ======================================================
    // CHECK COMPONENTS
    // ======================================================

    $sqlCheck = "
        SELECT COUNT(*) AS cnt
        FROM production_work_order_details pwd
        INNER JOIN item_component ic
            ON ic.parent_item_id = pwd.finished_good_id
        WHERE pwd.production_work_order_id = " . $wo_id . "
    ";

    $rsCheck = DB::Query($sqlCheck);
    $check = $rsCheck->fetchAssoc();

    if (!$check || intval($check["cnt"]) <= 0) {
        $result["message"] = "No raw material components found for this Production Work Order.";
        return;
    }

    // ======================================================
    // CHECK EXISTING RISP
    // If existing, delete old details and regenerate
    // ======================================================

    $sqlExisting = "
        SELECT id, risp_no
        FROM raw_material_request
        WHERE production_work_order_id = " . $wo_id . "
        LIMIT 1
    ";

    $rsExisting = DB::Query($sqlExisting);
    $existing = $rsExisting->fetchAssoc();

    if ($existing) {

        $raw_material_request_id = intval($existing["id"]);

        DB::Exec("
            DELETE FROM raw_material_request_details
            WHERE raw_material_request_id = " . $raw_material_request_id
        );

    } else {

        // ======================================================
        // GENERATE RISP NUMBER
        // ======================================================

        $prefix = "RISP";

        $sqlLast = "
            SELECT risp_no
            FROM raw_material_request
            WHERE risp_no LIKE '" . $prefix . "%'
            ORDER BY id DESC
            LIMIT 1
        ";

        $rsLast = DB::Query($sqlLast);
        $last = $rsLast->fetchAssoc();

        $nextNo = 1;

        if ($last && !empty($last["risp_no"])) {
            $lastNumber = intval(str_replace($prefix, "", $last["risp_no"]));
            $nextNo = $lastNumber + 1;
        }

        $risp_no = $prefix . str_pad($nextNo, 5, "0", STR_PAD_LEFT);

        $production_plan_id = "NULL";
        if (!empty($wo["production_plan_id"])) {
            $production_plan_id = intval($wo["production_plan_id"]);
        }

        $production_area = "";
        if (!empty($wo["production_area"])) {
            $production_area = db_addslashes($wo["production_area"]);
        }

        $requested_by = "NULL";
        if (!empty($wo["created_by"])) {
            $requested_by = intval($wo["created_by"]);
        }

        // ======================================================
        // INSERT RISP HEADER
        // ======================================================

        $sqlInsertHeader = "
            INSERT INTO raw_material_request
            (
                risp_no,
                risp_date,
                production_work_order_id,
                production_plan_id,
                requesting_unit,
                production_area,
                requested_by,
                status,
                remarks,
                created_at,
                updated_at
            )
            VALUES
            (
                '" . db_addslashes($risp_no) . "',
                CURDATE(),
                " . $wo_id . ",
                " . $production_plan_id . ",
                'Production',
                '" . $production_area . "',
                " . $requested_by . ",
                'Pending',
                'Auto-created from Work Order " . db_addslashes($wo["work_order_no"]) . "',
                NOW(),
                NOW()
            )
        ";

        DB::Exec($sqlInsertHeader);

        $raw_material_request_id = DB::LastId();

        if (!$raw_material_request_id) {
            $result["message"] = "Failed to create Raw Material Request header.";
            return;
        }
    }

    // ======================================================
    // INSERT RISP DETAILS
    // Formula:
    // requested_qty = production_work_order_details.target_qty * item_component.qty
    // ======================================================

    $sqlInsertDetails = "
        INSERT INTO raw_material_request_details
        (
            raw_material_request_id,
            line_no,
            raw_material_id,
            description,
            requested_qty,
            approved_qty,
            issued_qty,
            uom,
            purpose,
            is_buffer_item,
            remarks,
            created_at
        )
        SELECT
            " . intval($raw_material_request_id) . " AS raw_material_request_id,
            @line_no := @line_no + 1 AS line_no,
            x.raw_material_id,
            x.description,
            x.requested_qty,
            0 AS approved_qty,
            0 AS issued_qty,
            x.uom,
            'Production raw material request' AS purpose,
            0 AS is_buffer_item,
            x.remarks,
            NOW() AS created_at
        FROM
        (
            SELECT
                ic.component_item_id AS raw_material_id,

                COALESCE(
                    NULLIF(ic.component_description, ''),
                    NULLIF(rm.description, ''),
                    rm.name
                ) AS description,

                SUM(
                    IFNULL(pwd.target_qty, 0) * IFNULL(ic.qty, 0)
                ) AS requested_qty,

                iu.name AS uom,

                GROUP_CONCAT(
                    CONCAT(
                        'FG: ', IFNULL(fg.sku, pwd.finished_good_id),
                        ' | Production Qty: ', IFNULL(pwd.target_qty, 0),
                        ' | Component Qty: ', IFNULL(ic.qty, 0),
                        ' | Required Qty: ', IFNULL(pwd.target_qty, 0) * IFNULL(ic.qty, 0)
                    )
                    SEPARATOR '; '
                ) AS remarks

            FROM production_work_order_details pwd

            INNER JOIN item_component ic
                ON ic.parent_item_id = pwd.finished_good_id

            INNER JOIN item rm
                ON rm.id = ic.component_item_id

            LEFT JOIN item fg
                ON fg.id = pwd.finished_good_id

            LEFT JOIN itemunit iu
                ON iu.id = rm.unit_id

            WHERE pwd.production_work_order_id = " . $wo_id . "

            GROUP BY
                ic.component_item_id,
                COALESCE(
                    NULLIF(ic.component_description, ''),
                    NULLIF(rm.description, ''),
                    rm.name
                ),
                iu.name
        ) x
        CROSS JOIN (SELECT @line_no := 0) ln
        WHERE x.requested_qty > 0
        ORDER BY x.description
    ";

    DB::Exec($sqlInsertDetails);

    // ======================================================
    // VERIFY DETAILS
    // ======================================================

    $sqlVerify = "
        SELECT
            COUNT(*) AS detail_count,
            IFNULL(SUM(requested_qty), 0) AS total_requested_qty
        FROM raw_material_request_details
        WHERE raw_material_request_id = " . intval($raw_material_request_id) . "
    ";

    $rsVerify = DB::Query($sqlVerify);
    $verify = $rsVerify->fetchAssoc();

    if (!$verify || intval($verify["detail_count"]) <= 0) {
        $result["message"] = "RISP header was created, but no detail was inserted. Check target_qty and component qty.";
        $result["raw_material_request_id"] = $raw_material_request_id;
        return;
    }

    // ======================================================
    // OPTIONAL UPDATE WORK ORDER STATUS
    // ======================================================

    DB::Exec("
        UPDATE production_work_order
        SET status = 'RAW MATERIAL REQUESTED',
            updated_at = NOW()
        WHERE id = " . $wo_id
    );

    // ======================================================
    // RETURN SUCCESS
    // ======================================================

    $result["success"] = true;
    $result["message"] = "RISP generated successfully. Total requested qty: " . $verify["total_requested_qty"];
    $result["raw_material_request_id"] = $raw_material_request_id;

} catch (Exception $e) {

    $result["success"] = false;
    $result["message"] = "PHP/SQL Error: " . $e->getMessage();
    $result["raw_material_request_id"] = null;
};

		RunnerContext::pop();
		echo runner_json_encode( $result);
		$button->deleteTempFiles();
	}

		// custom button - RecontoRISP
	function buttonHandler_2608( $_params )
	{
		$result = array();

		$button = $this->prepareButtonContext( $_params );
		$ajax = $button; 
		$keys = $button->getKeys();

		// .NET naming
		$parameters = $_params;
		$params = &$_params;

		$result = array();
$result["success"] = false;
$result["message"] = "";

$rwoId = isset($params["reconditioning_wo_id"]) ? (int)$params["reconditioning_wo_id"] : 0;

if ($rwoId <= 0) {
    $result["message"] = "Invalid Reconditioning Work Order ID.";
    return;
}

try {

    DB::Exec("START TRANSACTION");

    // Check existing RISP
    $sqlCheck = "
        SELECT id, risp_no
        FROM raw_material_request
        WHERE source_type = 'RECONDITIONING_WORK_ORDER'
          AND source_id = ".$rwoId."
        LIMIT 1
    ";

    $rsCheck = DB::Query($sqlCheck);
    $existing = $rsCheck ? $rsCheck->fetchAssoc() : false;

    if ($existing) {
        DB::Exec("ROLLBACK");
        $result["message"] = "RISP already exists: ".$existing["risp_no"];
        return;
    }

    // Get Reconditioning WO header
    $sqlRwo = "
        SELECT *
        FROM reconditioning_work_order
        WHERE reconditioning_wo_id = ".$rwoId."
        LIMIT 1
    ";

    $rsRwo = DB::Query($sqlRwo);
    $rwo = $rsRwo ? $rsRwo->fetchAssoc() : false;

    if (!$rwo) {
        DB::Exec("ROLLBACK");
        $result["message"] = "Reconditioning Work Order not found.";
        return;
    }

    // Get components through detail table
    $sqlComp = "
        SELECT 
            rcd.*,
            rwod.item_id AS finished_good_id,
            rwod.sku_code AS finished_good_sku,
            rwod.item_description AS finished_good_description,
            rwod.qty_to_recondition
        FROM reconditioning_work_order_detail rwod
        INNER JOIN reconditioning_component_detail rcd
            ON rcd.reconditioning_wo_detail_id = rwod.reconditioning_wo_detail_id
        WHERE rwod.reconditioning_wo_id = ".$rwoId."
          AND IFNULL(rcd.qty, 0) > 0
          AND IFNULL(rcd.component_item_id, 0) > 0
        ORDER BY rcd.reconditioning_component_detail_id
    ";

    $rsComp = DB::Query($sqlComp);

    $components = array();

    while ($rsComp && ($row = $rsComp->fetchAssoc())) {
        $components[] = $row;
    }

    if (count($components) == 0) {
        DB::Exec("ROLLBACK");
        $result["message"] = "No valid reconditioning component details found.";
        return;
    }

    // Generate RISP number
    $sqlNum = "
        SELECT *
        FROM transaction_numbering
        WHERE transaction_code = 'RISP'
          AND is_active = 1
        LIMIT 1
    ";

    $rsNum = DB::Query($sqlNum);
    $num = $rsNum ? $rsNum->fetchAssoc() : false;

    if (!$num) {
        DB::Exec("ROLLBACK");
        $result["message"] = "No active transaction numbering setup for RISP.";
        return;
    }

    $prefix = $num["prefix"];
    $digitLength = (int)$num["digit_length"];
    $nextNo = (int)$num["next_no"];

    $rispNo = $prefix . str_pad($nextNo, $digitLength, "0", STR_PAD_LEFT);

    // Insert RISP header
    $insertHeader = DB::PrepareSQL("
        INSERT INTO raw_material_request
        (
            risp_no,
            risp_date,
            production_work_order_id,
            production_plan_id,
            source_type,
            source_id,
            source_no,
            requesting_unit,
            receiving_warehouse_id,
            production_area,
            method_of_transfer,
            status,
            remarks,
            created_at,
            updated_at
        )
        VALUES
        (
            ':1',
            CURDATE(),
            :2,
            NULL,
            'RECONDITIONING_WORK_ORDER',
            :3,
            ':4',
            'Reconditioning',
            :5,
            'Reconditioning Area',
            'For Reconditioning',
            'Pending',
            ':6',
            NOW(),
            NOW()
        )
    ",
        $rispNo,
        $rwoId,
        $rwoId,
        $rwo["reconditioning_wo_no"],
        ($rwo["warehouse_id"] ? $rwo["warehouse_id"] : 0),
        "Auto-created from Reconditioning Work Order ".$rwo["reconditioning_wo_no"]
    );

    DB::Exec($insertHeader);

    $rispId = DB::LastId();

    if (!$rispId) {
        DB::Exec("ROLLBACK");
        $result["message"] = "RISP header was not created.";
        return;
    }

    // Insert RISP details
    $lineNo = 1;

    foreach ($components as $c) {

        $componentItemId = (int)$c["component_item_id"];
        $qty = (float)$c["qty"];

        $insertDetail = DB::PrepareSQL("
            INSERT INTO raw_material_request_details
            (
                raw_material_request_id,
                line_no,
                raw_material_id,
                description,
                requested_qty,
                approved_qty,
                issued_qty,
                uom,
                batch_no,
                lot_no,
                purpose,
                remarks,
                created_at
            )
            VALUES
            (
                :1,
                :2,
                :3,
                ':4',
                :5,
                0,
                0,
                ':6',
                ':7',
                ':8',
                'Reconditioning raw material request',
                ':9',
                NOW()
            )
        ",
            $rispId,
            $lineNo,
            $componentItemId,
            $c["component_description"],
            $qty,
            $c["uom"],
            $c["from_batch_no"],
            $c["from_lot_no"],
            "From RWO ".$rwo["reconditioning_wo_no"]." | Action: ".$c["action_type"]
        );

        DB::Exec($insertDetail);

        $lineNo++;
    }

    // Update numbering
    DB::Exec("
        UPDATE transaction_numbering
        SET next_no = next_no + 1,
            updated_at = NOW()
        WHERE id = ".(int)$num["id"]
    );

    DB::Exec("COMMIT");

    $result["success"] = true;
    $result["message"] = "RISP created successfully: ".$rispNo;
    $result["risp_id"] = $rispId;
    $result["risp_no"] = $rispNo;

} catch (Throwable $e) {

    DB::Exec("ROLLBACK");

    $result["success"] = false;
    $result["message"] = "Server error: ".$e->getMessage();
};

		RunnerContext::pop();
		echo runner_json_encode( $result);
		$button->deleteTempFiles();
	}

		// custom button - QAtoReplacement
	function buttonHandler_2610( $_params )
	{
		$result = array();

		$button = $this->prepareButtonContext( $_params );
		$ajax = $button; 
		$keys = $button->getKeys();

		// .NET naming
		$parameters = $_params;
		$params = &$_params;

		$qaId = 0;

if (isset($params["qa_incoming_goods_id"])) {
    $qaId = (int)$params["qa_incoming_goods_id"];
} elseif (isset($params["keys"]) && is_array($params["keys"]) && count($params["keys"]) > 0) {
    $qaId = (int)$params["keys"][0];
}

if ($qaId <= 0) {
    $result["success"] = false;
    $result["message"] = "Invalid QA Incoming Goods record.";
    return;
}

$transactionCode = "RR";

DB::Exec("START TRANSACTION");

try {

    // Check if replacement request already exists
    $sqlCheck = "
        SELECT id, replacement_no
        FROM replacement_request
        WHERE source_reference_type = 'Quality Inspection'
          AND source_reference_id = " . $qaId . "
          AND status <> 'Cancelled'
        LIMIT 1
    ";

    $rsCheck = DB::Query($sqlCheck);
    $existing = $rsCheck ? $rsCheck->fetchAssoc() : null;

    if ($existing) {
        DB::Exec("ROLLBACK");

        $result["success"] = false;
        $result["message"] = "Replacement Request already exists: " . $existing["replacement_no"];
        $result["replacement_request_id"] = $existing["id"];
        return;
    }

    // Get QA Incoming Goods directly
    // Condition: basta rejected_quantity > 0, kahit ano status
    $sqlQA = "
        SELECT
            q.id AS qa_incoming_goods_id,
            q.qa_no,
            q.receiving_report_no,
            q.source_transaction_type,
            q.source_transaction_id,
            q.source_detail_id,
            q.po_no,
            q.dr_no,
            q.ar_no,
            q.supplier_donor,
            q.inspection_date,
            q.receiving_warehouse_id,
            q.receiving_warehouse_name,
            q.item_id,
            q.item_name,
            q.unit,
            q.delivered_quantity,
            q.inspected_quantity,
            q.accepted_quantity,
            q.rejected_quantity,
            q.returned_quantity,
            q.on_hold_quantity,
            q.batch_no,
            q.expiry_date,
            q.location AS rack_id,
            q.final_action_taken,
            q.receiving_status,
            q.approval_status,

            i.sku,
            i.reference_number AS stock_no,
            COALESCE(i.description, q.item_name) AS item_description,
            i.unit_id

        FROM qa_incoming_goods q
        LEFT JOIN item i ON i.id = q.item_id
        WHERE q.id = " . $qaId . "
          AND COALESCE(q.rejected_quantity, 0) > 0
        LIMIT 1
    ";

    $rsQA = DB::Query($sqlQA);

    if (!$rsQA) {
        DB::Exec("ROLLBACK");

        $result["success"] = false;
        $result["message"] = "Unable to read QA Incoming Goods.";
        return;
    }

    $qa = $rsQA->fetchAssoc();

    if (!$qa) {
        DB::Exec("ROLLBACK");

        $result["success"] = false;
        $result["message"] = "This QA record has no rejected quantity.";
        return;
    }

    $qtyForReplacement = (float)$qa["rejected_quantity"];

    if ($qtyForReplacement <= 0) {
        DB::Exec("ROLLBACK");

        $result["success"] = false;
        $result["message"] = "Rejected quantity must be greater than zero.";
        return;
    }

    // Get transaction number
    $sqlNo = "
        SELECT id, prefix, digit_length, next_no
        FROM transaction_numbering
        WHERE transaction_code = '" . db_addslashes($transactionCode) . "'
          AND is_active = 1
        LIMIT 1
        FOR UPDATE
    ";

    $rsNo = DB::Query($sqlNo);
    $noData = $rsNo ? $rsNo->fetchAssoc() : null;

    if (!$noData) {
        DB::Exec("ROLLBACK");

        $result["success"] = false;
        $result["message"] = "No active transaction numbering setup found for RR.";
        return;
    }

    $numberingId = (int)$noData["id"];
    $prefix = $noData["prefix"];
    $digitLength = (int)$noData["digit_length"];
    $nextNo = (int)$noData["next_no"];

    $replacementNo = $prefix . str_pad($nextNo, $digitLength, "0", STR_PAD_LEFT);

    $warehouseIdSql = "NULL";
    if ($qa["receiving_warehouse_id"] !== null && $qa["receiving_warehouse_id"] !== "") {
        $warehouseIdSql = (int)$qa["receiving_warehouse_id"];
    }

    $userIdSql = "NULL";
    if (isset($_SESSION["UserID"]) && is_numeric($_SESSION["UserID"])) {
        $userIdSql = (int)$_SESSION["UserID"];
    }

    // Insert replacement_request header
    $sqlHeader = "
        INSERT INTO replacement_request
        (
            replacement_no,
            request_date,
            request_type,
            source_reference_type,
            source_reference_id,
            warehouse_id,
            reason_for_replacement,
            remarks,
            status,
            created_by,
            created_at,
            updated_at
        )
        VALUES
        (
            '" . db_addslashes($replacementNo) . "',
            CURDATE(),
            'Replacement',
            'Quality Inspection',
            " . $qaId . ",
            " . $warehouseIdSql . ",
            '" . db_addslashes("Rejected item from QA Incoming Goods") . "',
            '" . db_addslashes("Generated from QA No. " . $qa["qa_no"]) . "',
            'Draft',
            " . $userIdSql . ",
            NOW(),
            NOW()
        )
    ";

    DB::Exec($sqlHeader);

    $replacementRequestId = DB::LastId();

    if (!$replacementRequestId) {
        DB::Exec("ROLLBACK");

        $result["success"] = false;
        $result["message"] = "Unable to create Replacement Request header.";
        return;
    }

    $unitIdSql = "NULL";
    if ($qa["unit_id"] !== null && $qa["unit_id"] !== "") {
        $unitIdSql = (int)$qa["unit_id"];
    }

    $rackIdSql = "NULL";
    if ($qa["rack_id"] !== null && $qa["rack_id"] !== "") {
        $rackIdSql = (int)$qa["rack_id"];
    }

    $expiryDateSql = "NULL";
    if ($qa["expiry_date"] !== null && $qa["expiry_date"] !== "") {
        $expiryDateSql = "'" . db_addslashes($qa["expiry_date"]) . "'";
    }

    // Insert replacement_request_items
    $sqlItem = "
        INSERT INTO replacement_request_items
        (
            replacement_request_id,
            item_id,
            stock_no,
            sku,
            item_description,
            unit_id,
            qty_requested,
            qty_defective,
            defect_reason,
            condition_notes,
            batch_no,
            expiration_date,
            item_status,
            rack_id,
            created_at,
            updated_at
        )
        VALUES
        (
            " . (int)$replacementRequestId . ",
            " . (int)$qa["item_id"] . ",
            '" . db_addslashes($qa["stock_no"]) . "',
            '" . db_addslashes($qa["sku"]) . "',
            '" . db_addslashes($qa["item_description"]) . "',
            " . $unitIdSql . ",
            " . $qtyForReplacement . ",
            " . $qtyForReplacement . ",
            '" . db_addslashes("Rejected during QA inspection") . "',
            '" . db_addslashes("Generated from QA No. " . $qa["qa_no"]) . "',
            '" . db_addslashes($qa["batch_no"]) . "',
            " . $expiryDateSql . ",
            'Pending',
            " . $rackIdSql . ",
            NOW(),
            NOW()
        )
    ";

    DB::Exec($sqlItem);

    // Update numbering
    DB::Exec("
        UPDATE transaction_numbering
        SET next_no = next_no + 1,
            updated_at = NOW()
        WHERE id = " . $numberingId . "
    ");

    DB::Exec("COMMIT");

    $result["success"] = true;
    $result["message"] = "Replacement Request created successfully: " . $replacementNo;
    $result["replacement_request_id"] = $replacementRequestId;
    $result["replacement_no"] = $replacementNo;

} catch (Exception $e) {

    DB::Exec("ROLLBACK");

    $result["success"] = false;
    $result["message"] = "Error creating Replacement Request: " . $e->getMessage();
};

		RunnerContext::pop();
		echo runner_json_encode( $result);
		$button->deleteTempFiles();
	}

		// custom button - View History
	function buttonHandler_2612( $_params )
	{
		$result = array();

		$button = $this->prepareButtonContext( $_params );
		$ajax = $button; 
		$keys = $button->getKeys();

		// .NET naming
		$parameters = $_params;
		$params = &$_params;

		$record =
    $button->getCurrentRecord();

if (!$record) {

    $result["success"] = false;
    $result["message"] =
        "Unable to identify the current record.";

    return;
}


$recordId = intval(
    $record["id"] ?? 0
);


if ($recordId <= 0) {

    $result["success"] = false;
    $result["message"] =
        "Invalid Production Plan.";

    return;
}


$result["success"] = true;

$result["module_code"] =
    "PRODUCTION_PLAN";

$result["record_id"] =
    $recordId;;

		RunnerContext::pop();
		echo runner_json_encode( $result);
		$button->deleteTempFiles();
	}

		// custom button - Create RISP
	function buttonHandler_2616( $_params )
	{
		$result = array();

		$button = $this->prepareButtonContext( $_params );
		$ajax = $button; 
		$keys = $button->getKeys();

		// .NET naming
		$parameters = $_params;
		$params = &$_params;

		$result["success"] = false;
$result["message"] = "";
$result["raw_material_request_id"] = null;

$wo_id = 0;

if (isset($keys["id"])) {
    $wo_id = intval($keys["id"]);
}

if ($wo_id <= 0) {
    $result["message"] = "Invalid Production Work Order.";
    return;
}

/*
    1. Get Production Work Order
*/
$sqlWO = "
    SELECT
        id,
        work_order_no,
        work_order_date,
        production_plan_id,
        production_area,
        status,
        created_by
    FROM production_work_order
    WHERE id = " . $wo_id . "
    LIMIT 1
";

$rsWO = DB::Query($sqlWO);
$wo = $rsWO->fetchAssoc();

if (!$wo) {
    $result["message"] = "Production Work Order not found.";
    return;
}

/*
    2. Prevent duplicate Raw Material Request
*/
$sqlExisting = "
    SELECT id
    FROM raw_material_request
    WHERE production_work_order_id = " . $wo_id . "
    LIMIT 1
";

$rsExisting = DB::Query($sqlExisting);
$existing = $rsExisting->fetchAssoc();

if ($existing) {
    $result["success"] = true;
    $result["message"] = "Raw Material Request already exists. Redirecting to existing request.";
    $result["raw_material_request_id"] = $existing["id"];
    return;
}

/*
    3. Check if work order has components
    Source:
    production_work_order_details.finished_good_id
    item_component.parent_item_id
    item_component.component_item_id
*/
$sqlCheckComponents = "
    SELECT COUNT(*) AS cnt
    FROM production_work_order_details wod
    INNER JOIN item_component ic
        ON ic.parent_item_id = wod.finished_good_id
    WHERE wod.production_work_order_id = " . $wo_id . "
";

$rsCheck = DB::Query($sqlCheckComponents);
$check = $rsCheck->fetchAssoc();

if (!$check || intval($check["cnt"]) <= 0) {
    $result["message"] = "No raw material components found for this Production Work Order.";
    return;
}

/*
    4. Generate RISP No.
    Format: RISP-YYYYMM-00001
*/
$prefix = "RISP-" . date("Ym") . "-";

$sqlLastNo = "
    SELECT risp_no
    FROM raw_material_request
    WHERE risp_no LIKE '" . $prefix . "%'
    ORDER BY id DESC
    LIMIT 1
";

$rsLastNo = DB::Query($sqlLastNo);
$lastNoRow = $rsLastNo->fetchAssoc();

$nextNo = 1;

if ($lastNoRow && !empty($lastNoRow["risp_no"])) {
    $lastNumber = intval(substr($lastNoRow["risp_no"], strlen($prefix)));
    $nextNo = $lastNumber + 1;
}

$risp_no = $prefix . str_pad($nextNo, 5, "0", STR_PAD_LEFT);

/*
    5. Insert Raw Material Request Header
*/
$production_plan_id = !empty($wo["production_plan_id"]) ? intval($wo["production_plan_id"]) : "NULL";
$production_area = isset($wo["production_area"]) ? db_addslashes($wo["production_area"]) : "";
$requested_by = !empty($wo["created_by"]) ? intval($wo["created_by"]) : "NULL";

$sqlInsertHeader = "
    INSERT INTO raw_material_request
    (
        risp_no,
        risp_date,
        production_work_order_id,
        production_plan_id,
        requesting_unit,
        production_area,
        requested_by,
        status,
        remarks,
        created_at,
        updated_at
    )
    VALUES
    (
        '" . db_addslashes($risp_no) . "',
        CURDATE(),
        " . $wo_id . ",
        " . $production_plan_id . ",
        'Production',
        '" . $production_area . "',
        " . $requested_by . ",
        'DRAFT',
        'Auto-generated from Production Work Order: " . db_addslashes($wo["work_order_no"]) . "',
        NOW(),
        NOW()
    )
";

DB::Exec($sqlInsertHeader);

$raw_material_request_id = DB::LastId();

if (!$raw_material_request_id) {
    $result["message"] = "Failed to create Raw Material Request header.";
    return;
}

/*
    6. Insert Raw Material Request Details
    Combines same raw material from multiple finished goods.
*/
$sqlInsertDetails = "
    INSERT INTO raw_material_request_details
    (
        raw_material_request_id,
        line_no,
        raw_material_id,
        description,
        requested_qty,
        approved_qty,
        issued_qty,
        uom,
        purpose,
        is_buffer_item,
        remarks,
        created_at
    )
    SELECT
        " . intval($raw_material_request_id) . " AS raw_material_request_id,
        ROW_NUMBER() OVER (ORDER BY rm.name) AS line_no,
        ic.component_item_id AS raw_material_id,
        COALESCE(ic.component_description, rm.description, rm.name) AS description,
        SUM(wod.target_qty * ic.qty) AS requested_qty,
        0 AS approved_qty,
        0 AS issued_qty,
        iu.name AS uom,
        CONCAT('For production work order ', '" . db_addslashes($wo["work_order_no"]) . "') AS purpose,
        0 AS is_buffer_item,
        GROUP_CONCAT(
            CONCAT(fg.sku, ' x ', wod.target_qty, ' @ ', ic.qty)
            SEPARATOR '; '
        ) AS remarks,
        NOW() AS created_at
    FROM production_work_order_details wod
    INNER JOIN item_component ic
        ON ic.parent_item_id = wod.finished_good_id
    INNER JOIN item rm
        ON rm.id = ic.component_item_id
    LEFT JOIN item fg
        ON fg.id = wod.finished_good_id
    LEFT JOIN itemunit iu
        ON iu.id = rm.unit_id
    WHERE wod.production_work_order_id = " . $wo_id . "
    GROUP BY
        ic.component_item_id,
        COALESCE(ic.component_description, rm.description, rm.name),
        iu.name
";

DB::Exec($sqlInsertDetails);

/*
    7. Final result
*/
$result["success"] = true;
$result["message"] = "Raw Material Request created successfully.";
$result["raw_material_request_id"] = $raw_material_request_id;;

		RunnerContext::pop();
		echo runner_json_encode( $result);
		$button->deleteTempFiles();
	}

		// custom button - Allocate
	function buttonHandler_2618( $_params )
	{
		$result = array();

		$button = $this->prepareButtonContext( $_params );
		$ajax = $button; 
		$keys = $button->getKeys();

		// .NET naming
		$parameters = $_params;
		$params = &$_params;

		$result["success"] = false;
$result["message"] = "";


/* ============================================================
   PARAMETERS FROM AVAILABLE INVENTORY ROW
   ============================================================ */

$requestId =
    intval($params["augmentation_request_id"]);

$requestItemId =
    intval($params["augmentation_request_item_id"]);

$itemId =
    intval($params["available_item_id"]);

$warehouseId =
    intval($params["warehouse_id"]);

$batchNo =
    trim((string)$params["batch_no"]);

$expiryDate =
    trim((string)$params["expiry_date"]);

$qty =
    floatval($params["allocated_qty"]);

$remarks =
    trim((string)$params["remarks"]);


/* ============================================================
   BASIC VALIDATION
   ============================================================ */

if ($requestId <= 0) {

    $result["message"] =
        "Invalid augmentation request.";

    return;
}


if ($requestItemId <= 0) {

    $result["message"] =
        "Invalid augmentation request item.";

    return;
}


if ($itemId <= 0) {

    $result["message"] =
        "Invalid inventory item.";

    return;
}


if ($warehouseId <= 0) {

    $result["message"] =
        "Invalid warehouse.";

    return;
}


if ($qty <= 0) {

    $result["message"] =
        "Allocated quantity must be greater than zero.";

    return;
}


/* ============================================================
   CHECK HEADER STATUS
   ============================================================ */

$sql = DB::PrepareSQL(
    "
    SELECT allocation_status

    FROM augmentation_request

    WHERE augmentation_request_id = :1
    ",
    $requestId
);

$requestStatus =
    DB::DBLookup($sql);


if ($requestStatus != "FOR_ALLOCATION") {

    $result["message"] =
        "This request is no longer open for allocation. "
        . "Current status: "
        . $requestStatus;

    return;
}


/* ============================================================
   RE-READ CURRENT AVAILABLE STOCK
   ============================================================ */

$sql = DB::PrepareSQL(
    "
    SELECT

        augmentation_request_id,
        augmentation_request_item_id,

        available_item_id,

        sku,
        item_description,

        warehouse_id,
        warehouse_code,
        warehouse_name,

        batch_no,
        expiry_date,

        requested_qty,
        requested_unit,

        available_qty

    FROM vw_augmentation_item_available_stock

    WHERE augmentation_request_item_id = :1

      AND available_item_id = :2

      AND warehouse_id = :3

      AND COALESCE(batch_no,'') = ':4'

      AND expiry_date <=>
          CAST(NULLIF(':5','') AS DATE)

    LIMIT 1
    ",
    $requestItemId,
    $itemId,
    $warehouseId,
    $batchNo,
    $expiryDate
);

$rs = DB::Query($sql);

$stock = $rs->fetchAssoc();


if (!$stock) {

    $result["message"] =
        "The selected stock record is no longer available. "
        . "Please refresh the dashboard.";

    return;
}


$liveAvailable =
    floatval($stock["available_qty"]);

$requestedQty =
    floatval($stock["requested_qty"]);


/* ============================================================
   CURRENT TOTAL ALLOCATED FOR REQUESTED ITEM
   ============================================================ */

$sql = DB::PrepareSQL(
    "
    SELECT COALESCE(SUM(allocated_qty),0)

    FROM augmentation_request_allocation

    WHERE augmentation_request_item_id = :1

      AND allocation_status IN (
          'PENDING',
          'APPROVED'
      )
    ",
    $requestItemId
);

$totalAllocated =
    floatval(DB::DBLookup($sql));


/* ============================================================
   REMAINING REQUESTED QUANTITY
   ============================================================ */

$remainingQty =
    $requestedQty - $totalAllocated;


if ($remainingQty < 0) {
    $remainingQty = 0;
}


/* ============================================================
   VALIDATE AGAINST REQUEST AND STOCK
   ============================================================ */

$maximumQty =
    min(
        $remainingQty,
        $liveAvailable
    );


if ($qty > ($maximumQty + 0.000001)) {

    $result["message"] =
        "Maximum quantity that can be allocated is "
        . number_format($maximumQty, 2)
        . ".";

    return;
}


/* ============================================================
   GET REQUEST ITEM LINE NUMBER
   ============================================================ */

$sql = DB::PrepareSQL(
    "
    SELECT line_no

    FROM augmentation_request_item

    WHERE augmentation_request_item_id = :1
    ",
    $requestItemId
);

$lineNo =
    intval(DB::DBLookup($sql));


if ($lineNo <= 0) {
    $lineNo = 1;
}


/* ============================================================
   CURRENT USER
   ============================================================ */

$userId = 0;

$userData =
    Security::currentUserData();

if (
    is_array($userData) &&
    isset($userData["ID"])
) {
    $userId =
        intval($userData["ID"]);
}


/* ============================================================
   CHECK IF SAME STOCK/BATCH ALREADY EXISTS
   ============================================================ */

$sql = DB::PrepareSQL(
    "
    SELECT allocation_id

    FROM augmentation_request_allocation

    WHERE augmentation_request_item_id = :1

      AND item_id = :2

      AND warehouse_id = :3

      AND COALESCE(batch_no,'') = ':4'

      AND expiry_date <=>
          CAST(NULLIF(':5','') AS DATE)

      AND allocation_status = 'PENDING'

    LIMIT 1
    ",
    $requestItemId,
    $itemId,
    $warehouseId,
    $batchNo,
    $expiryDate
);

$existingId =
    intval(DB::DBLookup($sql));


/* ============================================================
   IF SAME SKU/WH/BATCH ALREADY EXISTS:
   INCREASE ALLOCATED QTY
   ============================================================ */

if ($existingId > 0) {

    $sql = DB::PrepareSQL(
        "
        UPDATE augmentation_request_allocation

        SET
            allocated_qty =
                allocated_qty + :1,

            available_qty_snapshot = :2,

            remarks = ':3',

            updated_by = :4,

            updated_at = NOW()

        WHERE allocation_id = :5
        ",
        $qty,
        $liveAvailable,
        $remarks,
        $userId,
        $existingId
    );

    DB::Exec($sql);


    if (DB::LastError()) {

        $result["message"] =
            "Unable to update allocation: "
            . DB::LastError();

        return;
    }

}


/* ============================================================
   OTHERWISE INSERT NEW ALLOCATION ROW
   ============================================================ */

else {

    $data = array();


    $data["augmentation_request_id"] =
        $requestId;


    $data["augmentation_request_item_id"] =
        $requestItemId;


    $data["line_no"] =
        $lineNo;


    $data["item_id"] =
        $itemId;


    $data["sku"] =
        $stock["sku"];


    $data["item_description"] =
        $stock["item_description"];


    $data["warehouse_id"] =
        $warehouseId;


    $data["warehouse_code"] =
        $stock["warehouse_code"];


    $data["warehouse_name"] =
        $stock["warehouse_name"];


    $data["available_qty_snapshot"] =
        $liveAvailable;


    $data["allocated_qty"] =
        $qty;


    $data["allocation_status"] =
        "PENDING";


    if ($batchNo != "") {

        $data["batch_no"] =
            $batchNo;
    }


    if ($expiryDate != "") {

        $data["expiry_date"] =
            $expiryDate;
    }


    $data["unit"] =
        $stock["requested_unit"];


    $data["remarks"] =
        $remarks;


    $data["created_by"] =
        $userId;


    $data["updated_by"] =
        $userId;


    DB::Insert(
        "augmentation_request_allocation",
        $data
    );


    if (DB::LastError()) {

        $result["message"] =
            "Unable to create allocation: "
            . DB::LastError();

        return;
    }
}


/* ============================================================
   SUCCESS
   ============================================================ */

$result["success"] = true;

$result["message"] =
    number_format($qty, 2)
    . " "
    . $stock["requested_unit"]
    . " allocated successfully.";;

		RunnerContext::pop();
		echo runner_json_encode( $result);
		$button->deleteTempFiles();
	}

		// custom button - Production Forcast
	function buttonHandler_2624( $_params )
	{
		$result = array();

		$button = $this->prepareButtonContext( $_params );
		$ajax = $button; 
		$keys = $button->getKeys();

		// .NET naming
		$parameters = $_params;
		$params = &$_params;

		$warehouseId = isset($params["warehouse_id"]) ? (int)$params["warehouse_id"] : 0;
$warehouseCode = isset($params["warehouse_code"]) ? trim($params["warehouse_code"]) : "";

if ($warehouseId <= 0 && $warehouseCode == "") {
    $result["success"] = false;
    $result["message"] = "Missing warehouse ID or warehouse code.";
    return;
}

try {

    // Get warehouse
    if ($warehouseId > 0) {
        $rsWh = DB::Query("
            SELECT id, warehouse_code, name
            FROM warehouse
            WHERE id = ".$warehouseId."
            LIMIT 1
        ");
    } else {
        $rsWh = DB::Query("
            SELECT id, warehouse_code, name
            FROM warehouse
            WHERE warehouse_code = '".db_addslashes($warehouseCode)."'
            LIMIT 1
        ");
    }

    $wh = $rsWh->fetchAssoc();

    if (!$wh) {
        $result["success"] = false;
        $result["message"] = "Warehouse not found.";
        return;
    }

    $warehouseId = (int)$wh["id"];

    // Ensure PSF numbering exists
    DB::Exec("
        INSERT INTO transaction_numbering
        (
            transaction_code,
            transaction_name,
            prefix,
            digit_length,
            start_no,
            next_no,
            is_active
        )
        SELECT
            'PSF',
            'Production Suggestion Forecast',
            'PSF',
            5,
            1,
            1,
            1
        WHERE NOT EXISTS (
            SELECT 1
            FROM transaction_numbering
            WHERE transaction_code = 'PSF'
        )
    ");

    // Get numbering
    $rsNum = DB::Query("
        SELECT *
        FROM transaction_numbering
        WHERE transaction_code = 'PSF'
          AND is_active = 1
        LIMIT 1
    ");

    $num = $rsNum->fetchAssoc();

    if (!$num) {
        $result["success"] = false;
        $result["message"] = "No active transaction numbering for PSF.";
        return;
    }

    $runNo = $num["prefix"] . str_pad(
        (int)$num["next_no"],
        (int)$num["digit_length"],
        "0",
        STR_PAD_LEFT
    );

    // Check if forecast has food pack records.
    // IMPORTANT: no max_possible_qty > 0 filter here,
    // so even zero-producible food packs will be listed.
    $rsCheck = DB::Query("
        SELECT COUNT(*) AS cnt
        FROM vw_foodpack_forecast_ranking
        WHERE warehouse_id = ".$warehouseId."
    ");

    $check = $rsCheck->fetchAssoc();

    if ((int)$check["cnt"] <= 0) {
        $result["success"] = false;
        $result["message"] = "No food pack forecast records found. Please check item subcategory and BOM/item components.";
        return;
    }

    // Create forecast run
    DB::Exec("
        INSERT INTO production_suggestion_run
        (
            run_no,
            run_date,
            warehouse_id,
            warehouse_code,
            warehouse_name,
            status,
            remarks,
            created_at
        )
        VALUES
        (
            '".db_addslashes($runNo)."',
            NOW(),
            ".$warehouseId.",
            '".db_addslashes($wh["warehouse_code"])."',
            '".db_addslashes($wh["name"])."',
            'GENERATED',
            'Generated from food pack forecast including zero producible items',
            NOW()
        )
    ");

    $runId = DB::LastId();

    if (!$runId) {
        $result["success"] = false;
        $result["message"] = "Forecast run was not created.";
        return;
    }

    // Insert ALL food packs from forecast ranking,
    // including items with max_possible_qty = 0.
    DB::Exec("
        INSERT INTO production_suggestion_detail
        (
            run_id,
            warehouse_id,
            warehouse_code,
            warehouse_name,
            finished_good_id,
            finished_good_sku,
            finished_good_name,
            finished_good_description,
            component_count,
            insufficient_component_count,
            max_possible_qty,
            suggested_qty,
            target_qty,
            component_breakdown,
            selected_for_schedule,
            status,
            created_at
        )
        SELECT
            ".$runId.",
            warehouse_id,
            warehouse_code,
            warehouse_name,
            finished_good_id,
            finished_good_sku,
            finished_good_description,
            finished_good_description,
            component_count,
            insufficient_component_count,
            IFNULL(max_possible_qty, 0),
            IFNULL(max_possible_qty, 0),
            0,
            component_breakdown,
            0,
            CASE
                WHEN IFNULL(max_possible_qty, 0) > 0 THEN 'SUGGESTED'
                ELSE 'NO_STOCK'
            END,
            NOW()
        FROM vw_foodpack_forecast_ranking
        WHERE warehouse_id = ".$warehouseId."
        ORDER BY
            IFNULL(priority, 999) ASC,
            IFNULL(max_possible_qty, 0) DESC,
            finished_good_description ASC
    ");

    // Update numbering
    DB::Exec("
        UPDATE transaction_numbering
        SET next_no = next_no + 1
        WHERE transaction_code = 'PSF'
    ");

    $result["success"] = true;
    $result["message"] = "Production forecast generated successfully: ".$runNo;
    $result["run_id"] = $runId;
    $result["run_no"] = $runNo;

} catch (Exception $e) {

    $result["success"] = false;
    $result["message"] = $e->getMessage();
};

		RunnerContext::pop();
		echo runner_json_encode( $result);
		$button->deleteTempFiles();
	}

		// custom button - RISPtoSTF
	function buttonHandler_2626( $_params )
	{
		$result = array();

		$button = $this->prepareButtonContext( $_params );
		$ajax = $button; 
		$keys = $button->getKeys();

		// .NET naming
		$parameters = $_params;
		$params = &$_params;

		$rispId = isset($params["risp_id"]) ? (int)$params["risp_id"] : 0;

if ($rispId <= 0) {
    $result["success"] = false;
    $result["message"] = "Invalid RISP ID.";
    return;
}

DB::Exec("START TRANSACTION");

try {

    // Check existing STF
    $rsCheck = DB::Query("
        SELECT 
            stf.transfer_form_id,
            stf.transfer_form_no
        FROM stock_transfer_form stf
        INNER JOIN stock_transfer_form_detail stfd
            ON stfd.transfer_form_id = stf.transfer_form_id
        INNER JOIN raw_material_request_details rmrd
            ON rmrd.id = stfd.request_detail_id
        WHERE rmrd.raw_material_request_id = ".$rispId."
        LIMIT 1
    ");

    $existing = $rsCheck ? $rsCheck->fetchAssoc() : null;

    if ($existing) {
        DB::Exec("COMMIT");

        $result["success"] = true;
        $result["message"] = "STF already exists: ".$existing["transfer_form_no"];
        $result["transfer_form_id"] = $existing["transfer_form_id"];
        return;
    }

    // Get RISP header
    $rsHeader = DB::Query("
        SELECT *
        FROM raw_material_request
        WHERE id = ".$rispId."
        LIMIT 1
    ");

    $header = $rsHeader ? $rsHeader->fetchAssoc() : null;

    if (!$header) {
        DB::Exec("ROLLBACK");
        $result["success"] = false;
        $result["message"] = "RISP not found.";
        return;
    }

    // Get STF numbering
    $rsNum = DB::Query("
        SELECT *
        FROM transaction_numbering
        WHERE transaction_code = 'STF'
          AND is_active = 1
        LIMIT 1
        FOR UPDATE
    ");

    $num = $rsNum ? $rsNum->fetchAssoc() : null;

    if (!$num) {
        DB::Exec("ROLLBACK");
        $result["success"] = false;
        $result["message"] = "No active transaction numbering for STF.";
        return;
    }

    $stfNo = $num["prefix"] . str_pad((int)$num["next_no"], (int)$num["digit_length"], "0", STR_PAD_LEFT);

    // Insert STF header
    DB::Exec("
        INSERT INTO stock_transfer_form
        (
            transfer_form_no,
            transfer_form_date,
            source_production_work_order_id,
            to_location_id,
            transfer_scope,
            jurisdiction_type,
            purpose,
            remarks,
            encoded_at,
            status,
            created_at,
            to_warehouse
        )
        VALUES
        (
            '".db_addslashes($stfNo)."',
            CURDATE(),
            ".(int)$header["production_work_order_id"].",
            ".($header["receiving_warehouse_id"] ? (int)$header["receiving_warehouse_id"] : "NULL").",
            'WAREHOUSE_TO_WAREHOUSE',
            'SAME_JURISDICTION',
            'PRODUCTION',
            'Generated from RISP No. ".db_addslashes($header["risp_no"])."',
            NOW(),
            'Pending',
            NOW(),
            ".($header["receiving_warehouse_id"] ? (int)$header["receiving_warehouse_id"] : "NULL")."
        )
    ");

    $stfId = DB::LastId();

    if (!$stfId) {
        DB::Exec("ROLLBACK");
        $result["success"] = false;
        $result["message"] = "Failed to create STF header.";
        return;
    }

    // Insert STF details
    $rsDetails = DB::Query("
        SELECT 
            rmrd.*,
            i.sku,
            i.name AS item_name
        FROM raw_material_request_details rmrd
        LEFT JOIN item i
            ON i.id = rmrd.raw_material_id
        WHERE rmrd.raw_material_request_id = ".$rispId."
        ORDER BY rmrd.line_no, rmrd.id
    ");

    $detailCount = 0;

    while ($d = $rsDetails->fetchAssoc()) {

        $qty = (float)$d["approved_qty"];

        if ($qty <= 0) {
            $qty = (float)$d["requested_qty"];
        }

        if ($qty <= 0) {
            continue;
        }

        $desc = $d["description"] ? $d["description"] : $d["item_name"];

        DB::Exec("
            INSERT INTO stock_transfer_form_detail
            (
                transfer_form_id,
                request_detail_id,
                item_id,
                item_code,
                item_description,
                uom,
                requested_qty,
                approved_qty,
                issued_qty,
                received_qty,
                batch_no,
                lot_no,
                reference_no,
                expiration_date,
                line_remarks,
                created_at
            )
            VALUES
            (
                ".$stfId.",
                ".(int)$d["id"].",
                ".(int)$d["raw_material_id"].",
                ".($d["sku"] ? "'".db_addslashes($d["sku"])."'" : "NULL").",
                '".db_addslashes($desc)."',
                ".($d["uom"] ? "'".db_addslashes($d["uom"])."'" : "NULL").",
                ".$qty.",
                ".$qty.",
                0,
                0,
                ".($d["batch_no"] ? "'".db_addslashes($d["batch_no"])."'" : "NULL").",
                ".($d["lot_no"] ? "'".db_addslashes($d["lot_no"])."'" : "NULL").",
                '".db_addslashes($header["risp_no"])."',
                ".($d["expiry_date"] ? "'".db_addslashes($d["expiry_date"])."'" : "NULL").",
                ".($d["remarks"] ? "'".db_addslashes($d["remarks"])."'" : "NULL").",
                NOW()
            )
        ");

        $detailCount++;
    }

    if ($detailCount <= 0) {
        DB::Exec("ROLLBACK");
        $result["success"] = false;
        $result["message"] = "No valid RISP details found.";
        return;
    }

    DB::Exec("
        UPDATE transaction_numbering
        SET next_no = next_no + 1,
            updated_at = NOW()
        WHERE id = ".(int)$num["id"]."
    ");

    DB::Exec("COMMIT");

    $result["success"] = true;
    $result["message"] = "STF created successfully: ".$stfNo;
    $result["transfer_form_id"] = $stfId;

} catch (Exception $e) {

    DB::Exec("ROLLBACK");

    $result["success"] = false;
    $result["message"] = $e->getMessage();
};

		RunnerContext::pop();
		echo runner_json_encode( $result);
		$button->deleteTempFiles();
	}

		// custom button - Create DR
	function buttonHandler_2630( $_params )
	{
		$result = array();

		$button = $this->prepareButtonContext( $_params );
		$ajax = $button; 
		$keys = $button->getKeys();

		// .NET naming
		$parameters = $_params;
		$params = &$_params;

		// ======================================================
// CREATE ONE DELIVERY RECEIPT FROM DISPATCH PLAN
// ======================================================

$dispatchPlanId = intval($keys["id"] ?? 0);

if ($dispatchPlanId <= 0) {

    $result["success"] = false;
    $result["message"] = "Invalid Dispatch Plan.";

    return;
}


// ------------------------------------------------------
// Get Dispatch Plan
// ------------------------------------------------------

$sqlPlan = DB::PrepareSQL(
    "SELECT *
     FROM request_dispatch_plan
     WHERE id = :1
     LIMIT 1",
    $dispatchPlanId
);

$rsPlan = DB::Query($sqlPlan);
$plan = $rsPlan->fetchAssoc();

if (!$plan) {

    $result["success"] = false;
    $result["message"] = "Dispatch Plan was not found.";

    return;
}


// ------------------------------------------------------
// Prevent duplicate DR
// ------------------------------------------------------

$sqlExisting = DB::PrepareSQL(
    "SELECT
        id,
        delivery_receipt_no
     FROM delivery_receipt
     WHERE request_dispatch_plan_id = :1
     LIMIT 1",
    $dispatchPlanId
);

$rsExisting = DB::Query($sqlExisting);
$existing = $rsExisting->fetchAssoc();

if ($existing) {

    $result["success"] = true;
    $result["already_exists"] = true;
    $result["dr_id"] = $existing["id"];
    $result["dr_no"] = $existing["delivery_receipt_no"];

    return;
}


// ------------------------------------------------------
// Get source RIS information
// ------------------------------------------------------

$sqlSources = DB::PrepareSQL(
    "SELECT
        augmentation_request_id,
        ris_no
     FROM request_dispatch_plan_source
     WHERE request_dispatch_plan_id = :1
     ORDER BY source_sequence, id",
    $dispatchPlanId
);

$rsSources = DB::Query($sqlSources);

$sourceCount = 0;
$singleRisId = null;
$singleRisNo = null;
$risNumbers = array();

while ($source = $rsSources->fetchAssoc()) {

    $sourceCount++;

    $risNumbers[] = $source["ris_no"];

    if ($sourceCount == 1) {

        $singleRisId =
            intval($source["augmentation_request_id"]);

        $singleRisNo =
            $source["ris_no"];
    }
}


// ------------------------------------------------------
// Determine DR source
// ------------------------------------------------------

$sourceReferenceType = "RIS";

if ($sourceCount == 1) {

    $sourceReferenceId =
        $singleRisId;

    $sourceReferenceNo =
        $singleRisNo;

} else {

    $sourceReferenceId = null;

    $sourceReferenceNo =
        "MULTIPLE RIS";
}


// ------------------------------------------------------
// Totals from Dispatch Plan items
// ------------------------------------------------------

$sqlTotals = DB::PrepareSQL(
    "SELECT
        COUNT(*) AS total_lines,
        COALESCE(
            SUM(planned_dispatch_quantity),
            0
        ) AS total_qty

     FROM request_dispatch_plan_item

     WHERE request_dispatch_plan_id = :1",
    $dispatchPlanId
);

$rsTotals = DB::Query($sqlTotals);
$totals = $rsTotals->fetchAssoc();

$totalLines =
    intval($totals["total_lines"] ?? 0);

$totalQty =
    floatval($totals["total_qty"] ?? 0);


if ($totalLines <= 0) {

    $result["success"] = false;

    $result["message"] =
        "The Dispatch Plan has no items.";

    return;
}


// ------------------------------------------------------
// Temporary unique DR number
//
// We need a value because delivery_receipt_no
// is NOT NULL + UNIQUE.
// After insert we replace this using the new ID.
// ------------------------------------------------------

$tempDrNo =
    "TMP-DR-" .
    date("YmdHis") .
    "-" .
    mt_rand(1000, 9999);


// ------------------------------------------------------
// Create DR header
// ------------------------------------------------------

$dr = array();

$dr["delivery_receipt_no"] =
    $tempDrNo;

$dr["issue_date"] =
    date("Y-m-d");

$dr["dispatch_date"] =
    $plan["dispatch_date"];

$dr["warehouse_id"] =
    $plan["origin_warehouse_id"] ?? null;

$dr["origin_warehouse_code"] =
    $plan["origin_warehouse_code"] ?? null;

$dr["origin_warehouse_name"] =
    $plan["origin_warehouse_name"] ?? null;


// ------------------------------------------------------
// Destination
// ------------------------------------------------------

$dr["destination_type"] =
    $plan["destination_type"];

$dr["destination_warehouse_code"] =
    $plan["destination_warehouse_code"];

$dr["destination_warehouse_name"] =
    $plan["destination_warehouse_name"];

$dr["destination_name"] =
    $plan["destination_name"];

$dr["destination_address"] =
    $plan["destination_address"];


// ------------------------------------------------------
// Recipient/contact
// ------------------------------------------------------

$dr["recipient_name"] =
    $plan["contact_person"];

$dr["recipient_contact_no"] =
    $plan["contact_no"];


// ------------------------------------------------------
// Dispatch Plan reference
// ------------------------------------------------------

$dr["request_dispatch_plan_id"] =
    $dispatchPlanId;

$dr["dispatch_plan_no"] =
    $plan["dispatch_plan_no"];

$dr["source_reference_type"] =
    $sourceReferenceType;

$dr["source_reference_id"] =
    $sourceReferenceId;

$dr["source_reference_no"] =
    $sourceReferenceNo;


// ------------------------------------------------------
// Transport information
// ------------------------------------------------------

$dr["transporter_type"] =
    $plan["transporter_type"];

$dr["provider_id"] =
    $plan["provider_id"];

$dr["provider_name"] =
    $plan["provider_name"];

$dr["vehicle_id"] =
    $plan["vehicle_id"];

$dr["vehicle_plate_no"] =
    $plan["plate_no"];

$dr["vehicle_type"] =
    $plan["vehicle_type"];

$dr["driver_name"] =
    $plan["driver_name"];

$dr["driver_contact_no"] =
    $plan["driver_contact_no"];

$dr["helper_name"] =
    $plan["helper_name"];

$dr["helper_contact_no"] =
    $plan["helper_contact_no"];

$dr["mode_of_transport"] =
    $plan["mode_of_transport"];


// ------------------------------------------------------
// Totals/status
// ------------------------------------------------------

$dr["total_qty"] =
    $totalQty;

$dr["total_lines"] =
    $totalLines;

$dr["dispatch_status"] =
    "APPROVED";

$dr["remarks"] =
    "Auto-created from Dispatch Plan " .
    $plan["dispatch_plan_no"];

$dr["created_by"] =
    $_SESSION["uid"] ?? null;


DB::Insert(
    "delivery_receipt",
    $dr
);

$drId = DB::LastId();


// ------------------------------------------------------
// Final DR number
//
// Existing WINGS format:
// DR00002, DR00003, etc.
// ------------------------------------------------------

$drNo =
    "DR" .
    str_pad(
        $drId,
        5,
        "0",
        STR_PAD_LEFT
    );

$sqlUpdateDrNo = DB::PrepareSQL(
    "UPDATE delivery_receipt
     SET delivery_receipt_no = ':1'
     WHERE id = :2",
    $drNo,
    $drId
);

// ======================================================
// CREATE DELIVERY RECEIPT DETAILS
// ======================================================

$sqlItems = DB::PrepareSQL(
    "SELECT *
     FROM request_dispatch_plan_item
     WHERE request_dispatch_plan_id = :1
     ORDER BY id",
    $dispatchPlanId
);

$rsItems = DB::Query($sqlItems);

$lineNo = 1;

while ($item = $rsItems->fetchAssoc()) {

    // --------------------------------------------------
    // Get source allocation
    //
    // This gives us the actual warehouse from which
    // this allocation came.
    // --------------------------------------------------

    $warehouseId =
        $plan["origin_warehouse_id"] ?? null;

    $warehouseCode =
        $plan["origin_warehouse_code"] ?? null;

    $warehouseName =
        $plan["origin_warehouse_name"] ?? null;


    $allocationId =
        intval(
            $item[
                "augmentation_request_allocation_id"
            ] ?? 0
        );


    if ($allocationId > 0) {

        $sqlAllocation = DB::PrepareSQL(
            "SELECT
                warehouse_id,
                warehouse_code,
                warehouse_name,
                lot_no
             FROM augmentation_request_allocation
             WHERE allocation_id = :1
             LIMIT 1",
            $allocationId
        );

        $rsAllocation =
            DB::Query($sqlAllocation);

        $allocation =
            $rsAllocation->fetchAssoc();

        if ($allocation) {

            $warehouseId =
                $allocation["warehouse_id"];

            $warehouseCode =
                $allocation["warehouse_code"];

            $warehouseName =
                $allocation["warehouse_name"];
        }
    }


    // --------------------------------------------------
    // DR Detail
    // --------------------------------------------------

    $detail = array();

    $detail["delivery_receipt_id"] =
        $drId;


    // ==================================================
    // TRACEABILITY
    // ==================================================

    $detail["request_dispatch_plan_item_id"] =
        $item["id"];

    $detail["augmentation_request_item_id"] =
        $item["augmentation_request_item_id"];

    $detail["augmentation_request_allocation_id"] =
        $item["augmentation_request_allocation_id"];


    // --------------------------------------------------
    // Line
    // --------------------------------------------------

    $detail["line_no"] =
        $lineNo;


    // --------------------------------------------------
    // Stock/item
    // --------------------------------------------------

    $detail["stock_item_id"] =
        $item["item_id"];

    $detail["item_code"] =
        $item["item_code"];

    $detail["item_description"] =
        $item["item_description"];


    // --------------------------------------------------
    // Warehouse
    // --------------------------------------------------

    $detail["warehouse_id"] =
        $warehouseId;

    $detail["warehouse_code"] =
        $warehouseCode;

    $detail["warehouse_name"] =
        $warehouseName;


    // --------------------------------------------------
    // Batch
    // --------------------------------------------------

    $detail["batch_id"] =
        $item["batch_id"];

    $detail["batch_no"] =
        $item["batch_no"];

    if ($allocationId > 0 && isset($allocation)) {

        $detail["lot_no"] =
            $allocation["lot_no"];
    }

    $detail["expiry_date"] =
        $item["expiry_date"];

    $detail["production_date"] =
        $item["production_date"];

    $detail["production_time"] =
        $item["production_time"];


    // --------------------------------------------------
    // Quantity
    // --------------------------------------------------

    $detail["qty_for_dispatch"] =
        $item["planned_dispatch_quantity"];

    /*
     * Creating a DR does not mean it has
     * physically left the warehouse yet.
     */
    $detail["actual_dispatched_quantity"] =
        0;

    $detail["qty_received"] =
        0;

    $detail["qty_variance"] =
        0;

    $detail["uom"] =
        $item["uom"];


    // --------------------------------------------------
    // Status
    // --------------------------------------------------

    $detail["condition_status"] =
        "GOOD";

    $detail["detail_status"] =
        "FOR_DISPATCH";

    $detail["remarks"] =
        $item["remarks"];


    DB::Insert(
        "delivery_receipt_detail",
        $detail
    );

    $lineNo++;
}


// ======================================================
// LINK DR BACK TO DISPATCH PLAN
// ======================================================

$sqlUpdatePlan = DB::PrepareSQL(
    "UPDATE request_dispatch_plan

     SET
        generated_dr_id = :1,
        generated_dr_no = ':2'

     WHERE id = :3",
    $drId,
    $drNo,
    $dispatchPlanId
);

DB::Exec($sqlUpdatePlan);


// ======================================================
// RETURN RESULT
// ======================================================

$result["success"] = true;
$result["already_exists"] = false;
$result["dr_id"] = $drId;
$result["dr_no"] = $drNo;

DB::Exec($sqlUpdateDrNo);;

		RunnerContext::pop();
		echo runner_json_encode( $result);
		$button->deleteTempFiles();
	}

		// custom button - ProdtoMaterialUsage
	function buttonHandler_2632( $_params )
	{
		$result = array();

		$button = $this->prepareButtonContext( $_params );
		$ajax = $button; 
		$keys = $button->getKeys();

		// .NET naming
		$parameters = $_params;
		$params = &$_params;

		$pwoId = (int)$params["production_work_order_id"];

if ($pwoId <= 0) {
    $result["success"] = false;
    $result["message"] = "Invalid Production Work Order ID.";
    return;
}

$transactionCode = "MUR";

DB::Exec("START TRANSACTION");

try {

    // Check if MUR already exists
    $sqlCheck = "
        SELECT id, reference_number
        FROM material_usage_report
        WHERE production_work_order_id = " . $pwoId . "
          AND status <> 'Cancelled'
        LIMIT 1
    ";

    $rsCheck = DB::Query($sqlCheck);
    $existing = $rsCheck ? $rsCheck->fetchAssoc() : null;

    if ($existing) {
        DB::Exec("ROLLBACK");

        $result["success"] = false;
        $result["message"] = "Material Usage Report already exists: " . $existing["reference_number"];
        $result["mur_id"] = $existing["id"];
        return;
    }

    // Get transaction numbering
    $sqlNumber = "
        SELECT 
            id,
            prefix,
            digit_length,
            next_no
        FROM transaction_numbering
        WHERE transaction_code = '" . db_addslashes($transactionCode) . "'
          AND is_active = 1
        LIMIT 1
        FOR UPDATE
    ";

    $rsNumber = DB::Query($sqlNumber);
    $num = $rsNumber ? $rsNumber->fetchAssoc() : null;

    if (!$num) {
        DB::Exec("ROLLBACK");

        $result["success"] = false;
        $result["message"] = "No active transaction numbering setup found for MUR.";
        return;
    }

    $numberingId = (int)$num["id"];
    $prefix = $num["prefix"];
    $digitLength = (int)$num["digit_length"];
    $nextNo = (int)$num["next_no"];

    $referenceNumber = $prefix . str_pad($nextNo, $digitLength, "0", STR_PAD_LEFT);

    // Get PWO header
    $sqlPwo = "
        SELECT 
            pwo.id,
            pwo.work_order_no,
            pwo.work_order_date,
            pwo.schedule_date,
            pwo.production_area,
            pwo.production_line,
            pwo.production_plan_id
        FROM production_work_order pwo
        WHERE pwo.id = " . $pwoId . "
        LIMIT 1
    ";

    $rsPwo = DB::Query($sqlPwo);
    $pwo = $rsPwo ? $rsPwo->fetchAssoc() : null;

    if (!$pwo) {
        DB::Exec("ROLLBACK");

        $result["success"] = false;
        $result["message"] = "Production Work Order not found.";
        return;
    }

    // Check if PWO has details
    $sqlDetailCount = "
        SELECT COUNT(*) AS cnt
        FROM production_work_order_details
        WHERE production_work_order_id = " . $pwoId . "
    ";

    $rsCnt = DB::Query($sqlDetailCount);
    $cntData = $rsCnt ? $rsCnt->fetchAssoc() : null;

    if (!$cntData || (int)$cntData["cnt"] <= 0) {
        DB::Exec("ROLLBACK");

        $result["success"] = false;
        $result["message"] = "This Production Work Order has no details.";
        return;
    }

    // Check if components/BOM exist
    $sqlBomCount = "
        SELECT COUNT(*) AS cnt
        FROM production_work_order_details pwod
        INNER JOIN item_component ic
            ON ic.parent_item_id = pwod.finished_good_id
        WHERE pwod.production_work_order_id = " . $pwoId . "
    ";

    $rsBomCnt = DB::Query($sqlBomCount);
    $bomCnt = $rsBomCnt ? $rsBomCnt->fetchAssoc() : null;

    if (!$bomCnt || (int)$bomCnt["cnt"] <= 0) {
        DB::Exec("ROLLBACK");

        $result["success"] = false;
        $result["message"] = "No component/material setup found for this Production Work Order.";
        return;
    }

    // Insert MUR header
    $sqlInsertHeader = "
        INSERT INTO material_usage_report
        (
            reference_number,
            production_work_order_id,
            production_reference,
            production_area,
            production_date,
            product_item_id,
            product_name,
            planned_quantity,
            actual_quantity,
            status,
            created_by,
            created_at
        )
        SELECT
            '" . db_addslashes($referenceNumber) . "',
            pwo.id,
            pwo.work_order_no,
            pwo.production_area,
            IFNULL(pwo.schedule_date, pwo.work_order_date),
            MIN(pwod.finished_good_id),
            LEFT(GROUP_CONCAT(DISTINCT IFNULL(pwod.description, fg.description) SEPARATOR ', '), 255),
            SUM(IFNULL(pwod.target_qty,0)),
            SUM(
                CASE
                    WHEN IFNULL(pwod.actual_qty,0) > 0 THEN pwod.actual_qty
                    ELSE pwod.target_qty
                END
            ),
            'Draft',
            '" . db_addslashes(Security::getUserName()) . "',
            NOW()
        FROM production_work_order pwo
        INNER JOIN production_work_order_details pwod
            ON pwod.production_work_order_id = pwo.id
        LEFT JOIN item fg
            ON fg.id = pwod.finished_good_id
        WHERE pwo.id = " . $pwoId . "
        GROUP BY 
            pwo.id,
            pwo.work_order_no,
            pwo.production_area,
            pwo.schedule_date,
            pwo.work_order_date
    ";

    DB::Exec($sqlInsertHeader);

    $murId = DB::LastId();

    if (!$murId) {
        DB::Exec("ROLLBACK");

        $result["success"] = false;
        $result["message"] = "Unable to create Material Usage Report header.";
        return;
    }

    // Insert MUR details from PWO components
    $sqlInsertDetails = "
        INSERT INTO material_usage_report_detail
        (
            material_usage_report_id,
            line_no,
            item_category,
            item_id,
            item_name,
            brand,
            unit,
            beginning_balance,
            risp_stf_quantity,
            production_usage,
            defective_damaged,
            actual_count,
            remarks,
            source_risp_id,
            source_stf_id,
            created_at
        )
        SELECT
            " . $murId . " AS material_usage_report_id,
            ROW_NUMBER() OVER (ORDER BY x.item_name, x.item_id) AS line_no,
            x.item_category,
            x.item_id,
            x.item_name,
            x.brand,
            x.unit,
            SUM(x.beginning_balance) AS beginning_balance,
            SUM(x.risp_stf_quantity) AS risp_stf_quantity,
            SUM(x.production_usage) AS production_usage,
            0 AS defective_damaged,
            0 AS actual_count,
            NULL AS remarks,
            MIN(x.source_risp_id) AS source_risp_id,
            MIN(x.source_stf_id) AS source_stf_id,
            NOW()
        FROM
        (
            SELECT
                ic.component_item_id AS item_id,
                IFNULL(rm.description, rm.name) AS item_name,
                rm.brand AS brand,
                cat.name AS item_category,
                pwod.uom AS unit,

                IFNULL(inv.qty_balance,0) AS beginning_balance,

                IFNULL(risp.total_risp_qty,0) + IFNULL(stf.total_stf_qty,0) AS risp_stf_quantity,

                (
                    CASE
                        WHEN IFNULL(pwod.actual_qty,0) > 0 THEN pwod.actual_qty
                        ELSE pwod.target_qty
                    END
                    * IFNULL(ic.qty,0)
                ) AS production_usage,

                risp.source_risp_id,
                stf.source_stf_id

            FROM production_work_order_details pwod

            INNER JOIN item_component ic
                ON ic.parent_item_id = pwod.finished_good_id

            LEFT JOIN item rm
                ON rm.id = ic.component_item_id

            LEFT JOIN itemcategory cat
                ON cat.id = rm.category_id

            LEFT JOIN (
                SELECT
                    item_id,
                    SUM(qty_balance) AS qty_balance
                FROM view_bd_inventory_balance
                GROUP BY item_id
            ) inv
                ON inv.item_id = ic.component_item_id

            LEFT JOIN (
                SELECT
                    rmr.production_work_order_id,
                    rmrd.raw_material_id,
                    MIN(rmr.id) AS source_risp_id,
                    SUM(
                        CASE
                            WHEN IFNULL(rmrd.issued_qty,0) > 0 THEN rmrd.issued_qty
                            WHEN IFNULL(rmrd.approved_qty,0) > 0 THEN rmrd.approved_qty
                            ELSE rmrd.requested_qty
                        END
                    ) AS total_risp_qty
                FROM raw_material_request rmr
                INNER JOIN raw_material_request_details rmrd
                    ON rmrd.raw_material_request_id = rmr.id
                WHERE rmr.status <> 'Cancelled'
                GROUP BY rmr.production_work_order_id, rmrd.raw_material_id
            ) risp
                ON risp.production_work_order_id = pwod.production_work_order_id
               AND risp.raw_material_id = ic.component_item_id

            LEFT JOIN (
                SELECT
                    rmr.production_work_order_id,
                    stfd.item_id,
                    MIN(stfd.transfer_form_id) AS source_stf_id,
                    SUM(IFNULL(stfd.issued_qty,0)) AS total_stf_qty
                FROM raw_material_request rmr
                INNER JOIN raw_material_request_details rmrd
                    ON rmrd.raw_material_request_id = rmr.id
                INNER JOIN stock_transfer_form_detail stfd
                    ON stfd.request_detail_id = rmrd.id
                GROUP BY rmr.production_work_order_id, stfd.item_id
            ) stf
                ON stf.production_work_order_id = pwod.production_work_order_id
               AND stf.item_id = ic.component_item_id

            WHERE pwod.production_work_order_id = " . $pwoId . "
        ) x
        GROUP BY
            x.item_category,
            x.item_id,
            x.item_name,
            x.brand,
            x.unit
    ";

    DB::Exec($sqlInsertDetails);

    // Validate details inserted
    $sqlValidate = "
        SELECT COUNT(*) AS cnt
        FROM material_usage_report_detail
        WHERE material_usage_report_id = " . $murId . "
    ";

    $rsValidate = DB::Query($sqlValidate);
    $validate = $rsValidate ? $rsValidate->fetchAssoc() : null;

    if (!$validate || (int)$validate["cnt"] <= 0) {
        DB::Exec("ROLLBACK");

        $result["success"] = false;
        $result["message"] = "Material Usage Report was not created because no material details were inserted.";
        return;
    }

    // Update numbering
    DB::Exec("
        UPDATE transaction_numbering
        SET next_no = next_no + 1
        WHERE id = " . $numberingId . "
    ");

    DB::Exec("COMMIT");

    $result["success"] = true;
    $result["message"] = "Material Usage Report created successfully: " . $referenceNumber;
    $result["mur_id"] = $murId;
    $result["reference_number"] = $referenceNumber;

} catch (Exception $e) {

    DB::Exec("ROLLBACK");

    $result["success"] = false;
    $result["message"] = "Error: " . $e->getMessage();
};

		RunnerContext::pop();
		echo runner_json_encode( $result);
		$button->deleteTempFiles();
	}

		// custom button - Send to QA
	function buttonHandler_2636( $_params )
	{
		$result = array();

		$button = $this->prepareButtonContext( $_params );
		$ajax = $button; 
		$keys = $button->getKeys();

		// .NET naming
		$parameters = $_params;
		$params = &$_params;

		// ==========================================================
// PO TO QA INCOMING GOODS
// PHPRunner Custom Button - Server Event
// ==========================================================
// Expected client parameter:
// $params["po_detail_id"]
//
// Main functions:
// 1. Validate PO detail
// 2. Prevent duplicate QA creation
// 3. Generate QA No., Batch No., and VBN
// 4. Copy PO item and supplier information
// 5. Total Sample Inspected = 2% of Delivered Quantity
// 6. Import active QA criteria from item or parent item
// 7. Set source_transaction_type = PO_RECEIVING
// 8. Set donor = NULL
// ==========================================================


// ----------------------------------------------------------
// Get PO Detail ID
// ----------------------------------------------------------

$poDetailId = isset($params["po_detail_id"])
    ? (int)$params["po_detail_id"]
    : 0;

if ($poDetailId <= 0) {
    $result["success"] = false;
    $result["message"] = "Invalid PO detail ID.";
    return;
}


// ----------------------------------------------------------
// Database error helper
// ----------------------------------------------------------

if (!function_exists("getLastDbErrorQAIncoming")) {

    function getLastDbErrorQAIncoming()
    {
        if (method_exists("DB", "LastError")) {

            $error = DB::LastError();

            if ($error != "") {
                return $error;
            }
        }

        if (function_exists("db_error")) {

            $error = db_error();

            if ($error != "") {
                return $error;
            }
        }

        return "Unknown database error.";
    }
}


// ----------------------------------------------------------
// Execute SQL and throw error when unsuccessful
// ----------------------------------------------------------

if (!function_exists("execOrFailQAIncoming")) {

    function execOrFailQAIncoming($sql, $label)
    {
        $success = DB::Exec($sql);

        if ($success === false) {
            throw new Exception(
                $label . " failed: " .
                getLastDbErrorQAIncoming()
            );
        }

        return $success;
    }
}


// ----------------------------------------------------------
// Get transaction number
// Must be executed inside a transaction
// ----------------------------------------------------------

if (!function_exists("getTransactionNumberForQAIncoming")) {

    function getTransactionNumberForQAIncoming(
        $transactionCode
    ) {
        $transactionCode = trim($transactionCode);

        $sql = "
            SELECT
                id,
                prefix,
                digit_length,
                next_no
            FROM transaction_numbering
            WHERE transaction_code = '" .
                db_addslashes($transactionCode) . "'
              AND is_active = 1
            LIMIT 1
            FOR UPDATE
        ";

        $rs = DB::Query($sql);
        $numbering = $rs
            ? $rs->fetchAssoc()
            : null;

        if (!$numbering) {
            throw new Exception(
                "No active transaction numbering setup " .
                "was found for " . $transactionCode . "."
            );
        }

        $generatedNumber =
            $numbering["prefix"] .
            str_pad(
                (int)$numbering["next_no"],
                (int)$numbering["digit_length"],
                "0",
                STR_PAD_LEFT
            );

        execOrFailQAIncoming(
            "
                UPDATE transaction_numbering
                SET next_no = next_no + 1
                WHERE id = " . (int)$numbering["id"] . "
            ",
            "Update " . $transactionCode .
            " transaction numbering"
        );

        return $generatedNumber;
    }
}


// ----------------------------------------------------------
// Start transaction
// ----------------------------------------------------------

DB::Exec("START TRANSACTION");

try {

    // ======================================================
    // 1. GET PO DETAIL
    // ======================================================

    $sqlPo = "
        SELECT
            pod.id AS po_detail_id,
            po.id AS purchase_order_id,
            po.reference_number AS po_no,
            po.supplier_id,
            s.name AS supplier_name,

            pod.item_id,

            COALESCE(
                NULLIF(pod.parent_item_id, 0),
                NULLIF(i.parent_item_id, 0),
                0
            ) AS parent_item_id,

            i.sku,

            COALESCE(
                NULLIF(TRIM(i.description), ''),
                NULLIF(TRIM(pod.item_description), ''),
                NULLIF(TRIM(i.name), ''),
                ''
            ) AS item_name,

            TRIM(
                COALESCE(i.name, '')
            ) AS item_kind,

            i.brand_id,
            i.brand AS brand_text,

            COALESCE(
                NULLIF(pod.uom, 0),
                NULLIF(i.unit_id, 0)
            ) AS unit_id,

            iu.name AS unit_name,

            pod.quantity AS po_quantity,
            pod.unit_cost,
            pod.amount,
            pod.remarks AS po_detail_remarks,

            pod.warehouse AS po_detail_warehouse_id

        FROM purchaseorderdetail pod

        INNER JOIN purchaseorder po
            ON po.id = pod.purchase_order_id

        LEFT JOIN supplier s
            ON s.id = po.supplier_id

        LEFT JOIN item i
            ON i.id = pod.item_id

        LEFT JOIN itemunit iu
            ON iu.id = COALESCE(
                NULLIF(pod.uom, 0),
                NULLIF(i.unit_id, 0)
            )

        WHERE pod.id = " . $poDetailId . "

        LIMIT 1
    ";

    $rsPo = DB::Query($sqlPo);
    $po = $rsPo
        ? $rsPo->fetchAssoc()
        : null;

    if (!$po) {
        throw new Exception(
            "The selected PO detail was not found."
        );
    }

    if ((int)$po["purchase_order_id"] <= 0) {
        throw new Exception(
            "The Purchase Order header is missing."
        );
    }

    if ((int)$po["item_id"] <= 0) {
        throw new Exception(
            "The PO detail does not have a valid item."
        );
    }

    if (trim($po["item_name"]) == "") {
        throw new Exception(
            "Item description is missing from the PO " .
            "and Item Master."
        );
    }

    $deliveredQuantity =
        (float)$po["po_quantity"];

    if ($deliveredQuantity <= 0) {
        throw new Exception(
            "The PO delivered quantity must be greater " .
            "than zero."
        );
    }


    // ======================================================
    // 2. PREVENT DUPLICATE QA
    // ======================================================

    $sqlExistingQa = "
        SELECT
            id,
            qa_no
        FROM qa_incoming_goods
        WHERE source_transaction_type = 'PO_RECEIVING'
          AND source_transaction_id =
              " . (int)$po["purchase_order_id"] . "
          AND source_detail_id =
              " . (int)$po["po_detail_id"] . "
        LIMIT 1
    ";

    $rsExistingQa = DB::Query($sqlExistingQa);

    $existingQa = $rsExistingQa
        ? $rsExistingQa->fetchAssoc()
        : null;

    if ($existingQa) {

        DB::Exec("COMMIT");

        $result["success"] = true;
        $result["already_exists"] = true;

        $result["qa_id"] =
            (int)$existingQa["id"];

        $result["qa_no"] =
            $existingQa["qa_no"];

        $result["message"] =
            "QA Incoming Goods already exists. " .
            "QA No.: " . $existingQa["qa_no"];

        return;
    }


    // ======================================================
    // 3. GET CURRENT USER SETUP
    // ======================================================

    $userName = isset($_SESSION["UserID"])
        ? trim($_SESSION["UserID"])
        : "";

    if ($userName == "") {
        throw new Exception(
            "The current user session was not found."
        );
    }

    $sqlUser = "
        SELECT
            u.ID AS user_id,
            u.username,
            u.mother_facility_id AS user_mother_facility_id,
            u.warehouse_id AS user_warehouse_id
        FROM users u
        WHERE u.username = '" .
            db_addslashes($userName) . "'
        LIMIT 1
    ";

    $rsUser = DB::Query($sqlUser);

    $userData = $rsUser
        ? $rsUser->fetchAssoc()
        : null;

    if (!$userData) {
        throw new Exception(
            "The current user setup was not found."
        );
    }

    $createdById =
        (int)$userData["user_id"];

    $userWarehouseId =
        (int)$userData["user_warehouse_id"];

    $userMotherFacilityId =
        (int)$userData["user_mother_facility_id"];


    // ======================================================
    // 4. RESOLVE RECEIVING WAREHOUSE
    // ======================================================
    // Priority:
    // 1. Warehouse selected in PO Detail
    // 2. Warehouse assigned to the current user
    // ======================================================

    $poWarehouseId =
        (int)$po["po_detail_warehouse_id"];

    $warehouseCandidates = array();

    if ($poWarehouseId > 0) {
        $warehouseCandidates[] = $poWarehouseId;
    }

    if (
        $userWarehouseId > 0 &&
        $userWarehouseId != $poWarehouseId
    ) {
        $warehouseCandidates[] = $userWarehouseId;
    }

    if (count($warehouseCandidates) <= 0) {
        throw new Exception(
            "No warehouse is assigned in the PO detail " .
            "or current user profile."
        );
    }

    $warehouseData = null;
    $warehouseSource = "";

    $fallbackMotherFacilitySql =
        $userMotherFacilityId > 0
            ? (string)$userMotherFacilityId
            : "NULL";

    foreach ($warehouseCandidates as $candidateWarehouseId) {

        $candidateWarehouseId =
            (int)$candidateWarehouseId;

        $sqlWarehouse = "
            SELECT
                w.id AS warehouse_id,
                w.warehouse_code,
                w.name AS warehouse_name,

                COALESCE(
                    NULLIF(w.mother_facility_id, 0),
                    " . $fallbackMotherFacilitySql . "
                ) AS mother_facility_id,

                mf.facility_code,
                mf.facility_name

            FROM warehouse w

            LEFT JOIN mother_facility mf
                ON mf.id = COALESCE(
                    NULLIF(w.mother_facility_id, 0),
                    " . $fallbackMotherFacilitySql . "
                )

            WHERE w.id = " .
                $candidateWarehouseId . "

            LIMIT 1
        ";

        $rsWarehouse = DB::Query($sqlWarehouse);

        $candidateWarehouse = $rsWarehouse
            ? $rsWarehouse->fetchAssoc()
            : null;

        if ($candidateWarehouse) {

            $warehouseData =
                $candidateWarehouse;

            $warehouseSource =
                $candidateWarehouseId == $poWarehouseId
                    ? "PO_DETAIL"
                    : "USER_PROFILE";

            break;
        }
    }

    if (!$warehouseData) {
        throw new Exception(
            "The receiving warehouse record was not found."
        );
    }

    if (
        (int)$warehouseData["mother_facility_id"] <= 0
    ) {
        throw new Exception(
            "The receiving warehouse has no mother " .
            "facility assignment."
        );
    }

    if (
        trim($warehouseData["warehouse_code"]) == ""
    ) {
        throw new Exception(
            "The receiving warehouse code is missing."
        );
    }

    if (
        trim($warehouseData["facility_code"]) == ""
    ) {
        throw new Exception(
            "The mother facility code is missing."
        );
    }


    // ======================================================
    // 5. GENERATE NUMBERS
    // ======================================================

    $qaNo = getTransactionNumberForQAIncoming(
        "QA"
    );

    $batchNo = getTransactionNumberForQAIncoming(
        "BATCH"
    );

    $vbnSequence =
        getTransactionNumberForQAIncoming(
            "VBN"
        );

    $vbnSequenceOnly = preg_replace(
        "/[^0-9]/",
        "",
        $vbnSequence
    );

    if ($vbnSequenceOnly == "") {
        throw new Exception(
            "The generated VBN sequence is invalid."
        );
    }

    $vbn =
        trim($warehouseData["facility_code"]) .
        "-" .
        trim($warehouseData["warehouse_code"]) .
        "-" .
        date("Y") .
        "-" .
        $vbnSequenceOnly;


    // ======================================================
    // 6. CALCULATE TOTAL SAMPLE INSPECTED
    // ======================================================
    // Sample = 2% of delivered quantity
    // Rounded upward to ensure at least one whole sample unit.
    // Examples:
    // 20,000 delivered = 400 samples
    // 500 delivered = 10 samples
    // 30 delivered = 1 sample
    // ======================================================

    $totalSampleInspected = ceil(
        $deliveredQuantity * 0.02
    );

    if (
        $totalSampleInspected >
        $deliveredQuantity
    ) {
        $totalSampleInspected =
            $deliveredQuantity;
    }

    if (
        $deliveredQuantity > 0 &&
        $totalSampleInspected <= 0
    ) {
        $totalSampleInspected = 1;
    }

    $deliveredQuantitySql = number_format(
        $deliveredQuantity,
        4,
        ".",
        ""
    );

    $totalSampleInspectedSql = number_format(
        $totalSampleInspected,
        4,
        ".",
        ""
    );


    // ======================================================
    // 7. PREPARE VALUES
    // ======================================================

    $itemId =
        (int)$po["item_id"];

    $parentItemId =
        (int)$po["parent_item_id"];

    $supplierId =
        (int)$po["supplier_id"];

    $brandId =
        (int)$po["brand_id"];

    $unitId =
        (int)$po["unit_id"];

    $supplierSql =
        $supplierId > 0
            ? (string)$supplierId
            : "NULL";

    $brandSql =
        $brandId > 0
            ? (string)$brandId
            : "NULL";

    $unitSql =
        $unitId > 0
            ? (string)$unitId
            : "NULL";


    // ======================================================
    // 8. INSERT QA HEADER
    // ======================================================

    $insertQa = "
        INSERT INTO qa_incoming_goods
        (
            qa_no,
            receiving_report_no,

            source_transaction_type,
            source_transaction_id,
            source_detail_id,

            po_no,
            supplier_donor,

            po_receiving_id,
            po_receiving_detail_id,

            inspection_date,

            receiving_warehouse_id,
            receiving_warehouse_name,
            warehouse_code,

            no_of_inspectors,

            item_id,
            item_name,
            kind,
            brand,
            unit,

            source,

            delivered_quantity,
            inspected_quantity,
            accepted_quantity,
            rejected_quantity,

            total_sample_inspected,

            average_acceptance_rate,
            average_rejection_rate,

            receiving_status,
            approval_status,

            batch_no,
            vbn,

            mother_facility_id,
            mother_facility_code,
            mother_facility_name,

            supplier,
            donor,

            created_by,
            createdAt,
            updatedAt
        )
        VALUES
        (
            '" . db_addslashes($qaNo) . "',
            '" . db_addslashes($qaNo) . "',

            'PO_RECEIVING',
            " . (int)$po["purchase_order_id"] . ",
            " . (int)$po["po_detail_id"] . ",

            '" . db_addslashes($po["po_no"]) . "',
            '" . db_addslashes(
                $po["supplier_name"]
            ) . "',

            " . (int)$po["purchase_order_id"] . ",
            " . (int)$po["po_detail_id"] . ",

            CURDATE(),

            " . (int)$warehouseData["warehouse_id"] . ",
            '" . db_addslashes(
                $warehouseData["warehouse_name"]
            ) . "',
            '" . db_addslashes(
                $warehouseData["warehouse_code"]
            ) . "',

            1,

            " . $itemId . ",
            '" . db_addslashes(
                $po["item_name"]
            ) . "',
            '" . db_addslashes(
                $po["item_kind"]
            ) . "',
            " . $brandSql . ",
            " . $unitSql . ",

            'PURCHASE_ORDER',

            " . $deliveredQuantitySql . ",
            0,
            0,
            0,

            " . $totalSampleInspectedSql . ",

            0,
            0,

            'FOR_QA',
            'DRAFT',

            '" . db_addslashes($batchNo) . "',
            '" . db_addslashes($vbn) . "',

            " . (int)$warehouseData["mother_facility_id"] . ",
            '" . db_addslashes(
                $warehouseData["facility_code"]
            ) . "',
            '" . db_addslashes(
                $warehouseData["facility_name"]
            ) . "',

            " . $supplierSql . ",
            NULL,

            " . $createdById . ",
            NOW(),
            NOW()
        )
    ";

    execOrFailQAIncoming(
        $insertQa,
        "Insert QA Incoming Goods"
    );


    // ======================================================
    // 9. GET QA ID
    // ======================================================

    $qaId = (int)DB::LastId();

    if ($qaId <= 0) {

        $sqlQaId = "
            SELECT id
            FROM qa_incoming_goods
            WHERE qa_no = '" .
                db_addslashes($qaNo) . "'
            ORDER BY id DESC
            LIMIT 1
        ";

        $rsQaId = DB::Query($sqlQaId);

        $qaIdRow = $rsQaId
            ? $rsQaId->fetchAssoc()
            : null;

        if ($qaIdRow) {
            $qaId = (int)$qaIdRow["id"];
        }
    }

    if ($qaId <= 0) {
        throw new Exception(
            "The QA header was inserted, but the " .
            "generated QA ID could not be retrieved."
        );
    }


    // ======================================================
    // 10. DETERMINE CRITERIA SOURCE
    // ======================================================
    // Priority:
    // 1. Item-specific criteria
    // 2. Parent-item criteria
    // ======================================================

    $criteriaItemId = $itemId;
    $criteriaSource = "ITEM";

    $sqlItemCriteriaCount = "
        SELECT COUNT(*) AS criteria_count
        FROM qa_item_criteria
        WHERE item_id = " . $itemId . "
          AND qa_module = 'INCOMING_GOODS'
          AND status = 'ACTIVE'
    ";

    $rsItemCriteriaCount =
        DB::Query($sqlItemCriteriaCount);

    $itemCriteriaCountRow =
        $rsItemCriteriaCount
            ? $rsItemCriteriaCount->fetchAssoc()
            : null;

    $itemCriteriaCount =
        $itemCriteriaCountRow
            ? (int)$itemCriteriaCountRow[
                "criteria_count"
            ]
            : 0;

    if (
        $itemCriteriaCount <= 0 &&
        $parentItemId > 0
    ) {
        $criteriaItemId = $parentItemId;
        $criteriaSource = "PARENT_ITEM";
    }


    // ======================================================
    // 11. GET ACTIVE CRITERIA
    // ======================================================

    $sqlCriteria = "
        SELECT
            id,
            criteria_code,
            criteria_description,
            expected_result,
            inspection_method,
            sort_order
        FROM qa_item_criteria
        WHERE item_id = " .
            (int)$criteriaItemId . "
          AND qa_module = 'INCOMING_GOODS'
          AND status = 'ACTIVE'
        ORDER BY
            sort_order,
            id
    ";

    $rsCriteria = DB::Query($sqlCriteria);

    $insertedCriteria = 0;


    // ======================================================
    // 12. INSERT QA CRITERIA DETAILS
    // ======================================================

    while (
        $rsCriteria &&
        ($criteria = $rsCriteria->fetchAssoc())
    ) {

        $inspectionMethod =
            trim($criteria["inspection_method"]);

        if ($inspectionMethod == "") {
            $inspectionMethod = "VISUAL";
        }

        $sortOrder =
            (int)$criteria["sort_order"];

        if ($sortOrder <= 0) {
            $sortOrder =
                $insertedCriteria + 1;
        }

        $insertDetail = "
            INSERT INTO qa_incoming_goods_detail
            (
                qa_incoming_goods_id,

                item_id,
                item_name,

                criteria_id,
                criteria_code,

                sample_quantity,
                sample_unit,

                criteria_description,
                expected_result,
                inspection_method,
                inspection_result,

                sort_order,

                createdAt,
                updatedAt
            )
            VALUES
            (
                " . $qaId . ",

                " . $itemId . ",
                '" . db_addslashes(
                    $po["item_name"]
                ) . "',

                " . (int)$criteria["id"] . ",
                '" . db_addslashes(
                    $criteria["criteria_code"]
                ) . "',

                " . $totalSampleInspectedSql . ",
                '" . db_addslashes(
                    $po["unit_name"]
                ) . "',

                '" . db_addslashes(
                    $criteria[
                        "criteria_description"
                    ]
                ) . "',
                '" . db_addslashes(
                    $criteria[
                        "expected_result"
                    ]
                ) . "',
                '" . db_addslashes(
                    $inspectionMethod
                ) . "',
                'PASSED',

                " . $sortOrder . ",

                NOW(),
                NOW()
            )
        ";

        execOrFailQAIncoming(
            $insertDetail,
            "Insert QA Incoming Goods criterion"
        );

        $insertedCriteria++;
    }

    if ($insertedCriteria <= 0) {
        $criteriaSource = "NO_ACTIVE_CRITERIA";
    }


    // ======================================================
    // 13. COMMIT
    // ======================================================

    DB::Exec("COMMIT");


    // ======================================================
    // 14. RETURN RESULT TO CLIENT BUTTON
    // ======================================================

    $result["success"] = true;
    $result["already_exists"] = false;

    $result["message"] =
        "QA Incoming Goods created successfully. " .
        "QA No.: " . $qaNo;

    $result["qa_id"] = $qaId;
    $result["qa_no"] = $qaNo;

    $result["batch_no"] = $batchNo;
    $result["vbn"] = $vbn;

    $result["source_transaction_type"] =
        "PO_RECEIVING";

    $result["is_po"] = 1;
    $result["is_donation"] = 0;

    $result["purchase_order_id"] =
        (int)$po["purchase_order_id"];

    $result["po_detail_id"] =
        (int)$po["po_detail_id"];

    $result["po_no"] =
        $po["po_no"];

    $result["supplier_id"] =
        $supplierId;

    $result["supplier_name"] =
        $po["supplier_name"];

    $result["donor_id"] = null;

    $result["item_id"] = $itemId;
    $result["parent_item_id"] =
        $parentItemId;

    $result["sku"] =
        $po["sku"];

    $result["item_name"] =
        $po["item_name"];

    $result["kind"] =
        $po["item_kind"];

    $result["brand_id"] =
        $brandId;

    $result["unit_id"] =
        $unitId;

    $result["unit_name"] =
        $po["unit_name"];

    $result["delivered_quantity"] =
        $deliveredQuantity;

    $result["total_sample_inspected"] =
        $totalSampleInspected;

    $result["sample_rate"] = 2;

    $result["warehouse_id"] =
        (int)$warehouseData["warehouse_id"];

    $result["warehouse_name"] =
        $warehouseData["warehouse_name"];

    $result["warehouse_code"] =
        $warehouseData["warehouse_code"];

    $result["warehouse_source"] =
        $warehouseSource;

    $result["mother_facility_id"] =
        (int)$warehouseData[
            "mother_facility_id"
        ];

    $result["mother_facility_code"] =
        $warehouseData["facility_code"];

    $result["mother_facility_name"] =
        $warehouseData["facility_name"];

    $result["criteria_count"] =
        $insertedCriteria;

    $result["criteria_source"] =
        $criteriaSource;


// ==========================================================
// ERROR HANDLING
// ==========================================================

} catch (Exception $e) {

    DB::Exec("ROLLBACK");

    $result["success"] = false;
    $result["message"] = $e->getMessage();
};

		RunnerContext::pop();
		echo runner_json_encode( $result);
		$button->deleteTempFiles();
	}

		// custom button - Create Production Work Order
	function buttonHandler_2640( $_params )
	{
		$result = array();

		$button = $this->prepareButtonContext( $_params );
		$ajax = $button; 
		$keys = $button->getKeys();

		// .NET naming
		$parameters = $_params;
		$params = &$_params;

		$production_plan_detail_id = 0;

if (isset($params["production_plan_detail_id"])) {
    $production_plan_detail_id = intval($params["production_plan_detail_id"]);
}

if ($production_plan_detail_id <= 0) {
    $result["success"] = false;
    $result["message"] = "Invalid Production Plan Detail ID.";
    return;
}

/*
    Check if already imported
*/
$sqlCheck = "
    SELECT id, work_order_no
    FROM production_work_order
    WHERE production_plan_detail_id = ".$production_plan_detail_id."
    LIMIT 1
";

$rsCheck = DB::Query($sqlCheck);
$existing = $rsCheck ? $rsCheck->fetchAssoc() : null;

if ($existing) {
    $result["success"] = false;
    $result["message"] = "Already imported. Existing Work Order No.: ".$existing["work_order_no"];
    return;
}

/*
    Read source from custom view
*/
$sqlSource = "
    SELECT
        production_plan_id,
        production_plan_detail_id,
        schedule_date,
        warehouse_id,
        production_area,
        shift_code,
        production_line,
        finished_good_id,
        finished_good_name,
        finished_good_description,
        work_description,
        production_qty,
        uom,
        notes
    FROM vw_production_plan_for_work_order
    WHERE production_plan_detail_id = ".$production_plan_detail_id."
    LIMIT 1
";

$rsSource = DB::Query($sqlSource);

if (!$rsSource) {
    $result["success"] = false;
    $result["message"] = "Unable to read Production Plan source.";
    return;
}

$source = $rsSource->fetchAssoc();

if (!$source) {
    $result["success"] = false;
    $result["message"] = "Production Plan Detail not found or already imported.";
    return;
}

/*
    Generate Work Order No.
    Format: PWO-YYYYMM-0001
*/
$prefix = "PWO-" . date("Ym") . "-";

$sqlNo = "
    SELECT work_order_no
    FROM production_work_order
    WHERE work_order_no LIKE '".$prefix."%'
    ORDER BY work_order_no DESC
    LIMIT 1
";

$rsNo = DB::Query($sqlNo);
$rowNo = $rsNo ? $rsNo->fetchAssoc() : null;

$nextNo = 1;

if ($rowNo && !empty($rowNo["work_order_no"])) {
    $lastNo = intval(substr($rowNo["work_order_no"], -4));
    $nextNo = $lastNo + 1;
}

$work_order_no = $prefix . str_pad($nextNo, 4, "0", STR_PAD_LEFT);

/*
    Prepare values
*/
$production_plan_id = intval($source["production_plan_id"]);
$schedule_date = !empty($source["schedule_date"]) ? "'".db_addslashes($source["schedule_date"])."'" : "NULL";

$production_area = !empty($source["production_area"]) ? db_addslashes($source["production_area"]) : "";
$production_line = !empty($source["production_line"]) ? db_addslashes($source["production_line"]) : "";
$shift_code = !empty($source["shift_code"]) ? db_addslashes($source["shift_code"]) : "";

$finished_good_id = intval($source["finished_good_id"]);
$finished_good_description = !empty($source["finished_good_description"])
    ? db_addslashes($source["finished_good_description"])
    : db_addslashes($source["finished_good_name"]);

$target_qty = floatval($source["production_qty"]);
$uom = !empty($source["uom"]) ? db_addslashes($source["uom"]) : "";
$notes = !empty($source["notes"]) ? db_addslashes($source["notes"]) : "";

/*
    Insert header: production_work_order
*/
$sqlInsertHeader = "
    INSERT INTO production_work_order
    (
        work_order_no,
        work_order_date,
        production_plan_id,
        production_plan_detail_id,
        schedule_date,
        production_area,
        production_line,
        shift_code,
        date_start,
        status,
        remarks,
        created_at,
        updated_at
    )
    VALUES
    (
        '".$work_order_no."',
        CURDATE(),
        ".$production_plan_id.",
        ".$production_plan_detail_id.",
        ".$schedule_date.",
        '".$production_area."',
        '".$production_line."',
        '".$shift_code."',
        ".$schedule_date.",
        'OPEN',
        '".$notes."',
        NOW(),
        NOW()
    )
";

$okHeader = DB::Exec($sqlInsertHeader);

if (!$okHeader) {
    $result["success"] = false;
    $result["message"] = "Failed to create Production Work Order header.";
    return;
}

/*
    Get inserted work order ID
*/
$rsID = DB::Query("SELECT LAST_INSERT_ID() AS new_id");
$rowID = $rsID ? $rsID->fetchAssoc() : null;

if (!$rowID || empty($rowID["new_id"])) {
    $result["success"] = false;
    $result["message"] = "Work Order created but unable to get new Work Order ID.";
    return;
}

$production_work_order_id = intval($rowID["new_id"]);

/*
    Insert detail: production_work_order_details
*/
$sqlInsertDetail = "
    INSERT INTO production_work_order_details
    (
        production_work_order_id,
        line_no,
        finished_good_id,
        description,
        target_qty,
        actual_qty,
        uom,
        notes,
        created_at
    )
    VALUES
    (
        ".$production_work_order_id.",
        1,
        ".$finished_good_id.",
        '".$finished_good_description."',
        ".$target_qty.",
        0,
        '".$uom."',
        '".$notes."',
        NOW()
    )
";

$okDetail = DB::Exec($sqlInsertDetail);

if (!$okDetail) {
    $result["success"] = false;
    $result["message"] = "Work Order header created, but detail insert failed.";
    return;
}

$result["success"] = true;
$result["message"] = "Production Work Order created successfully: ".$work_order_no;
$result["work_order_no"] = $work_order_no;
$result["production_work_order_id"] = $production_work_order_id;;

		RunnerContext::pop();
		echo runner_json_encode( $result);
		$button->deleteTempFiles();
	}

		// custom button - Approve_Selected_Items
	function buttonHandler_2644( $_params )
	{
		$result = array();

		$button = $this->prepareButtonContext( $_params );
		$ajax = $button; 
		$keys = $button->getKeys();

		// .NET naming
		$parameters = $_params;
		$params = &$_params;

		$result["success"] = false;
$result["txt"] = "";

$approvedCount = 0;
$skippedCount = 0;

/*
 * Get the currently logged-in PHPRunner user.
 * The WINGS users table uses ID as its primary key.
 */
$userData = Security::currentUserData();

$approvedBy = 0;

if (isset($userData["ID"])) {
    $approvedBy = (int)$userData["ID"];
} elseif (isset($userData["id"])) {
    $approvedBy = (int)$userData["id"];
}

$approvedBySQL = $approvedBy > 0
    ? (string)$approvedBy
    : "NULL";

DB::Exec("START TRANSACTION");

$dbError = DB::LastError();

if ($dbError != "") {
    $result["txt"] = "Unable to start approval transaction: " . $dbError;
    return;
}

/*
 * Process every record checked on the dashboard.
 */
while ($record = $button->getNextSelectedRecord()) {

    $itemId = isset($record["id"])
        ? (int)$record["id"]
        : 0;

    if ($itemId <= 0) {
        $skippedCount++;
        continue;
    }

    /*
     * Lock and verify the record before approving.
     */
    $rsItem = DB::Query("
        SELECT
            id,
            status
        FROM item
        WHERE id = " . $itemId . "
        FOR UPDATE
    ");

    $dbError = DB::LastError();

    if ($dbError != "") {
        DB::Exec("ROLLBACK");

        $result["txt"] =
            "Approval failed while checking Item ID " .
            $itemId . ": " . $dbError;

        return;
    }

    $itemData = $rsItem
        ? $rsItem->fetchAssoc()
        : null;

    /*
     * Skip records that no longer exist or were already processed
     * by another approver.
     */
    if (
        !$itemData ||
        $itemData["status"] !== "Pending"
    ) {
        $skippedCount++;
        continue;
    }

    $approvalRemarks = db_addslashes(
        "Approved through the Approval Dashboard"
    );

    $sqlUpdate = "
        UPDATE item
        SET
            status = 'Approved',
            approved_by = " . $approvedBySQL . ",
            approved_date = NOW(),
            approval_remarks = '" . $approvalRemarks . "',
            updatedAt = NOW()
        WHERE id = " . $itemId . "
          AND status = 'Pending'
    ";

    DB::Exec($sqlUpdate);

    $dbError = DB::LastError();

    if ($dbError != "") {
        DB::Exec("ROLLBACK");

        $result["txt"] =
            "Approval failed for Item ID " .
            $itemId . ": " . $dbError;

        return;
    }

    $approvedCount++;
}

DB::Exec("COMMIT");

$dbError = DB::LastError();

if ($dbError != "") {
    DB::Exec("ROLLBACK");

    $result["txt"] =
        "Unable to complete the approval: " . $dbError;

    return;
}

$result["success"] = true;

if ($approvedCount > 0) {
    $result["txt"] =
        $approvedCount .
        ($approvedCount === 1
            ? " item was approved successfully."
            : " items were approved successfully.");
} else {
    $result["txt"] =
        "No pending items were approved.";
}

if ($skippedCount > 0) {
    $result["txt"] .=
        " " . $skippedCount .
        ($skippedCount === 1
            ? " record was skipped because it was already processed."
            : " records were skipped because they were already processed.");
};

		RunnerContext::pop();
		echo runner_json_encode( $result);
		$button->deleteTempFiles();
	}

		// custom button - Import DROMIC Approved RIS
	function buttonHandler_2646( $_params )
	{
		$result = array();

		$button = $this->prepareButtonContext( $_params );
		$ajax = $button; 
		$keys = $button->getKeys();

		// .NET naming
		$parameters = $_params;
		$params = &$_params;

		/*
===============================================================
 DSWD WINGS
 DROMIC APPROVED RIS IMPORT

 UPDATED FLOW:

 DROMIC Approved RIS
        ↓
 WINGS Request = PENDING
        ↓
 Allocation Status = FOR_ALLOCATION
        ↓
 Generic requested items only
        ↓
 Allocation Officer selects actual:
 SKU + Warehouse + Batch + Expiry
        ↓
 DROMIC Confirmation
        ↓
 WINGS Director Approval

 IMPORTANT:
 - DROMIC item is NOT automatically mapped to WINGS item_id.
 - item_id remains NULL during import.
 - DROMIC values populate both:
      1. WINGS working fields
      2. DROMIC original/audit fields
===============================================================
*/


/* ============================================================
   HELPER: SQL VALUE
   ============================================================ */

if (!function_exists("dromic_sql_value")) {

    function dromic_sql_value($value)
    {
        if ($value === null || $value === "") {
            return "NULL";
        }

        return "'" . db_addslashes($value) . "'";
    }
}


/* ============================================================
   HELPER: DATE ONLY
   ============================================================ */

if (!function_exists("dromic_date_only")) {

    function dromic_date_only($value)
    {
        if (!$value) {
            return null;
        }

        $ts = strtotime($value);

        if (!$ts) {
            return null;
        }

        return date("Y-m-d", $ts);
    }
}


/* ============================================================
   HELPER: JSON
   ============================================================ */

if (!function_exists("dromic_json_encode")) {

    function dromic_json_encode($value)
    {
        $json = json_encode(
            $value,
            JSON_UNESCAPED_UNICODE |
            JSON_UNESCAPED_SLASHES
        );

        if ($json === false) {
            return "";
        }

        return $json;
    }
}


/* ============================================================
   HELPER: LAST INSERT ID
   ============================================================ */

if (!function_exists("dromic_last_id")) {

    function dromic_last_id()
    {
        $rs = DB::Query(
            "SELECT LAST_INSERT_ID() AS last_id"
        );

        $data = $rs
            ? $rs->fetchAssoc()
            : null;

        return isset($data["last_id"])
            ? (int)$data["last_id"]
            : 0;
    }
}


/* ============================================================
   HELPER: API CALL
   ============================================================ */

if (!function_exists("dromic_api_call")) {

    function dromic_api_call(
        $method,
        $url,
        $headers = array(),
        $body = null
    )
    {
        $ch = curl_init();

        curl_setopt(
            $ch,
            CURLOPT_URL,
            $url
        );

        curl_setopt(
            $ch,
            CURLOPT_CUSTOMREQUEST,
            $method
        );

        curl_setopt(
            $ch,
            CURLOPT_RETURNTRANSFER,
            true
        );

        curl_setopt(
            $ch,
            CURLOPT_TIMEOUT,
            60
        );

        curl_setopt(
            $ch,
            CURLOPT_CONNECTTIMEOUT,
            30
        );

        if (!empty($headers)) {

            curl_setopt(
                $ch,
                CURLOPT_HTTPHEADER,
                $headers
            );
        }

        if ($body !== null) {

            curl_setopt(
                $ch,
                CURLOPT_POSTFIELDS,
                $body
            );
        }


        $response =
            curl_exec($ch);

        $error =
            curl_error($ch);

        $httpCode =
            curl_getinfo(
                $ch,
                CURLINFO_HTTP_CODE
            );


        curl_close($ch);


        return array(

            "http_code" =>
                $httpCode,

            "response" =>
                $response,

            "error" =>
                $error

        );
    }
}


/* ============================================================
   HELPER: IMPORT LOG
   ============================================================ */

if (!function_exists("dromic_log")) {

    function dromic_log(
        $externalRequestId,
        $requestNo,
        $actionType,
        $status,
        $message,
        $payload = ""
    )
    {
        DB::Exec("
            INSERT INTO dromic_api_import_log
            (
                external_request_id,
                request_no,
                action_type,
                status,
                message,
                raw_payload,
                created_at
            )
            VALUES
            (
                " . dromic_sql_value(
                        $externalRequestId
                    ) . ",

                " . dromic_sql_value(
                        $requestNo
                    ) . ",

                " . dromic_sql_value(
                        $actionType
                    ) . ",

                " . dromic_sql_value(
                        $status
                    ) . ",

                " . dromic_sql_value(
                        $message
                    ) . ",

                " . dromic_sql_value(
                        $payload
                    ) . ",

                NOW()
            )
        ");
    }
}




/* ============================================================
   HELPER: NORMALIZE OFFICE / FACILITY TEXT
   ============================================================ */

if (!function_exists("dromic_normalize_facility_text")) {

    function dromic_normalize_facility_text($value)
    {
        $value = trim((string)$value);

        if ($value === "") {
            return "";
        }

        if (function_exists("mb_strtoupper")) {
            $value = mb_strtoupper($value, "UTF-8");
        } else {
            $value = strtoupper($value);
        }

        $value = str_replace(
            array(".", ",", ";", ":", "(", ")", "[", "]", "{", "}"),
            " ",
            $value
        );

        $value = preg_replace(
            '/\s+/',
            ' ',
            $value
        );

        return trim($value);
    }
}


/* ============================================================
   HELPER: EXTRACT MOTHER FACILITY CODE FROM DROMIC TEXT

   Examples:
   - DSWD Field Office VI     -> VI
   - DSWD FO VI               -> VI
   - Region VI                -> VI
   - Field Office CALABARZON  -> CALABARZON
   - Region IV-A / 4A         -> CALABARZON
   - Region IV-B / 4B         -> MIMAROPA
   ============================================================ */

if (!function_exists("dromic_extract_facility_code")) {

    function dromic_extract_facility_code($value)
    {
        $value =
            dromic_normalize_facility_text(
                $value
            );

        if ($value === "") {
            return "";
        }

        if (
            strpos($value, "NEGROS ISLAND REGION") !== false
        ) {
            return "NIR";
        }

        if (
            strpos($value, "NATIONAL CAPITAL REGION") !== false
        ) {
            return "NCR";
        }

        if (
            strpos($value, "CORDILLERA ADMINISTRATIVE REGION") !== false
        ) {
            return "CAR";
        }

        if (
            preg_match(
                '/\b(?:REGION|FIELD OFFICE|FO)\s+(?:IV[\-\s]?A|4[\-\s]?A)\b/i',
                $value
            )
        ) {
            return "CALABARZON";
        }

        if (
            preg_match(
                '/\b(?:REGION|FIELD OFFICE|FO)\s+(?:IV[\-\s]?B|4[\-\s]?B)\b/i',
                $value
            )
        ) {
            return "MIMAROPA";
        }

        if (
            preg_match(
                '/\b(?:DSWD\s+)?(?:FIELD\s+OFFICE|FO|REGION)\s+' .
                '(CALABARZON|MIMAROPA|CARAGA|NCR|NIR|CAR|' .
                'XII|XI|IX|VIII|VII|VI|V|III|II|I)\b/i',
                $value,
                $matches
            )
        ) {
            return strtoupper(
                trim($matches[1])
            );
        }

        return "";
    }
}


/* ============================================================
   HELPER: GET ACTIVE MOTHER FACILITY BY CODE
   ============================================================ */

if (!function_exists("dromic_get_facility_by_code")) {

    function dromic_get_facility_by_code($facilityCode)
    {
        $facilityCode =
            trim((string)$facilityCode);

        if ($facilityCode === "") {
            return null;
        }

        $sql = "
            SELECT
                id,
                facility_code,
                facility_name
            FROM mother_facility
            WHERE
                CONVERT(facility_code USING utf8mb4)
                    COLLATE utf8mb4_general_ci
                =
                _utf8mb4'" .
                    db_addslashes($facilityCode) . "'
                    COLLATE utf8mb4_general_ci
              AND status = 'ACTIVE'
            LIMIT 1
        ";

        $rs =
            DB::Query($sql);

        return $rs
            ? $rs->fetchAssoc()
            : null;
    }
}


/* ============================================================
   HELPER: RESOLVE DROMIC OFFICE TO MOTHER FACILITY

   Resolution order:
   1. Exact match with facility code/name/region
   2. Parse Field Office / FO / Region code
   3. Use delivery site
   4. Use first barangay-detail region

   The request still imports when no mapping is found.
   mother_facility_id remains NULL for manual assignment.
   ============================================================ */

if (!function_exists("dromic_resolve_mother_facility")) {

    function dromic_resolve_mother_facility(
        $requestingOffice,
        $deliverySite,
        $row = array()
    )
    {
        $candidates = array();

        if (trim((string)$requestingOffice) !== "") {
            $candidates[] = array(
                "value" => $requestingOffice,
                "source" => "requesting_office"
            );
        }

        if (trim((string)$deliverySite) !== "") {
            $candidates[] = array(
                "value" => $deliverySite,
                "source" => "delivery_site"
            );
        }

        if (
            isset($row["details"]) &&
            is_array($row["details"])
        ) {
            foreach ($row["details"] as $detail) {

                if (
                    !isset($detail["location"]) ||
                    !is_array($detail["location"])
                ) {
                    continue;
                }

                $location =
                    $detail["location"];

                if (
                    isset($location["region"]) &&
                    trim((string)$location["region"]) !== ""
                ) {
                    $candidates[] = array(
                        "value" => $location["region"],
                        "source" => "detail_region"
                    );

                    break;
                }
            }
        }

        /*
         * First pass:
         * Exact normalized match against mother_facility.
         */
        foreach ($candidates as $candidate) {

            $normalized =
                dromic_normalize_facility_text(
                    $candidate["value"]
                );

            if ($normalized === "") {
                continue;
            }

            $sql = "
                SELECT
                    id,
                    facility_code,
                    facility_name
                FROM mother_facility
                WHERE status = 'ACTIVE'
                  AND
                  (
                      CONVERT(UPPER(TRIM(facility_code)) USING utf8mb4)
                          COLLATE utf8mb4_general_ci
                      =
                      _utf8mb4'" .
                          db_addslashes($normalized) . "'
                          COLLATE utf8mb4_general_ci

                      OR

                      CONVERT(UPPER(TRIM(facility_name)) USING utf8mb4)
                          COLLATE utf8mb4_general_ci
                      =
                      _utf8mb4'" .
                          db_addslashes($normalized) . "'
                          COLLATE utf8mb4_general_ci

                      OR

                      CONVERT(UPPER(TRIM(COALESCE(region,''))) USING utf8mb4)
                          COLLATE utf8mb4_general_ci
                      =
                      _utf8mb4'" .
                          db_addslashes($normalized) . "'
                          COLLATE utf8mb4_general_ci
                  )
                LIMIT 1
            ";

            $rs =
                DB::Query($sql);

            $facility =
                $rs
                    ? $rs->fetchAssoc()
                    : null;

            if (
                $facility &&
                isset($facility["id"]) &&
                (int)$facility["id"] > 0
            ) {
                return array(
                    "mother_facility_id" =>
                        (int)$facility["id"],

                    "facility_code" =>
                        $facility["facility_code"],

                    "facility_name" =>
                        $facility["facility_name"],

                    "matched_from" =>
                        $candidate["source"],

                    "matched_value" =>
                        $candidate["value"]
                );
            }
        }

        /*
         * Second pass:
         * Parse a regional/facility code from the text.
         */
        foreach ($candidates as $candidate) {

            $facilityCode =
                dromic_extract_facility_code(
                    $candidate["value"]
                );

            if ($facilityCode === "") {
                continue;
            }

            $facility =
                dromic_get_facility_by_code(
                    $facilityCode
                );

            if (
                $facility &&
                isset($facility["id"]) &&
                (int)$facility["id"] > 0
            ) {
                return array(
                    "mother_facility_id" =>
                        (int)$facility["id"],

                    "facility_code" =>
                        $facility["facility_code"],

                    "facility_name" =>
                        $facility["facility_name"],

                    "matched_from" =>
                        $candidate["source"],

                    "matched_value" =>
                        $candidate["value"]
                );
            }
        }

        return array(
            "mother_facility_id" => 0,
            "facility_code" => "",
            "facility_name" => "",
            "matched_from" => "",
            "matched_value" => ""
        );
    }
}


/* ============================================================
   MAIN PROCESS
   ============================================================ */

try {


    /* ========================================================
       CURRENT WINGS USER
       ======================================================== */

    $createdBy = 0;


    /*
       Prefer PHPRunner Security API.
    */

    $currentUser =
        Security::currentUserData();


    if (is_array($currentUser)) {

        if (
            isset($currentUser["ID"]) &&
            $currentUser["ID"] !== ""
        ) {

            $createdBy =
                (int)$currentUser["ID"];

        } elseif (
            isset($currentUser["id"]) &&
            $currentUser["id"] !== ""
        ) {

            $createdBy =
                (int)$currentUser["id"];
        }
    }


    /*
       Fallback to existing session variable.
    */

    if (
        $createdBy <= 0 &&
        isset($_SESSION["user_id"]) &&
        $_SESSION["user_id"] !== ""
    ) {

        $createdBy =
            (int)$_SESSION["user_id"];
    }



    /*
       mother_facility_id is resolved per DROMIC request
       from requesting_office / delivery_site / detail region.
    */


    /* ========================================================
       1. GET ACTIVE DROMIC API CONFIG
       ======================================================== */

    $rsConfig = DB::Query("
        SELECT *
        FROM dromic_api_config
        WHERE is_active = 1
        ORDER BY config_id DESC
        LIMIT 1
    ");


    $config = $rsConfig
        ? $rsConfig->fetchAssoc()
        : null;


    if (!$config) {

        $result["success"] = false;

        $result["message"] =
            "No active DROMIC API setting found. " .
            "Please add one active record in DROMIC API Settings.";

        return;
    }


    $configId =
        (int)$config["config_id"];

    $baseUrl =
        rtrim(
            $config["base_url"],
            "/"
        );

    $username =
        $config["username"];

    $password =
        $config["password_value"];



    /* ========================================================
       2. REUSE EXISTING TOKEN IF VALID
       ======================================================== */

    $accessToken = "";

    $reuseExistingToken =
        false;


    if (
        isset($config["access_token"]) &&
        trim($config["access_token"]) != "" &&

        isset($config["token_expires_at"]) &&
        trim($config["token_expires_at"]) != ""
    ) {

        $tokenExpiryTime =
            strtotime(
                $config["token_expires_at"]
            );


        if (
            $tokenExpiryTime !== false &&
            $tokenExpiryTime > time() + 60
        ) {

            $accessToken =
                trim(
                    $config["access_token"]
                );

            $reuseExistingToken =
                true;
        }
    }



    /* ========================================================
       TOKEN STILL VALID
       ======================================================== */

    if ($reuseExistingToken) {

        dromic_log(
            null,
            null,
            "TOKEN_TEST",
            "SUCCESS",
            "Existing DROMIC token reused.",
            ""
        );
    }


    /* ========================================================
       REQUEST NEW TOKEN
       ======================================================== */

    else {

        $tokenBody =
            dromic_json_encode(
                array(

                    "username" =>
                        $username,

                    "password" =>
                        $password
                )
            );


        $tokenCall =
            dromic_api_call(

                "POST",

                $baseUrl .
                "/api/assistance/auth/token",

                array(
                    "Content-Type: application/json",
                    "Accept: application/json"
                ),

                $tokenBody
            );


        if ($tokenCall["error"]) {

            dromic_log(
                null,
                null,
                "TOKEN_TEST",
                "FAILED",
                $tokenCall["error"],
                $tokenCall["response"]
            );


            $result["success"] =
                false;

            $result["message"] =
                "Token request failed: " .
                $tokenCall["error"];

            return;
        }



        if (
            $tokenCall["http_code"] != 200 &&
            $tokenCall["http_code"] != 201
        ) {

            dromic_log(
                null,
                null,
                "TOKEN_TEST",
                "FAILED",
                "HTTP " .
                $tokenCall["http_code"],
                $tokenCall["response"]
            );


            $result["success"] =
                false;

            $result["message"] =
                "Token request failed. HTTP Code: " .
                $tokenCall["http_code"] .
                "\nResponse: " .
                $tokenCall["response"];

            return;
        }



        $tokenJson =
            json_decode(
                $tokenCall["response"],
                true
            );


        if (
            !is_array($tokenJson) ||
            !isset(
                $tokenJson["access_token"]
            )
        ) {

            dromic_log(
                null,
                null,
                "TOKEN_TEST",
                "FAILED",
                "Access token not returned.",
                $tokenCall["response"]
            );


            $result["success"] =
                false;

            $result["message"] =
                "Token request failed. " .
                "Access token not returned.\nResponse: " .
                $tokenCall["response"];

            return;
        }



        $accessToken =
            $tokenJson["access_token"];


        $expiresIn =
            isset(
                $tokenJson["expires_in"]
            )
            ? (int)$tokenJson["expires_in"]
            : 86400;


        $tokenExpiresAt =
            date(
                "Y-m-d H:i:s",
                time() + $expiresIn - 300
            );


        DB::Exec("
            UPDATE dromic_api_config

            SET
                access_token =
                " . dromic_sql_value(
                        $accessToken
                    ) . ",

                token_expires_at =
                " . dromic_sql_value(
                        $tokenExpiresAt
                    ) . ",

                updated_at = NOW()

            WHERE config_id =
                " . $configId
        );


        dromic_log(
            null,
            null,
            "TOKEN_TEST",
            "SUCCESS",
            "New DROMIC token generated successfully.",
            ""
        );
    }



    /* ========================================================
       3. GET ALL APPROVED DROMIC AUGMENTATION REQUESTS
       ======================================================== */

    $allRows =
        array();

    $page = 1;

    $limit = 100;

    $totalRecords =
        null;

    $maxPages = 1000;



    while (true) {


        $listUrl =
            $baseUrl .
            "/api/assistance/approved-augmentation-requests" .
            "?page=" .
            $page .
            "&limit=" .
            $limit;



        $listCall =
            dromic_api_call(

                "GET",

                $listUrl,

                array(
                    "Accept: application/json",
                    "Authorization: Bearer " .
                    $accessToken
                ),

                null
            );



        if ($listCall["error"]) {

            dromic_log(
                null,
                null,
                "API_TEST",
                "FAILED",
                "Page " .
                $page .
                ": " .
                $listCall["error"],
                $listCall["response"]
            );


            $result["success"] =
                false;

            $result["message"] =
                "Approved RIS API call failed on page " .
                $page .
                ": " .
                $listCall["error"];

            return;
        }



        if (
            $listCall["http_code"] != 200
        ) {

            dromic_log(
                null,
                null,
                "API_TEST",
                "FAILED",
                "Page " .
                $page .
                " HTTP " .
                $listCall["http_code"],
                $listCall["response"]
            );


            $result["success"] =
                false;

            $result["message"] =
                "Approved RIS API failed on page " .
                $page .
                ". HTTP Code: " .
                $listCall["http_code"] .
                "\nResponse: " .
                $listCall["response"];

            return;
        }



        $listJson =
            json_decode(
                $listCall["response"],
                true
            );



        if (
            !is_array($listJson) ||
            !isset(
                $listJson["success"]
            ) ||
            !$listJson["success"]
        ) {

            dromic_log(
                null,
                null,
                "API_TEST",
                "FAILED",
                "API returned unsuccessful response on page " .
                $page,
                $listCall["response"]
            );


            $result["success"] =
                false;

            $result["message"] =
                "Approved RIS API returned unsuccessful response on page " .
                $page .
                ".";

            return;
        }



        if (
            !isset($listJson["data"]) ||
            !is_array(
                $listJson["data"]
            )
        ) {

            dromic_log(
                null,
                null,
                "API_TEST",
                "FAILED",
                "No valid data array returned on page " .
                $page,
                $listCall["response"]
            );


            $result["success"] =
                false;

            $result["message"] =
                "No valid data array returned by DROMIC on page " .
                $page .
                ".";

            return;
        }



        if (
            $totalRecords === null &&
            isset(
                $listJson["total_records"]
            )
        ) {

            $totalRecords =
                (int)$listJson["total_records"];
        }



        $pageRows =
            $listJson["data"];



        if (count($pageRows) == 0) {
            break;
        }



        foreach ($pageRows as $r) {

            $allRows[] = $r;
        }



        if (
            $totalRecords !== null &&
            count($allRows) >=
            $totalRecords
        ) {
            break;
        }



        if (
            count($pageRows) <
            $limit
        ) {
            break;
        }



        $page++;



        if ($page > $maxPages) {

            dromic_log(
                null,
                null,
                "API_TEST",
                "FAILED",
                "Max page limit reached.",
                ""
            );


            $result["success"] =
                false;

            $result["message"] =
                "Import stopped because max page limit was reached.";

            return;
        }
    }



    dromic_log(
        null,
        null,
        "API_TEST",
        "SUCCESS",
        "Approved RIS API fetched successfully. Total rows fetched: " .
        count($allRows),
        ""
    );



    /* ========================================================
       4. IMPORT COUNTERS
       ======================================================== */

    $imported = 0;

    $skipped = 0;

    $errorCount = 0;

    $facilityMapped = 0;

    $facilityUnmapped = 0;



    /* ========================================================
       BEGIN DATABASE TRANSACTION
       ======================================================== */

    DB::Exec(
        "START TRANSACTION"
    );



    /* ========================================================
       LOOP THROUGH DROMIC REQUESTS
       ======================================================== */

    foreach ($allRows as $row) {


        /* ====================================================
           IDENTIFIERS
           ==================================================== */

        $externalRequestId =
            isset(
                $row["external_request_id"]
            )
            ? trim(
                $row["external_request_id"]
            )
            : "";


        $requestNo =
            isset(
                $row["request_no"]
            )
            ? trim(
                $row["request_no"]
            )
            : "";



        if (
            $externalRequestId == "" ||
            $requestNo == ""
        ) {

            $skipped++;


            dromic_log(

                $externalRequestId,

                $requestNo,

                "ERROR",

                "WARNING",

                "Skipped record due to missing external_request_id or request_no.",

                dromic_json_encode(
                    $row
                )
            );


            continue;
        }



        /* ====================================================
           DUPLICATE CHECK

           Primary:
           external_request_id

           Secondary:
           request_no / ris_no
           ==================================================== */

        $rsDup =
            DB::Query("
                SELECT
                    augmentation_request_id

                FROM augmentation_request

                WHERE
                    external_request_id =
                    " . dromic_sql_value(
                            $externalRequestId
                        ) . "

                    OR request_no =
                    " . dromic_sql_value(
                            $requestNo
                        ) . "

                    OR ris_no =
                    " . dromic_sql_value(
                            $requestNo
                        ) . "

                LIMIT 1
            ");



        $dup =
            $rsDup
            ? $rsDup->fetchAssoc()
            : null;



        if ($dup) {

            $skipped++;


            dromic_log(

                $externalRequestId,

                $requestNo,

                "SKIP_DUPLICATE",

                "WARNING",

                "Already imported or request number already exists.",

                dromic_json_encode(
                    $row
                )
            );


            continue;
        }



        /* ====================================================
           EXTRACT HEADER OBJECTS
           ==================================================== */

        $delivery =
            isset($row["delivery"]) &&
            is_array(
                $row["delivery"]
            )
            ? $row["delivery"]
            : array();


        $requestedBy =
            isset($row["requested_by"]) &&
            is_array(
                $row["requested_by"]
            )
            ? $row["requested_by"]
            : array();


        $approvedBy =
            isset($row["approved_by"]) &&
            is_array(
                $row["approved_by"]
            )
            ? $row["approved_by"]
            : array();


        $report =
            isset($row["dromic_report"]) &&
            is_array(
                $row["dromic_report"]
            )
            ? $row["dromic_report"]
            : array();



        /* ====================================================
           REQUEST VALUES
           ==================================================== */

        $purpose =
            isset($row["purpose"])
            ? $row["purpose"]
            : "";


        $requestingOffice =
            isset(
                $row["requesting_office"]
            )
            ? $row["requesting_office"]
            : "";



        /* ====================================================
           DELIVERY
           ==================================================== */

        $deliverySite =
            isset(
                $delivery["delivery_site"]
            )
            ? $delivery["delivery_site"]
            : "";


        $deliveryDate =
            isset(
                $delivery["delivery_date"]
            )
            ? dromic_date_only(
                $delivery["delivery_date"]
            )
            : null;


        $contactPerson =
            isset(
                $delivery["contact_person"]
            )
            ? $delivery["contact_person"]
            : "";


        $contactNumber =
            isset(
                $delivery["contact_number"]
            )
            ? $delivery["contact_number"]
            : "";



        /* ====================================================
           REQUESTOR
           ==================================================== */

        $requestorName =
            isset(
                $requestedBy["name"]
            )
            ? $requestedBy["name"]
            : "DROMIC Requestor";


        $requestorDesignation =
            isset(
                $requestedBy["designation"]
            )
            ? $requestedBy["designation"]
            : "";


        $requestDate =
            isset(
                $requestedBy["date"]
            )
            ? dromic_date_only(
                $requestedBy["date"]
            )
            : date("Y-m-d");


        if (!$requestDate) {

            $requestDate =
                date("Y-m-d");
        }



        /* ====================================================
           DROMIC SOURCE APPROVAL

           These remain available inside the original payload.

           We DO NOT use the WINGS approved_by_* fields here
           because the WINGS Director still needs to approve
           this request after allocation.
           ==================================================== */

        $dromicApprovedByName =
            isset(
                $approvedBy["name"]
            )
            ? $approvedBy["name"]
            : "";


        $dromicApprovedByDesignation =
            isset(
                $approvedBy["designation"]
            )
            ? $approvedBy["designation"]
            : "";


        $dromicApprovedDate =
            isset(
                $approvedBy["date"]
            )
            ? dromic_date_only(
                $approvedBy["date"]
            )
            : null;



        /* ====================================================
           DROMIC REPORT
           ==================================================== */

        $dromicReportId =
            isset(
                $report["report_id"]
            )
            ? $report["report_id"]
            : "";


        $dromicReportName =
            isset(
                $report["report_name"]
            )
            ? $report["report_name"]
            : "";


        $disasterType =
            isset(
                $report["disaster_type"]
            )
            ? $report["disaster_type"]
            : "";


        $dromicReportStatus =
            isset(
                $report["report_status"]
            )
            ? $report["report_status"]
            : "";



        $payloadJson =
            dromic_json_encode(
                $row
            );


        /* ====================================================
           AUTOMATIC MOTHER FACILITY RESOLUTION

           Example:
           DSWD Field Office VI
                    ↓
           mother_facility.facility_code = VI
                    ↓
           mother_facility_id = 14

           The import continues even when no mapping is found.
           ==================================================== */

        $facilityResolution =
            dromic_resolve_mother_facility(
                $requestingOffice,
                $deliverySite,
                $row
            );

        $resolvedMotherFacilityId =
            isset(
                $facilityResolution[
                    "mother_facility_id"
                ]
            )
            ? (int)$facilityResolution[
                "mother_facility_id"
              ]
            : 0;


        if ($resolvedMotherFacilityId > 0) {

            $motherFacilitySql =
                (string)$resolvedMotherFacilityId;

            $facilityMapped++;

        } else {

            $motherFacilitySql =
                "NULL";

            $facilityUnmapped++;


            dromic_log(
                $externalRequestId,
                $requestNo,
                "IMPORT",
                "WARNING",
                "No active Mother Facility was matched for DROMIC requesting office: " .
                    ($requestingOffice !== ""
                        ? $requestingOffice
                        : "(blank)") .
                    ". The request was imported with mother_facility_id = NULL.",
                $payloadJson
            );
        }



        /* ====================================================
           5. INSERT WINGS AUGMENTATION HEADER

           DROMIC may have approved the request externally.

           BUT inside WINGS:
              status            = PENDING
              allocation_status = FOR_ALLOCATION

           because allocation + WINGS approval have not
           happened yet.
           ==================================================== */

        DB::Exec("
            INSERT INTO augmentation_request
            (
                request_no,
                ris_no,

                request_type_id,

                request_date,
                ris_date,
                date_needed,

                request_channel,
                external_source,
                external_request_id,

                dromic_report_id,
                dromic_report_name,
                dromic_report_status,

                dromic_sync_status,
                dromic_payload_json,
                dromic_last_synced_at,

                dromic_allocation_go_signal_status,

                mother_facility_id,

                requesting_office,

                requestor_name,
                requestor_position,
                requestor_contact_no,

                delivery_site,
                delivery_date,
                address,

                contact_person,
                contact_number,

                disaster_type,
                purpose,

                requested_by_name,
                requested_by_designation,
                requested_signature_date,

                status_id,
                current_step,
                status,
                allocation_status,

                created_by,
                created_at,

                updated_by,
                updated_at
            )
            VALUES
            (
                " . dromic_sql_value(
                        $requestNo
                    ) . ",

                " . dromic_sql_value(
                        $requestNo
                    ) . ",

                0,

                " . dromic_sql_value(
                        $requestDate
                    ) . ",

                " . dromic_sql_value(
                        $dromicApprovedDate
                    ) . ",

                " . dromic_sql_value(
                        $deliveryDate
                    ) . ",

                'dromic',

                'DROMIC',

                " . dromic_sql_value(
                        $externalRequestId
                    ) . ",

                " . dromic_sql_value(
                        $dromicReportId
                    ) . ",

                " . dromic_sql_value(
                        $dromicReportName
                    ) . ",

                " . dromic_sql_value(
                        $dromicReportStatus
                    ) . ",

                'IMPORTED',

                " . dromic_sql_value(
                        $payloadJson
                    ) . ",

                NOW(),

                'PENDING',

                " . $motherFacilitySql . ",

                " . dromic_sql_value(
                        $requestingOffice
                    ) . ",

                " . dromic_sql_value(
                        $requestorName
                    ) . ",

                " . dromic_sql_value(
                        $requestorDesignation
                    ) . ",

                NULL,

                " . dromic_sql_value(
                        $deliverySite
                    ) . ",

                " . dromic_sql_value(
                        $deliveryDate
                    ) . ",

                " . dromic_sql_value(
                        $deliverySite
                    ) . ",

                " . dromic_sql_value(
                        $contactPerson
                    ) . ",

                " . dromic_sql_value(
                        $contactNumber
                    ) . ",

                " . dromic_sql_value(
                        $disasterType
                    ) . ",

                " . dromic_sql_value(
                        $purpose
                    ) . ",

                " . dromic_sql_value(
                        $requestorName
                    ) . ",

                " . dromic_sql_value(
                        $requestorDesignation
                    ) . ",

                " . dromic_sql_value(
                        $requestDate
                    ) . ",

                0,

                'FOR_ALLOCATION',

                'PENDING',

                'FOR_ALLOCATION',

                " . $createdBy . ",

                NOW(),

                " . $createdBy . ",

                NOW()
            )
        ");



        if (DB::LastError()) {

            throw new Exception(
                "Header insert failed for request " .
                $requestNo .
                ": " .
                DB::LastError()
            );
        }



        $augmentationRequestId =
            dromic_last_id();



        if (
            $augmentationRequestId <= 0
        ) {

            throw new Exception(
                "Header insert failed for request " .
                $requestNo .
                ". No augmentation_request_id returned."
            );
        }



        /* ====================================================
           6. INSERT REQUESTED ITEM LINES

           IMPORTANT:

           item_id = NULL

           because DROMIC only tells WINGS WHAT IS NEEDED.

           Allocation Officer later decides:
              item_id / SKU
              warehouse
              batch
              expiry
              allocated qty

           Both working fields and original DROMIC fields
           are populated here.
           ==================================================== */

        $items =
            isset($row["items"]) &&
            is_array(
                $row["items"]
            )
            ? $row["items"]
            : array();



        foreach ($items as $item) {


            $lineNo =
                isset(
                    $item["line_no"]
                )
                ? (int)$item["line_no"]
                : 1;


            $category =
                isset(
                    $item["category"]
                )
                ? trim(
                    $item["category"]
                )
                : "";


            $desc =
                isset(
                    $item[
                        "requested_item_description"
                    ]
                )
                ? trim(
                    $item[
                        "requested_item_description"
                    ]
                )
                : "";


            $unit =
                isset(
                    $item["unit"]
                )
                ? trim(
                    $item["unit"]
                )
                : "";


            $qty =
                isset(
                    $item[
                        "requisition_quantity"
                    ]
                )
                ? (float)$item[
                    "requisition_quantity"
                ]
                : 0;


            $remarks =
                isset(
                    $item["remarks"]
                )
                ? trim(
                    $item["remarks"]
                )
                : "";


            $itemPayload =
                dromic_json_encode(
                    $item
                );



            if ($desc == "") {

                $desc =
                    "Unspecified DROMIC Item";
            }



            /*
               Skip meaningless zero/negative quantities.
            */

            if ($qty <= 0) {

                dromic_log(

                    $externalRequestId,

                    $requestNo,

                    "ITEM_WARNING",

                    "WARNING",

                    "Skipped DROMIC item line " .
                    $lineNo .
                    " because requisition quantity is zero or negative.",

                    $itemPayload
                );


                continue;
            }



            DB::Exec("
                INSERT INTO augmentation_request_item
                (
                    augmentation_request_id,
                    line_no,

                    item_id,

                    item_description,
                    requested_category,
                    unit,
                    requested_qty,

                    stock_available_status,
                    stock_available_qty,

                    approved_qty,
                    approval_status,

                    item_status,

                    remarks,

                    dromic_line_no,
                    dromic_category,
                    dromic_requested_item_description,
                    dromic_original_unit,
                    dromic_original_quantity,
                    dromic_payload_json,

                    created_at
                )
                VALUES
                (
                    " . (int)$augmentationRequestId . ",

                    " . (int)$lineNo . ",

                    NULL,

                    " . dromic_sql_value(
                            $desc
                        ) . ",

                    " . dromic_sql_value(
                            $category
                        ) . ",

                    " . dromic_sql_value(
                            $unit
                        ) . ",

                    " . (float)$qty . ",

                    NULL,

                    0,

                    0,

                    'PENDING',

                    'REQUESTED',

                    " . dromic_sql_value(
                            $remarks
                        ) . ",

                    " . (int)$lineNo . ",

                    " . dromic_sql_value(
                            $category
                        ) . ",

                    " . dromic_sql_value(
                            $desc
                        ) . ",

                    " . dromic_sql_value(
                            $unit
                        ) . ",

                    " . (float)$qty . ",

                    " . dromic_sql_value(
                            $itemPayload
                        ) . ",

                    NOW()
                )
            ");



            if (DB::LastError()) {

                throw new Exception(
                    "Unable to import DROMIC item line " .
                    $lineNo .
                    " for request " .
                    $requestNo .
                    ": " .
                    DB::LastError()
                );
            }
        }



        /* ====================================================
           7. INSERT BARANGAY-LEVEL DROMIC DETAILS
           ==================================================== */

        $details =
            isset($row["details"]) &&
            is_array(
                $row["details"]
            )
            ? $row["details"]
            : array();



        foreach ($details as $detail) {


            $location =
                isset(
                    $detail["location"]
                ) &&
                is_array(
                    $detail["location"]
                )
                ? $detail["location"]
                : array();


            $impact =
                isset(
                    $detail["impact"]
                ) &&
                is_array(
                    $detail["impact"]
                )
                ? $detail["impact"]
                : array();


            $transactionId =
                isset(
                    $detail[
                        "transaction_id"
                    ]
                )
                ? trim(
                    $detail[
                        "transaction_id"
                    ]
                )
                : "";



            DB::Exec("
                INSERT INTO dromic_augmentation_request_detail
                (
                    augmentation_request_id,
                    external_request_id,
                    transaction_id,

                    region,
                    region_code,

                    province,
                    province_code,

                    city_municipality,
                    city_municipality_code,

                    barangay,
                    barangay_code,

                    affected_families,
                    affected_individuals,

                    displaced_families,
                    displaced_persons,

                    detail_payload_json,

                    created_at
                )
                VALUES
                (
                    " . (int)$augmentationRequestId . ",

                    " . dromic_sql_value(
                            $externalRequestId
                        ) . ",

                    " . dromic_sql_value(
                            $transactionId
                        ) . ",

                    " . dromic_sql_value(
                            isset(
                                $location["region"]
                            )
                            ? $location["region"]
                            : ""
                        ) . ",

                    " . dromic_sql_value(
                            isset(
                                $location["region_code"]
                            )
                            ? $location["region_code"]
                            : ""
                        ) . ",

                    " . dromic_sql_value(
                            isset(
                                $location["province"]
                            )
                            ? $location["province"]
                            : ""
                        ) . ",

                    " . dromic_sql_value(
                            isset(
                                $location[
                                    "province_code"
                                ]
                            )
                            ? $location[
                                "province_code"
                              ]
                            : ""
                        ) . ",

                    " . dromic_sql_value(
                            isset(
                                $location[
                                    "city_municipality"
                                ]
                            )
                            ? $location[
                                "city_municipality"
                              ]
                            : ""
                        ) . ",

                    " . dromic_sql_value(
                            isset(
                                $location[
                                    "city_municipality_code"
                                ]
                            )
                            ? $location[
                                "city_municipality_code"
                              ]
                            : ""
                        ) . ",

                    " . dromic_sql_value(
                            isset(
                                $location["barangay"]
                            )
                            ? $location["barangay"]
                            : ""
                        ) . ",

                    " . dromic_sql_value(
                            isset(
                                $location[
                                    "barangay_code"
                                ]
                            )
                            ? $location[
                                "barangay_code"
                              ]
                            : ""
                        ) . ",

                    " . (
                        isset(
                            $impact[
                                "affected_families"
                            ]
                        )
                        ? (int)$impact[
                            "affected_families"
                          ]
                        : 0
                    ) . ",

                    " . (
                        isset(
                            $impact[
                                "affected_individuals"
                            ]
                        )
                        ? (int)$impact[
                            "affected_individuals"
                          ]
                        : 0
                    ) . ",

                    " . (
                        isset(
                            $impact[
                                "displaced_families"
                            ]
                        )
                        ? (int)$impact[
                            "displaced_families"
                          ]
                        : 0
                    ) . ",

                    " . (
                        isset(
                            $impact[
                                "displaced_persons"
                            ]
                        )
                        ? (int)$impact[
                            "displaced_persons"
                          ]
                        : 0
                    ) . ",

                    " . dromic_sql_value(
                            dromic_json_encode(
                                $detail
                            )
                        ) . ",

                    NOW()
                )
            ");



            if (DB::LastError()) {

                throw new Exception(
                    "Unable to import barangay detail for request " .
                    $requestNo .
                    ": " .
                    DB::LastError()
                );
            }



            $detailId =
                dromic_last_id();



            if ($detailId <= 0) {

                throw new Exception(
                    "Unable to retrieve DROMIC detail ID for request " .
                    $requestNo .
                    "."
                );
            }



            /* ================================================
               BARANGAY DETAIL ITEMS
               ================================================ */

            $detailItems =
                isset(
                    $detail["items"]
                ) &&
                is_array(
                    $detail["items"]
                )
                ? $detail["items"]
                : array();



            foreach (
                $detailItems
                as
                $detailItem
            ) {


                $detailDesc =
                    isset(
                        $detailItem[
                            "requested_item_description"
                        ]
                    )
                    ? $detailItem[
                        "requested_item_description"
                      ]
                    : "";


                $detailUnit =
                    isset(
                        $detailItem["unit"]
                    )
                    ? $detailItem["unit"]
                    : "";


                $detailQty =
                    isset(
                        $detailItem["quantity"]
                    )
                    ? (float)$detailItem[
                        "quantity"
                      ]
                    : 0;



                DB::Exec("
                    INSERT INTO dromic_augmentation_request_detail_item
                    (
                        detail_id,

                        requested_item_description,

                        unit,

                        quantity,

                        created_at
                    )
                    VALUES
                    (
                        " . (int)$detailId . ",

                        " . dromic_sql_value(
                                $detailDesc
                            ) . ",

                        " . dromic_sql_value(
                                $detailUnit
                            ) . ",

                        " . (float)$detailQty . ",

                        NOW()
                    )
                ");



                if (DB::LastError()) {

                    throw new Exception(
                        "Unable to import barangay item detail for request " .
                        $requestNo .
                        ": " .
                        DB::LastError()
                    );
                }
            }
        }



        /* ====================================================
           REQUEST SUCCESS
           ==================================================== */

        $imported++;



        dromic_log(

            $externalRequestId,

            $requestNo,

            "IMPORT",

            "SUCCESS",

            "Imported successfully into WINGS as PENDING / FOR_ALLOCATION. " .
            (
                $resolvedMotherFacilityId > 0
                    ? "Mother Facility: " .
                      $facilityResolution["facility_code"] .
                      " - " .
                      $facilityResolution["facility_name"] .
                      "."
                    : "Mother Facility was not automatically mapped."
            ),

            $payloadJson
        );
    }



    /* ========================================================
       8. COMMIT
       ======================================================== */

    DB::Exec(
        "COMMIT"
    );



    /* ========================================================
       RESULT
       ======================================================== */

    $result["success"] =
        true;


    $result["message"] =

        "DROMIC import finished.\n" .

        "Fetched from API: " .
        count($allRows) .
        "\n" .

        "Imported: " .
        $imported .
        "\n" .

        "Skipped duplicates/existing: " .
        $skipped .
        "\n" .

        "Mother Facility mapped: " .
        $facilityMapped .
        "\n" .

        "Mother Facility not mapped: " .
        $facilityUnmapped .
        "\n" .

        "Errors: " .
        $errorCount;
}


/* ============================================================
   ERROR HANDLER
   ============================================================ */

catch (Exception $e) {


    DB::Exec(
        "ROLLBACK"
    );


    dromic_log(

        null,

        null,

        "ERROR",

        "FAILED",

        $e->getMessage(),

        ""
    );


    $result["success"] =
        false;


    $result["message"] =
        "DROMIC import failed: " .
        $e->getMessage();
};

		RunnerContext::pop();
		echo runner_json_encode( $result);
		$button->deleteTempFiles();
	}

		// custom button - Approve
	function buttonHandler_64850( $_params )
	{
		$result = array();

		$button = $this->prepareButtonContext( $_params );
		$ajax = $button; 
		$keys = $button->getKeys();

		// .NET naming
		$parameters = $_params;
		$params = &$_params;

		;

		RunnerContext::pop();
		echo runner_json_encode( $result);
		$button->deleteTempFiles();
	}

		// custom button - Return
	function buttonHandler_64853( $_params )
	{
		$result = array();

		$button = $this->prepareButtonContext( $_params );
		$ajax = $button; 
		$keys = $button->getKeys();

		// .NET naming
		$parameters = $_params;
		$params = &$_params;

		// ======================================================
// RETURN PURCHASE REQUEST CUSTOM BUTTON SERVER
// ======================================================


$id = intval($_GET["editid"]);



if($id <= 0)
{

    throw new Exception("Cannot detect Purchase Request ID.");

}




$rs = DB::Query("

SELECT

reference_number,

status

FROM purchaserequest

WHERE id=".$id."

");



$pr = $rs->fetchAssoc();



if(!$pr)
{

    throw new Exception("Purchase Request not found.");

}




// UPDATE STATUS

DB::Exec("

UPDATE purchaserequest

SET status='RETURNED'

WHERE id=".$id."

");




// INSERT ACTIVITY LOG

DB::Exec("

INSERT INTO transaction_history_log

(

module_code,

record_id,

record_no,

action_code,

action_label,

from_status,

to_status,

acted_by,

actor_username,

actor_name,

action_at

)

VALUES

(

'PURCHASE_REQUEST',

".$id.",

'".addslashes($pr["reference_number"])."',

'RETURN_PR',

'Returned Purchase Request',

'".addslashes($pr["status"])."',

'RETURNED',

1,

'".addslashes($_SESSION["UserID"])."',

'".addslashes($_SESSION["UserName"])."',

NOW()

)

");



return true;;

		RunnerContext::pop();
		echo runner_json_encode( $result);
		$button->deleteTempFiles();
	}

		// custom button - Cancel
	function buttonHandler_64856( $_params )
	{
		$result = array();

		$button = $this->prepareButtonContext( $_params );
		$ajax = $button; 
		$keys = $button->getKeys();

		// .NET naming
		$parameters = $_params;
		$params = &$_params;

		// ======================================================
// CANCEL PURCHASE REQUEST CUSTOM BUTTON SERVER
// ======================================================


$id = intval($_GET["editid"]);



if($id <= 0)
{

    throw new Exception("Cannot detect Purchase Request ID.");

}





$rs = DB::Query("

SELECT

reference_number,

status

FROM purchaserequest

WHERE id=".$id."

");



$pr=$rs->fetchAssoc();



if(!$pr)
{

    throw new Exception("Purchase Request not found.");

}





// UPDATE STATUS

DB::Exec("

UPDATE purchaserequest

SET status='CANCELLED'

WHERE id=".$id."

");






// INSERT ACTIVITY LOG

DB::Exec("

INSERT INTO transaction_history_log

(

module_code,

record_id,

record_no,

action_code,

action_label,

from_status,

to_status,

acted_by,

actor_username,

actor_name,

action_at

)

VALUES

(

'PURCHASE_REQUEST',

".$id.",

'".addslashes($pr["reference_number"])."',

'CANCEL_PR',

'Cancelled Purchase Request',

'".addslashes($pr["status"])."',

'CANCELLED',

1,

'".addslashes($_SESSION["UserID"])."',

'".addslashes($_SESSION["UserName"])."',

NOW()

)

");



return true;;

		RunnerContext::pop();
		echo runner_json_encode( $result);
		$button->deleteTempFiles();
	}

		// custom button - Save Application
	function buttonHandler_66720( $_params )
	{
		$result = array();

		$button = $this->prepareButtonContext( $_params );
		$ajax = $button; 
		$keys = $button->getKeys();

		// .NET naming
		$parameters = $_params;
		$params = &$_params;

		// ============================================================
// SAVE APPLICATION CONFIGURATION
// SERVER
// ============================================================

$environment =
    strtoupper(
        trim(
            $params["environment"] ?? ""
        )
    );


$baseUrl =
    trim(
        $params["base_url"] ?? ""
    );


$appIsActive =
    intval(
        $params["app_is_active"] ?? 0
    );


// ------------------------------------------------------------
// VALIDATE
// ------------------------------------------------------------

if (
    $environment !== "STAGING" &&
    $environment !== "PRODUCTION"
)
{
    $result["success"] = false;

    $result["message"] =
        "Invalid application environment.";

    return;
}


if (
    $baseUrl !== "" &&
    !preg_match(
        '/^https?:\/\//i',
        $baseUrl
    )
)
{
    $result["success"] = false;

    $result["message"] =
        "Base URL must start with http:// or https://.";

    return;
}


// ------------------------------------------------------------
// UPDATE APPLICATION SETTINGS
// ------------------------------------------------------------

DB::Exec(
    DB::PrepareSQL(
        "
        UPDATE system_setting
        SET
            setting_value = :1,
            updated_at = NOW()
        WHERE setting_key = 'APP_ENVIRONMENT'
        ",
        $environment
    )
);


DB::Exec(
    DB::PrepareSQL(
        "
        UPDATE system_setting
        SET
            setting_value = :1,
            updated_at = NOW()
        WHERE setting_key = 'APP_BASE_URL'
        ",
        $baseUrl
    )
);


DB::Exec(
    DB::PrepareSQL(
        "
        UPDATE system_setting
        SET
            setting_value = :1,
            updated_at = NOW()
        WHERE setting_key = 'APP_IS_ACTIVE'
        ",
        strval($appIsActive)
    )
);


// ------------------------------------------------------------
// GET CURRENT PHPRUNNER USER
// IMPORTANT: YOUR LOGIN SOURCE IS `users`
// ------------------------------------------------------------

$username =
    Security::getUserName();


$userId   = null;
$fullName = $username;
$roleName = "";


$sqlUser =
    DB::PrepareSQL(
        "
        SELECT
            ID,
            username,
            fullname,
            role_id
        FROM users
        WHERE username = :1
        LIMIT 1
        ",
        $username
    );


$rsUser =
    DB::Query(
        $sqlUser
    );


$user =
    $rsUser->fetchAssoc();


if ($user)
{
    $userId =
        intval(
            $user["ID"]
        );

    if (
        trim(
            $user["fullname"] ?? ""
        ) !== ""
    )
    {
        $fullName =
            $user["fullname"];
    }


    $roleId =
        intval(
            $user["role_id"] ?? 0
        );


    if ($roleId > 0)
    {
        $sqlRole =
            DB::PrepareSQL(
                "
                SELECT name
                FROM role
                WHERE id = :1
                LIMIT 1
                ",
                $roleId
            );


        $rsRole =
            DB::Query(
                $sqlRole
            );


        $role =
            $rsRole->fetchAssoc();


        if ($role)
        {
            $roleName =
                $role["name"];
        }
    }
}


// ------------------------------------------------------------
// INSERT AUDIT LOG
// ------------------------------------------------------------

$sqlAudit =
    DB::PrepareSQL(
        "
        INSERT INTO system_setting_audit
        (
            setting_area,
            action_code,
            change_summary,
            changed_by_user_id,
            changed_by_username,
            changed_by_name,
            changed_by_role,
            changed_at
        )
        VALUES
        (
            'APPLICATION',
            'UPDATED',
            'Application configuration updated.',
            :1,
            :2,
            :3,
            :4,
            NOW()
        )
        ",
        $userId,
        $username,
        $fullName,
        $roleName
    );


DB::Exec(
    $sqlAudit
);


// ------------------------------------------------------------
// RETURN
// ------------------------------------------------------------

$result["success"] = true;

$result["message"] =
    "Application configuration saved successfully.";;

		RunnerContext::pop();
		echo runner_json_encode( $result);
		$button->deleteTempFiles();
	}

	
	// ajax code snippets
	
	
	// field events
		// field event - backuup
	function fieldEvent_2544( $_params )
	{
		$result = array();

		$button = $this->prepareButtonContext( $_params );
		$ajax = $button; 
		$keys = $button->getKeys();
		
		// .NET naming
		$parameters = $_params;
		$params = &$_params;

		$result["success"] = false;
$result["message"] = "";
$result["sku"] = "";
$result["description"] = "";

$procurement_type = isset($params["procurement_type"]) ? strtoupper(trim($params["procurement_type"])) : "";
$category_id = isset($params["category_id"]) ? intval($params["category_id"]) : 0;
$subcategory_id = isset($params["subcategory_id"]) ? intval($params["subcategory_id"]) : 0;
$parent_item_id = isset($params["parent_item_id"]) ? intval($params["parent_item_id"]) : 0;
$brand_id = isset($params["brand_id"]) ? intval($params["brand_id"]) : 0;
$weight = isset($params["weight"]) ? trim($params["weight"]) : "";
$dimensions = isset($params["dimensions"]) ? trim($params["dimensions"]) : "";
$parent_name_from_client = isset($params["parent_item_name"]) ? trim($params["parent_item_name"]) : "";

$goods_type = "WG";

if ($procurement_type == "" || $category_id <= 0 || $subcategory_id <= 0) {
    $result["message"] = "Procurement Type, Item Category, and Subcategory are required.";
    return;
}

/* =====================================================
   1. PROCUREMENT PREFIX
===================================================== */

$procurement_prefix = strtoupper(substr($procurement_type, 0, 1));

if ($procurement_prefix == "") {
    $result["message"] = "Invalid procurement type.";
    return;
}

/* =====================================================
   2. GET CATEGORY PREFIX
===================================================== */

$sqlCategory = "
    SELECT prefix
    FROM item_category
    WHERE id = ".$category_id."
    LIMIT 1
";

$rsCategory = DB::Query($sqlCategory);

if (!$rsCategory) {
    $result["message"] = "Category SQL error: " . DB::LastError();
    return;
}

$dataCategory = $rsCategory->fetchAssoc();

if (!$dataCategory) {
    $result["message"] = "Item Category not found.";
    return;
}

$category_prefix = isset($dataCategory["prefix"]) ? strtoupper(trim($dataCategory["prefix"])) : "";

if ($category_prefix == "") {
    $category_prefix = "RM";
}

/* =====================================================
   3. GET SUBCATEGORY PREFIX
===================================================== */

$sqlSubcategory = "
    SELECT prefix
    FROM item_subcategory
    WHERE id = ".$subcategory_id."
      AND category_id = ".$category_id."
    LIMIT 1
";

$rsSubcategory = DB::Query($sqlSubcategory);

if (!$rsSubcategory) {
    $result["message"] = "Subcategory SQL error: " . DB::LastError();
    return;
}

$dataSubcategory = $rsSubcategory->fetchAssoc();

if (!$dataSubcategory) {
    $result["message"] = "Item Subcategory not found.";
    return;
}

$class_code = isset($dataSubcategory["prefix"]) ? strtoupper(trim($dataSubcategory["prefix"])) : "";

if ($class_code == "") {
    $result["message"] = "Subcategory prefix is required.";
    return;
}

/* =====================================================
   4. SKU GENERATION
   Format: P-WG-FI-FP-00001
===================================================== */

$sku_prefix = $procurement_prefix . "-" . $goods_type . "-" . $category_prefix . "-" . $class_code . "-";
$safe_sku_prefix = str_replace("'", "''", $sku_prefix);

$sqlNext = "
    SELECT 
        COALESCE(MAX(CAST(RIGHT(sku, 5) AS UNSIGNED)), 0) + 1 AS next_no
    FROM item
    WHERE sku IS NOT NULL
      AND sku <> ''
      AND sku LIKE '".$safe_sku_prefix."%'
      AND RIGHT(sku, 5) REGEXP '^[0-9]{5}$'
";

$rsNext = DB::Query($sqlNext);

if (!$rsNext) {
    $result["message"] = "SKU SQL error: " . DB::LastError();
    return;
}

$dataNext = $rsNext->fetchAssoc();

$next_no = 1;

if ($dataNext && isset($dataNext["next_no"])) {
    $next_no = intval($dataNext["next_no"]);
}

if ($next_no < 1) {
    $next_no = 1;
}

$auto_no = str_pad($next_no, 5, "0", STR_PAD_LEFT);
$sku = $sku_prefix . $auto_no;

/* =====================================================
   5. DESCRIPTION GENERATION
   Parent Item Name / Brand / Weight / Dimensions
===================================================== */

$parent_name = "";
$brand_name = "";

if ($parent_name_from_client != "") {
    $parent_name = $parent_name_from_client;
}

if ($parent_name == "" && $parent_item_id > 0) {

    $sqlParent = "
        SELECT 
            COALESCE(NULLIF(description, ''), NULLIF(name, ''), NULLIF(parent_item_name, '')) AS parent_name
        FROM item
        WHERE id = ".$parent_item_id."
        LIMIT 1
    ";

    $rsParent = DB::Query($sqlParent);

    if (!$rsParent) {
        $result["message"] = "Parent Item SQL error: " . DB::LastError();
        return;
    }

    $dataParent = $rsParent->fetchAssoc();

    if ($dataParent && isset($dataParent["parent_name"])) {
        $parent_name = trim($dataParent["parent_name"]);
    }
}

if ($brand_id > 0) {

    $sqlBrand = "
        SELECT brand_name
        FROM itembrand
        WHERE id = ".$brand_id."
        LIMIT 1
    ";

    $rsBrand = DB::Query($sqlBrand);

    if (!$rsBrand) {
        $result["message"] = "Brand SQL error: " . DB::LastError();
        return;
    }

    $dataBrand = $rsBrand->fetchAssoc();

    if ($dataBrand && isset($dataBrand["brand_name"])) {
        $brand_name = trim($dataBrand["brand_name"]);
    }
}

$description_parts = array();

if ($parent_name != "") {
    $description_parts[] = $parent_name;
}

if ($brand_name != "") {
    $description_parts[] = $brand_name;
}

if ($weight != "") {
    $description_parts[] = $weight;
}

if ($dimensions != "") {
    $description_parts[] = $dimensions;
}

$description = implode(" / ", $description_parts);

/* =====================================================
   FINAL RESULT
===================================================== */

$result["success"] = true;
$result["sku"] = $sku;
$result["description"] = $description;
$result["message"] = "SKU and description generated successfully.";;

		RunnerContext::pop();
		echo runner_json_encode( $result);
		$button->deleteTempFiles();
	}


		// field event - itemskuandname
	function fieldEvent_2584( $_params )
	{
		$result = array();

		$button = $this->prepareButtonContext( $_params );
		$ajax = $button; 
		$keys = $button->getKeys();
		
		// .NET naming
		$parameters = $_params;
		$params = &$_params;

		$result["success"] = false;
$result["message"] = "";
$result["sku"] = "";
$result["description"] = "";

$procurement_type = isset($params["procurement_type"]) ? strtoupper(trim($params["procurement_type"])) : "";
$category_id = isset($params["category_id"]) ? intval($params["category_id"]) : 0;
$subcategory_id = isset($params["subcategory_id"]) ? intval($params["subcategory_id"]) : 0;
$parent_item_id = isset($params["parent_item_id"]) ? intval($params["parent_item_id"]) : 0;
$brand_id = isset($params["brand_id"]) ? intval($params["brand_id"]) : 0;
$weight = isset($params["weight"]) ? trim($params["weight"]) : "";
$dimensions = isset($params["dimensions"]) ? trim($params["dimensions"]) : "";
$parent_name_from_client = isset($params["parent_item_name"]) ? trim($params["parent_item_name"]) : "";

$goods_type = "WG";

if ($procurement_type == "" || $category_id <= 0 || $subcategory_id <= 0) {
    $result["message"] = "Procurement Type, Item Category, and Subcategory are required.";
    return;
}

/* =====================================================
   1. PROCUREMENT PREFIX
===================================================== */

$procurement_prefix = strtoupper(substr($procurement_type, 0, 1));

if ($procurement_prefix == "") {
    $result["message"] = "Invalid procurement type.";
    return;
}

/* =====================================================
   2. GET CATEGORY PREFIX
===================================================== */

$sqlCategory = "
    SELECT prefix
    FROM item_category
    WHERE id = ".$category_id."
    LIMIT 1
";

$rsCategory = DB::Query($sqlCategory);

if (!$rsCategory) {
    $result["message"] = "Category SQL error: " . DB::LastError();
    return;
}

$dataCategory = $rsCategory->fetchAssoc();

if (!$dataCategory) {
    $result["message"] = "Item Category not found.";
    return;
}

$category_prefix = isset($dataCategory["prefix"]) ? strtoupper(trim($dataCategory["prefix"])) : "";

if ($category_prefix == "") {
    $category_prefix = "RM";
}

/* =====================================================
   3. GET SUBCATEGORY PREFIX
===================================================== */

$sqlSubcategory = "
    SELECT prefix
    FROM item_subcategory
    WHERE id = ".$subcategory_id."
      AND category_id = ".$category_id."
    LIMIT 1
";

$rsSubcategory = DB::Query($sqlSubcategory);

if (!$rsSubcategory) {
    $result["message"] = "Subcategory SQL error: " . DB::LastError();
    return;
}

$dataSubcategory = $rsSubcategory->fetchAssoc();

if (!$dataSubcategory) {
    $result["message"] = "Item Subcategory not found.";
    return;
}

$class_code = isset($dataSubcategory["prefix"]) ? strtoupper(trim($dataSubcategory["prefix"])) : "";

if ($class_code == "") {
    $result["message"] = "Subcategory prefix is required.";
    return;
}

/* =====================================================
   4. SKU GENERATION
   Format: P-WG-FI-FP-00001
===================================================== */

$sku_prefix = $procurement_prefix . "-" . $goods_type . "-" . $category_prefix . "-" . $class_code . "-";
$safe_sku_prefix = str_replace("'", "''", $sku_prefix);

$sqlNext = "
    SELECT 
        COALESCE(MAX(CAST(RIGHT(sku, 5) AS UNSIGNED)), 0) + 1 AS next_no
    FROM item
    WHERE sku IS NOT NULL
      AND sku <> ''
      AND sku LIKE '".$safe_sku_prefix."%'
      AND RIGHT(sku, 5) REGEXP '^[0-9]{5}$'
";

$rsNext = DB::Query($sqlNext);

if (!$rsNext) {
    $result["message"] = "SKU SQL error: " . DB::LastError();
    return;
}

$dataNext = $rsNext->fetchAssoc();

$next_no = 1;

if ($dataNext && isset($dataNext["next_no"])) {
    $next_no = intval($dataNext["next_no"]);
}

if ($next_no < 1) {
    $next_no = 1;
}

$auto_no = str_pad($next_no, 5, "0", STR_PAD_LEFT);
$sku = $sku_prefix . $auto_no;

/* =====================================================
   5. DESCRIPTION GENERATION
   Parent Item Name / Brand / Weight / Dimensions
===================================================== */

$parent_name = "";
$brand_name = "";

if ($parent_name_from_client != "") {
    $parent_name = $parent_name_from_client;
}

if ($parent_name == "" && $parent_item_id > 0) {

    $sqlParent = "
        SELECT 
            COALESCE(NULLIF(description, ''), NULLIF(name, ''), NULLIF(parent_item_name, '')) AS parent_name
        FROM item
        WHERE id = ".$parent_item_id."
        LIMIT 1
    ";

    $rsParent = DB::Query($sqlParent);

    if (!$rsParent) {
        $result["message"] = "Parent Item SQL error: " . DB::LastError();
        return;
    }

    $dataParent = $rsParent->fetchAssoc();

    if ($dataParent && isset($dataParent["parent_name"])) {
        $parent_name = trim($dataParent["parent_name"]);
    }
}

if ($brand_id > 0) {

    $sqlBrand = "
        SELECT brand_name
        FROM itembrand
        WHERE id = ".$brand_id."
        LIMIT 1
    ";

    $rsBrand = DB::Query($sqlBrand);

    if (!$rsBrand) {
        $result["message"] = "Brand SQL error: " . DB::LastError();
        return;
    }

    $dataBrand = $rsBrand->fetchAssoc();

    if ($dataBrand && isset($dataBrand["brand_name"])) {
        $brand_name = trim($dataBrand["brand_name"]);
    }
}

$description_parts = array();

if ($parent_name != "") {
    $description_parts[] = $parent_name;
}

if ($brand_name != "") {
    $description_parts[] = $brand_name;
}

if ($weight != "") {
    $description_parts[] = $weight;
}

if ($dimensions != "") {
    $description_parts[] = $dimensions;
}

$description = implode(" / ", $description_parts);

/* =====================================================
   FINAL RESULT
===================================================== */

$result["success"] = true;
$result["sku"] = $sku;
$result["description"] = $description;
$result["message"] = "SKU and description generated successfully.";;

		RunnerContext::pop();
		echo runner_json_encode( $result);
		$button->deleteTempFiles();
	}


		// field event - itemSKU
	function fieldEvent_2634( $_params )
	{
		$result = array();

		$button = $this->prepareButtonContext( $_params );
		$ajax = $button; 
		$keys = $button->getKeys();
		
		// .NET naming
		$parameters = $_params;
		$params = &$_params;

		$result["success"] = false;
$result["message"] = "";
$result["sku"] = "";

$procurement_type = isset($params["procurement_type"]) ? strtoupper(trim($params["procurement_type"])) : "";
$category_id = isset($params["category_id"]) ? intval($params["category_id"]) : 0;

$goods_type = "WG";   // default
$class_code = "F";    // default for meantime

if ($procurement_type == "" || $category_id <= 0) {
    $result["message"] = "Procurement Type and Item Category are required.";
    return;
}

// Only first letter of procurement type
$procurement_prefix = strtoupper(substr($procurement_type, 0, 1));

// Get item category prefix
$sqlCategory = "
    SELECT prefix
    FROM item_category
    WHERE id = ".$category_id."
    LIMIT 1
";

$rsCategory = DB::Query($sqlCategory);
$dataCategory = $rsCategory->fetchAssoc();

if (!$dataCategory) {
    $result["message"] = "Item Category not found.";
    return;
}

$category_prefix = strtoupper(trim($dataCategory["prefix"]));

if ($category_prefix == "") {
    $category_prefix = "RM";
}

// Build prefix combination
// Example: P-WG-FI-F-
$sku_prefix = $procurement_prefix . "-" . $goods_type . "-" . $category_prefix . "-" . $class_code . "-";

// Get next number based only on the same prefix combination
$sqlNext = "
    SELECT 
        COALESCE(MAX(CAST(RIGHT(sku, 5) AS UNSIGNED)), 0) + 1 AS next_no
    FROM item
    WHERE sku IS NOT NULL
      AND sku <> ''
      AND sku LIKE '" . db_addslashes($sku_prefix) . "%'
      AND RIGHT(sku, 5) REGEXP '^[0-9]{5}$'
";

$rsNext = DB::Query($sqlNext);
$dataNext = $rsNext->fetchAssoc();

$next_no = intval($dataNext["next_no"]);

if ($next_no < 1) {
    $next_no = 1;
}

$auto_no = str_pad($next_no, 5, "0", STR_PAD_LEFT);

// Final SKU
$sku = $sku_prefix . $auto_no;

$result["success"] = true;
$result["sku"] = $sku;
$result["message"] = "SKU generated successfully.";;

		RunnerContext::pop();
		echo runner_json_encode( $result);
		$button->deleteTempFiles();
	}


	

	// code snippets
	
	// code snippet - Snippet6
	function event_2532(  ) {
		
		global $pageObject;

dswdHistoryShow(
    "VEHICLE_TYPE",
    $pageObject
);
		;
		
	}










	// code snippet - Stockfile
	function event_2552(  ) {
		
		/* =========================================================
   WINGS DASHBOARD
   TOTAL FFP / NFI STOCKPILE
   NEW UI DESIGN
   ========================================================= */


/* =========================================================
   1. LOAD MAIN STOCKPILE DATA
   ========================================================= */

$sql = "
    SELECT
        total_ffp_stockpile,
        total_nfi_stockpile,

        hubs_ffp,
        hubs_nfi,

        spokes_ffp,
        spokes_nfi,

        last_mile_ffp,
        last_mile_nfi,

        data_as_of

    FROM vw_dashboard_stockpile_summary

    ORDER BY data_as_of DESC
    LIMIT 1
";


$rs = DB::Query($sql);


if (!$rs) {

    echo "
        <div style=\"
            padding:15px;
            color:#ee1c25;
            font-family:Arial, Helvetica, sans-serif;
            font-size:12px;
            font-weight:700;
        \">
            SQL error while loading stockpile data.
        </div>
    ";

    return;

}


$data = $rs->fetchAssoc();



if (!$data) {


    echo "
        <div style=\"
            padding:15px;
            color:#ee1c25;
            font-family:Arial, Helvetica, sans-serif;
            font-size:12px;
            font-weight:700;
        \">
            No stockpile data found.
        </div>
    ";


    return;

}



/* =========================================================
   2. LOAD RTEF DATA
   ========================================================= */


$rtefSQL = "

SELECT

COALESCE(
SUM(
CASE
WHEN UPPER(TRIM(warehouse_type))='HUB'
THEN rtef_qty
ELSE 0
END
),0
) AS hubs_rtef,


COALESCE(
SUM(
CASE
WHEN UPPER(TRIM(warehouse_type))='SPOKE'
THEN rtef_qty
ELSE 0
END
),0
) AS spokes_rtef,


COALESCE(
SUM(
CASE
WHEN UPPER(TRIM(warehouse_type))='LAST_MILE'
THEN rtef_qty
ELSE 0
END
),0
) AS last_mile_rtef


FROM vw_dashboard_food_inventory

";


$rtefRS = DB::Query($rtefSQL);



$rtefData = array(

    "hubs_rtef"      => 0,
    "spokes_rtef"    => 0,
    "last_mile_rtef" => 0

);



if ($rtefRS){

    $tempRtefData = $rtefRS->fetchAssoc();


    if($tempRtefData){

        $rtefData = $tempRtefData;

    }

}



/* =========================================================
   NUMBER FORMAT
   ========================================================= */


if(!function_exists("wingsDashboardCompactNumber")){


function wingsDashboardCompactNumber($value){


$value=(float)$value;



if($value>=1000000000){

return number_format(
$value/1000000000,
1
)." B";

}



if($value>=1000000){

return number_format(
$value/1000000,
1
)." M";

}



if($value>=1000){

return number_format(
$value/1000,
1
)." K";

}



return number_format($value,0);


}


}




/* =========================================================
   TOTALS
   ========================================================= */


$totalFFP = number_format(
(float)$data["total_ffp_stockpile"],
0
);


$totalNFI = number_format(
(float)$data["total_nfi_stockpile"],
0
);



/* =========================================================
   VALUES
   ========================================================= */


$hubsFFP = wingsDashboardCompactNumber(
$data["hubs_ffp"]
);


$hubsRTEF = wingsDashboardCompactNumber(
$rtefData["hubs_rtef"]
);


$hubsNFI = wingsDashboardCompactNumber(
$data["hubs_nfi"]
);



$spokesFFP = wingsDashboardCompactNumber(
$data["spokes_ffp"]
);


$spokesRTEF = wingsDashboardCompactNumber(
$rtefData["spokes_rtef"]
);


$spokesNFI = wingsDashboardCompactNumber(
$data["spokes_nfi"]
);



$lastMileFFP = wingsDashboardCompactNumber(
$data["last_mile_ffp"]
);


$lastMileRTEF = wingsDashboardCompactNumber(
$rtefData["last_mile_rtef"]
);


$lastMileNFI = wingsDashboardCompactNumber(
$data["last_mile_nfi"]
);

/* =========================================================
   OUTPUT
   ========================================================= */

echo '

<style>

/* =========================================================
   WINGS STOCKPILE CARD
   FIGMA 2026 DESIGN
   ========================================================= */


.wings-stockpile-card,
.wings-stockpile-card * {

    box-sizing:border-box;

}



.wings-stockpile-card {


    position:relative;


    width:100%;


    height:145px;


    min-height:145px;


    padding:

        10px;



    overflow:hidden;


    font-family:

        Arial,
        Helvetica,
        sans-serif;



    color:#ffffff;



    background:

        linear-gradient(
            135deg,
            #3539ae 0%,
            #484bd7 55%,
            #5e61f5 100%
        );



    border-radius:

        10px;



    box-shadow:

        0 3px 10px
        rgba(0,0,0,.20);


}




/* =========================================================
   ICON
   ========================================================= */


.wings-stockpile-icon {


    position:absolute;


    top:10px;


    right:10px;



    width:28px;


    height:28px;



    display:flex;


    align-items:center;


    justify-content:center;



    background:#ffffff;



    border-radius:50%;


}



.wings-stockpile-icon svg {


    width:17px;


    height:17px;



    stroke:#4045cd;


    fill:none;


    stroke-width:1.8;


}




/* =========================================================
   TOP SUMMARY
   ========================================================= */


.wings-stockpile-summary {


    display:flex;


    align-items:flex-start;


    justify-content:flex-start;


    gap:55px;



    width:
        calc(100% - 40px);


}




/* FFP */


.wings-stockpile-ffp {


    width:160px;


}





.wings-stockpile-title {


    margin:0;


    padding:0;



    color:
        rgba(255,255,255,.95);



    font-size:
        10px;



    font-weight:
        700;



    line-height:
        12px;



    text-transform:
        uppercase;


}




.wings-stockpile-main-value {


    margin-top:2px;



    color:#ffffff;



    font-size:
        22px;



    font-weight:
        700;



    line-height:
        24px;


}





/* =========================================================
   NFI
   ========================================================= */


.wings-stockpile-nfi-block {


    width:140px;


    text-align:left;


}





.wings-stockpile-nfi-label {


    color:
        rgba(255,255,255,.95);



    font-size:
        30px;



    font-weight:
        700;



    line-height:
        12px;



    text-transform:
        uppercase;


}




.wings-stockpile-nfi-value {


    margin-top:2px;



    color:#ffffff;



    font-size:
        30px;



    font-weight:
        700;



    line-height:
        24px;


}





/* =========================================================
   BREAKDOWN TABLE
   ========================================================= */


.wings-stockpile-breakdown {


    position:absolute;



    left:
        10px;



    right:
        10px;



    bottom:
        7px;



    height:
        55px;



    padding:

        4px
        8px;



    background:

        rgba(5,26,90,.85);



    border-radius:
        5px;


}





.wings-stockpile-grid {


    display:grid;



    grid-template-columns:

        1.2fr
        1fr
        1fr
        1fr;



    height:100%;



    align-items:center;


}





.wings-stockpile-grid-head {


    color:#ffffff;



    font-size:
        10px;



    font-weight:
        700;



    text-align:center;


}



.wings-stockpile-grid-head.blank {


    text-align:left;


}





.wings-stockpile-row-label {


    color:

        rgba(255,255,255,.90);



    font-size:
        9px;



    font-weight:
        500;



    text-transform:
        uppercase;


}




.wings-stockpile-grid-value {


    color:#ffffff;



    font-size:
        10px;



    font-weight:
        500;



    text-align:center;


}


</style>




<div class="wings-stockpile-card">



<!-- ICON -->

<div class="wings-stockpile-icon">


<svg viewBox="0 0 24 24">


<path d="M5 7h9"></path>

<path d="M5 7v9"></path>

<path d="M9 11h9"></path>

<path d="M18 11v8"></path>

<path d="M9 11v5"></path>

<path d="M9 16h5"></path>


</svg>


</div>





<!-- TOP TOTALS -->


<div class="wings-stockpile-summary">



<div class="wings-stockpile-ffp">


<div class="wings-stockpile-title">

Total FFP Stockpile

</div>


<div class="wings-stockpile-main-value">

' . $totalFFP . '

</div>


</div>





<div class="wings-stockpile-nfi-block">


<div class="wings-stockpile-nfi-label">

Total NFI Stockpile

</div>


<div class="wings-stockpile-nfi-value">

' . $totalNFI . '

</div>


</div>



</div>







<!-- TABLE -->


<div class="wings-stockpile-breakdown">


<div class="wings-stockpile-grid">



<div class="wings-stockpile-grid-head blank"></div>


<div class="wings-stockpile-grid-head">

FFP

</div>


<div class="wings-stockpile-grid-head">

RTEF

</div>


<div class="wings-stockpile-grid-head">

NFI

</div>





<div class="wings-stockpile-row-label">

HUBS

</div>


<div class="wings-stockpile-grid-value">

' . $hubsFFP . '

</div>


<div class="wings-stockpile-grid-value">

' . $hubsRTEF . '

</div>


<div class="wings-stockpile-grid-value">

' . $hubsNFI . '

</div>





<div class="wings-stockpile-row-label">

SPOKES

</div>


<div class="wings-stockpile-grid-value">

' . $spokesFFP . '

</div>


<div class="wings-stockpile-grid-value">

' . $spokesRTEF . '

</div>


<div class="wings-stockpile-grid-value">

' . $spokesNFI . '

</div>





<div class="wings-stockpile-row-label">

LAST MILE

</div>


<div class="wings-stockpile-grid-value">

' . $lastMileFFP . '

</div>


<div class="wings-stockpile-grid-value">

' . $lastMileRTEF . '

</div>


<div class="wings-stockpile-grid-value">

' . $lastMileNFI . '

</div>



</div>


</div>



</div>


';
		;
		
	}


	// code snippet - FoodClassification
	function event_2556(  ) {
		
		/* =========================================================
   WINGS DASHBOARD - FOOD INVENTORY
   COMPACT DASHBOARD VERSION
   ========================================================= */


/* =========================================================
   LOAD FOOD INVENTORY DATA
   ========================================================= */

$sql = "

    SELECT

        warehouse_code,

        warehouse_name,

        warehouse_type,

        family_food_pack_qty,

        rtef_qty,

        prepack_family_food_pack_qty,

        sort_order


    FROM vw_dashboard_food_inventory


    ORDER BY sort_order

";



$rs = DB::Query($sql);



/* =========================================================
   CHECK QUERY
   ========================================================= */

if (!$rs) {


    echo "

        <div style='

            padding:15px;

            color:#ee1c25;

            font-family:Arial,Helvetica,sans-serif;

            font-weight:700;

        '>

            SQL error while loading Food Inventory.

        </div>

    ";


    return;

}



/* =========================================================
   STORE RESULT
   ========================================================= */

$rows = array();



while ($data = $rs->fetchAssoc()) {


    $rows[] = $data;


}



/* =========================================================
   NO DATA
   ========================================================= */

if (count($rows) === 0) {


    echo "

        <div style='

            padding:15px;

            color:#ee1c25;

            font-family:Arial,Helvetica,sans-serif;

            font-weight:700;

        '>

            No Food Inventory data found.

        </div>

    ";


    return;

}




/* =========================================================
   NUMBER FORMAT
   ========================================================= */

if (!function_exists("wingsFormatFoodInventoryQty")) {


    function wingsFormatFoodInventoryQty($value)
    {


        $value = (float)$value;



        if ($value == 0) {


            return "-";


        }



        return number_format(
            $value,
            0
        );


    }

}





/* =========================================================
   UNIQUE CARD ID
   ========================================================= */

$foodCardId =

    "wingsFoodInventory_" .

    uniqid();

echo '

<style>

/* =========================================================
   WINGS DASHBOARD
   FOOD INVENTORY CARD
   ========================================================= */


/* RESET */

.wings-food-card,
.wings-food-card * {

    box-sizing:border-box;

}



/* =========================================================
   MAIN CARD
   ========================================================= */

.wings-food-card {

    --food-blue:#302f92;

    --food-row:#eeeeee;

    --food-text:#202020;



    width:100% !important;

    height:145px !important;

    min-height:145px !important;

    max-height:145px !important;



    display:flex !important;

    flex-direction:column !important;



    background:#ffffff !important;



    border-radius:8px !important;



    padding:

        9px

        10px

        8px !important;



    overflow:hidden !important;



    box-shadow:

        0 3px 10px rgba(0,0,0,0.12) !important;



    font-family:

        Arial,

        Helvetica,

        sans-serif !important;


}




/* =========================================================
   TITLE
   ========================================================= */

.wings-food-title {


    flex:

        0 0 auto;



    margin:

        0

        0

        7px !important;



    padding:0 !important;



    color:#202020 !important;



    font-size:

        10px !important;



    line-height:

        12px !important;



    font-weight:

        700 !important;



    text-transform:

        uppercase !important;


}





/* =========================================================
   TABLE CONTAINER
   ========================================================= */

.wings-food-table-scroll {


    flex:

        1 1 auto !important;



    width:

        100% !important;



    overflow-x:

        auto !important;



    overflow-y:

        hidden !important;


}





/* =========================================================
   TABLE
   ========================================================= */

.wings-food-table {


    width:

        100% !important;



    min-width:

        520px !important;



    border-collapse:

        separate !important;



    border-spacing:

        0

        3px !important;



    table-layout:

        fixed !important;


}




/* =========================================================
   COLUMN WIDTH
   ========================================================= */


.wings-food-table col.food-col-warehouse {

    width:22%;

}


.wings-food-table col.food-col-ffp {

    width:26%;

}


.wings-food-table col.food-col-rtef {

    width:18%;

}


.wings-food-table col.food-col-prepack {

    width:34%;

}



/* =========================================================
   HEADER - DSWD BLUE
   ========================================================= */


.wings-food-card
.wings-food-table
thead > tr > th {


    --bs-table-bg:#302f92 !important;

    --bs-table-accent-bg:#302f92 !important;

    --bs-table-striped-bg:#302f92 !important;

    --bs-table-hover-bg:#302f92 !important;

    --bs-table-color:#ffffff !important;



    background:#302f92 !important;

    background-color:#302f92 !important;

    background-image:none !important;



    color:#ffffff !important;

    -webkit-text-fill-color:#ffffff !important;



    border:0 !important;



    height:20px !important;



    padding:

        3px

        5px !important;



    font-size:8px !important;



    font-weight:700 !important;



    line-height:10px !important;



    text-align:center !important;



    text-transform:uppercase !important;



    white-space:nowrap !important;


}


/* FORCE HEADER ROW COLOR */


.wings-food-card
.wings-food-table
thead > tr {


    background:#302f92 !important;

    background-color:#302f92 !important;


}

.wings-food-table thead tr th:first-child {


    border-radius:

        5px

        0

        0

        5px;


}




.wings-food-table thead tr th:last-child {


    border-radius:

        0

        5px

        5px

        0;


}




/* =========================================================
   BODY ROW
   ========================================================= */

.wings-food-table tbody tr td {


    height:20px !important;


    padding:
        4px
        8px !important;


    background:#ffffff !important;


    color:#202020 !important;


    border:0 !important;


    font-size:9px !important;


    line-height:11px !important;


    font-weight:700 !important;


    text-align:center !important;


    white-space:nowrap !important;


    overflow:hidden !important;


    text-overflow:ellipsis !important;


}

/* =========================================================
   ALTERNATING ROW COLOR
   ========================================================= */


.wings-food-table tbody tr:nth-child(even) td {


    background:#eeeeee !important;


}



.wings-food-table tbody tr:nth-child(odd) td {


    background:#ffffff !important;


}

.wings-food-table tbody tr td:first-child {


    border-radius:

        5px

        0

        0

        5px !important;


    text-align:left !important;


    padding-left:10px !important;


}




.wings-food-table tbody tr td:last-child {


    border-radius:

        0

        5px

        5px

        0 !important;


}




.wings-food-table tbody tr:hover td {


    filter:brightness(0.97);


}




/* =========================================================
   WAREHOUSE TEXT
   ========================================================= */


.wings-food-warehouse-code {


    display:block;



    font-size:

        9px !important;



    font-weight:

        700 !important;



    color:

        #202020 !important;


}



/* =========================================================
   TOOLTIP
   ========================================================= */


.wings-food-tooltip {


    position:fixed;



    z-index:999999;



    display:none;



    min-width:180px;



    padding:

        8px

        10px;



    background:

        rgba(30,30,30,0.95);



    color:#ffffff;



    border-radius:6px;



    font-size:12px;


}



.wings-food-tooltip.show {


    display:block;


}



.wings-food-tooltip-code {


    display:block;



    font-weight:700;



}



.wings-food-tooltip-name {


    opacity:.85;


}



/* =========================================================
   MOBILE
   ========================================================= */


@media(max-width:768px){


    .wings-food-card {


        height:

            145px !important;


        min-height:

            145px !important;


    }


}


</style>

';

echo '

<div
    class="wings-food-card"
    id="' . $foodCardId . '"
>


    <div class="wings-food-title">
        FOOD INVENTORY
    </div>



    <div class="wings-food-table-scroll">


        <table class="wings-food-table">


            <colgroup>


                <col class="food-col-warehouse">


                <col class="food-col-ffp">


                <col class="food-col-rtef">


                <col class="food-col-prepack">


            </colgroup>




            <thead>

                <tr>

                    <th>
                        WAREHOUSES
                    </th>


                    <th>
                        FAMILY FOOD PACK
                    </th>


                    <th>
                        RTEF
                    </th>


                    <th>
                        PREPACK FAMILY FOOD PACK
                    </th>


                </tr>

            </thead>




            <tbody>

';



foreach ($rows as $row) {


    $warehouseCode = htmlspecialchars(
        isset($row["warehouse_code"])
            ? $row["warehouse_code"]
            : "",
        ENT_QUOTES,
        "UTF-8"
    );


    $warehouseName = htmlspecialchars(
        isset($row["warehouse_name"])
            ? $row["warehouse_name"]
            : "",
        ENT_QUOTES,
        "UTF-8"
    );


    $warehouseType = htmlspecialchars(
        isset($row["warehouse_type"])
            ? $row["warehouse_type"]
            : "",
        ENT_QUOTES,
        "UTF-8"
    );



    echo '


        <tr>



            <td

                class="
                    wings-food-warehouse-cell
                    wings-food-tooltip-target
                "


                data-code="' . $warehouseCode . '"


                data-name="' . $warehouseName . '"


                data-type="' . $warehouseType . '"


            >


                <span class="wings-food-warehouse-code">

                    ' . $warehouseCode . '

                </span>


            </td>





            <td>

                ' .

                wingsFormatFoodInventoryQty(
                    $row["family_food_pack_qty"]
                )

                . '

            </td>





            <td>

                ' .

                wingsFormatFoodInventoryQty(
                    $row["rtef_qty"]
                )

                . '

            </td>





            <td>

                ' .

                wingsFormatFoodInventoryQty(
                    $row["prepack_family_food_pack_qty"]
                )

                . '

            </td>



        </tr>


    ';


}



echo '


            </tbody>


        </table>



    </div>




    <div class="wings-food-tooltip">


        <strong class="wings-food-tooltip-code"></strong>


        <span class="wings-food-tooltip-name"></span>


    </div>



</div>



';

echo '

<script>

(function () {


    "use strict";



    var card = document.getElementById(
        "' . $foodCardId . '"
    );



    if (!card) {

        return;

    }





    var tooltip =
        card.querySelector(
            ".wings-food-tooltip"
        );



    var targets =
        card.querySelectorAll(
            ".wings-food-tooltip-target"
        );




    if (
        !tooltip ||
        !targets.length
    ) {

        return;

    }




    var tooltipCode =
        tooltip.querySelector(
            ".wings-food-tooltip-code"
        );



    var tooltipName =
        tooltip.querySelector(
            ".wings-food-tooltip-name"
        );






    function moveTooltip(event) {


        var offset = 12;


        var left =
            event.clientX + offset;


        var top =
            event.clientY + offset;



        var tooltipWidth =
            tooltip.offsetWidth;



        var tooltipHeight =
            tooltip.offsetHeight;




        if (
            left + tooltipWidth >
            window.innerWidth - 10
        ) {


            left =
                event.clientX -
                tooltipWidth -
                offset;


        }





        if (
            top + tooltipHeight >
            window.innerHeight - 10
        ) {


            top =
                event.clientY -
                tooltipHeight -
                offset;


        }




        tooltip.style.left =
            left + "px";



        tooltip.style.top =
            top + "px";


    }







    function showTooltip(
        target,
        event
    ) {



        var code =
            target.getAttribute(
                "data-code"
            ) || "";



        var name =
            target.getAttribute(
                "data-name"
            ) || "";



        var type =
            target.getAttribute(
                "data-type"
            ) || "";




        tooltipCode.textContent =
            code;




        tooltipName.textContent =
            name +
            (
                type
                    ?
                    " • " + type
                    :
                    ""
            );




        tooltip.classList.add(
            "show"
        );



        moveTooltip(event);


    }







    function hideTooltip() {


        tooltip.classList.remove(
            "show"
        );


    }








    targets.forEach(
        function(target){



            target.addEventListener(
                "mouseenter",
                function(event){


                    showTooltip(
                        target,
                        event
                    );


                }
            );





            target.addEventListener(
                "mousemove",
                function(event){


                    moveTooltip(event);


                }
            );





            target.addEventListener(
                "mouseleave",
                function(){


                    hideTooltip();


                }
            );



        }
    );



})();


</script>

';
		;
		
	}



	// code snippet - Ranking
	function event_2562(  ) {
		
		

/* =========================================================
   FOOD PACK SKU PRIORITY RANKING WITH COMPONENT DETAILS
   ========================================================= */

/*
 * 1. Load all Food Pack SKUs.
 */
$rs = DB::Query("
    SELECT
        i.id,
        i.sku,
        i.name,
        i.description,
        i.priority
    FROM item i
    WHERE i.subcategory_id = 5
    ORDER BY
        CASE
            WHEN i.priority IS NULL OR i.priority = 0 THEN 999999
            ELSE i.priority
        END ASC,
        i.sku ASC
");

/*
 * 2. Load all components of Food Pack SKUs.
 */
$componentRs = DB::Query("
    SELECT
        ic.parent_item_id,
        ic.component_item_id,
        ic.qty,
        ic.sort_order,

        ci.sku AS component_sku,

        COALESCE(
            NULLIF(ic.component_description, ''),
            NULLIF(ci.description, ''),
            NULLIF(ci.name, ''),
            'Unnamed Component'
        ) AS component_description,

        COALESCE(
            NULLIF(iu.name, ''),
            ''
        ) AS component_unit

    FROM item_component ic

    INNER JOIN item parent_item
        ON parent_item.id = ic.parent_item_id
       AND parent_item.subcategory_id = 5

    LEFT JOIN item ci
        ON ci.id = ic.component_item_id

    LEFT JOIN itemunit iu
        ON iu.id = ci.unit_id

    ORDER BY
        ic.parent_item_id,
        ic.sort_order,
        ci.description,
        ci.name
");

/*
 * 3. Group components by parent Food Pack ID.
 */
$componentsByParent = array();

while ($component = $componentRs->fetchAssoc()) {

    $parentItemId = (int)$component["parent_item_id"];

    if (!isset($componentsByParent[$parentItemId])) {
        $componentsByParent[$parentItemId] = array();
    }

    $componentsByParent[$parentItemId][] = $component;
}

/*
 * Helper for safe HTML output.
 */
if (!function_exists("foodPackHtml")) {
    function foodPackHtml($value)
    {
        return htmlspecialchars(
            (string)$value,
            ENT_QUOTES,
            "UTF-8"
        );
    }
}

/*
 * Helper for component quantity.
 * Examples:
 * 2.0000  = 2
 * 2.5000  = 2.5
 * 0.2500  = 0.25
 */
if (!function_exists("foodPackQty")) {
    function foodPackQty($value)
    {
        $quantity = number_format((float)$value, 4, ".", "");

        return rtrim(rtrim($quantity, "0"), ".");
    }
}

echo '
<style>

.rank-wrapper {
    width: 100%;
    max-width: 900px;
    padding: 8px 4px 20px 4px;
}

.rank-wrapper h3 {
    margin: 0 0 4px 0;
    font-size: 22px;
    font-weight: 700;
    color: #222;
}

.rank-note {
    margin: 0 0 14px 0;
    color: #6b7280;
    font-size: 13px;
}

#foodpack-sortable {
    list-style: none;
    margin: 0;
    padding: 0;
}

.foodpack-row {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    width: 100%;
    margin-bottom: 10px;
    padding: 14px 16px;
    background: #ffffff;
    border: 1px solid #e5e7eb;
    border-radius: 7px;
    box-shadow: 0 2px 5px rgba(0, 0, 0, 0.04);
    cursor: move;
    box-sizing: border-box;
}

.foodpack-row:hover {
    border-color: #f1a5aa;
    box-shadow: 0 3px 9px rgba(220, 53, 69, 0.10);
}

.drag-handle {
    flex: 0 0 auto;
    margin-top: 2px;
    color: #7b7b7b;
    font-size: 18px;
    cursor: grab;
    user-select: none;
}

.drag-handle:active {
    cursor: grabbing;
}

.priority-badge {
    flex: 0 0 32px;
    min-width: 32px;
    height: 28px;
    line-height: 28px;
    text-align: center;
    background: #f4f4f5;
    border-radius: 5px;
    color: #333;
    font-size: 13px;
    font-weight: 700;
}

.foodpack-info {
    flex: 1;
    min-width: 0;
}

.foodpack-header {
    padding-bottom: 9px;
}

.foodpack-sku {
    display: block;
    color: #202124;
    font-size: 14px;
    font-weight: 700;
    word-break: break-word;
}

.foodpack-name {
    display: block;
    margin-top: 2px;
    color: #555;
    font-size: 13px;
}

.component-section {
    margin-top: 5px;
    padding: 10px 12px;
    background: #fafafa;
    border-left: 3px solid #e5252a;
    border-radius: 3px;
}

.component-title {
    margin-bottom: 7px;
    color: #555;
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.4px;
}

.component-row {
    display: grid;
    grid-template-columns: 85px minmax(130px, 1fr) minmax(180px, 2fr);
    column-gap: 12px;
    align-items: start;
    padding: 4px 0;
    border-bottom: 1px dashed #e1e1e1;
    font-size: 13px;
}

.component-row:last-child {
    border-bottom: 0;
}

.component-qty {
    color: #111;
    font-weight: 700;
    white-space: nowrap;
}

.component-sku {
    color: #555;
    font-size: 12px;
    word-break: break-word;
}

.component-description {
    color: #222;
    word-break: break-word;
}

.no-components {
    color: #9a6700;
    font-size: 12px;
    font-style: italic;
}

#save-ranking {
    margin-top: 10px;
}

#ranking-message {
    margin-top: 10px;
    font-size: 13px;
}

@media (max-width: 700px) {

    .foodpack-row {
        padding: 12px 10px;
        gap: 8px;
    }

    .component-row {
        grid-template-columns: 80px 1fr;
    }

    .component-description {
        grid-column: 1 / -1;
        padding-left: 92px;
        margin-top: 2px;
    }
}

</style>
';

echo '<div class="rank-wrapper">';

echo '<h3>Food Pack SKU Priority Ranking</h3>';

echo '
<p class="rank-note">
    Drag items up or down, then click Save Ranking.
    The components included in each Food Pack are shown below the SKU.
</p>
';

echo '<ul id="foodpack-sortable">';

$displayPriority = 1;

while ($data = $rs->fetchAssoc()) {

    $itemId = (int)$data["id"];

    $sku = foodPackHtml($data["sku"]);

    $itemName = !empty($data["name"])
        ? $data["name"]
        : $data["description"];

    $itemName = foodPackHtml($itemName);

    /*
     * Show the existing priority when present.
     * Otherwise, use the current display order.
     */
    $priority = (int)$data["priority"];

    if ($priority <= 0) {
        $priority = $displayPriority;
    }

    echo '
    <li class="foodpack-row" data-id="'.$itemId.'">

        <span class="drag-handle" title="Drag to reorder">
            &#9776;
        </span>

        <span class="priority-badge">
            '.$priority.'
        </span>

        <div class="foodpack-info">

            <div class="foodpack-header">
                <span class="foodpack-sku">
                    '.$sku.'
                </span>

                <span class="foodpack-name">
                    '.$itemName.'
                </span>
            </div>
    ';

    /*
     * Display the components of the current Food Pack.
     */
    if (
        isset($componentsByParent[$itemId]) &&
        count($componentsByParent[$itemId]) > 0
    ) {

        echo '
        <div class="component-section">
            <div class="component-title">
                Food Pack Components
            </div>
        ';

        foreach ($componentsByParent[$itemId] as $component) {

            $componentQty = foodPackQty($component["qty"]);
            $componentUnit = foodPackHtml($component["component_unit"]);
            $componentSku = foodPackHtml($component["component_sku"]);
            $componentDescription = foodPackHtml(
                $component["component_description"]
            );

            $quantityDisplay = $componentQty;

            if ($componentUnit !== "") {
                $quantityDisplay .= " ".$componentUnit;
            }

            echo '
            <div class="component-row">

                <div class="component-qty">
                    '.$quantityDisplay.'
                </div>

                <div class="component-sku">
                    '.$componentSku.'
                </div>

                <div class="component-description">
                    '.$componentDescription.'
                </div>

            </div>
            ';
        }

        echo '</div>';

    } else {

        echo '
        <div class="component-section">
            <span class="no-components">
                No components have been configured for this Food Pack.
            </span>
        </div>
        ';
    }

    echo '
        </div>
    </li>
    ';

    $displayPriority++;
}

echo '</ul>';

echo '
<button
    type="button"
    id="save-ranking"
    class="btn btn-danger"
>
    Save Ranking
</button>
';

echo '<div id="ranking-message"></div>';

echo '</div>';


		;
		
	}



	// code snippet - Snippet
	function event_2568( &$header, &$icon, &$tab ) {
		
		// Place event code here.
// Use "Add Action" button to add code snippets.

// Put your code here.
//$header = "Your header here";
//$tab = "Tab label";	//	when the snippet is inside a group
echo "<br><br><br>";

		;
		
	}


	// code snippet - Snippet3
	function event_2572(  ) {
		
		global $pageObject;

dswdHistoryShow(
    "LOGISTICS_VEHICLE",
    $pageObject
);
		;
		
	}

	// code snippet - Snippet7
	function event_2574(  ) {
		
		global $pageObject;

dswdHistoryShow(
    "SAVED_LOCATION",
    $pageObject
);
		;
		
	}

	// code snippet - ManageWarehouse
	function event_2576(  ) {
		
		

/* =========================================================
   WINGS DASHBOARD
   MANAGE WAREHOUSE
   NEW DASHBOARD DESIGN
   ========================================================= */


/* =========================================================
   1. LOAD WAREHOUSE SUMMARY
   ========================================================= */

$sql = "
    SELECT
        total_warehouses,
        hubs_count,
        spokes_count,
        last_mile_count,
        data_as_of

    FROM vw_dashboard_warehouse_summary

    ORDER BY data_as_of DESC
    LIMIT 1
";

$rs = DB::Query($sql);


/* =========================================================
   2. QUERY ERROR
   ========================================================= */

if (!$rs) {

    echo "
        <div style='
            padding:15px;
            color:#ee1c25;
            font-family:Arial, Helvetica, sans-serif;
            font-size:12px;
            font-weight:700;
        '>
            SQL error while loading managed warehouses.
        </div>
    ";

    return;
}


/* =========================================================
   3. FETCH DATA
   ========================================================= */

$data = $rs->fetchAssoc();

if (!$data) {

    echo "
        <div style='
            padding:15px;
            color:#ee1c25;
            font-family:Arial, Helvetica, sans-serif;
            font-size:12px;
            font-weight:700;
        '>
            No managed warehouse data found.
        </div>
    ";

    return;
}


/* =========================================================
   4. FORMAT VALUES
   ========================================================= */

$totalWarehouses = number_format(
    (float)$data["total_warehouses"],
    0
);

$hubsCount = number_format(
    (float)$data["hubs_count"],
    0
);

$spokesCount = number_format(
    (float)$data["spokes_count"],
    0
);

$lastMileCount = number_format(
    (float)$data["last_mile_count"],
    0
);


/* =========================================================
   5. OUTPUT
   ========================================================= */

echo '

<style>

/* =========================================================
   WINGS MANAGE WAREHOUSE CARD
   NEW 2026 DASHBOARD DESIGN
   ========================================================= */

.wings-warehouse-card,
.wings-warehouse-card * {
    box-sizing: border-box;
}


/* =========================================================
   MAIN CARD
   ========================================================= */
.wings-warehouse-card {

    --dswd-blue:#2e3192;

    width:100%;

   height:220px !important;

min-height:220px !important;
    

    position:relative;

    padding:
        10px
        12px;

    overflow:hidden;

    background:#ffffff;

    border-radius:10px;

    box-shadow:
        0 3px 10px rgba(0,0,0,.14);

    font-family:
        Arial,
        Helvetica,
        sans-serif;

}


/* =========================================================
   HEADER
   ========================================================= */

.wings-warehouse-header {

    position:relative;

    width:100%;

    height:72px;

}
/* =========================================================
   TITLE
   ========================================================= */

.wings-warehouse-title {

    margin: 0;
    padding: 0;

    color: #242424;

    font-size: 12px;
    font-weight: 700;
    line-height: 15px;

    text-transform: uppercase;

    white-space: nowrap;

    overflow: hidden;
    text-overflow: ellipsis;
}


/* =========================================================
   TOTAL WAREHOUSE COUNT
   ========================================================= */
.wings-warehouse-total {

    width:100%;

    margin-top:10px;

    padding:0;

    text-align:center;

    color:#2e3192;

    font-size:30px;

    font-weight:700;

    line-height:34px;

}


/* =========================================================
   TOP RIGHT ICON
   ========================================================= */
.wings-warehouse-icon-wrap {

    position:absolute;

    top:-2px;

    right:5px;

    width:45px;

    height:45px;

    display:flex;

    align-items:center;

    justify-content:center;

}

/*
 * Existing uploaded/imported icon.
 *
 * Your current implementation already uses:
 * harvest-bag-of-cereal.png
 *
 * We retain it but make it much smaller and move it
 * to the upper-right, matching the new dashboard.
 */
.wings-warehouse-icon {

    width:42px;

    height:42px;

    object-fit:contain;

}


/* =========================================================
   BOTTOM BREAKDOWN PANEL
   ========================================================= */
.wings-warehouse-breakdown {

    position:absolute;

    left:10px;

    right:10px;

    bottom:8px;

    height:58px;

    display:grid;

    grid-template-columns:
        repeat(3,1fr);

    background:#f1f1f1;

    border-radius:5px;

    padding:
        8px
        6px;

}

/* =========================================================
   BREAKDOWN COLUMN
   ========================================================= */
.wings-warehouse-column {

    display:flex;

    flex-direction:column;

    align-items:center;

    justify-content:center;

    text-align:center;

}

/* =========================================================
   LABEL
   ========================================================= */
.wings-warehouse-label {

    color:#2e3192;

    font-size:9px;

    font-weight:500;

    line-height:12px;

    text-transform:uppercase;

}


/* =========================================================
   VALUE
   ========================================================= */
.wings-warehouse-value {

    margin-top:5px;

    color:#2e3192;

    font-size:20px;

    font-weight:700;

    line-height:22px;

}


/* =========================================================
   OPTIONAL COLUMN SEPARATION
   ---------------------------------------------------------
   Screenshot does not use visible vertical borders.
   Keep it clean.
   ========================================================= */

.wings-warehouse-column + .wings-warehouse-column {

    border-left: 0;
}


/* =========================================================
   MEDIUM DESKTOP
   ========================================================= */

@media screen and (max-width: 1200px) {

    .wings-warehouse-card {

        padding-left: 8px;
        padding-right: 8px;
    }

    .wings-warehouse-column {

        padding-left: 4px;
        padding-right: 4px;
    }

    .wings-warehouse-label {

        font-size: 8px;
    }

    .wings-warehouse-value {

        font-size: 19px;
        line-height: 22px;
    }

}


/* =========================================================
   TABLET
   ========================================================= */

@media screen and (max-width: 991px) {

    .wings-warehouse-card {

        height: 184px;
        min-height: 184px;
    }

    .wings-warehouse-total {

        font-size: 22px;
        line-height: 25px;
    }

}


/* =========================================================
   MOBILE
   ========================================================= */

@media screen and (max-width: 767px) {

    .wings-warehouse-card {

        height: 190px;
        min-height: 190px;

        padding:
            12px
            10px
            8px;
    }

    .wings-warehouse-title {

        font-size: 12px;
        line-height: 15px;
    }

    .wings-warehouse-total {

        margin-top: 8px;

        font-size: 24px;
        line-height: 27px;
    }

    .wings-warehouse-icon-wrap {

        width: 42px;
        height: 42px;
    }

    .wings-warehouse-icon {

        width: 35px;
        height: 35px;
    }

    .wings-warehouse-breakdown {

        height: 68px;
        min-height: 68px;

        padding:
            8px
            7px
            7px;
    }

    .wings-warehouse-label {

        font-size: 9px;
    }

    .wings-warehouse-value {

        font-size: 21px;
        line-height: 24px;
    }

}


/* =========================================================
   SMALL MOBILE
   ========================================================= */

@media screen and (max-width: 420px) {

    .wings-warehouse-column {

        padding-left: 3px;
        padding-right: 3px;
    }

    .wings-warehouse-label {

        font-size: 8px;
    }

    .wings-warehouse-value {

        font-size: 19px;
        line-height: 22px;
    }

}


/* =========================================================
   EXTRA SMALL
   ========================================================= */

@media screen and (max-width: 340px) {

    .wings-warehouse-card {

        padding-left: 7px;
        padding-right: 7px;
    }

    .wings-warehouse-label {

        font-size: 7px;
    }

    .wings-warehouse-value {

        font-size: 18px;
    }

}

</style>



<div class="wings-warehouse-card">


    <!-- ================================================
         HEADER
         ================================================ -->

    <div class="wings-warehouse-header">


        <!-- TITLE -->

        <div class="wings-warehouse-title">
            Manage Warehouse
        </div>


        <!-- TOTAL WAREHOUSES -->

        <div class="wings-warehouse-total">
            ' . $totalWarehouses . '
        </div>


        <!-- TOP RIGHT ICON -->

        <div class="wings-warehouse-icon-wrap">

            <img
                src="harvest-bag-of-cereal.png"
                alt=""
                class="wings-warehouse-icon"
            >

        </div>


    </div>



    <!-- ================================================
         BREAKDOWN
         ================================================ -->

    <div class="wings-warehouse-breakdown">


        <!-- HUBS -->

        <div class="wings-warehouse-column">

            <div class="wings-warehouse-label">
                Hubs
            </div>

            <div class="wings-warehouse-value">
                ' . $hubsCount . '
            </div>

        </div>



        <!-- SPOKES -->

        <div class="wings-warehouse-column">

            <div class="wings-warehouse-label">
                Spokes
            </div>

            <div class="wings-warehouse-value">
                ' . $spokesCount . '
            </div>

        </div>



        <!-- LAST MILE -->

        <div class="wings-warehouse-column">

            <div class="wings-warehouse-label">
                Last Mile
            </div>

            <div class="wings-warehouse-value">
                ' . $lastMileCount . '
            </div>

        </div>


    </div>


</div>
';



		;
		
	}





	// code snippet - Snippet5
	function event_2586(  ) {
		
		global $pageObject;

dswdHistoryShow(
    "LOGISTICS_PROVIDER",
    $pageObject
);
		;
		
	}

	// code snippet - Snippet1
	function event_2588(  ) {
		
		global $pageObject;

dswdHistoryPreview(
    "DISPATCH_PLAN",
    "id",
    $pageObject
);
		;
		
	}

	// code snippet - searchmap
	function event_2590(  ) {
		
		echo '
<style>
    .saved-location-map-panel {
        background: #ffffff;
        border: 1px solid #e5e7eb;
        border-radius: 12px;
        padding: 12px;
        width: 100%;
        box-sizing: border-box;
        box-shadow: 0 2px 8px rgba(15, 23, 42, 0.05);
        margin-bottom: 15px;
    }

    .sl-map-title {
        font-size: 16px;
        font-weight: 700;
        margin-bottom: 8px;
        color: #0f172a;
    }

    .sl-map-search {
        width: 100%;
        height: 38px;
        border: 1px solid #cbd5e1;
        border-radius: 8px;
        padding: 8px 10px;
        font-size: 13px;
        margin-bottom: 10px;
        box-sizing: border-box;
    }

    #slGoogleMap {
        width: 100%;
        height: 430px;
        border-radius: 10px;
        border: 1px solid #e5e7eb;
    }

    .sl-map-help {
        font-size: 12px;
        color: #64748b;
        margin-top: 8px;
        line-height: 1.4;
    }
</style>

<div class="saved-location-map-panel">
    <div class="sl-map-title">Pin Location</div>

    <input
        type="text"
        id="slMapSearch"
        class="sl-map-search"
        placeholder="Search location, address, city, barangay..."
    >

    <div id="slGoogleMap"></div>

    <div class="sl-map-help">
        Search location, click on the map, or drag the pin to update latitude, longitude, address, and landmark.
    </div>
</div>
';
		;
		
	}



	// code snippet - Near Expiring
	function event_2596(  ) {
		
		/* =========================================================
   WINGS DASHBOARD
   NEARING EXPIRY TABLE DESIGN
   ========================================================= */


/* =========================================================
   1. LOAD DATA
   ========================================================= */

$sql = "

SELECT

    expiry_month_label,

    ffp_qty,

    rtef_qty,

    hygiene_kit_qty,

    sort_order


FROM vw_dashboard_nearing_expiry


ORDER BY sort_order


LIMIT 5

";


$rs = DB::Query($sql);



/* =========================================================
   QUERY ERROR
   ========================================================= */

if (!$rs) {

    echo "

    <div style='
        padding:15px;
        color:#ee1c25;
        font-family:Arial;
        font-weight:bold;
    '>

        SQL error loading nearing expiry.

    </div>";

    return;

}



/* =========================================================
   STORE DATA
   ========================================================= */

$rows = array();


while ($data = $rs->fetchAssoc()) {


    $rows[] = array(

        "month" =>
            strtoupper(
                trim(
                    $data["expiry_month_label"]
                )
            ),


        "ffp" =>
            (float)$data["ffp_qty"],


        "rtef" =>
            (float)$data["rtef_qty"],


        "hygiene" =>
            (float)$data["hygiene_kit_qty"]

    );


}



/* =========================================================
   NO DATA
   ========================================================= */

if (count($rows)==0) {


    echo "

    <div style='
        padding:15px;
        color:#ee1c25;
        font-family:Arial;
        font-weight:bold;
    '>

        No nearing expiry data found.

    </div>";

    return;

}


/* =========================================================
   OUTPUT
   ========================================================= */

echo '

<style>

/* =========================================================
   CARD
   ========================================================= */
.wings-expiry-table-card {
    width: 100%;
    height: 180px; /* taller for clarity */
    background: #ffffff;
    border-radius: 8px;
    padding: 12px;
    box-sizing: border-box;
    box-shadow: 0 2px 8px rgba(0,0,0,.12);
    display: flex;
    flex-direction: column;
    overflow: hidden;
    font-family: Arial, Helvetica, sans-serif;
}

/* =========================================================
   TITLE
   ========================================================= */
.wings-expiry-table-title {
    flex: 0 0 auto;
    height: 22px;
    line-height: 22px;
    margin-bottom: 6px;
    font-size: 13px;
    font-weight: 700;
    text-transform: uppercase;
    color: #2e3192; /* match DSWD blue */
}


/* =========================================================
   SCROLL CONTAINER
   ========================================================= */
.wings-expiry-scroll {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    overflow-x: hidden;
}




/* =========================================================
   TABLE
   ========================================================= */
.wings-expiry-table {
    width: 100%;
    table-layout: fixed;
    border-collapse: collapse;
}







/* Column widths */
.wings-expiry-table th:nth-child(1),
.wings-expiry-table td:nth-child(1) { width: 28%; }
.wings-expiry-table th:nth-child(2),
.wings-expiry-table td:nth-child(2),
.wings-expiry-table th:nth-child(3),
.wings-expiry-table td:nth-child(3),
.wings-expiry-table th:nth-child(4),
.wings-expiry-table td:nth-child(4) { width: 24%; }

/* Header */
.wings-expiry-table > thead > tr > th {
    background-color: #2e3192 !important;
    color: #ffffff !important;
    height: 22px;
    padding: 4px 8px;
    font-size: 10px;
    font-weight: 700;
    text-align: right;
    border: none !important;
    white-space: nowrap;
    position: sticky;
    top: 0;
    z-index: 99;
}
.wings-expiry-table > thead > tr > th:first-child {
    text-align: left;
    border-radius: 3px 0 0 3px;
}
.wings-expiry-table > thead > tr > th:last-child {
    border-radius: 0 3px 3px 0;
}

/* Body */
.wings-expiry-table tbody td {
    height: 22px;
    padding: 3px 8px;
    font-size: 10px;
    color: #333;
    font-weight: 500;
    text-align: right;
    white-space: nowrap;
}
.wings-expiry-table tbody tr:nth-child(odd) td { background: #f9f9f9; }
.wings-expiry-table tbody tr:nth-child(even) td { background: #f1f1f1; }
.wings-expiry-table tbody td:first-child { text-align: left; }

/* Scrollbar */
.wings-expiry-scroll::-webkit-scrollbar { width: 6px; }
.wings-expiry-scroll::-webkit-scrollbar-thumb {
    background: #bdbdbd;
    border-radius: 5px;
}


/* =========================================================
   SCROLLBAR
   ========================================================= */


.wings-expiry-scroll::-webkit-scrollbar {


    width:6px;


}



.wings-expiry-scroll::-webkit-scrollbar-thumb {


    background:#bdbdbd;


    border-radius:5px;


}



</style>





<div class="wings-expiry-table-card">



    <div class="wings-expiry-table-title">

        NEARING EXPIRY

    </div>




    <div class="wings-expiry-scroll">



        <table class="wings-expiry-table">



            <thead>


                <tr>


                    <th>
                        MONTH
                    </th>


                    <th>
                        FFP
                    </th>


                    <th>
                        RTEF
                    </th>


                    <th>
                        HYGIENE KIT
                    </th>


                </tr>


            </thead>



            <tbody>

';



foreach($rows as $row){


echo '

<tr>


<td>
'
.htmlspecialchars(
    $row["month"],
    ENT_QUOTES,
    "UTF-8"
).
'
</td>


<td>
'
.number_format(
    $row["ffp"],
    0
).
'
</td>


<td>
'
.number_format(
    $row["rtef"],
    0
).
'
</td>


<td>
'
.number_format(
    $row["hygiene"],
    0
).
'
</td>


</tr>


';


}



echo '

            </tbody>


        </table>



    </div>



</div>



';
		;
		
	}


	// code snippet - Activity Log_Production Plan
	function event_2600(  ) {
		
		// ======================================================
// PRODUCTION PLAN
// ACTIVITY LOG PREVIEW
//
// Source:
// transaction_history_log
//
// Shows:
// Latest activity only
// ======================================================

global $pageObject;


// ======================================================
// MODULE CONFIGURATION
// ======================================================

$historyModule  = "PRODUCTION_PLAN";
$historyPkField = "id";


// ======================================================
// GET CURRENT PRODUCTION PLAN
// ======================================================

$currentRecord =
    $pageObject->getCurrentRecord();


if (!$currentRecord) {

    echo "
        <div class='module-activity-log'>
            Unable to identify the Production Plan.
        </div>
    ";

    return;
}


$recordId = intval(
    $currentRecord[$historyPkField] ?? 0
);


if ($recordId <= 0) {

    echo "
        <div class='module-activity-log'>
            Unable to identify the Production Plan.
        </div>
    ";

    return;
}


// ======================================================
// GET LATEST HISTORY
// ======================================================

$sqlHistory = "
    SELECT
        id,
        action_code,
        action_label,
        actor_name,
        actor_username,
        action_at

    FROM transaction_history_log

    WHERE module_code = '" .
        db_addslashes(
            $historyModule
        ) .
    "'

    AND record_id = " .
        $recordId . "

    ORDER BY
        action_at DESC,
        id DESC

    LIMIT 1
";


$rsHistory =
    DB::Query(
        $sqlHistory
    );


$history =
    $rsHistory
        ? $rsHistory->fetchAssoc()
        : null;


// ======================================================
// DEFAULT VALUES
// ======================================================

$activity       = "";
$activityColor  = "#666666";

$name           = "";
$performedBy    = "";
$timeDisplay    = "";


// ======================================================
// FORMAT HISTORY
// ======================================================

if ($history) {

    $actionCode = strtoupper(
        trim(
            (string)(
                $history["action_code"] ?? ""
            )
        )
    );


    // --------------------------------------------------
    // ACTIVITY
    // --------------------------------------------------

    switch ($actionCode) {


        case "SUBMITTED":

            $activity =
                "Submitted by";

            $activityColor =
                "#ff3b30";

            break;


        case "CREATED":

            $activity =
                "Created by";

            $activityColor =
                "#3f51b5";

            break;


        case "UPDATED":

            $activity =
                "Edited by";

            $activityColor =
                "#ff9500";

            break;


        case "APPROVED":

            $activity =
                "Approved by";

            $activityColor =
                "#34c759";

            break;


        case "RETURNED":

            $activity =
                "Returned by";

            $activityColor =
                "#af52de";

            break;


        case "REJECTED":

            $activity =
                "Rejected by";

            $activityColor =
                "#d0021b";

            break;


        case "CANCELLED":
        case "CANCELED":

            $activity =
                "Cancelled by";

            $activityColor =
                "#8e8e93";

            break;


        case "COMPLETED":

            $activity =
                "Completed by";

            $activityColor =
                "#34c759";

            break;


        default:

            $activity = trim(
                (string)(
                    $history["action_label"] ?? ""
                )
            );


            if ($activity == "") {

                $activity =
                    $actionCode;
            }


            $activityColor =
                "#666666";

            break;
    }


    // --------------------------------------------------
    // NAME
    // --------------------------------------------------

    $name = trim(
        (string)(
            $history["actor_name"] ?? ""
        )
    );


    if ($name == "") {

        $name = trim(
            (string)(
                $history["actor_username"] ?? ""
            )
        );
    }


    if ($name == "") {

        $name =
            "System";
    }


    // --------------------------------------------------
    // PERFORMED BY
    // --------------------------------------------------

    $performedBy =
        $name;


    // --------------------------------------------------
    // TIME
    // --------------------------------------------------

    $actionAt = trim(
        (string)(
            $history["action_at"] ?? ""
        )
    );


    if ($actionAt != "") {

        try {

            $dt = new DateTime(
                $actionAt,
                new DateTimeZone(
                    "Asia/Manila"
                )
            );


            $timeDisplay =
                $dt->format(
                    "M d, Y | h:i A"
                );

        }
        catch (Exception $e) {

            $timeDisplay =
                $actionAt;
        }
    }
}


// ======================================================
// CSS
// ======================================================

echo '

<style>

/* =====================================================
   ACTIVITY LOG
===================================================== */

.module-activity-log {

    width: 100% !important;

    min-width: 100% !important;

    max-width: none !important;

    margin:
        16px
        0
        14px
        0 !important;

    padding:
        0 !important;

    background:
        #f7f7f7 !important;

    border:
        0 !important;

    border-radius:
        3px !important;

    overflow:
        hidden !important;

    box-sizing:
        border-box !important;

    font-family:
        Arial,
        sans-serif !important;
}


/* =====================================================
   HEADER
===================================================== */

.module-activity-header {

    width:
        100% !important;

    height:
        36px !important;

    min-height:
        36px !important;

    display:
        flex !important;

    align-items:
        center !important;

    justify-content:
        space-between !important;

    padding:
        0
        9px
        0
        14px !important;

    margin:
        0 !important;

    background:
        #34349a !important;

    box-sizing:
        border-box !important;
}


/* =====================================================
   TITLE
===================================================== */

.module-activity-title {

    margin:
        0 !important;

    padding:
        0 !important;

    color:
        #ffffff !important;

    font-size:
        11px !important;

    font-weight:
        600 !important;

    line-height:
        36px !important;
}


/* =====================================================
   VIEW ALL BUTTON
===================================================== */

.btnViewAllHistory {

    height:
        24px !important;

    min-height:
        24px !important;

    margin:
        0 !important;

    padding:
        0
        9px !important;

    display:
        inline-flex !important;

    align-items:
        center !important;

    justify-content:
        center !important;

    background:
        #ffffff !important;

    color:
        #34349a !important;

    border:
        1px solid
        #d6d6d6 !important;

    border-radius:
        3px !important;

    font-family:
        Arial,
        sans-serif !important;

    font-size:
        9px !important;

    font-weight:
        500 !important;

    line-height:
        22px !important;

    cursor:
        pointer !important;

    white-space:
        nowrap !important;

    box-shadow:
        none !important;
}


.btnViewAllHistory:hover {

    background:
        #f4f4f4 !important;

    color:
        #34349a !important;
}


/* =====================================================
   TABLE AREA
===================================================== */

.module-activity-table {

    width:
        100% !important;

    min-width:
        100% !important;

    margin:
        0 !important;

    padding:
        0 !important;

    background:
        #f7f7f7 !important;

    box-sizing:
        border-box !important;
}


/* =====================================================
   TABLE HEADER
===================================================== */

.module-activity-table-head {

    width:
        100% !important;

    display:
        grid !important;

    grid-template-columns:
        25%
        25%
        30%
        20% !important;

    align-items:
        center !important;

    margin:
        0 !important;

    padding:
        9px
        14px
        3px
        14px !important;

    box-sizing:
        border-box !important;
}


.module-activity-table-head > div {

    margin:
        0 !important;

    padding:
        0 !important;

    color:
        #666666 !important;

    font-size:
        10px !important;

    font-weight:
        400 !important;

    line-height:
        15px !important;

    text-align:
        left !important;

    white-space:
        nowrap !important;
}


/* =====================================================
   TABLE ROW
===================================================== */

.module-activity-table-row {

    width:
        100% !important;

    display:
        grid !important;

    grid-template-columns:
        25%
        25%
        30%
        20% !important;

    align-items:
        center !important;

    margin:
        0 !important;

    padding:
        2px
        14px
        12px
        14px !important;

    box-sizing:
        border-box !important;
}


.module-activity-table-row > div {

    margin:
        0 !important;

    padding:
        0 !important;

    color:
        #222222 !important;

    font-size:
        11px !important;

    font-weight:
        400 !important;

    line-height:
        16px !important;

    text-align:
        left !important;

    overflow:
        hidden !important;

    text-overflow:
        ellipsis !important;

    white-space:
        nowrap !important;
}


/* =====================================================
   EMPTY HISTORY
===================================================== */

.module-activity-empty {

    width:
        100% !important;

    padding:
        14px !important;

    color:
        #888888 !important;

    font-size:
        10px !important;

    text-align:
        center !important;

    box-sizing:
        border-box !important;
}


/* =====================================================
   FORCE PHPRUNNER CONTAINER FULL WIDTH
===================================================== */

.activity-log-full-width {

    width:
        100% !important;

    min-width:
        100% !important;

    max-width:
        100% !important;

    flex:
        0 0 100% !important;

    flex-basis:
        100% !important;

    float:
        none !important;

    display:
        block !important;

    clear:
        both !important;

    box-sizing:
        border-box !important;
}


/* =====================================================
   MOBILE / SMALL SCREEN
===================================================== */

@media screen and (max-width: 768px) {

    .module-activity-log {

        overflow-x:
            auto !important;
    }


    .module-activity-header,
    .module-activity-table {

        min-width:
            650px !important;
    }

}

</style>

';


// ======================================================
// OUTPUT
// ======================================================

echo '

<div
    class="
        module-activity-log
    "
>


    <!-- =============================================
         HEADER
    ============================================== -->

    <div
        class="
            module-activity-header
        "
    >


        <div
            class="
                module-activity-title
            "
        >

            Activity Logs

        </div>


        <button
            type="button"

            class="
                btnViewAllHistory
            "

            data-module="' .
                htmlspecialchars(
                    $historyModule
                ) .
            '"

            data-recordid="' .
                intval(
                    $recordId
                ) .
            '"
        >

            &#8634;&nbsp;
            View All

        </button>


    </div>



    <!-- =============================================
         TABLE
    ============================================== -->

    <div
        class="
            module-activity-table
        "
    >


        <!-- =========================================
             HEADINGS
        ========================================== -->

        <div
            class="
                module-activity-table-head
            "
        >


            <div>
                Activity
            </div>


            <div>
                Name
            </div>


            <div>
                Time
            </div>


            <div>
                Performed by
            </div>


        </div>

';


// ======================================================
// LATEST ACTIVITY
// ======================================================

if ($history) {


    echo '

        <div
            class="
                module-activity-table-row
            "
        >


            <!-- ACTIVITY -->

            <div>

                <span
                    style="
                        color:' .
                        htmlspecialchars(
                            $activityColor
                        ) .
                        ' !important;

                        font-weight:
                            500 !important;
                    "
                >

                    ' .
                    htmlspecialchars(
                        $activity
                    ) .
                    '

                </span>

            </div>



            <!-- NAME -->

            <div>

                ' .
                htmlspecialchars(
                    $name
                ) .
                '

            </div>



            <!-- TIME -->

            <div>

                ' .
                htmlspecialchars(
                    $timeDisplay
                ) .
                '

            </div>



            <!-- PERFORMED BY -->

            <div>

                ' .
                htmlspecialchars(
                    $performedBy
                ) .
                '

            </div>


        </div>

    ';


}
else {


    echo '

        <div
            class="
                module-activity-empty
            "
        >

            No activity history yet.

        </div>

    ';

}


// ======================================================
// CLOSE OUTPUT
// ======================================================

echo '

    </div>

</div>

';


// ======================================================
// FORCE PHPRUNNER PARENT TO FULL WIDTH
// ======================================================

echo '

<script>

(function () {


    function forceActivityLogFullWidth() {


        var log =
            document.querySelector(
                ".module-activity-log"
            );


        if (!log) {

            return;
        }


        // ---------------------------------------------
        // Always force Activity Log itself
        // ---------------------------------------------

        log.style.width =
            "100%";

        log.style.maxWidth =
            "none";

        log.style.minWidth =
            "100%";


        // ---------------------------------------------
        // FIND THE HALF-WIDTH PHPRUNNER CONTAINER
        // ---------------------------------------------

        var current =
            log.parentElement;


        var level =
            0;


        while (
            current &&
            current.parentElement &&
            level < 10
        ) {


            var parent =
                current.parentElement;


            var currentWidth =
                current.getBoundingClientRect().width;


            var parentWidth =
                parent.getBoundingClientRect().width;


            /*
             * Example:
             *
             * Activity Log parent = 628px
             * Available parent     = 1288px
             *
             * This identifies the container that is
             * making the Activity Log half-width.
             */

            if (
                parentWidth > 0 &&
                currentWidth > 0 &&
                currentWidth <
                    (
                        parentWidth * 0.75
                    )
            ) {


                current.classList.add(
                    "activity-log-full-width"
                );


                current.style.width =
                    "100%";

                current.style.minWidth =
                    "100%";

                current.style.maxWidth =
                    "100%";

                current.style.flex =
                    "0 0 100%";

                current.style.flexBasis =
                    "100%";

                current.style.float =
                    "none";

                current.style.display =
                    "block";

                current.style.clear =
                    "both";


                // -------------------------------------
                // REMOVE BOOTSTRAP HALF-WIDTH CLASSES
                // -------------------------------------

                var classes =
                    Array.from(
                        current.classList
                    );


                classes.forEach(
                    function (cls) {


                        if (
                            /^col-(xs|sm|md|lg|xl|xxl)-[0-9]+$/.test(
                                cls
                            )
                        ) {

                            current.classList.remove(
                                cls
                            );
                        }

                    }
                );


                current.classList.add(
                    "col-xs-12"
                );


                current.classList.add(
                    "col-sm-12"
                );


                current.classList.add(
                    "col-md-12"
                );


                current.classList.add(
                    "col-lg-12"
                );


                break;
            }


            current =
                parent;


            level++;

        }


        // ---------------------------------------------
        // FORCE IMMEDIATE WRAPPERS
        // ---------------------------------------------

        var wrapper =
            log.parentElement;


        for (
            var i = 0;
            i < 3 && wrapper;
            i++
        ) {


            wrapper.style.maxWidth =
                "100%";


            if (
                wrapper.getBoundingClientRect().width <
                log.getBoundingClientRect().width
            ) {

                wrapper.style.width =
                    "100%";
            }


            wrapper =
                wrapper.parentElement;

        }

    }


    // ---------------------------------------------
    // RUN NOW
    // ---------------------------------------------

    forceActivityLogFullWidth();


    // ---------------------------------------------
    // RUN AGAIN AFTER PHPRUNNER FINISHES RENDERING
    // ---------------------------------------------

    setTimeout(
        forceActivityLogFullWidth,
        100
    );


    setTimeout(
        forceActivityLogFullWidth,
        300
    );


    setTimeout(
        forceActivityLogFullWidth,
        800
    );


    // ---------------------------------------------
    // ALSO FIX AFTER WINDOW RESIZE / ZOOM
    // ---------------------------------------------

    window.addEventListener(
        "resize",
        function () {

            forceActivityLogFullWidth();

        }
    );


})();

</script>

';
		;
		
	}


	// code snippet - FamilyFoodPack
	function event_2604(  ) {
		
		/* =========================================================
   WINGS DASHBOARD
   FAMILY FOOD PACKS PER DSWD DRCs AND FIELD OFFICES

   MODERN BAR CHART V8
   FIXED CARD PROPORTION VERSION
   ========================================================= */


/* =========================================================
   LOAD DATA
   ========================================================= */

$sql = "

SELECT

    office_code,
    office_name,
    ffp_qty,
    sort_order

FROM vw_dashboard_ffp_by_office

ORDER BY sort_order

";


$rs = DB::Query($sql);



if(!$rs)
{

    echo "

    <div style='
        color:#ee1c25;
        font-weight:bold;
        padding:10px;
    '>

        Error loading FFP data.

    </div>

    ";

    return;

}





/* =========================================================
   PREPARE DATA
   ========================================================= */


$rows = array();

$maxValue = 0;



while($data = $rs->fetchAssoc())
{

    $qty = (float)$data["ffp_qty"];


    if($qty > $maxValue)
    {
        $maxValue = $qty;
    }



    $rows[] = array(

        "office_code" =>
            trim($data["office_code"]),


        "office_name" =>
            trim($data["office_name"]),


        "ffp_qty" =>
            $qty

    );


}





if(count($rows)==0)
{

    echo "

    <div style='
        color:#ee1c25;
        font-weight:bold;
        padding:10px;
    '>

        No FFP data found.

    </div>

    ";

    return;

}





/* =========================================================
   SCALE
   ========================================================= */


$chartMax = 140000;



if($maxValue > $chartMax)
{

    $chartMax =

        ceil($maxValue / 10000)

        * 10000;

}



$minimumThreshold = 70000;



$y75 = $chartMax * .75;

$y50 = $chartMax * .50;

$y25 = $chartMax * .25;



$rowCount = count($rows);






/* =========================================================
   OUTPUT CARD + CSS
   ========================================================= */


echo "

<style>


.wings-ffp-card,
.wings-ffp-card * {

    box-sizing:border-box;

}



.wings-ffp-card {

    width:100%;

    height:420px;

    padding:16px;

    background:#ffffff;

    border-radius:10px;

    box-shadow:

        0 4px 14px rgba(0,0,0,.12);


    font-family:

        Arial,

        Helvetica,

        sans-serif;


    overflow:hidden;

}




.wings-ffp-title {

    font-size:14px;

    font-weight:700;

    color:#2e3192;

    text-transform:uppercase;

    margin-bottom:30px;

}





.wings-ffp-chart {

    display:grid;


    grid-template-columns:

        50px

        1fr;


    height:300px;

}

.wings-ffp-chart {
    margin-top:20px;
}



.wings-ffp-y-axis {

    position:relative;


    height:260px;


    border-right:

        1px solid #cccccc;


    color:#555;


    font-size:10px;

}





.wings-ffp-y-label {

    position:absolute;

    right:6px;

    font-weight:600;

}



.wings-ffp-y-label.max {

    top:0;

}


.wings-ffp-y-label.v75 {

    top:25%;

}


.wings-ffp-y-label.v50 {

    top:50%;

}


.wings-ffp-y-label.v25 {

    top:75%;

}


.wings-ffp-y-label.zero {

    bottom:0;

}





.wings-ffp-plot {

    position:relative;

    height:260px;


    border-left:

        1px solid #cccccc;


    border-bottom:

        1px solid #cccccc;


}





.wings-ffp-bars {

    position:absolute;


    left:0;

    right:0;

    bottom:0;


    height:260px;


    display:grid;


    grid-template-columns:

        repeat(" . $rowCount . ",1fr);


    column-gap:4px;


    align-items:end;

}





.wings-ffp-bar-cell {

    height:100%;


    display:flex;


    justify-content:center;


    align-items:flex-end;

}





.wings-ffp-track {

    width:70%;


    max-width:32px;


    min-width:18px;


    height:100%;


    position:relative;

}





.wings-ffp-bar {

    position:absolute;


    bottom:0;


    left:50%;


    transform:translateX(-50%);


    width:100%;


    border-radius:

        6px

        6px

        0

        0;

}



.wings-ffp-bar.safe {

    background:#55b15b;

}



.wings-ffp-bar.critical {

    background:#ee1c25;

}





";

/* =========================================================
   VALUE LABEL STYLE
   ========================================================= */


echo "

<style>


.wings-ffp-value-label {
    position: absolute;
    bottom: 100%;   /* sits right above the bar */
    left: 50%;
    transform: translateX(-50%);
    font-size: 10px;
    font-weight: 700;
    color: #222;
}




.wings-ffp-x-axis {


    margin-left:50px;


    margin-top:0px;


    display:grid;


    grid-template-columns:

        repeat(" . $rowCount . ",1fr);


    column-gap:4px;


}



.wings-ffp-x-label {


    text-align:center;


    font-size:8px;


    font-weight:700;


    color:#222;


    white-space:nowrap;


    overflow:hidden;


    text-overflow:ellipsis;


}



</style>



<div class='wings-ffp-title'>

FAMILY FOOD PACKS PER DSWD DRCs AND FIELD OFFICES

</div>



<div class='wings-ffp-chart'>



<div class='wings-ffp-y-axis'>


<div class='wings-ffp-y-label max'>

" . number_format($chartMax,0) . "

</div>


<div class='wings-ffp-y-label v75'>

" . number_format($y75,0) . "

</div>


<div class='wings-ffp-y-label v50'>

" . number_format($y50,0) . "

</div>


<div class='wings-ffp-y-label v25'>

" . number_format($y25,0) . "

</div>


<div class='wings-ffp-y-label zero'>

0

</div>


</div>




<div class='wings-ffp-plot'>



<div class='wings-ffp-bars'>

";




/* =========================================================
   GENERATE BARS
   ========================================================= */


foreach($rows as $row)
{


    $qty = (float)$row["ffp_qty"];



    $heightPercent = 0;



    if($chartMax > 0)
    {

        $heightPercent =

            ($qty / $chartMax)

            * 100;

    }



    if($heightPercent > 100)
    {

        $heightPercent = 100;

    }



    if($heightPercent < 0)
    {

        $heightPercent = 0;

    }



    $heightCss = number_format(

        $heightPercent,

        2,

        ".",

        ""

    );





    if($qty < $minimumThreshold)
    {

        $statusClass = "critical";

    }
    else
    {

        $statusClass = "safe";

    }




    $safeQuantity = htmlspecialchars(

        number_format($qty,0),

        ENT_QUOTES,

        "UTF-8"

    );





    echo "


<div class='wings-ffp-bar-cell'>


<div class='wings-ffp-track'>


<div

class='wings-ffp-bar ".$statusClass."'

style='height:".$heightCss."%;'


>


<div class='wings-ffp-value-label'>


".$safeQuantity."


</div>



</div>



</div>



</div>


";



}



echo "

</div>


</div>


</div>


";

/* =========================================================
   X AXIS LABELS
   ========================================================= */


echo "

<div class='wings-ffp-x-axis'>

";




foreach($rows as $row)
{


    $officeCode = htmlspecialchars(

        $row["office_code"],

        ENT_QUOTES,

        "UTF-8"

    );




    echo "

    <div class='wings-ffp-x-label'>

        ".$officeCode."

    </div>

    ";


}





echo "

</div>


</div>


</div>


</div>


</div>


";


		;
		
	}

	// code snippet - NFI Inventory
	function event_2606(  ) {
		
		

/* =========================================================
   WINGS DASHBOARD - NFI INVENTORY
   ========================================================= */

$sql = "
    SELECT
        warehouse_code,
        warehouse_name,
        warehouse_type,
        family_clothing_qty,
        kitchen_kit_qty,
        sleeping_kit_qty,
        hygiene_kit_qty,
        family_tents_qty,
        water_jerrican_qty,
        others_qty,
        sort_order
    FROM vw_dashboard_nfi_inventory
    ORDER BY sort_order
";

$rs = DB::Query($sql);

if (!$rs) {
    echo "
        <div style='
            padding:15px;
            color:#ee1c25;
            font-family:Arial,Helvetica,sans-serif;
            font-weight:700;
        '>
            SQL error while loading NFI Inventory.
        </div>
    ";
    return;
}


$rows = array();

while ($data = $rs->fetchAssoc()) {
    $rows[] = $data;
}


if (count($rows) === 0) {
    echo "
        <div style='
            padding:15px;
            color:#ee1c25;
            font-family:Arial,Helvetica,sans-serif;
            font-weight:700;
        '>
            No NFI Inventory data found.
        </div>
    ";
    return;
}


if (!function_exists("wingsFormatNfiDashboardQty")) {

    function wingsFormatNfiDashboardQty($value)
    {
        $value = (float)$value;

        if ($value == 0) {
            return "-";
        }

        return number_format($value, 0);
    }
}


$nfiCardId =
    "wingsNfiInventory_" .
    uniqid();


echo '

<style>

/* =========================================================
   NFI INVENTORY
   ========================================================= */

.wings-nfi-card,
.wings-nfi-card * {
    box-sizing: border-box;
}


/* =========================================================
   CARD
   ========================================================= */

.wings-nfi-card {

    --nfi-blue: #2e3192;
    --nfi-row: #f1f1f1;
    --nfi-row-hover: #e7e7e7;

    width: 100% !important;
    max-width: 100% !important;
    min-width: 0 !important;

       height: auto !important;

 min-height: 0 !important;

    max-height: none !important;

    display: flex !important;

    flex-direction: column !important;

    padding:
        11px
        13px
        10px !important;

    background:
        #ffffff !important;

    border:
        0 !important;

    border-radius:
        8px !important;

    overflow:
        hidden !important;

    box-shadow:
        0 3px 10px
        rgba(0,0,0,0.13) !important;

    font-family:
        Arial,
        Helvetica,
        sans-serif !important;
}


/* =========================================================
   TITLE
   ========================================================= */

.wings-nfi-title {

    flex:
        0
        0
        auto;

    margin:
        0
        0
        6px !important;

    padding:
        0 !important;

    color:
        #242424 !important;

    font-size:
        13px !important;

    font-weight:
        700 !important;

    line-height:
        16px !important;

    text-transform:
        uppercase !important;

    white-space:
        nowrap;
}


/* =========================================================
   SCROLL
   ========================================================= */

.wings-nfi-table-scroll {

    flex:
        0
        0
        auto !important;

    width:
        100% !important;

    min-width:
        0 !important;

    min-height:
        0 !important;

    overflow-x:
        auto !important;

    overflow-y:
        auto !important;

    padding-bottom:
        2px !important;

    scrollbar-width:
        thin;

    scrollbar-color:
        #adadad
        transparent;
}


.wings-nfi-table-scroll::-webkit-scrollbar {

    width: 5px;

    height: 5px;
}


.wings-nfi-table-scroll::-webkit-scrollbar-track {

    background:
        transparent;
}


.wings-nfi-table-scroll::-webkit-scrollbar-thumb {

    background:
        #adadad;

    border-radius:
        5px;
}


/* =========================================================
   TABLE
   ========================================================= */

.wings-nfi-table {

    width:
        100% !important;

    min-width:
        950px !important;

    margin:
        0 !important;

    border-collapse:
        separate !important;

    border-spacing:
        0
        6px !important;

    table-layout:
        fixed !important;

    background:
        transparent !important;
}


/* =========================================================
   WIDTHS
   ========================================================= */

.wings-nfi-table col.nfi-col-warehouse {
    width: 18%;
}

.wings-nfi-table col.nfi-col-clothing {
    width: 15%;
}

.wings-nfi-table col.nfi-col-kitchen {
    width: 12%;
}

.wings-nfi-table col.nfi-col-sleeping {
    width: 12%;
}

.wings-nfi-table col.nfi-col-hygiene {
    width: 12%;
}

.wings-nfi-table col.nfi-col-tents {
    width: 12%;
}

.wings-nfi-table col.nfi-col-water {
    width: 13%;
}

.wings-nfi-table col.nfi-col-others {
    width: 10%;
}


/* =========================================================
   BLUE HEADER
   ========================================================= */

.wings-nfi-card
.wings-nfi-table
thead > tr {

    --bs-table-bg:
        #2e3192 !important;

    background:
        #2e3192 !important;

    background-color:
        #2e3192 !important;
}


.wings-nfi-card
.wings-nfi-table
thead > tr > th {

    --bs-table-bg:
        #2e3192 !important;

    --bs-table-accent-bg:
        #2e3192 !important;

    --bs-table-striped-bg:
        #2e3192 !important;

    --bs-table-hover-bg:
        #2e3192 !important;

    --bs-table-color:
        #ffffff !important;

    position:
        sticky !important;

    top:
        0 !important;

    z-index:
        20 !important;

    height:
        29px !important;

    padding:
        7px
        8px !important;

    background:
        #2e3192 !important;

    background-color:
        #2e3192 !important;

    background-image:
        none !important;

    color:
        #ffffff !important;

    -webkit-text-fill-color:
        #ffffff !important;

    opacity:
        1 !important;

    border:
        0 !important;

    box-shadow:
        none !important;

    font-family:
        Arial,
        Helvetica,
        sans-serif !important;

    font-size:
        10px !important;

    font-weight:
        700 !important;

    line-height:
        12px !important;

    text-align:
        center !important;

    vertical-align:
        middle !important;

    text-transform:
        uppercase !important;

    white-space:
        nowrap !important;

    overflow:
        hidden !important;

    text-overflow:
        ellipsis !important;
}


.wings-nfi-card
.wings-nfi-table
thead > tr > th:first-child {

    border-radius:
        5px
        0
        0
        5px !important;
}


.wings-nfi-card
.wings-nfi-table
thead > tr > th:last-child {

    border-radius:
        0
        5px
        5px
        0 !important;
}


/* =========================================================
   NFI ROWS
   ========================================================= */

.wings-nfi-card
.wings-nfi-table
tbody > tr > td {

    --bs-table-bg:
        #f1f1f1 !important;

    --bs-table-accent-bg:
        #f1f1f1 !important;

    --bs-table-striped-bg:
        #f1f1f1 !important;

    height:
        24px !important;

    padding:
        4px
        6px !important;

    background:
        #f1f1f1 !important;

    background-color:
        #f1f1f1 !important;

    background-image:
        none !important;

    color:
        #202020 !important;

    border:
        0 !important;

    font-family:
        Arial,
        Helvetica,
        sans-serif !important;

    font-size:
        10px !important;

    font-weight:
        700 !important;

    line-height:
        13px !important;

    text-align:
        center !important;

    vertical-align:
        middle !important;

    white-space:
        nowrap !important;

    overflow:
        hidden !important;

    text-overflow:
        ellipsis !important;
}


.wings-nfi-card
.wings-nfi-table
tbody > tr > td:first-child {

    border-radius:
        5px
        0
        0
        5px !important;

    text-align:
        left !important;

    padding-left:
        12px !important;
}


.wings-nfi-card
.wings-nfi-table
tbody > tr > td:last-child {

    border-radius:
        0
        5px
        5px
        0 !important;
}


.wings-nfi-card
.wings-nfi-table
tbody > tr:hover > td {

    --bs-table-bg:
        #e5e5e5 !important;

    background:
        #e5e5e5 !important;

    background-color:
        #e5e5e5 !important;
}


/* =========================================================
   WAREHOUSE
   ========================================================= */

.wings-nfi-warehouse-code {

    display:
        block;

    color:
        #202020 !important;

    font-size:
        10px !important;

    font-weight:
        700 !important;

    white-space:
        nowrap;

    overflow:
        hidden;

    text-overflow:
        ellipsis;
}


/* =========================================================
   TOOLTIP
   ========================================================= */

.wings-nfi-tooltip {

    position:
        fixed;

    z-index:
        999999;

    display:
        none;

    min-width:
        190px;

    max-width:
        320px;

    padding:
        9px
        11px;

    background:
        rgba(24,24,27,0.97);

    color:
        #ffffff;

    border-radius:
        6px;

    box-shadow:
        0 5px 16px
        rgba(0,0,0,0.25);

    font-family:
        Arial,
        Helvetica,
        sans-serif;

    font-size:
        12px;

    line-height:
        16px;

    pointer-events:
        none;
}


.wings-nfi-tooltip.show {

    display:
        block;
}


.wings-nfi-tooltip-code {

    display:
        block;

    margin-bottom:
        2px;

    color:
        #ffffff;

    font-size:
        13px;

    font-weight:
        700;
}


.wings-nfi-tooltip-name {

    color:
        rgba(255,255,255,0.88);
}


/* =========================================================
   SHORT SCREEN
   ========================================================= */

@media screen and (min-width: 993px) and (max-height: 720px) {

    .wings-nfi-card {

        height:
            225px !important;

        min-height:
            225px !important;

        max-height:
            225px !important;
    }

}


/* =========================================================
   ZOOMED OUT / LARGE VIEWPORT
   ========================================================= */

@media screen and (min-width: 1800px) {

    .wings-nfi-card {

        height:
            300px !important;

        min-height:
            300px !important;

        max-height:
            300px !important;
    }

}


@media screen and (min-width: 2600px) {

    .wings-nfi-card {

        height:
            300px !important;

        min-height:
            300px !important;

        max-height:
            300px !important;
    }

}


/* =========================================================
   TABLET
   ========================================================= */

@media screen and (max-width: 992px) {

    .wings-nfi-card {

        height:
            235px !important;

        min-height:
            235px !important;

        max-height:
            235px !important;

        padding:
            10px
            10px
            9px !important;
    }


    .wings-nfi-table {

        min-width:
            900px !important;
    }

}


/* =========================================================
   MOBILE / HIGH ZOOM
   ========================================================= */

@media screen and (max-width: 768px) {

    .wings-nfi-card {

        height:
            225px !important;

        min-height:
            225px !important;

        max-height:
            225px !important;
    }


    .wings-nfi-title {

        font-size:
            12px !important;

        margin-bottom:
            9px !important;
    }


    .wings-nfi-table-scroll {

        overflow-x:
            auto !important;

        overflow-y:
            auto !important;
    }

}

</style>



<div
    class="wings-nfi-card"
    id="' . $nfiCardId . '"
>

    <div class="wings-nfi-title">
        NFI Inventory
    </div>


    <div class="wings-nfi-table-scroll">

        <table class="wings-nfi-table">

            <colgroup>

                <col class="nfi-col-warehouse">

                <col class="nfi-col-clothing">

                <col class="nfi-col-kitchen">

                <col class="nfi-col-sleeping">

                <col class="nfi-col-hygiene">

                <col class="nfi-col-tents">

                <col class="nfi-col-water">

                <col class="nfi-col-others">

            </colgroup>


            <thead>

                <tr>

                    <th>Warehouses</th>

                    <th>Family Clothing</th>

                    <th>Kitchen Kit</th>

                    <th>Sleeping Kit</th>

                    <th>Hygiene Kit</th>

                    <th>Family Tents</th>

                    <th>Water Jerrican</th>

                    <th>Others</th>

                </tr>

            </thead>


            <tbody>
';


foreach ($rows as $row) {

    $warehouseCode = htmlspecialchars(
        isset($row["warehouse_code"])
            ? $row["warehouse_code"]
            : "",
        ENT_QUOTES,
        "UTF-8"
    );

    $warehouseName = htmlspecialchars(
        isset($row["warehouse_name"])
            ? $row["warehouse_name"]
            : "",
        ENT_QUOTES,
        "UTF-8"
    );

    $warehouseType = htmlspecialchars(
        isset($row["warehouse_type"])
            ? $row["warehouse_type"]
            : "",
        ENT_QUOTES,
        "UTF-8"
    );


    echo '

        <tr>

            <td
                class="
                    wings-nfi-warehouse-cell
                    wings-nfi-tooltip-target
                "
                data-code="' . $warehouseCode . '"
                data-name="' . $warehouseName . '"
                data-type="' . $warehouseType . '"
            >

                <span class="wings-nfi-warehouse-code">
                    ' . $warehouseCode . '
                </span>

            </td>


            <td>
                ' . wingsFormatNfiDashboardQty(
                    $row["family_clothing_qty"]
                ) . '
            </td>


            <td>
                ' . wingsFormatNfiDashboardQty(
                    $row["kitchen_kit_qty"]
                ) . '
            </td>


            <td>
                ' . wingsFormatNfiDashboardQty(
                    $row["sleeping_kit_qty"]
                ) . '
            </td>


            <td>
                ' . wingsFormatNfiDashboardQty(
                    $row["hygiene_kit_qty"]
                ) . '
            </td>


            <td>
                ' . wingsFormatNfiDashboardQty(
                    $row["family_tents_qty"]
                ) . '
            </td>


            <td>
                ' . wingsFormatNfiDashboardQty(
                    $row["water_jerrican_qty"]
                ) . '
            </td>


            <td>
                ' . wingsFormatNfiDashboardQty(
                    $row["others_qty"]
                ) . '
            </td>

        </tr>
    ';
}


echo '

            </tbody>

        </table>

    </div>


    <div class="wings-nfi-tooltip">

        <strong class="wings-nfi-tooltip-code"></strong>

        <span class="wings-nfi-tooltip-name"></span>

    </div>

</div>



<script>

(function () {

    "use strict";

    var card =
        document.getElementById(
            "' . $nfiCardId . '"
        );

    if (!card) {
        return;
    }


    var tooltip =
        card.querySelector(
            ".wings-nfi-tooltip"
        );


    var targets =
        card.querySelectorAll(
            ".wings-nfi-tooltip-target"
        );


    if (
        !tooltip ||
        !targets.length
    ) {
        return;
    }


    var tooltipCode =
        tooltip.querySelector(
            ".wings-nfi-tooltip-code"
        );


    var tooltipName =
        tooltip.querySelector(
            ".wings-nfi-tooltip-name"
        );


    function positionTooltip(event) {

        var offset = 12;

        var left =
            event.clientX +
            offset;

        var top =
            event.clientY +
            offset;

        var width =
            tooltip.offsetWidth;

        var height =
            tooltip.offsetHeight;


        if (
            left + width >
            window.innerWidth - 8
        ) {

            left =
                event.clientX -
                width -
                offset;
        }


        if (
            top + height >
            window.innerHeight - 8
        ) {

            top =
                event.clientY -
                height -
                offset;
        }


        tooltip.style.left =
            left + "px";


        tooltip.style.top =
            top + "px";
    }


    function showTooltip(
        target,
        event
    ) {

        var code =
            target.getAttribute(
                "data-code"
            ) || "";


        var name =
            target.getAttribute(
                "data-name"
            ) || "";


        var type =
            target.getAttribute(
                "data-type"
            ) || "";


        tooltipCode.textContent =
            code;


        tooltipName.textContent =
            name +
            (
                type
                    ? " • " + type
                    : ""
            );


        tooltip.classList.add(
            "show"
        );


        positionTooltip(
            event
        );
    }


    function hideTooltip() {

        tooltip.classList.remove(
            "show"
        );
    }


    targets.forEach(
        function (target) {

            target.addEventListener(
                "mouseenter",
                function (event) {

                    showTooltip(
                        target,
                        event
                    );
                }
            );


            target.addEventListener(
                "mousemove",
                positionTooltip
            );


            target.addEventListener(
                "mouseleave",
                hideTooltip
            );

        }
    );

})();

</script>

';
		;
		
	}








	// code snippet - ranks
	function event_2622(  ) {
		
		$rs = DB::Query("
    SELECT id, sku, name, description, brand, parent_item_name, priority
    FROM item
    WHERE subcategory_id = 5
    ORDER BY priority ASC
");

echo '
<style>
#foodpack-sortable {
    list-style: none;
    padding: 0;
    max-width: 900px;
}
.foodpack-row {
    padding: 12px;
    margin-bottom: 8px;
    background: #fff;
    border: 1px solid #ddd;
    cursor: move;
    display: flex;
    gap: 15px;
    align-items: center;
}
.drag-handle {
    font-size: 20px;
    cursor: move;
}
.priority-badge {
    width: 40px;
    font-weight: bold;
}
.foodpack-info {
    flex: 1;
}
#save-ranking {
    margin-top: 15px;
}
</style>

<ul id="foodpack-sortable">
';

while ($data = $rs->fetchAssoc()) {
    echo '
    <li class="foodpack-row" data-id="'.$data["id"].'">
        <span class="drag-handle">☰</span>
        <span class="priority-badge">'.$data["priority"].'</span>
        <div class="foodpack-info">
            <b>'.$data["sku"].'</b> - '.$data["name"].'<br>
            <small>'.$data["description"].'</small>
        </div>
    </li>';
}

echo '
</ul>

<button id="save-ranking" class="btn btn-primary">
    Save Ranking
</button>

<div id="ranking-message" style="margin-top:10px;"></div>
';
		;
		
	}



	// code snippet - Storage Capacity
	function event_2628(  ) {
		
		

/* =========================================================
   WINGS DASHBOARD
   STORAGE CAPACITY
   NEW DASHBOARD DESIGN
   FFP / NFI / RTEF
   ========================================================= */


/* =========================================================
   1. LOAD STORAGE CAPACITY
   ========================================================= */

$sql = "
    SELECT
        stock_type,
        capacity_qty,
        current_stock_qty,
        utilization_percent,
        data_as_of

    FROM vw_dashboard_storage_capacity

    WHERE stock_type IN (
        'FFP',
        'RTEF',
        'NFI'
    )

    ORDER BY
        FIELD(
            stock_type,
            'FFP',
            'RTEF',
            'NFI'
        ),
        data_as_of DESC
";

$rs = DB::Query($sql);


/* =========================================================
   ERROR
   ========================================================= */

if (!$rs) {

    echo "
        <div style='
            padding:15px;
            color:#ee1c25;
            font-family:Arial, Helvetica, sans-serif;
            font-size:12px;
            font-weight:700;
        '>
            SQL error while loading storage capacity.
        </div>
    ";

    return;
}


/* =========================================================
   2. GET LATEST VALUE PER TYPE
   ========================================================= */

$items = array();

while ($data = $rs->fetchAssoc()) {

    $stockType = strtoupper(
        trim(
            (string)$data["stock_type"]
        )
    );

    /*
     * Query is ordered newest first.
     * Only retain the latest record
     * for each stock type.
     */
    if (!isset($items[$stockType])) {

        $percent = (float)$data["utilization_percent"];

        /*
         * Safety limits
         */
        if ($percent < 0) {
            $percent = 0;
        }

        if ($percent > 100) {
            $percent = 100;
        }

        $items[$stockType] = array(

            "stock_type" => $stockType,

            "capacity" =>
                isset($data["capacity_qty"])
                    ? (float)$data["capacity_qty"]
                    : 0,

            "current_stock" =>
                isset($data["current_stock_qty"])
                    ? (float)$data["current_stock_qty"]
                    : 0,

            "percent" => $percent,

            /*
             * conic-gradient degree
             */
            "degree" => $percent * 3.6
        );
    }
}


/* =========================================================
   3. DEFAULT VALUES
   ========================================================= */

$ffpPercent = isset($items["FFP"])
    ? $items["FFP"]["percent"]
    : 0;

$nfiPercent = isset($items["NFI"])
    ? $items["NFI"]["percent"]
    : 0;

$rtefPercent = isset($items["RTEF"])
    ? $items["RTEF"]["percent"]
    : 0;


$ffpDegree = isset($items["FFP"])
    ? $items["FFP"]["degree"]
    : 0;

$nfiDegree = isset($items["NFI"])
    ? $items["NFI"]["degree"]
    : 0;

$rtefDegree = isset($items["RTEF"])
    ? $items["RTEF"]["degree"]
    : 0;


/* =========================================================
   4. CSS-SAFE DECIMAL VALUES
   ========================================================= */

$ffpDegreeCss = number_format(
    $ffpDegree,
    2,
    ".",
    ""
);

$nfiDegreeCss = number_format(
    $nfiDegree,
    2,
    ".",
    ""
);

$rtefDegreeCss = number_format(
    $rtefDegree,
    2,
    ".",
    ""
);


/* =========================================================
   5. DISPLAY VALUES
   ========================================================= */

$ffpPercentText = number_format(
    $ffpPercent,
    0
);

$nfiPercentText = number_format(
    $nfiPercent,
    0
);

$rtefPercentText = number_format(
    $rtefPercent,
    0
);


/* =========================================================
   6. OUTPUT
   ========================================================= */

echo '

<style>

/* =========================================================
   WINGS STORAGE CAPACITY CARD
   FIGMA COMPACT DESIGN
   ========================================================= */


.wings-storage-card,
.wings-storage-card * {

    box-sizing:border-box;

}

.wings-storage-card {

    width:100% !important;

    height:140% !important;

    min-height:145px !important;

    position:relative;

    padding:
        10px
        12px;

    overflow:hidden !important;

    background:#ffffff;

    border-radius:10px;

    box-shadow:
        0 3px 10px rgba(0,0,0,.14);

    font-family:
        Arial,
        Helvetica,
        sans-serif;

        display:flex;

flex-direction:column;
}

/* TITLE */

.wings-storage-title {

    margin:0 0 5px 0 !important;

    padding:0 !important;

    color:#242424 !important;

    font-size:20px !important;

    font-weight:700 !important;

    line-height:22px !important;

    text-transform:uppercase !important;
}




/* DONUT ROW */
.wings-storage-donuts {

    display:grid;

    grid-template-columns:
        repeat(3, 1fr);

    width:100%;

    margin-top:10px;

    flex:1;

    align-items:start;

}


/* ITEM */

.wings-storage-item {


    display:flex;


    flex-direction:column;


    align-items:center;


}





/* LABEL */

.wings-storage-label {


    margin-bottom:5px;


    color:#222222;


    font-size:18px;


    font-weight:700;


    line-height:12px;


    text-transform:uppercase;

}





/* DONUT */
.wings-storage-donut {

    width:140px;

    height:140px;

    position:relative;

    display:flex;

    align-items:center;

    justify-content:center;

    border-radius:50%;
}





/* INNER WHITE */

.wings-storage-donut::before {


    content:"";


    position:absolute;


    inset:18px;


    background:#ffffff;


    border-radius:50%;

}





/* PERCENT */

.wings-storage-percent {


    position:relative;


    z-index:2;


    color:#555555;


    font-size:20px;


    font-weight:700;

}





/* LEGEND */

.wings-storage-legend {


    position:absolute;


    left:12px;


    bottom:7px;


    display:flex;


    flex-direction:column;


    gap:4px;

}





.wings-storage-legend-item {


    display:flex;


    align-items:center;


    gap:7px;


    color:#333333;


    font-size:10px;

}


/* =========================================================
   WINGS DASHBOARD - TOP CARDS EQUAL HEIGHT
   ========================================================= */

.wings-stockpile-card,
.wings-manage-warehouse-card {

    height:150px !important;

    min-height:150px !important;

    max-height:150px !important;

    box-sizing:border-box !important;
}
.wings-storage-card {

    height:220px !important;

    min-height:220px !important;

    max-height:220px !important;

    box-sizing:border-box !important;
}

.wings-storage-dot {


    width:10px;


    height:10px;


    border-radius:50%;

}



.wings-storage-dot.capacity {

    background:#ee1c25;

}



.wings-storage-dot.current {

    background:#4caf60;

}

</style>

<div class="wings-storage-card">


    <!-- ================================================
         TITLE
         ================================================ -->

    <div class="wings-storage-title">
        Storage Capacity
    </div>



    <!-- ================================================
         DONUTS
         ================================================ -->

    <div class="wings-storage-donuts">


        <!-- ============================================
             FFP
             ============================================ -->

        <div class="wings-storage-item">

            <div class="wings-storage-label">
                FFP
            </div>

            <div
                class="wings-storage-donut"

                style="
                    background:
                        conic-gradient(
                            #4caf60 0deg,
                            #4caf60 ' . $ffpDegreeCss . 'deg,
                            #ee1c25 ' . $ffpDegreeCss . 'deg,
                            #ee1c25 360deg
                        );
                "
            >

                <div class="wings-storage-percent">
                    ' . $ffpPercentText . '%
                </div>

            </div>

        </div>


<!-- RTEF -->

<div class="wings-storage-item">

    <div class="wings-storage-label">
        RTEF
    </div>

    <div
        class="wings-storage-donut"

        style="
            background:
                conic-gradient(
                    #4caf60 0deg,
                    #4caf60 ' . $rtefDegreeCss . 'deg,
                    #ee1c25 ' . $rtefDegreeCss . 'deg,
                    #ee1c25 360deg
                );
        "
    >

        <div class="wings-storage-percent">
            ' . $rtefPercentText . '%
        </div>

    </div>

</div>



<!-- NFI -->

<div class="wings-storage-item">

    <div class="wings-storage-label">
        NFI
    </div>

    <div
        class="wings-storage-donut"

        style="
            background:
                conic-gradient(
                    #4caf60 0deg,
                    #4caf60 ' . $nfiDegreeCss . 'deg,
                    #ee1c25 ' . $nfiDegreeCss . 'deg,
                    #ee1c25 360deg
                );
        "
    >

        <div class="wings-storage-percent">
            ' . $nfiPercentText . '%
        </div>

    </div>

</div>


    </div>



    <!-- ================================================
         LEGEND
         ================================================ -->

    <div class="wings-storage-legend">


        <div class="wings-storage-legend-item">

            <span
                class="
                    wings-storage-dot
                    capacity
                ">
            </span>

            <span>
                Storage Capacity
            </span>

        </div>


        <div class="wings-storage-legend-item">

            <span
                class="
                    wings-storage-dot
                    current
                ">
            </span>

            <span>
                Current Stocks
            </span>

        </div>


    </div>


</div>
';

		;
		
	}







	// code snippet - Snippet8
	function event_2642(  ) {
		
		global $pageObject;

dswdHistoryShow(
    "LOCATION_TYPE",
    $pageObject
);
		;
		
	}



	// code snippet - Snippet4
	function event_2648(  ) {
		
		global $pageObject;

dswdHistoryShow(
    "LOGISTICS_DRIVER_APP_ACCESS",
    $pageObject
);
		;
		
	}

	// code snippet - mapv6
	function event_63373(  ) {
		
		/* =========================================================
   WINGS FACILITY MAPPING
   COMBINED FILTER + GOOGLE MAP
   PHPRUNNER 11.3

   ONE CUSTOM CODE NODE ONLY

   FILTER DATA:
   warehouse.warehouse_type
   warehouse.region
   warehouse.province
   warehouse.city / warehouse.municipality

   MAP DATA:
   vw_warehouse_google_map_dashboard
   vw_trip_ticket_vehicle_map_dashboard

   IMPORTANT:
   DO NOT ADD <?php
   DO NOT ADD ?>
   ========================================================= */


/* =========================================================
   1. GOOGLE MAPS API KEY
   ========================================================= */

$googleApiKey = "";

$rsSettingTable = DB::Query(
    "SHOW TABLES LIKE 'system_setting'"
);

$hasSystemSettingTable =
    $rsSettingTable &&
    $rsSettingTable->fetchAssoc();


if ($hasSystemSettingTable) {

    $rsGoogleMapsSetting = DB::Query("

        SELECT
            setting_value

        FROM
            system_setting

        WHERE
            setting_group = 'MAP'

            AND
            setting_key = 'GOOGLE_MAPS_API_KEY'

            AND
            is_active = 1

        LIMIT 1

    ");


    if ($rsGoogleMapsSetting) {

        $googleMapsSetting =
            $rsGoogleMapsSetting->fetchAssoc();


        if (
            $googleMapsSetting &&
            isset($googleMapsSetting["setting_value"])
        ) {

            $googleApiKey =
                trim(
                    (string)$googleMapsSetting["setting_value"]
                );

        }

    }

}


/* =========================================================
   2. GOOGLE MAP ERROR
   ========================================================= */

if ($googleApiKey === "") {

    echo "

        <div style='
            margin:10px;
            padding:15px;
            border:1px solid #ee1c25;
            border-radius:6px;
            background:#fff5f5;
            color:#991b1b;
            font-family:Arial,Helvetica,sans-serif;
        '>

            <strong>
                Google Maps configuration error.
            </strong>

            <br><br>

            Configure:

            <br>

            setting_group = MAP

            <br>

            setting_key = GOOGLE_MAPS_API_KEY

        </div>

    ";

    return;

}


/* =========================================================
   3. PHP SAFE HELPERS
   ========================================================= */

$mapSafeFloat = function (
    $row,
    $key
) {

    return (
        isset($row[$key]) &&
        $row[$key] !== null &&
        $row[$key] !== ""
    )
        ? (float)$row[$key]
        : 0;

};


$mapSafeInt = function (
    $row,
    $key
) {

    return (
        isset($row[$key]) &&
        $row[$key] !== null &&
        $row[$key] !== ""
    )
        ? (int)$row[$key]
        : 0;

};


$mapSafeString = function (
    $row,
    $key
) {

    return (
        isset($row[$key]) &&
        $row[$key] !== null
    )
        ? trim((string)$row[$key])
        : "";

};


/* =========================================================
   4. FILTER DATA DIRECTLY FROM WAREHOUSE
   ========================================================= */

$warehouseFilterRows = array();


$rsWarehouseFilter = DB::Query("

    SELECT DISTINCT

        TRIM(warehouse_type)
            AS warehouse_type,

        TRIM(region)
            AS region,

        TRIM(province)
            AS province,

        COALESCE(

            NULLIF(
                TRIM(city),
                ''
            ),

            NULLIF(
                TRIM(municipality),
                ''
            )

        ) AS city_municipality

    FROM
        warehouse

    WHERE

        (
            inactive = 0
            OR inactive IS NULL
        )

        AND
        (
            warehouse_type IS NOT NULL
            OR region IS NOT NULL
            OR province IS NOT NULL
            OR city IS NOT NULL
            OR municipality IS NOT NULL
        )

    ORDER BY

        region,
        province,
        city_municipality,
        warehouse_type

");


if ($rsWarehouseFilter) {

    while (
        $row =
            $rsWarehouseFilter->fetchAssoc()
    ) {

        $warehouseFilterRows[] =
            array(

                "warehouse_type" =>
                    $mapSafeString(
                        $row,
                        "warehouse_type"
                    ),

                "region" =>
                    $mapSafeString(
                        $row,
                        "region"
                    ),

                "province" =>
                    $mapSafeString(
                        $row,
                        "province"
                    ),

                "city" =>
                    $mapSafeString(
                        $row,
                        "city_municipality"
                    )

            );

    }

}


/* =========================================================
   5. WAREHOUSE MAP DATA

   IMPORTANT FIX:
   The warehouse markers now come DIRECTLY from the
   warehouse master table.

   This means HUB / SPOKE / LAST_MILE icons can appear
   even when vw_warehouse_google_map_dashboard has no
   inventory/dashboard rows yet.

   LOCATION SOURCE:
   warehouse.lat
   warehouse.long

   OPTIONAL INVENTORY SOURCE:
   vw_warehouse_google_map_dashboard
   ========================================================= */

$warehouses = array();


/* =========================================================
   CHECK OPTIONAL DASHBOARD VIEW
   ========================================================= */

$warehouseViewCheck = DB::Query(
    "SHOW TABLES LIKE 'vw_warehouse_google_map_dashboard'"
);


$hasWarehouseView =
    $warehouseViewCheck &&
    $warehouseViewCheck->fetchAssoc();


/* =========================================================
   BUILD OPTIONAL INVENTORY JOIN
   ========================================================= */

$warehouseDashboardJoin =
    "";


$warehouseFfpSelect =
    "0 AS ffp_stock";


$warehouseNfiSelect =
    "0 AS nfi_stock";


$warehouseCapacityPercentSelect =
    "0 AS capacity_percent";


$warehouseCapacityStatusSelect =
    "'' AS capacity_status";


if ($hasWarehouseView) {


    /*
     * Aggregate by warehouse_id first so only ONE row is
     * joined to each physical warehouse marker.
     */

    $warehouseDashboardJoin = "

        LEFT JOIN
        (
            SELECT

                warehouse_id,

                MAX(
                    COALESCE(
                        ffp_stock,
                        0
                    )
                ) AS ffp_stock,

                MAX(
                    COALESCE(
                        nfi_stock,
                        0
                    )
                ) AS nfi_stock,

                MAX(
                    COALESCE(
                        capacity_percent,
                        0
                    )
                ) AS capacity_percent,

                MAX(
                    COALESCE(
                        capacity_status,
                        ''
                    )
                ) AS capacity_status

            FROM
                vw_warehouse_google_map_dashboard

            GROUP BY
                warehouse_id

        ) AS map_dashboard

            ON map_dashboard.warehouse_id =
               w.id

    ";


    $warehouseFfpSelect =
        "COALESCE(map_dashboard.ffp_stock, 0) AS ffp_stock";


    $warehouseNfiSelect =
        "COALESCE(map_dashboard.nfi_stock, 0) AS nfi_stock";


    $warehouseCapacityPercentSelect =
        "COALESCE(map_dashboard.capacity_percent, 0) AS capacity_percent";


    $warehouseCapacityStatusSelect =
        "COALESCE(map_dashboard.capacity_status, '') AS capacity_status";

}


/* =========================================================
   LOAD WAREHOUSE MARKERS DIRECTLY FROM WAREHOUSE MASTER
   ========================================================= */

$rsWarehouse = DB::Query("

    SELECT

        w.id
            AS warehouse_id,


        COALESCE(
            w.warehouse_code,
            ''
        ) AS warehouse_code,


        COALESCE(
            w.name,
            ''
        ) AS warehouse_name,


        COALESCE(
            w.warehouse_type,
            ''
        ) AS warehouse_type,


        COALESCE(
            w.region,
            ''
        ) AS region,


        COALESCE(
            w.province,
            ''
        ) AS province,


        COALESCE(

            NULLIF(
                TRIM(w.city),
                ''
            ),

            NULLIF(
                TRIM(w.municipality),
                ''
            ),

            ''

        ) AS city,


        COALESCE(
            w.complete_address,
            ''
        ) AS address,


        w.lat
            AS lat,


        w.`long`
            AS lng,


        ".$warehouseFfpSelect.",


        ".$warehouseNfiSelect.",


        COALESCE(
            w.capacity,
            0
        ) AS warehouse_capacity,


        ".$warehouseCapacityPercentSelect.",


        ".$warehouseCapacityStatusSelect."


    FROM

        warehouse AS w


        ".$warehouseDashboardJoin."


    WHERE

        (
            w.inactive = 0
            OR w.inactive IS NULL
        )


        AND
        w.lat IS NOT NULL


        AND
        w.`long` IS NOT NULL


        AND
        w.lat <> 0


        AND
        w.`long` <> 0


    ORDER BY

        w.warehouse_type,

        w.region,

        w.province,

        w.name

");


if ($rsWarehouse) {

    while (
        $row =
            $rsWarehouse->fetchAssoc()
    ) {


        $row["warehouse_id"] =
            $mapSafeInt(
                $row,
                "warehouse_id"
            );


        $row["lat"] =
            $mapSafeFloat(
                $row,
                "lat"
            );


        $row["lng"] =
            $mapSafeFloat(
                $row,
                "lng"
            );


        $row["ffp_stock"] =
            $mapSafeFloat(
                $row,
                "ffp_stock"
            );


        $row["nfi_stock"] =
            $mapSafeFloat(
                $row,
                "nfi_stock"
            );


        $row["warehouse_capacity"] =
            $mapSafeFloat(
                $row,
                "warehouse_capacity"
            );


        $row["capacity_percent"] =
            $mapSafeFloat(
                $row,
                "capacity_percent"
            );


        $row["warehouse_code"] =
            $mapSafeString(
                $row,
                "warehouse_code"
            );


        $row["warehouse_name"] =
            $mapSafeString(
                $row,
                "warehouse_name"
            );


        $row["warehouse_type"] =
            $mapSafeString(
                $row,
                "warehouse_type"
            );


        $row["region"] =
            $mapSafeString(
                $row,
                "region"
            );


        $row["province"] =
            $mapSafeString(
                $row,
                "province"
            );


        $row["city"] =
            $mapSafeString(
                $row,
                "city"
            );


        $row["address"] =
            $mapSafeString(
                $row,
                "address"
            );


        $row["capacity_status"] =
            $mapSafeString(
                $row,
                "capacity_status"
            );


        $warehouses[] =
            $row;

    }

}


/* =========================================================
   MAP DIAGNOSTIC
   ========================================================= */

if (count($warehouses) === 0) {

    $facilityServerIssues[] =
        "No active warehouse records with lat/long coordinates were found in warehouse.";

}



/* =========================================================
   6. VEHICLE MAP DATA
   ========================================================= */

$vehicles = array();


$vehicleViewCheck = DB::Query(
    "SHOW TABLES LIKE 'vw_trip_ticket_vehicle_map_dashboard'"
);


$hasVehicleView =
    $vehicleViewCheck &&
    $vehicleViewCheck->fetchAssoc();


if ($hasVehicleView) {

    $rsVehicle = DB::Query("

        SELECT

            map_vehicle.*,


            COALESCE(
                NULLIF(
                    TRIM(origin_warehouse.region),
                    ''
                ),
                ''
            ) AS origin_region,


            COALESCE(
                NULLIF(
                    TRIM(destination_warehouse.region),
                    ''
                ),
                ''
            ) AS destination_region


        FROM

            vw_trip_ticket_vehicle_map_dashboard
                AS map_vehicle


        LEFT JOIN

            warehouse AS origin_warehouse

            ON origin_warehouse.id =
               map_vehicle.origin_warehouse_id


        LEFT JOIN

            warehouse AS destination_warehouse

            ON destination_warehouse.id =
               map_vehicle.destination_warehouse_id


        WHERE

            map_vehicle.current_lat IS NOT NULL

            AND
            map_vehicle.current_lng IS NOT NULL


        ORDER BY

            map_vehicle.trip_ticket_id DESC

    ");


    if ($rsVehicle) {

        while (
            $row =
                $rsVehicle->fetchAssoc()
        ) {

            $row["trip_ticket_id"] =
                $mapSafeInt(
                    $row,
                    "trip_ticket_id"
                );


            $row["vehicle_id"] =
                $mapSafeInt(
                    $row,
                    "vehicle_id"
                );


            $row["current_lat"] =
                $mapSafeFloat(
                    $row,
                    "current_lat"
                );


            $row["current_lng"] =
                $mapSafeFloat(
                    $row,
                    "current_lng"
                );


            $stringFields =
                array(

                    "trip_ticket_no",
                    "vehicle_code",
                    "plate_no",
                    "vehicle_type",
                    "transporter_type",
                    "vehicle_group",
                    "driver_name",
                    "driver_contact_no",

                    "origin_region",
                    "origin_province",
                    "origin_city",

                    "destination_region",
                    "destination_province",
                    "destination_city",

                    "trip_status",
                    "delivery_status",
                    "last_gps_datetime"

                );


            foreach (
                $stringFields as $field
            ) {

                $row[$field] =
                    $mapSafeString(
                        $row,
                        $field
                    );

            }


            $vehicles[] =
                $row;

        }

    }

}


/* =========================================================
   7. VEHICLE FILTER GROUPS
   ========================================================= */

$vehicleGroups =
    array();


foreach (
    $vehicles as $vehicle
) {

    $group =
        isset($vehicle["vehicle_group"])
            ? trim(
                (string)$vehicle["vehicle_group"]
            )
            : "";


    if (
        $group !== "" &&
        !in_array(
            $group,
            $vehicleGroups,
            true
        )
    ) {

        $vehicleGroups[] =
            $group;

    }

}


sort(
    $vehicleGroups
);


/* =========================================================
   8. JSON
   ========================================================= */

$warehouseFilterJson =
    json_encode(
        $warehouseFilterRows,
        JSON_HEX_TAG |
        JSON_HEX_APOS |
        JSON_HEX_QUOT |
        JSON_HEX_AMP
    );


$warehouseJson =
    json_encode(
        $warehouses,
        JSON_HEX_TAG |
        JSON_HEX_APOS |
        JSON_HEX_QUOT |
        JSON_HEX_AMP
    );


$vehicleJson =
    json_encode(
        $vehicles,
        JSON_HEX_TAG |
        JSON_HEX_APOS |
        JSON_HEX_QUOT |
        JSON_HEX_AMP
    );


$vehicleGroupJson =
    json_encode(
        $vehicleGroups,
        JSON_HEX_TAG |
        JSON_HEX_APOS |
        JSON_HEX_QUOT |
        JSON_HEX_AMP
    );


/* =========================================================
   9. HTML + CSS
   ========================================================= */

echo <<<'HTML'

<style>

/* =========================================================
   WHOLE COMPONENT
   ========================================================= */

#wingsFacilityMappingCombined {

    --wings-blue:#2e3192;
    --wings-red:#ee1c25;
    --wings-yellow:#fef200;

    width:100% !important;
    min-width:0 !important;

    margin:0 !important;
    padding:0 !important;

    box-sizing:border-box !important;

    font-family:
        Arial,
        Helvetica,
        sans-serif;

}


/* =========================================================
   FILTER BAR
   ========================================================= */

#wingsFacilityFilters {

    width:100% !important;

    margin:
        0
        0
        7px
        0 !important;

    padding:0 !important;

    box-sizing:border-box !important;

}


#wingsFacilityFilters
.wings-filter-bar {

    width:100% !important;

    display:grid !important;

    grid-template-columns:
        repeat(
            5,
            minmax(0,1fr)
        ) !important;

    gap:6px !important;

    padding:7px !important;

    margin:0 !important;

    border-radius:6px !important;

    background:#2e3192 !important;

    box-sizing:border-box !important;

}


#wingsFacilityFilters
.wings-filter-box {

    min-width:0 !important;

    height:45px !important;

    padding:
        5px
        9px
        3px
        9px !important;

    border-radius:4px !important;

    background:#ffffff !important;

    box-sizing:border-box !important;

}


#wingsFacilityFilters
.wings-filter-label {

    display:block !important;

    margin:
        0
        0
        1px
        0 !important;

    padding:0 !important;

    overflow:hidden !important;

    color:#707070 !important;

    font-size:8px !important;

    font-weight:400 !important;

    line-height:11px !important;

    white-space:nowrap !important;

    text-overflow:ellipsis !important;

}


#wingsFacilityFilters
.wings-filter-select {

    width:100% !important;
    min-width:0 !important;

    height:24px !important;

    margin:0 !important;

    padding:
        0
        20px
        0
        0 !important;

    border:0 !important;

    outline:0 !important;

    background:transparent !important;

    color:#222222 !important;

    font-family:
        Arial,
        Helvetica,
        sans-serif !important;

    font-size:11px !important;

    font-weight:700 !important;

    line-height:24px !important;

    box-shadow:none !important;

    cursor:pointer !important;

}


/* =========================================================
   MAP ROOT
   ========================================================= */

#wingsFacilityMap {

    position:relative;

    width:100% !important;

    min-width:0 !important;

    margin:0 !important;
    padding:0 !important;

    box-sizing:border-box !important;

}


/* =========================================================
   MAP STAGE
   ========================================================= */

#wingsFacilityMapStage {

    position:relative !important;

    display:block !important;

    width:100% !important;

    height:680px !important;
    min-height:680px !important;

    margin:0 !important;
    padding:0 !important;

    overflow:hidden !important;

    border-radius:7px !important;

    background:#70cee0 !important;

    box-sizing:border-box !important;

}


/* =========================================================
   GOOGLE MAP
   ========================================================= */

#facilityGoogleMap {

    position:absolute !important;

    inset:0 !important;

    display:block !important;

    width:100% !important;
    height:100% !important;

    min-height:680px !important;

}


/* =========================================================
   MAP TABS
   ========================================================= */

#wingsFacilityMap
.wings-map-tabs {

    position:absolute;

    top:8px;
    left:50%;

    z-index:100;

    display:flex;

    align-items:center;
    justify-content:center;

    gap:4px;

    transform:
        translateX(-50%);

    white-space:nowrap;

}


#wingsFacilityMap
.wings-map-tab {

    height:31px;

    min-width:91px;

    display:inline-flex;

    align-items:center;
    justify-content:center;

    gap:6px;

    padding:
        0
        12px;

    border:
        1px solid
        #d8dae1;

    border-radius:4px;

    outline:0;

    background:
        rgba(
            255,
            255,
            255,
            .97
        );

    color:#555555;

    font-family:
        Arial,
        Helvetica,
        sans-serif;

    font-size:10px;

    font-weight:400;

    cursor:pointer;

    box-shadow:
        0
        1px
        4px
        rgba(
            0,
            0,
            0,
            .18
        );

}


#wingsFacilityMap
.wings-map-tab.active {

    border-color:#2e3192 !important;

    background:#2e3192 !important;

    color:#ffffff !important;

}


#wingsFacilityMap
.wings-map-tab-icon {

    display:inline-flex;

    align-items:center;
    justify-content:center;

    width:17px;
    height:17px;

    font-size:13px;

}


/* =========================================================
   INFO WINDOW
   ========================================================= */

.wings-map-info {

    min-width:210px;

    max-width:270px;

    padding:3px;

    color:#333333;

    font-family:
        Arial,
        Helvetica,
        sans-serif;

    font-size:10px;

    line-height:1.55;

}


.wings-map-info-title {

    margin-bottom:5px;

    color:#2e3192;

    font-size:12px;

    font-weight:800;

}


.wings-map-info-badge {

    display:inline-block;

    margin-bottom:6px;

    padding:
        3px
        7px;

    border-radius:3px;

    background:#2e3192;

    color:#ffffff;

    font-size:8px;

    font-weight:700;

}


/* =========================================================
   NO DATA
   ========================================================= */

#wingsFacilityMap
.wings-map-no-data {

    position:absolute;

    top:50%;
    left:50%;

    z-index:80;

    display:none;

    padding:
        10px
        15px;

    border-radius:5px;

    background:
        rgba(
            255,
            255,
            255,
            .95
        );

    color:#666666;

    font-size:10px;

    transform:
        translate(
            -50%,
            -50%
        );

}


/* =========================================================
   RESPONSIVE
   ========================================================= */

@media (max-width:900px) {

    #wingsFacilityFilters
    .wings-filter-bar {

        grid-template-columns:
            repeat(
                3,
                minmax(0,1fr)
            ) !important;

    }

}


@media (max-width:650px) {

    #wingsFacilityFilters
    .wings-filter-bar {

        grid-template-columns:
            repeat(
                2,
                minmax(0,1fr)
            ) !important;

    }


    #wingsFacilityMapStage {

        height:560px !important;
        min-height:560px !important;

    }


    #facilityGoogleMap {

        min-height:560px !important;

    }


    #wingsFacilityMap
    .wings-map-tabs {

        width:
            calc(
                100% - 14px
            );

    }


    #wingsFacilityMap
    .wings-map-tab {

        flex:1;

        min-width:0;

        padding:
            0
            5px;

        font-size:9px;

    }

}

</style>


<div id="wingsFacilityMappingCombined">


    <!-- ==================================================
         FILTERS
         ================================================== -->

    <div id="wingsFacilityFilters">

        <div class="wings-filter-bar">


            <div class="wings-filter-box">

                <label
                    class="wings-filter-label"
                    for="facilityWarehouseType">

                    Warehouse Type

                </label>

                <select
                    id="facilityWarehouseType"
                    class="wings-filter-select">

                    <option value="">
                        All
                    </option>

                </select>

            </div>


            <div class="wings-filter-box">

                <label
                    class="wings-filter-label"
                    for="facilityRegion">

                    Region

                </label>

                <select
                    id="facilityRegion"
                    class="wings-filter-select">

                    <option value="">
                        All
                    </option>

                </select>

            </div>


            <div class="wings-filter-box">

                <label
                    class="wings-filter-label"
                    for="facilityProvince">

                    Province

                </label>

                <select
                    id="facilityProvince"
                    class="wings-filter-select">

                    <option value="">
                        All
                    </option>

                </select>

            </div>


            <div class="wings-filter-box">

                <label
                    class="wings-filter-label"
                    for="facilityCity">

                    City/Municipality

                </label>

                <select
                    id="facilityCity"
                    class="wings-filter-select">

                    <option value="">
                        All
                    </option>

                </select>

            </div>


            <div class="wings-filter-box">

                <label
                    class="wings-filter-label"
                    for="facilityVehicle">

                    Vehicles

                </label>

                <select
                    id="facilityVehicle"
                    class="wings-filter-select">

                    <option value="">
                        All
                    </option>

                </select>

            </div>


        </div>

    </div>


    <!-- ==================================================
         MAP
         ================================================== -->

    <div id="wingsFacilityMap">

        <div id="wingsFacilityMapStage">


            <div id="facilityGoogleMap"></div>


            <div class="wings-map-tabs">


                <button
                    type="button"
                    id="facilityTabOverview"
                    class="wings-map-tab active">

                    <span class="wings-map-tab-icon">
                        ▣
                    </span>

                    Overview

                </button>


                <button
                    type="button"
                    id="facilityTabWarehouse"
                    class="wings-map-tab">

                    <span class="wings-map-tab-icon">
                        ⌂
                    </span>

                    Warehouse

                </button>


                <button
                    type="button"
                    id="facilityTabVehicles"
                    class="wings-map-tab">

                    <span class="wings-map-tab-icon">
                        ▱
                    </span>

                    Vehicles

                </button>


            </div>


            <div
                id="facilityMapNoData"
                class="wings-map-no-data">

                No map records found.

            </div>


        </div>

    </div>


</div>

HTML;


/* =========================================================
   10. JAVASCRIPT DATA
   ========================================================= */

echo '

<script>

window.facilityWarehouseFilterRows =
' . $warehouseFilterJson . ';

window.facilityWarehouseData =
' . $warehouseJson . ';

window.facilityVehicleData =
' . $vehicleJson . ';

window.facilityVehicleGroups =
' . $vehicleGroupJson . ';

</script>

';


/* =========================================================
   11. MAP + FILTER JAVASCRIPT
   ========================================================= */

echo <<<'HTML'

<script>

"use strict";


/* =========================================================
   GLOBALS
   ========================================================= */

var facilityMap =
    null;


var facilityInfoWindow =
    null;


var facilityCurrentMode =
    "overview";


var facilityWarehouseMarkers =
    {};


var facilityVehicleMarkers =
    {};


var facilityMarkerTimer =
    null;


var FACILITY_PH_CENTER = {

    lat:12.8797,

    lng:121.7740

};


var FACILITY_PH_ZOOM =
    6;


var FACILITY_ICON_BASE =
    "images/";


var FACILITY_WAREHOUSE_ICONS = {

    HUB:
        "Warehouse-Green.png",

    SPOKE:
        "Warehouse-Yellow.png",

    LAST_MILE:
        "Warehouse-Red.png"

};


var FACILITY_VEHICLE_COLORS = {

    DSWD:
        "#ee1c25",

    TPL:
        "#2e3192",

    PARTNER:
        "#fef200",

    OTHER:
        "#fef200"

};


/* =========================================================
   INITIALIZE MAP
   ========================================================= */

window.initFacilityMapDashboard =
function () {


    var mapElement =
        document.getElementById(
            "facilityGoogleMap"
        );


    if (!mapElement) {

        console.error(
            "Facility map container was not found."
        );

        return;

    }


    if (
        mapElement.dataset
            .facilityInitialized === "1"
    ) {

        return;

    }


    mapElement.dataset
        .facilityInitialized =
            "1";


    /*
     * FILTERS ARE INITIALIZED INSIDE
     * THE SAME NODE NOW.
     */

    initializeFacilityFilters();


    facilityMap =
        new google.maps.Map(

            mapElement,

            {

                center:
                    FACILITY_PH_CENTER,

                zoom:
                    FACILITY_PH_ZOOM,

                minZoom:
                    5,

                maxZoom:
                    19,

                mapTypeId:
                    google.maps.MapTypeId.ROADMAP,

                mapTypeControl:
                    false,

                streetViewControl:
                    false,

                fullscreenControl:
                    false,

                zoomControl:
                    false,

                clickableIcons:
                    false,

                gestureHandling:
                    "greedy",

                styles:[

                    {

                        featureType:
                            "poi.business",

                        stylers:[

                            {
                                visibility:
                                    "off"
                            }

                        ]

                    },

                    {

                        featureType:
                            "transit",

                        stylers:[

                            {
                                visibility:
                                    "off"
                            }

                        ]

                    }

                ]

            }

        );


    facilityInfoWindow =
        new google.maps.InfoWindow();


    createFacilityWarehouseMarkers();


    createFacilityVehicleMarkers();


    bindFacilityTabs();


    bindFacilityFilterEvents();


    setFacilityMode(
        "overview",
        false
    );


    resetFacilityPhilippinesView();


    facilityMap.addListener(

        "zoom_changed",

        function () {


            clearTimeout(
                facilityMarkerTimer
            );


            facilityMarkerTimer =
                setTimeout(

                    function () {

                        updateFacilityMarkerPresentation();

                    },

                    50

                );

        }

    );


    setTimeout(

        function () {


            google.maps.event.trigger(
                facilityMap,
                "resize"
            );


            resetFacilityPhilippinesView();


            updateFacilityMarkerPresentation();

        },

        250

    );

};


/* =========================================================
   INITIALIZE FILTER OPTIONS
   ========================================================= */

function initializeFacilityFilters() {


    var type =
        document.getElementById(
            "facilityWarehouseType"
        );


    var region =
        document.getElementById(
            "facilityRegion"
        );


    var province =
        document.getElementById(
            "facilityProvince"
        );


    var city =
        document.getElementById(
            "facilityCity"
        );


    var vehicle =
        document.getElementById(
            "facilityVehicle"
        );


    if (
        !type ||
        !region ||
        !province ||
        !city ||
        !vehicle
    ) {

        return;

    }


    populateFacilitySelect(

        type,

        facilityUniqueValues(

            facilityWarehouseFilterRows,

            "warehouse_type"

        ),

        false

    );


    populateFacilitySelect(

        region,

        facilityUniqueValues(

            facilityWarehouseFilterRows,

            "region"

        ),

        false

    );


    populateFacilitySelect(

        province,

        facilityUniqueValues(

            facilityWarehouseFilterRows,

            "province"

        ),

        false

    );


    populateFacilitySelect(

        city,

        facilityUniqueValues(

            facilityWarehouseFilterRows,

            "city"

        ),

        false

    );


    populateFacilitySelect(

        vehicle,

        facilityVehicleGroups,

        false

    );

}


/* =========================================================
   UNIQUE VALUES
   ========================================================= */

function facilityUniqueValues(
    rows,
    field
) {


    var values =
        {};


    rows.forEach(

        function (row) {


            var value =
                facilityText(
                    row[field]
                ).trim();


            if (value !== "") {

                values[value] =
                    true;

            }

        }

    );


    return Object
        .keys(values)
        .sort();

}


/* =========================================================
   POPULATE SELECT
   ========================================================= */

function populateFacilitySelect(
    select,
    values,
    preserve
) {


    if (!select) {

        return;

    }


    var previous =
        preserve
            ? select.value
            : "";


    select.innerHTML =
        "<option value=''>All</option>";


    values.forEach(

        function (value) {


            var option =
                document.createElement(
                    "option"
                );


            option.value =
                value;


            option.textContent =
                value;


            select.appendChild(
                option
            );

        }

    );


    if (
        previous &&
        values.indexOf(
            previous
        ) >= 0
    ) {

        select.value =
            previous;

    } else {

        select.value =
            "";

    }

}


/* =========================================================
   BIND FILTER EVENTS
   ========================================================= */

function bindFacilityFilterEvents() {


    var type =
        document.getElementById(
            "facilityWarehouseType"
        );


    var region =
        document.getElementById(
            "facilityRegion"
        );


    var province =
        document.getElementById(
            "facilityProvince"
        );


    var city =
        document.getElementById(
            "facilityCity"
        );


    var vehicle =
        document.getElementById(
            "facilityVehicle"
        );


    /* =====================================================
       WAREHOUSE TYPE
       ===================================================== */

    type.addEventListener(

        "change",

        function () {


            /*
             * Warehouse filter selected:
             * remove vehicle-specific filter.
             */

            if (
                type.value !== ""
            ) {

                vehicle.value =
                    "";


                /*
                 * Automatically show warehouse mode.
                 */

                setFacilityMode(
                    "warehouse",
                    false
                );

            }


            facilityFilterChanged();

        }

    );


    /* =====================================================
       REGION
       ===================================================== */

    region.addEventListener(

        "change",

        function () {


            refreshFacilityProvince();


            refreshFacilityCity();


            facilityFilterChanged();

        }

    );


    /* =====================================================
       PROVINCE
       ===================================================== */

    province.addEventListener(

        "change",

        function () {


            refreshFacilityCity();


            facilityFilterChanged();

        }

    );


    /* =====================================================
       CITY
       ===================================================== */

    city.addEventListener(

        "change",

        function () {


            facilityFilterChanged();

        }

    );


    /* =====================================================
       VEHICLE
       ===================================================== */

    vehicle.addEventListener(

        "change",

        function () {


            if (
                vehicle.value !== ""
            ) {

                type.value =
                    "";


                setFacilityMode(
                    "vehicles",
                    false
                );

            }


            facilityFilterChanged();

        }

    );

}


/* =========================================================
   REFRESH PROVINCES
   ========================================================= */

function refreshFacilityProvince() {


    var region =
        getFacilityElementValue(
            "facilityRegion"
        );


    var province =
        document.getElementById(
            "facilityProvince"
        );


    var filteredRows =
        facilityWarehouseFilterRows.filter(

            function (row) {


                if (
                    region &&
                    facilityNormalizeText(
                        row.region
                    )
                    !==
                    facilityNormalizeText(
                        region
                    )
                ) {

                    return false;

                }


                return true;

            }

        );


    populateFacilitySelect(

        province,

        facilityUniqueValues(

            filteredRows,

            "province"

        ),

        false

    );

}


/* =========================================================
   REFRESH CITY / MUNICIPALITY
   ========================================================= */

function refreshFacilityCity() {


    var region =
        getFacilityElementValue(
            "facilityRegion"
        );


    var province =
        getFacilityElementValue(
            "facilityProvince"
        );


    var city =
        document.getElementById(
            "facilityCity"
        );


    var filteredRows =
        facilityWarehouseFilterRows.filter(

            function (row) {


                if (
                    region &&
                    facilityNormalizeText(
                        row.region
                    )
                    !==
                    facilityNormalizeText(
                        region
                    )
                ) {

                    return false;

                }


                if (
                    province &&
                    facilityNormalizeText(
                        row.province
                    )
                    !==
                    facilityNormalizeText(
                        province
                    )
                ) {

                    return false;

                }


                return true;

            }

        );


    populateFacilitySelect(

        city,

        facilityUniqueValues(

            filteredRows,

            "city"

        ),

        false

    );

}


/* =========================================================
   GET FILTER VALUE
   ========================================================= */

function getFacilityElementValue(
    id
) {


    var element =
        document.getElementById(
            id
        );


    return element
        ? element.value
        : "";

}


/* =========================================================
   GET ALL FILTERS
   ========================================================= */

function getFacilityFilters() {


    return {

        warehouseType:
            getFacilityElementValue(
                "facilityWarehouseType"
            ),

        region:
            getFacilityElementValue(
                "facilityRegion"
            ),

        province:
            getFacilityElementValue(
                "facilityProvince"
            ),

        city:
            getFacilityElementValue(
                "facilityCity"
            ),

        vehicle:
            getFacilityElementValue(
                "facilityVehicle"
            )

    };

}


/* =========================================================
   HAS FILTER
   ========================================================= */

function hasFacilityFilters() {


    var filter =
        getFacilityFilters();


    return Boolean(

        filter.warehouseType ||

        filter.region ||

        filter.province ||

        filter.city ||

        filter.vehicle

    );

}


/* =========================================================
   FILTER CHANGE
   ========================================================= */

function facilityFilterChanged() {


    if (
        facilityInfoWindow
    ) {

        facilityInfoWindow.close();

    }


    applyFacilityVisibility();


    updateFacilityMarkerPresentation();


    if (
        !hasFacilityFilters()
    ) {


        if (
            facilityCurrentMode ===
            "overview"
        ) {

            resetFacilityPhilippinesView();

        } else {

            fitFacilityVisibleMarkers();

        }


        return;

    }


    fitFacilityVisibleMarkers();

}


/* =========================================================
   WAREHOUSE PASSES FILTER
   ========================================================= */

function warehousePassesFacilityFilter(
    warehouse
) {


    var filter =
        getFacilityFilters();


    /* WAREHOUSE TYPE */

    if (
        filter.warehouseType &&
        normalizeFacilityWarehouseType(
            warehouse.warehouse_type
        )
        !==
        normalizeFacilityWarehouseType(
            filter.warehouseType
        )
    ) {

        return false;

    }


    /* REGION */

    if (
        filter.region &&
        facilityNormalizeText(
            warehouse.region
        )
        !==
        facilityNormalizeText(
            filter.region
        )
    ) {

        return false;

    }


    /* PROVINCE */

    if (
        filter.province &&
        facilityNormalizeText(
            warehouse.province
        )
        !==
        facilityNormalizeText(
            filter.province
        )
    ) {

        return false;

    }


    /* CITY / MUNICIPALITY */

    if (
        filter.city &&
        facilityNormalizeText(
            warehouse.city
        )
        !==
        facilityNormalizeText(
            filter.city
        )
    ) {

        return false;

    }


    return true;

}


/* =========================================================
   VEHICLE PASSES FILTER
   ========================================================= */

function vehiclePassesFacilityFilter(
    vehicle
) {


    var filter =
        getFacilityFilters();


    if (
        filter.vehicle &&
        facilityNormalizeText(
            vehicle.vehicle_group
        )
        !==
        facilityNormalizeText(
            filter.vehicle
        )
    ) {

        return false;

    }


    if (filter.region) {

        if (
            facilityNormalizeText(
                vehicle.origin_region
            )
            !==
            facilityNormalizeText(
                filter.region
            )

            &&

            facilityNormalizeText(
                vehicle.destination_region
            )
            !==
            facilityNormalizeText(
                filter.region
            )
        ) {

            return false;

        }

    }


    if (filter.province) {

        if (
            facilityNormalizeText(
                vehicle.origin_province
            )
            !==
            facilityNormalizeText(
                filter.province
            )

            &&

            facilityNormalizeText(
                vehicle.destination_province
            )
            !==
            facilityNormalizeText(
                filter.province
            )
        ) {

            return false;

        }

    }


    if (filter.city) {

        if (
            facilityNormalizeText(
                vehicle.origin_city
            )
            !==
            facilityNormalizeText(
                filter.city
            )

            &&

            facilityNormalizeText(
                vehicle.destination_city
            )
            !==
            facilityNormalizeText(
                filter.city
            )
        ) {

            return false;

        }

    }


    return true;

}


/* =========================================================
   BIND MAP TABS
   ========================================================= */

function bindFacilityTabs() {


    document
        .getElementById(
            "facilityTabOverview"
        )
        .addEventListener(

            "click",

            function () {

                setFacilityMode(
                    "overview",
                    true
                );

            }

        );


    document
        .getElementById(
            "facilityTabWarehouse"
        )
        .addEventListener(

            "click",

            function () {

                setFacilityMode(
                    "warehouse",
                    true
                );

            }

        );


    document
        .getElementById(
            "facilityTabVehicles"
        )
        .addEventListener(

            "click",

            function () {

                setFacilityMode(
                    "vehicles",
                    true
                );

            }

        );

}


/* =========================================================
   SET MAP MODE
   ========================================================= */

function setFacilityMode(
    mode,
    moveMap
) {


    facilityCurrentMode =
        mode;


    document
        .querySelectorAll(
            "#wingsFacilityMap .wings-map-tab"
        )
        .forEach(

            function (button) {

                button.classList.remove(
                    "active"
                );

            }

        );


    var activeButton =
        null;


    if (
        mode === "overview"
    ) {

        activeButton =
            document.getElementById(
                "facilityTabOverview"
            );

    }


    if (
        mode === "warehouse"
    ) {

        activeButton =
            document.getElementById(
                "facilityTabWarehouse"
            );

    }


    if (
        mode === "vehicles"
    ) {

        activeButton =
            document.getElementById(
                "facilityTabVehicles"
            );

    }


    if (activeButton) {

        activeButton.classList.add(
            "active"
        );

    }


    if (
        facilityInfoWindow
    ) {

        facilityInfoWindow.close();

    }


    applyFacilityVisibility();


    updateFacilityMarkerPresentation();


    if (
        moveMap === false
    ) {

        return;

    }


    if (
        mode === "overview" &&
        !hasFacilityFilters()
    ) {

        resetFacilityPhilippinesView();

        return;

    }


    fitFacilityVisibleMarkers();

}


/* =========================================================
   CREATE WAREHOUSE MARKERS
   ========================================================= */

function createFacilityWarehouseMarkers() {


    facilityWarehouseData.forEach(

        function (warehouse) {


            if (
                !facilityValidCoordinate(
                    warehouse.lat
                )
                ||
                !facilityValidCoordinate(
                    warehouse.lng
                )
            ) {

                return;

            }


            var marker =
                new google.maps.Marker({

                    map:
                        facilityMap,

                    position:{

                        lat:
                            parseFloat(
                                warehouse.lat
                            ),

                        lng:
                            parseFloat(
                                warehouse.lng
                            )

                    },

                    title:
                        facilityText(
                            warehouse.warehouse_name
                        ),

                    icon:
                        getFacilityWarehouseIcon(
                            warehouse.warehouse_type
                        ),

                    optimized:
                        true

                });


            marker.addListener(

                "click",

                function () {

                    showFacilityWarehouseInfo(
                        warehouse,
                        marker
                    );

                }

            );


            facilityWarehouseMarkers[
                warehouse.warehouse_id
            ] =
                marker;

        }

    );

}


/* =========================================================
   CREATE VEHICLE MARKERS
   ========================================================= */

function createFacilityVehicleMarkers() {


    facilityVehicleData.forEach(

        function (vehicle) {


            if (
                !facilityValidCoordinate(
                    vehicle.current_lat
                )
                ||
                !facilityValidCoordinate(
                    vehicle.current_lng
                )
            ) {

                return;

            }


            var marker =
                new google.maps.Marker({

                    map:
                        facilityMap,

                    position:{

                        lat:
                            parseFloat(
                                vehicle.current_lat
                            ),

                        lng:
                            parseFloat(
                                vehicle.current_lng
                            )

                    },

                    title:
                        facilityText(
                            vehicle.plate_no ||
                            vehicle.vehicle_code
                        ),

                    icon:
                        getFacilityVehicleIcon(
                            vehicle.vehicle_group,
                            vehicle.transporter_type
                        ),

                    optimized:
                        true

                });


            marker.addListener(

                "click",

                function () {

                    showFacilityVehicleInfo(
                        vehicle,
                        marker
                    );

                }

            );


            facilityVehicleMarkers[
                vehicle.trip_ticket_id
            ] =
                marker;

        }

    );

}


/* =========================================================
   APPLY MARKER VISIBILITY
   ========================================================= */

function applyFacilityVisibility() {


    var totalVisible =
        0;


    var filter =
        getFacilityFilters();


    var warehouseTypeSelected =
        Boolean(
            filter.warehouseType
        );


    var vehicleSelected =
        Boolean(
            filter.vehicle
        );


    /* =====================================================
       WAREHOUSES
       ===================================================== */

    Object.keys(
        facilityWarehouseMarkers
    )
    .forEach(

        function (id) {


            var warehouse =
                facilityWarehouseData.find(

                    function (row) {

                        return (
                            parseInt(
                                row.warehouse_id,
                                10
                            )
                            ===
                            parseInt(
                                id,
                                10
                            )
                        );

                    }

                );


            if (!warehouse) {

                return;

            }


            var allowedByMode =
                (
                    facilityCurrentMode ===
                        "overview"
                )
                ||
                (
                    facilityCurrentMode ===
                        "warehouse"
                );


            /*
             * A specific Vehicle filter means
             * show vehicle markers only.
             */

            if (
                vehicleSelected
            ) {

                allowedByMode =
                    false;

            }


            var visible =
                allowedByMode
                &&
                warehousePassesFacilityFilter(
                    warehouse
                );


            facilityWarehouseMarkers[
                id
            ].setVisible(
                visible
            );


            if (visible) {

                totalVisible++;

            }

        }

    );


    /* =====================================================
       VEHICLES
       ===================================================== */

    Object.keys(
        facilityVehicleMarkers
    )
    .forEach(

        function (id) {


            var vehicle =
                facilityVehicleData.find(

                    function (row) {

                        return (
                            parseInt(
                                row.trip_ticket_id,
                                10
                            )
                            ===
                            parseInt(
                                id,
                                10
                            )
                        );

                    }

                );


            if (!vehicle) {

                return;

            }


            var allowedByMode =
                (
                    facilityCurrentMode ===
                        "overview"
                )
                ||
                (
                    facilityCurrentMode ===
                        "vehicles"
                );


            /*
             * A Warehouse Type filter means
             * show warehouses only.
             */

            if (
                warehouseTypeSelected
            ) {

                allowedByMode =
                    false;

            }


            var visible =
                allowedByMode
                &&
                vehiclePassesFacilityFilter(
                    vehicle
                );


            facilityVehicleMarkers[
                id
            ].setVisible(
                visible
            );


            if (visible) {

                totalVisible++;

            }

        }

    );


    var noData =
        document.getElementById(
            "facilityMapNoData"
        );


    if (noData) {

        noData.style.display =
            totalVisible > 0
                ? "none"
                : "block";

    }

}


/* =========================================================
   MARKER SIZE
   ========================================================= */

function getFacilityMarkerSize(
    markerType
) {


    var zoom =
        facilityMap
            ? (
                facilityMap.getZoom() ||
                FACILITY_PH_ZOOM
            )
            : FACILITY_PH_ZOOM;


    if (
        facilityCurrentMode ===
        "overview"
    ) {

        if (zoom <= 5) {

            return markerType === "vehicle"
                ? 7
                : 8;

        }


        if (zoom <= 6) {

            return markerType === "vehicle"
                ? 8
                : 9;

        }


        if (zoom <= 7) {

            return markerType === "vehicle"
                ? 10
                : 11;

        }


        if (zoom <= 8) {

            return markerType === "vehicle"
                ? 12
                : 13;

        }


        if (zoom <= 10) {

            return markerType === "vehicle"
                ? 16
                : 17;

        }


        if (zoom <= 12) {

            return markerType === "vehicle"
                ? 21
                : 22;

        }


        return markerType === "vehicle"
            ? 26
            : 27;

    }


    if (zoom <= 5) {
        return 11;
    }


    if (zoom <= 6) {
        return 13;
    }


    if (zoom <= 7) {
        return 16;
    }


    if (zoom <= 8) {
        return 19;
    }


    if (zoom <= 10) {
        return 24;
    }


    if (zoom <= 12) {
        return 29;
    }


    return 35;

}


/* =========================================================
   UPDATE MARKER ICONS
   ========================================================= */

function updateFacilityMarkerPresentation() {


    if (!facilityMap) {

        return;

    }


    Object.keys(
        facilityWarehouseMarkers
    )
    .forEach(

        function (id) {


            var warehouse =
                facilityWarehouseData.find(

                    function (row) {

                        return (
                            parseInt(
                                row.warehouse_id,
                                10
                            )
                            ===
                            parseInt(
                                id,
                                10
                            )
                        );

                    }

                );


            if (!warehouse) {

                return;

            }


            var marker =
                facilityWarehouseMarkers[id];


            marker.setIcon(

                getFacilityWarehouseIcon(
                    warehouse.warehouse_type
                )

            );


            marker.setOpacity(

                facilityCurrentMode ===
                    "overview"

                    ? 0.82
                    : 1

            );


            marker.setZIndex(
                10
            );

        }

    );


    Object.keys(
        facilityVehicleMarkers
    )
    .forEach(

        function (id) {


            var vehicle =
                facilityVehicleData.find(

                    function (row) {

                        return (
                            parseInt(
                                row.trip_ticket_id,
                                10
                            )
                            ===
                            parseInt(
                                id,
                                10
                            )
                        );

                    }

                );


            if (!vehicle) {

                return;

            }


            var marker =
                facilityVehicleMarkers[id];


            marker.setIcon(

                getFacilityVehicleIcon(
                    vehicle.vehicle_group,
                    vehicle.transporter_type
                )

            );


            marker.setOpacity(

                facilityCurrentMode ===
                    "overview"

                    ? 0.88
                    : 1

            );


            marker.setZIndex(
                20
            );

        }

    );

}


/* =========================================================
   WAREHOUSE ICON
   ========================================================= */

function getFacilityWarehouseIcon(
    type
) {


    var normalized =
        normalizeFacilityWarehouseType(
            type
        );


    var iconFile =
        FACILITY_WAREHOUSE_ICONS[
            normalized
        ]
        ||
        FACILITY_WAREHOUSE_ICONS
            .SPOKE;


    var size =
        getFacilityMarkerSize(
            "warehouse"
        );


    return {

        url:
            FACILITY_ICON_BASE +
            iconFile,

        scaledSize:
            new google.maps.Size(
                size,
                size
            ),

        anchor:
            new google.maps.Point(
                Math.round(
                    size / 2
                ),
                size
            )

    };

}


/* =========================================================
   VEHICLE ICON
   ========================================================= */

function getFacilityVehicleIcon(
    group,
    transporterType
) {


    var size =
        getFacilityMarkerSize(
            "vehicle"
        );


    return {

        url:
            createFacilityVehicleSvg(
                group,
                transporterType
            ),

        scaledSize:
            new google.maps.Size(
                size,
                size
            ),

        anchor:
            new google.maps.Point(
                Math.round(
                    size / 2
                ),
                Math.round(
                    size / 2
                )
            )

    };

}


/* =========================================================
   VEHICLE SVG
   ========================================================= */

function createFacilityVehicleSvg(
    group,
    transporterType
) {


    var normalized =
        normalizeFacilityVehicleGroup(
            group,
            transporterType
        );


    var color =
        FACILITY_VEHICLE_COLORS[
            normalized
        ]
        ||
        FACILITY_VEHICLE_COLORS.OTHER;


    var svg =

        "<svg " +

            "xmlns='http://www.w3.org/2000/svg' " +

            "width='64' " +

            "height='64' " +

            "viewBox='0 0 64 64'>" +


            "<path " +

                "d='M7 18a4 4 0 0 1 4-4h29v28H7z' " +

                "fill='" +
                color +
                "' " +

                "stroke='#ffffff' " +

                "stroke-width='3'/>" +


            "<path " +

                "d='M40 24h10l9 10v8H40z' " +

                "fill='" +
                color +
                "' " +

                "stroke='#ffffff' " +

                "stroke-width='3'/>" +


            "<path " +

                "d='M46 28h4l5 6h-9z' " +

                "fill='#ffffff'/>" +


            "<circle " +

                "cx='18' " +

                "cy='44' " +

                "r='7' " +

                "fill='#202124' " +

                "stroke='#ffffff' " +

                "stroke-width='3'/>" +


            "<circle " +

                "cx='50' " +

                "cy='44' " +

                "r='7' " +

                "fill='#202124' " +

                "stroke='#ffffff' " +

                "stroke-width='3'/>" +


        "</svg>";


    return (

        "data:image/svg+xml;charset=UTF-8," +

        encodeURIComponent(
            svg
        )

    );

}


/* =========================================================
   DEFAULT PHILIPPINES VIEW
   ========================================================= */

function resetFacilityPhilippinesView() {


    if (!facilityMap) {

        return;

    }


    facilityMap.setCenter(
        FACILITY_PH_CENTER
    );


    facilityMap.setZoom(
        FACILITY_PH_ZOOM
    );

}


/* =========================================================
   FIT VISIBLE MARKERS
   ========================================================= */

function fitFacilityVisibleMarkers() {


    if (!facilityMap) {

        return;

    }


    var bounds =
        new google.maps.LatLngBounds();


    var count =
        0;


    Object.keys(
        facilityWarehouseMarkers
    )
    .forEach(

        function (id) {


            var marker =
                facilityWarehouseMarkers[id];


            if (
                marker &&
                marker.getVisible()
            ) {

                bounds.extend(
                    marker.getPosition()
                );


                count++;

            }

        }

    );


    Object.keys(
        facilityVehicleMarkers
    )
    .forEach(

        function (id) {


            var marker =
                facilityVehicleMarkers[id];


            if (
                marker &&
                marker.getVisible()
            ) {

                bounds.extend(
                    marker.getPosition()
                );


                count++;

            }

        }

    );


    if (
        count === 0
    ) {

        return;

    }


    if (
        count === 1
    ) {

        facilityMap.setCenter(
            bounds.getCenter()
        );


        facilityMap.setZoom(
            12
        );


        return;

    }


    facilityMap.fitBounds(

        bounds,

        {

            top:55,

            right:35,

            bottom:35,

            left:35

        }

    );


    google.maps.event.addListenerOnce(

        facilityMap,

        "idle",

        function () {


            if (!facilityMap) {

                return;

            }


            var zoom =
                facilityMap.getZoom();


            if (zoom < 6) {

                facilityMap.setZoom(
                    6
                );

            }


            if (zoom > 13) {

                facilityMap.setZoom(
                    13
                );

            }


            updateFacilityMarkerPresentation();

        }

    );

}


/* =========================================================
   WAREHOUSE INFO
   ========================================================= */

function showFacilityWarehouseInfo(
    warehouse,
    marker
) {


    var location = [

        facilityText(
            warehouse.city
        ),

        facilityText(
            warehouse.province
        )

    ]
    .filter(Boolean)
    .join(", ");


    var html =

        "<div class='wings-map-info'>" +

            "<div class='wings-map-info-title'>" +

                facilityEscape(
                    warehouse.warehouse_name
                ) +

            "</div>" +


            "<span class='wings-map-info-badge'>" +

                facilityEscape(
                    warehouse.warehouse_type
                ) +

            "</span>" +


            "<br>" +


            "<b>Warehouse Code:</b> " +

            facilityEscape(
                warehouse.warehouse_code
            ) +

            "<br>" +


            "<b>Location:</b> " +

            facilityEscape(
                location
            ) +

            "<br>" +


            "<b>Region:</b> " +

            facilityEscape(
                warehouse.region
            ) +

            "<br>" +


            "<b>FFP:</b> " +

            facilityFormatNumber(
                warehouse.ffp_stock
            ) +

            "<br>" +


            "<b>NFI:</b> " +

            facilityFormatNumber(
                warehouse.nfi_stock
            ) +

            "<br>" +


            "<b>Capacity:</b> " +

            facilityFormatNumber(
                warehouse.capacity_percent
            ) +

            "%" +

        "</div>";


    facilityInfoWindow.setContent(
        html
    );


    facilityInfoWindow.open(
        facilityMap,
        marker
    );

}


/* =========================================================
   VEHICLE INFO
   ========================================================= */

function showFacilityVehicleInfo(
    vehicle,
    marker
) {


    var status =
        vehicle.delivery_status ||
        vehicle.trip_status ||
        "";


    var html =

        "<div class='wings-map-info'>" +

            "<div class='wings-map-info-title'>" +

                facilityEscape(
                    vehicle.plate_no ||
                    vehicle.vehicle_code
                ) +

            "</div>" +


            "<span class='wings-map-info-badge'>" +

                facilityEscape(
                    vehicle.vehicle_group ||
                    vehicle.transporter_type
                ) +

            "</span>" +


            "<br>" +


            "<b>Trip Ticket:</b> " +

            facilityEscape(
                vehicle.trip_ticket_no
            ) +

            "<br>" +


            "<b>Vehicle:</b> " +

            facilityEscape(
                vehicle.vehicle_type
            ) +

            "<br>" +


            "<b>Driver:</b> " +

            facilityEscape(
                vehicle.driver_name
            ) +

            "<br>" +


            "<b>Status:</b> " +

            facilityEscape(
                status
            ) +

            "<br>" +


            "<b>Last GPS:</b> " +

            facilityEscape(
                vehicle.last_gps_datetime
            ) +

        "</div>";


    facilityInfoWindow.setContent(
        html
    );


    facilityInfoWindow.open(
        facilityMap,
        marker
    );

}


/* =========================================================
   NORMALIZE WAREHOUSE TYPE
   ========================================================= */

function normalizeFacilityWarehouseType(
    value
) {


    var normalized =
        facilityText(
            value
        )
        .trim()
        .toUpperCase()
        .replace(
            /-/g,
            "_"
        )
        .replace(
            /\s+/g,
            "_"
        );


    if (
        normalized === "HUB"
    ) {

        return "HUB";

    }


    if (
        normalized === "LAST_MILE"
        ||
        normalized === "LASTMILE"
    ) {

        return "LAST_MILE";

    }


    if (
        normalized === "SPOKE"
    ) {

        return "SPOKE";

    }


    /*
     * Unknown warehouse types stay unique.
     * Do NOT automatically convert everything
     * unknown to SPOKE because that can produce
     * incorrect filtering.
     */

    return normalized;

}


/* =========================================================
   NORMALIZE VEHICLE GROUP
   ========================================================= */

function normalizeFacilityVehicleGroup(
    group,
    transporterType
) {


    var g =
        facilityNormalizeKey(
            group
        );


    var t =
        facilityNormalizeKey(
            transporterType
        );


    if (
        g === "DSWD"
        ||
        g === "DSWD_FLEET"
        ||
        t === "DSWD_FLEET"
    ) {

        return "DSWD";

    }


    if (
        g === "TPL"
        ||
        g === "THIRD_PARTY"
        ||
        g === "THIRD_PARTY_LOGISTICS"
        ||
        g === "SERVICE_PROVIDER"
        ||
        t === "TPL"
        ||
        t === "THIRD_PARTY"
        ||
        t === "THIRD_PARTY_LOGISTICS"
        ||
        t === "SERVICE_PROVIDER"
    ) {

        return "TPL";

    }


    if (
        g === "PARTNER"
        ||
        g === "PARTNERS"
        ||
        g === "PARTNER_WFP_TRANSPORT"
        ||
        t === "PARTNER"
        ||
        t === "PARTNERS"
        ||
        t === "PARTNER_WFP_TRANSPORT"
    ) {

        return "PARTNER";

    }


    return "OTHER";

}


/* =========================================================
   HELPERS
   ========================================================= */

function facilityText(
    value
) {


    if (
        value === null ||
        value === undefined
    ) {

        return "";

    }


    return String(
        value
    );

}


function facilityNormalizeText(
    value
) {


    return facilityText(
        value
    )
    .trim()
    .toUpperCase();

}


function facilityNormalizeKey(
    value
) {


    return facilityNormalizeText(
        value
    )
    .replace(
        /[\s-]+/g,
        "_"
    );

}


function facilityEscape(
    value
) {


    return facilityText(
        value
    )
    .replace(
        /&/g,
        "&amp;"
    )
    .replace(
        /</g,
        "&lt;"
    )
    .replace(
        />/g,
        "&gt;"
    )
    .replace(
        /"/g,
        "&quot;"
    )
    .replace(
        /'/g,
        "&#039;"
    );

}


function facilityFormatNumber(
    value
) {


    return parseFloat(
        value || 0
    )
    .toLocaleString(

        undefined,

        {

            minimumFractionDigits:0,

            maximumFractionDigits:0

        }

    );

}


function facilityValidCoordinate(
    value
) {


    var number =
        parseFloat(
            value
        );


    return (

        Number.isFinite(
            number
        )

        &&

        number !== 0

    );

}


/* =========================================================
   WINDOW RESIZE
   ========================================================= */

window.addEventListener(

    "resize",

    function () {


        clearTimeout(
            facilityMarkerTimer
        );


        facilityMarkerTimer =
            setTimeout(

                function () {


                    if (!facilityMap) {

                        return;

                    }


                    var center =
                        facilityMap.getCenter();


                    google.maps.event.trigger(
                        facilityMap,
                        "resize"
                    );


                    if (center) {

                        facilityMap.setCenter(
                            center
                        );

                    }


                    updateFacilityMarkerPresentation();

                },

                120

            );

    }

);

</script>

HTML;


/* =========================================================
   12. SAFE GOOGLE MAPS LOADER
   KEEP THIS LOADER
   ========================================================= */

echo '

<script>

(function () {

    "use strict";


    var GOOGLE_API_KEY =
        ' . json_encode($googleApiKey) . ';


    function startFacilityMap() {


        if (
            typeof window.initFacilityMapDashboard
            !== "function"
        ) {

            console.error(
                "Facility Mapping initialization function is missing."
            );

            return;

        }


        window.initFacilityMapDashboard();

    }


    /* =====================================================
       GOOGLE MAPS ALREADY AVAILABLE
       ===================================================== */

    if (
        window.google &&
        window.google.maps
    ) {

        setTimeout(
            startFacilityMap,
            100
        );

        return;

    }


    /* =====================================================
       GOOGLE SCRIPT ALREADY LOADING
       ===================================================== */

    var existingScript =
        document.getElementById(
            "wingsGoogleMapsApi"
        );


    if (existingScript) {


        var waitCount =
            0;


        var waitForGoogle =
            setInterval(

                function () {


                    waitCount++;


                    if (
                        window.google &&
                        window.google.maps
                    ) {

                        clearInterval(
                            waitForGoogle
                        );


                        startFacilityMap();

                        return;

                    }


                    if (
                        waitCount >= 100
                    ) {

                        clearInterval(
                            waitForGoogle
                        );


                        console.error(
                            "Timed out waiting for Google Maps API."
                        );

                    }

                },

                100

            );


        return;

    }


    /* =====================================================
       LOAD GOOGLE MAPS
       ===================================================== */

    var script =
        document.createElement(
            "script"
        );


    script.id =
        "wingsGoogleMapsApi";


    script.type =
        "text/javascript";


    script.async =
        true;


    script.defer =
        true;


    script.src =

        "https://maps.googleapis.com/maps/api/js" +

        "?key=" +

        encodeURIComponent(
            GOOGLE_API_KEY
        ) +

        "&v=weekly";


    script.onload =
        function () {


            if (
                window.google &&
                window.google.maps
            ) {

                startFacilityMap();

            } else {

                console.error(
                    "Google Maps loaded but google.maps is unavailable."
                );

            }

        };


    script.onerror =
        function () {


            console.error(
                "Unable to load Google Maps API."
            );


            var map =
                document.getElementById(
                    "facilityGoogleMap"
                );


            if (map) {

                map.innerHTML =

                    "<div style=\'" +

                        "position:absolute;" +

                        "inset:0;" +

                        "display:flex;" +

                        "align-items:center;" +

                        "justify-content:center;" +

                        "background:#f5f5f5;" +

                        "color:#ee1c25;" +

                        "font-family:Arial;" +

                        "font-size:13px;" +

                        "font-weight:700;" +

                    "\'>" +

                        "Unable to load Google Maps." +

                    "</div>";

            }

        };


    document.head.appendChild(
        script
    );


})();

</script>

';
		;
		
	}

	// code snippet - INV MAP
	function event_63473(  ) {
		
		/* =========================================================
   WINGS - FACILITY MAPPING
   INVENTORY MONITORING - LEFT PANEL
   PHPRUNNER 11.3

   SEPARATE CUSTOM CODE NODE

   DO NOT ADD:
   <?php
   ?>
   ========================================================= */


/* =========================================================
   1. DEFAULT VALUES
   ========================================================= */

$familyFoodPackQty = 0;
$familyFoodPackPrice = 0;

$prepackQty = 0;
$prepackPrice = 0;

$rtefQty = 0;
$rtefPrice = 0;

$totalFfpQty = 0;
$totalFfpPrice = 0;

$totalNfiQty = 0;
$totalNfiPrice = 0;

$nearFfpQty = 0;
$nearRtefQty = 0;
$nearNfiQty = 0;

$nfiRows = array();


/* =========================================================
   2. HELPER - CHECK TABLE / VIEW
   ========================================================= */

function wingsInventoryObjectExists($name)
{
    $safeName = addslashes($name);

    $rs = DB::Query(
        "SHOW TABLES LIKE '" . $safeName . "'"
    );

    return (
        $rs &&
        $rs->fetchAssoc()
    );
}


/* =========================================================
   3. FOOD INVENTORY
   ACTUAL INVENTORY + RECEIVED COST
   ========================================================= */

$hasInventoryBalance =
    wingsInventoryObjectExists(
        "view_bd_inventory_balance"
    );

$hasItem =
    wingsInventoryObjectExists(
        "item"
    );

$hasFoodClassification =
    wingsInventoryObjectExists(
        "food_classification"
    );

$hasItemCost =
    wingsInventoryObjectExists(
        "vw_item_received_cost"
    );


if (
    $hasInventoryBalance &&
    $hasItem &&
    $hasFoodClassification
) {

    /*
     * Cost view is optional.
     * If unavailable, quantity still loads.
     */

    $costJoin = "";

    $costExpression = "0";


    if ($hasItemCost) {

        $costJoin = "
            LEFT JOIN vw_item_received_cost AS item_cost
                ON item_cost.item_id = inventory.item_id
        ";

        $costExpression =
            "COALESCE(item_cost.unit_cost, 0)";

    }


    $sqlFood = "

        SELECT

            SUM(
                CASE

                    WHEN UPPER(
                        COALESCE(
                            fc.classification_code,
                            ''
                        )
                    ) = 'FFP'

                    THEN COALESCE(
                        inventory.qty_balance,
                        0
                    )

                    ELSE 0

                END
            ) AS family_food_pack_qty,


            SUM(
                CASE

                    WHEN UPPER(
                        COALESCE(
                            fc.classification_code,
                            ''
                        )
                    ) = 'FFP'

                    THEN
                        COALESCE(
                            inventory.qty_balance,
                            0
                        )
                        *
                        " . $costExpression . "

                    ELSE 0

                END
            ) AS family_food_pack_price,


            SUM(
                CASE

                    WHEN UPPER(
                        COALESCE(
                            fc.classification_code,
                            ''
                        )
                    ) = 'PREPACK_FFP'

                    THEN COALESCE(
                        inventory.qty_balance,
                        0
                    )

                    ELSE 0

                END
            ) AS prepack_qty,


            SUM(
                CASE

                    WHEN UPPER(
                        COALESCE(
                            fc.classification_code,
                            ''
                        )
                    ) = 'PREPACK_FFP'

                    THEN
                        COALESCE(
                            inventory.qty_balance,
                            0
                        )
                        *
                        " . $costExpression . "

                    ELSE 0

                END
            ) AS prepack_price,


            SUM(
                CASE

                    WHEN UPPER(
                        COALESCE(
                            fc.classification_code,
                            ''
                        )
                    ) = 'RTEF'

                    THEN COALESCE(
                        inventory.qty_balance,
                        0
                    )

                    ELSE 0

                END
            ) AS rtef_qty,


            SUM(
                CASE

                    WHEN UPPER(
                        COALESCE(
                            fc.classification_code,
                            ''
                        )
                    ) = 'RTEF'

                    THEN
                        COALESCE(
                            inventory.qty_balance,
                            0
                        )
                        *
                        " . $costExpression . "

                    ELSE 0

                END
            ) AS rtef_price


        FROM view_bd_inventory_balance
            AS inventory


        INNER JOIN item AS item_master

            ON item_master.id =
               inventory.item_id


        LEFT JOIN food_classification AS fc

            ON fc.food_classification_id =
               item_master.food_classification_id


        " . $costJoin . "


        WHERE
            COALESCE(
                inventory.qty_balance,
                0
            ) > 0

    ";


    $rsFood =
        DB::Query(
            $sqlFood
        );


    if ($rsFood) {

        $food =
            $rsFood->fetchAssoc();


        if ($food) {

            $familyFoodPackQty =
                (float)$food[
                    "family_food_pack_qty"
                ];


            $familyFoodPackPrice =
                (float)$food[
                    "family_food_pack_price"
                ];


            $prepackQty =
                (float)$food[
                    "prepack_qty"
                ];


            $prepackPrice =
                (float)$food[
                    "prepack_price"
                ];


            $rtefQty =
                (float)$food[
                    "rtef_qty"
                ];


            $rtefPrice =
                (float)$food[
                    "rtef_price"
                ];

        }

    }

}


/* =========================================================
   4. FALLBACK FOOD DASHBOARD VIEW
   ========================================================= */

if (
    $familyFoodPackQty == 0 &&
    $prepackQty == 0 &&
    $rtefQty == 0 &&
    wingsInventoryObjectExists(
        "vw_dashboard_food_inventory"
    )
) {

    $rsFoodFallback =
        DB::Query("

            SELECT

                SUM(
                    COALESCE(
                        family_food_pack_qty,
                        0
                    )
                )
                    AS family_food_pack_qty,

                SUM(
                    COALESCE(
                        prepack_family_food_pack_qty,
                        0
                    )
                )
                    AS prepack_qty,

                SUM(
                    COALESCE(
                        rtef_qty,
                        0
                    )
                )
                    AS rtef_qty

            FROM
                vw_dashboard_food_inventory

        ");


    if ($rsFoodFallback) {

        $foodFallback =
            $rsFoodFallback->fetchAssoc();


        if ($foodFallback) {

            $familyFoodPackQty =
                (float)$foodFallback[
                    "family_food_pack_qty"
                ];


            $prepackQty =
                (float)$foodFallback[
                    "prepack_qty"
                ];


            $rtefQty =
                (float)$foodFallback[
                    "rtef_qty"
                ];

        }

    }

}


/* =========================================================
   5. TOTAL FFP
   ========================================================= */

$totalFfpQty =
    $familyFoodPackQty +
    $prepackQty;


$totalFfpPrice =
    $familyFoodPackPrice +
    $prepackPrice;


/* =========================================================
   6. NFI ACTUAL INVENTORY
   ========================================================= */

if (
    $hasInventoryBalance &&
    $hasItem
) {

    $nfiCostJoin = "";

    $nfiCostExpression =
        "0";


    if ($hasItemCost) {

        $nfiCostJoin = "

            LEFT JOIN
                vw_item_received_cost
                    AS item_cost

                ON item_cost.item_id =
                   inventory.item_id

        ";


        $nfiCostExpression =
            "COALESCE(item_cost.unit_cost, 0)";

    }


    /*
     * Detailed NFI rows.
     */

    $sqlNfi = "

        SELECT

            inventory.item_id,


            COALESCE(

                NULLIF(
                    TRIM(item_master.name),
                    ''
                ),

                NULLIF(
                    TRIM(inventory.description),
                    ''
                ),

                NULLIF(
                    TRIM(inventory.subcategory_name),
                    ''
                ),

                'Other NFI'

            ) AS item_name,


            SUM(
                COALESCE(
                    inventory.qty_balance,
                    0
                )
            ) AS quantity,


            SUM(

                COALESCE(
                    inventory.qty_balance,
                    0
                )

                *

                " . $nfiCostExpression . "

            ) AS total_price


        FROM
            view_bd_inventory_balance
                AS inventory


        INNER JOIN item
            AS item_master

            ON item_master.id =
               inventory.item_id


        " . $nfiCostJoin . "


        WHERE

            COALESCE(
                inventory.qty_balance,
                0
            ) > 0


            AND (

                UPPER(
                    COALESCE(
                        inventory.category_name,
                        ''
                    )
                )
                    LIKE '%NON%FOOD%'

                OR

                UPPER(
                    COALESCE(
                        inventory.category_name,
                        ''
                    )
                )
                    LIKE '%NON-FOOD%'

            )


        GROUP BY

            inventory.item_id,

            item_name


        ORDER BY

            quantity DESC,

            item_name ASC

    ";


    $rsNfi =
        DB::Query(
            $sqlNfi
        );


    if ($rsNfi) {

        while (
            $nfi =
                $rsNfi->fetchAssoc()
        ) {

            $qty =
                (float)$nfi[
                    "quantity"
                ];


            $price =
                (float)$nfi[
                    "total_price"
                ];


            $totalNfiQty +=
                $qty;


            $totalNfiPrice +=
                $price;


            $nfiRows[] = array(

                "item_name" =>
                    (string)$nfi[
                        "item_name"
                    ],

                "quantity" =>
                    $qty,

                "total_price" =>
                    $price

            );

        }

    }

}


/* =========================================================
   7. NFI FALLBACK
   ========================================================= */

if (
    count($nfiRows) === 0 &&
    wingsInventoryObjectExists(
        "vw_dashboard_nfi_inventory"
    )
) {

    $rsNfiFallback =
        DB::Query("

            SELECT

                SUM(
                    COALESCE(
                        family_clothing_qty,
                        0
                    )
                )
                    AS family_clothing_qty,


                SUM(
                    COALESCE(
                        kitchen_kit_qty,
                        0
                    )
                )
                    AS kitchen_kit_qty,


                SUM(
                    COALESCE(
                        sleeping_kit_qty,
                        0
                    )
                )
                    AS sleeping_kit_qty,


                SUM(
                    COALESCE(
                        hygiene_kit_qty,
                        0
                    )
                )
                    AS hygiene_kit_qty,


                SUM(
                    COALESCE(
                        family_tents_qty,
                        0
                    )
                )
                    AS family_tents_qty,


                SUM(
                    COALESCE(
                        water_jerrican_qty,
                        0
                    )
                )
                    AS water_jerrican_qty,


                SUM(
                    COALESCE(
                        others_qty,
                        0
                    )
                )
                    AS others_qty


            FROM
                vw_dashboard_nfi_inventory

        ");


    if ($rsNfiFallback) {

        $nfiFallback =
            $rsNfiFallback->fetchAssoc();


        if ($nfiFallback) {

            $fallbackItems = array(

                "Family Clothing Kit" =>
                    (float)$nfiFallback[
                        "family_clothing_qty"
                    ],

                "Kitchen Kit" =>
                    (float)$nfiFallback[
                        "kitchen_kit_qty"
                    ],

                "Sleeping Kit" =>
                    (float)$nfiFallback[
                        "sleeping_kit_qty"
                    ],

                "Hygiene Kit" =>
                    (float)$nfiFallback[
                        "hygiene_kit_qty"
                    ],

                "Family Tent" =>
                    (float)$nfiFallback[
                        "family_tents_qty"
                    ],

                "Water Jerrican" =>
                    (float)$nfiFallback[
                        "water_jerrican_qty"
                    ],

                "Others" =>
                    (float)$nfiFallback[
                        "others_qty"
                    ]

            );


            foreach (
                $fallbackItems
                as $name => $qty
            ) {

                if ($qty <= 0) {
                    continue;
                }


                $nfiRows[] = array(

                    "item_name" =>
                        $name,

                    "quantity" =>
                        $qty,

                    "total_price" =>
                        0

                );


                $totalNfiQty +=
                    $qty;

            }

        }

    }

}


/* =========================================================
   8. NEARING EXPIRY
   ========================================================= */

if (
    wingsInventoryObjectExists(
        "vw_dashboard_nearing_expiry"
    )
) {

    /*
     * Check optional columns so this works with both
     * older and newer versions of your dashboard view.
     */

    $nearColumns = array();


    $rsNearColumns =
        DB::Query(
            "SHOW COLUMNS
             FROM vw_dashboard_nearing_expiry"
        );


    if ($rsNearColumns) {

        while (
            $column =
                $rsNearColumns->fetchAssoc()
        ) {

            $nearColumns[
                strtolower(
                    $column["Field"]
                )
            ] = true;

        }

    }


    $nearSelect = array();


    $nearSelect[] =
        "SUM(COALESCE(ffp_qty,0))
            AS ffp_qty";


    if (
        isset(
            $nearColumns[
                "rtef_qty"
            ]
        )
    ) {

        $nearSelect[] =
            "SUM(COALESCE(rtef_qty,0))
                AS rtef_qty";

    } else {

        $nearSelect[] =
            "0 AS rtef_qty";

    }


    if (
        isset(
            $nearColumns[
                "nfi_qty"
            ]
        )
    ) {

        $nearSelect[] =
            "SUM(COALESCE(nfi_qty,0))
                AS nfi_qty";

    } elseif (
        isset(
            $nearColumns[
                "hygiene_kit_qty"
            ]
        )
    ) {

        $nearSelect[] =
            "SUM(COALESCE(hygiene_kit_qty,0))
                AS nfi_qty";

    } else {

        $nearSelect[] =
            "0 AS nfi_qty";

    }


    $sqlNear = "

        SELECT

            " .
            implode(
                ",",
                $nearSelect
            ) . "

        FROM
            vw_dashboard_nearing_expiry

    ";


    $rsNear =
        DB::Query(
            $sqlNear
        );


    if ($rsNear) {

        $near =
            $rsNear->fetchAssoc();


        if ($near) {

            $nearFfpQty =
                (float)$near[
                    "ffp_qty"
                ];


            $nearRtefQty =
                (float)$near[
                    "rtef_qty"
                ];


            $nearNfiQty =
                (float)$near[
                    "nfi_qty"
                ];

        }

    }

}


/* =========================================================
   9. FORMAT HELPERS
   ========================================================= */

function wingsInventoryNumber($value)
{
    return number_format(
        (float)$value,
        0
    );
}


function wingsInventoryMoney($value)
{
    $value =
        (float)$value;


    if ($value <= 0) {
        return "—";
    }


    return
        "₱" .
        number_format(
            $value,
            2
        );
}


function wingsInventoryEscape($value)
{
    return htmlspecialchars(
        (string)$value,
        ENT_QUOTES,
        "UTF-8"
    );
}


/* =========================================================
   10. CSS + MAIN HTML
   ========================================================= */

echo <<<'HTML'

<style>

/* =========================================================
   INVENTORY MONITORING ROOT
   ========================================================= */

#wingsInventoryMonitoring {

    --wings-blue:#2e3192;
    --wings-green:#43af52;
    --wings-red:#ee1c25;
    --wings-bg:#f0f0f8;
    --wings-card:#ffffff;
    --wings-text:#262626;
    --wings-muted:#6b6b6b;

    width:100% !important;
    min-width:0 !important;

    height:100% !important;
    min-height:720px !important;

    margin:0 !important;

    padding:
        12px
        10px
        10px
        10px !important;

    overflow:hidden !important;

    border-radius:8px !important;

    background:
        var(--wings-bg) !important;

    box-sizing:border-box !important;

    color:
        var(--wings-text);

    font-family:
        Arial,
        Helvetica,
        sans-serif;

}


/* =========================================================
   TITLE
   ========================================================= */

#wingsInventoryMonitoring
.wings-inventory-title {

    margin:
        0
        0
        12px
        0;

    color:
        var(--wings-blue);

    font-size:20px;

    font-weight:800;

    line-height:24px;

    text-align:center;

}


/* =========================================================
   SEARCH
   ========================================================= */

#wingsInventoryMonitoring
.wings-inventory-search-wrap {

    position:relative;

    width:100%;

    margin-bottom:7px;

}


#wingsInventoryMonitoring
.wings-inventory-search-icon {

    position:absolute;

    top:50%;

    left:10px;

    color:
        var(--wings-blue);

    font-size:15px;

    line-height:1;

    transform:
        translateY(-50%);

    pointer-events:none;

}


#wingsInventoryMonitoring
#wingsInventorySearch {

    width:100% !important;

    height:34px !important;

    margin:0 !important;

    padding:
        0
        10px
        0
        31px !important;

    border:
        1px solid
        #d4d6df !important;

    border-radius:5px !important;

    outline:0 !important;

    background:#ffffff !important;

    color:#444444 !important;

    font-size:10px !important;

    box-shadow:
        0
        1px
        3px
        rgba(0,0,0,.12) !important;

}


/* =========================================================
   CARD
   ========================================================= */

#wingsInventoryMonitoring
.wings-monitor-card {

    width:100%;

    margin:
        0
        0
        7px
        0;

    padding:
        10px
        10px
        9px
        10px;

    overflow:hidden;

    border-radius:5px;

    background:
        var(--wings-card);

    box-shadow:
        0
        1px
        4px
        rgba(0,0,0,.13);

    box-sizing:border-box;

}


/* CARD TITLE */

#wingsInventoryMonitoring
.wings-monitor-card-title {

    margin:
        0
        0
        3px
        0;

    color:#252525;

    font-size:12px;

    font-weight:800;

    line-height:14px;

    text-align:center;

}


/* LARGE NUMBER */

#wingsInventoryMonitoring
.wings-monitor-total {

    margin:
        2px
        0
        8px
        0;

    color:
        var(--wings-green);

    font-size:17px;

    font-weight:800;

    line-height:19px;

    text-align:center;

}


#wingsInventoryMonitoring
.wings-monitor-total.red {

    color:
        var(--wings-red);

}


/* =========================================================
   TABLE
   ========================================================= */

#wingsInventoryMonitoring
.wings-monitor-table {

    width:100%;

    border-collapse:collapse;

    table-layout:fixed;

}


#wingsInventoryMonitoring
.wings-monitor-table th {

    padding:
        0
        2px
        4px
        2px;

    color:#555555;

    font-size:8px;

    font-weight:500;

    line-height:10px;

    text-align:left;

}


#wingsInventoryMonitoring
.wings-monitor-table th:nth-child(1) {

    width:42%;

}


#wingsInventoryMonitoring
.wings-monitor-table th:nth-child(2) {

    width:25%;

    text-align:right;

}


#wingsInventoryMonitoring
.wings-monitor-table th:nth-child(3) {

    width:33%;

    text-align:right;

}


#wingsInventoryMonitoring
.wings-monitor-table td {

    padding:
        2px
        2px;

    border:0;

    color:#4f4f4f;

    font-size:8px;

    font-weight:400;

    line-height:10px;

    vertical-align:top;

}


#wingsInventoryMonitoring
.wings-monitor-table td:nth-child(2),
#wingsInventoryMonitoring
.wings-monitor-table td:nth-child(3) {

    text-align:right;

}


#wingsInventoryMonitoring
.wings-monitor-table td:nth-child(3) {

    color:#272727;

}


/* =========================================================
   RTEF COMPACT CARD
   ========================================================= */

#wingsInventoryMonitoring
.wings-rtef-card {

    padding-top:10px;
    padding-bottom:9px;

}


#wingsInventoryMonitoring
.wings-rtef-summary {

    display:grid;

    grid-template-columns:
        1fr
        auto
        auto;

    gap:7px;

    align-items:center;

    color:#555555;

    font-size:8px;

}


#wingsInventoryMonitoring
.wings-rtef-summary strong {

    color:#222222;

    font-size:8px;

    font-weight:500;

}


/* =========================================================
   NFI CARD
   ========================================================= */

#wingsInventoryMonitoring
.wings-nfi-card {

    padding-bottom:7px;

}


#wingsInventoryMonitoring
.wings-nfi-scroll {

    max-height:245px;

    overflow-x:hidden;

    overflow-y:auto;

    scrollbar-width:thin;

}


/* =========================================================
   NEARING EXPIRY
   ========================================================= */

#wingsInventoryMonitoring
.wings-near-table td {

    padding-top:3px;
    padding-bottom:3px;

}


/* =========================================================
   FILTERED SEARCH
   ========================================================= */

#wingsInventoryMonitoring
.wings-search-hidden {

    display:none !important;

}


/* =========================================================
   SCROLLBAR
   ========================================================= */

#wingsInventoryMonitoring
.wings-nfi-scroll::-webkit-scrollbar {

    width:5px;

}


#wingsInventoryMonitoring
.wings-nfi-scroll::-webkit-scrollbar-thumb {

    border-radius:5px;

    background:#c8c8d4;

}


/* =========================================================
   SMALL DASHBOARD WIDTH
   ========================================================= */

@media (max-width:420px) {

    #wingsInventoryMonitoring {

        min-height:650px !important;

        padding:
            10px
            7px !important;

    }


    #wingsInventoryMonitoring
    .wings-inventory-title {

        font-size:18px;

    }

}

</style>


<div id="wingsInventoryMonitoring">


    <div class="wings-inventory-title">

        Inventory Monitoring

    </div>


    <div class="wings-inventory-search-wrap">

        <span class="wings-inventory-search-icon">
            ⌕
        </span>

        <input
            type="search"
            id="wingsInventorySearch"
            placeholder="Search">

    </div>

HTML;


/* =========================================================
   11. TOTAL FFP CARD
   ========================================================= */

echo '

<div
    class="wings-monitor-card wings-inventory-searchable"
    data-search-text="total ffp food family pack prepack">

    <div class="wings-monitor-card-title">
        TOTAL FFPs
    </div>

    <div class="wings-monitor-total">
        ' .
        wingsInventoryNumber(
            $totalFfpQty
        ) .
        '
    </div>


    <table class="wings-monitor-table">

        <thead>

            <tr>

                <th>
                    Details
                </th>

                <th>
                    Quantity
                </th>

                <th>
                    Total Price
                </th>

            </tr>

        </thead>


        <tbody>

            <tr>

                <td>
                    Food Family Pack
                </td>

                <td>
                    ' .
                    wingsInventoryNumber(
                        $familyFoodPackQty
                    ) .
                    '
                </td>

                <td>
                    ' .
                    wingsInventoryMoney(
                        $familyFoodPackPrice
                    ) .
                    '
                </td>

            </tr>


            <tr>

                <td>
                    Pre-pack
                </td>

                <td>
                    ' .
                    wingsInventoryNumber(
                        $prepackQty
                    ) .
                    '
                </td>

                <td>
                    ' .
                    wingsInventoryMoney(
                        $prepackPrice
                    ) .
                    '
                </td>

            </tr>

        </tbody>

    </table>

</div>

';


/* =========================================================
   12. TOTAL RTEF CARD
   ========================================================= */

echo '

<div
    class="wings-monitor-card
           wings-rtef-card
           wings-inventory-searchable"
    data-search-text="total rtef ready to eat food">

    <div class="wings-monitor-card-title">

        TOTAL RTEF

    </div>


    <div class="wings-monitor-total">

        ' .
        wingsInventoryNumber(
            $rtefQty
        ) .
        '

    </div>


    <div class="wings-rtef-summary">

        <span>
            Total Cost
        </span>

        <strong>
            ' .
            wingsInventoryNumber(
                $rtefQty
            ) .
            '
        </strong>

        <strong>
            ' .
            wingsInventoryMoney(
                $rtefPrice
            ) .
            '
        </strong>

    </div>

</div>

';


/* =========================================================
   13. TOTAL NFI CARD
   ========================================================= */

echo '

<div
    class="
        wings-monitor-card
        wings-nfi-card
        wings-inventory-searchable
    "
    data-search-text="total nfi non food items">

    <div class="wings-monitor-card-title">

        TOTAL NFIs

    </div>


    <div class="wings-monitor-total">

        ' .
        wingsInventoryNumber(
            $totalNfiQty
        ) .
        '

    </div>


    <div class="wings-nfi-scroll">


        <table class="wings-monitor-table">

            <thead>

                <tr>

                    <th>
                        Details
                    </th>

                    <th>
                        Quantity
                    </th>

                    <th>
                        Total Price
                    </th>

                </tr>

            </thead>


            <tbody>

';


/* =========================================================
   14. NFI DETAIL ROWS
   ========================================================= */

if (
    count($nfiRows) > 0
) {

    foreach (
        $nfiRows as $nfiRow
    ) {

        echo '

            <tr
                class="wings-nfi-search-row"
                data-search-text="' .
                wingsInventoryEscape(
                    strtolower(
                        $nfiRow[
                            "item_name"
                        ]
                    )
                ) .
                '">

                <td>

                    ' .
                    wingsInventoryEscape(
                        $nfiRow[
                            "item_name"
                        ]
                    ) .
                    '

                </td>


                <td>

                    ' .
                    wingsInventoryNumber(
                        $nfiRow[
                            "quantity"
                        ]
                    ) .
                    '

                </td>


                <td>

                    ' .
                    wingsInventoryMoney(
                        $nfiRow[
                            "total_price"
                        ]
                    ) .
                    '

                </td>

            </tr>

        ';

    }

} else {

    echo '

        <tr>

            <td colspan="3"
                style="
                    padding:12px 3px;
                    text-align:center;
                    color:#999999;
                ">

                No NFI inventory available.

            </td>

        </tr>

    ';

}


echo '

            </tbody>

        </table>

    </div>

</div>

';


/* =========================================================
   15. NEARING EXPIRY CARD
   ========================================================= */

$nearTotal =
    $nearFfpQty +
    $nearRtefQty +
    $nearNfiQty;


echo '

<div
    class="
        wings-monitor-card
        wings-inventory-searchable
    "
    data-search-text="nearing expiry ffp rtef nfi">

    <div class="wings-monitor-card-title">

        NEARING EXPIRY

    </div>


    <div class="
        wings-monitor-total
        red
    ">

        ' .
        wingsInventoryNumber(
            $nearTotal
        ) .
        '

    </div>


    <table class="
        wings-monitor-table
        wings-near-table
    ">

        <tbody>


            <tr>

                <td>
                    FFPs
                </td>

                <td>

                    ' .
                    wingsInventoryNumber(
                        $nearFfpQty
                    ) .
                    '

                </td>

                <td>
                    —
                </td>

            </tr>


            <tr>

                <td>
                    RTEF
                </td>

                <td>

                    ' .
                    wingsInventoryNumber(
                        $nearRtefQty
                    ) .
                    '

                </td>

                <td>
                    —
                </td>

            </tr>


            <tr>

                <td>
                    NFIs
                </td>

                <td>

                    ' .
                    wingsInventoryNumber(
                        $nearNfiQty
                    ) .
                    '

                </td>

                <td>
                    —
                </td>

            </tr>


        </tbody>

    </table>

</div>

';


/* =========================================================
   16. CLOSE MAIN PANEL
   ========================================================= */

echo <<<'HTML'

</div>


<script>

(function () {

    "use strict";


    var search =
        document.getElementById(
            "wingsInventorySearch"
        );


    if (!search) {

        return;

    }


    search.addEventListener(

        "input",

        function () {


            var keyword =
                String(
                    search.value || ""
                )
                .trim()
                .toLowerCase();


            /*
             * Search individual NFI rows.
             */

            document
                .querySelectorAll(
                    "#wingsInventoryMonitoring " +
                    ".wings-nfi-search-row"
                )
                .forEach(

                    function (row) {


                        var text =
                            String(
                                row.getAttribute(
                                    "data-search-text"
                                ) || ""
                            )
                            .toLowerCase();


                        row.classList.toggle(

                            "wings-search-hidden",

                            (
                                keyword &&
                                text.indexOf(
                                    keyword
                                ) === -1
                            )

                        );

                    }

                );


            /*
             * FFP/RTEF/Nearing Expiry cards remain available
             * when search is empty. When searching, hide a
             * summary card only if it clearly does not match.
             */

            document
                .querySelectorAll(
                    "#wingsInventoryMonitoring " +
                    ".wings-inventory-searchable"
                )
                .forEach(

                    function (card) {


                        if (
                            card.classList.contains(
                                "wings-nfi-card"
                            )
                        ) {

                            /*
                             * Keep NFI card visible because
                             * its individual items are filtered.
                             */

                            card.classList.remove(
                                "wings-search-hidden"
                            );

                            return;

                        }


                        var text =
                            String(
                                card.getAttribute(
                                    "data-search-text"
                                ) || ""
                            )
                            .toLowerCase();


                        card.classList.toggle(

                            "wings-search-hidden",

                            (
                                keyword &&
                                text.indexOf(
                                    keyword
                                ) === -1
                            )

                        );

                    }

                );

        }

    );

})();

</script>

HTML;
		;
		
	}


	// code snippet - Procument Dashboard
	function event_63987(  ) {
		
		/* =========================================================
   WINGS PROCUREMENT DASHBOARD
   COMPLETE UPDATED VERSION

   IMPORTANT FILTER CHANGE:
   ---------------------------------------------------------
   NO FILTER USES URL NAVIGATION ANYMORE.

   This prevents:
       Procurement Dashboard
           ↓ click filter
       Executive Dashboard

   ALL FILTERING IS DONE IN JAVASCRIPT.

   FILTERS:
   ---------------------------------------------------------
   All Categories ▼
       All Categories
       Sort by Status
       Sort by Reference Number
       Sort by Date - Newest
       Sort by Date - Oldest

   Raw Materials ▼
       Food raw materials such as:
       Canned Cornedbeef
       Canned Sardines
       Canned Tuna
       Coffee
       Chocomalt
       Rice
       etc.

   Pre-packed RTEF

   Pre-packed FFPs

   Non-Food Items ▼

   STATUS / ACTION:
   ---------------------------------------------------------
   Pending                 -> Approve
   Approved                -> Convert to PO
   Converted to PO         -> Approve
   Ongoing Delivery        -> no button
   Delivered               -> no button

   FILTER MESSAGE:
   ---------------------------------------------------------
   Filtered by:
   Pre-packed RTEF
   10 Items found
   Clear filter

   DO NOT ADD <?php OR ?>
   ========================================================= */


/* =========================================================
   1. HELPERS
   ========================================================= */

if (!function_exists("procDashHtml")) {

    function procDashHtml($value)
    {
        return htmlspecialchars(
            (string)$value,
            ENT_QUOTES,
            "UTF-8"
        );
    }
}


if (!function_exists("procDashOne")) {

    function procDashOne($sql)
    {
        $rs = DB::Query($sql);

        if (!$rs) {
            return array();
        }

        $row = $rs->fetchAssoc();

        return $row
            ? $row
            : array();
    }
}


if (!function_exists("procDashActionUrl")) {

    function procDashActionUrl(
        $template,
        $id
    ) {

        return str_replace(
            "{ID}",
            intval($id),
            $template
        );
    }
}



/* =========================================================
   2. WORKFLOW ACTION URLS

   Change these only if your actual approval/conversion
   pages use different URLs.
   ========================================================= */

$PROC_PR_APPROVE_URL =
    "purchaserequest_view.php?editid1={ID}";


$PROC_CONVERT_TO_PO_URL =
    "purchaseorder_add.php?pr_id={ID}";


$PROC_PO_APPROVE_URL =
    "purchaseorder_view.php?editid1={ID}";



/* =========================================================
   3. DEFAULT DATE RANGE
   ========================================================= */

$currentYear =
    date("Y");


$fromDate =
    $currentYear . "-01-01";


$toDate =
    $currentYear . "-12-31";



/* =========================================================
   4. RAW MATERIAL PARENTS

   FOOD RAW MATERIALS:
       category_id         = 1
       subcategory_id      = 8
       item_classification = RAW_MATERIAL

   We show parent/generic items only.

   Example:
       Canned Cornedbeef

   Child brands still match the parent:
       Cornedbeef, 555
       Cornedbeef, Bongga
   ========================================================= */

$rawMaterials =
    array();


$rsRawMaterials = DB::Query("

    SELECT

        id,
        name

    FROM
        item

    WHERE

        category_id = 1

        AND
        subcategory_id = 8

        AND
        item_classification = 'RAW_MATERIAL'

        AND
        parent_item_id IS NULL

        AND
        TRIM(
            COALESCE(
                name,
                ''
            )
        ) <> ''

        AND
        UPPER(
            COALESCE(
                status,
                ''
            )
        ) = 'APPROVED'

    ORDER BY

        name

");


if ($rsRawMaterials) {

    while (
        $raw =
            $rsRawMaterials->fetchAssoc()
    ) {

        $rawMaterials[] =
            $raw;
    }
}



/* =========================================================
   5. NON FOOD ITEM PARENTS
   ========================================================= */

$nfiItems =
    array();


$rsNfi = DB::Query("

    SELECT

        id,
        name

    FROM
        item

    WHERE

        category_id = 2

        AND
        parent_item_id IS NULL

        AND
        TRIM(
            COALESCE(
                name,
                ''
            )
        ) <> ''

        AND
        UPPER(
            COALESCE(
                status,
                ''
            )
        ) = 'APPROVED'

    ORDER BY

        name

");


if ($rsNfi) {

    while (
        $nfi =
            $rsNfi->fetchAssoc()
    ) {

        $nfiItems[] =
            $nfi;
    }
}



/* =========================================================
   6. DELIVERY AGGREGATE

   PRIORITY:
   1. po_receiving
   2. qa_incoming_goods fallback

   qa_incoming_goods.source_transaction_id corresponds
   to the Purchase Order ID for PO_RECEIVING records.
   ========================================================= */

$deliveryAggregateSql = "

    SELECT

        ordered.purchase_order_id,

        ordered.ordered_qty,

        CASE

            WHEN
                COALESCE(
                    actual_receiving.received_qty,
                    0
                ) > 0

            THEN
                actual_receiving.received_qty

            ELSE
                COALESCE(
                    qa_receiving.received_qty,
                    0
                )

        END AS received_qty


    FROM
    (

        SELECT

            purchase_order_id,

            SUM(
                COALESCE(
                    quantity,
                    0
                )
            ) AS ordered_qty

        FROM
            purchaseorderdetail

        WHERE
            purchase_order_id IS NOT NULL

        GROUP BY
            purchase_order_id

    ) ordered


    LEFT JOIN
    (

        SELECT

            pod.purchase_order_id,

            SUM(
                COALESCE(
                    prd.received_qty,
                    0
                )
            ) AS received_qty

        FROM
            po_receiving_detail prd

        INNER JOIN
            po_receiving pr

            ON
            pr.id =
            prd.po_receiving_id

        INNER JOIN
            purchaseorderdetail pod

            ON
            pod.id =
            prd.purchase_order_detail_id

        WHERE

            UPPER(
                COALESCE(
                    pr.status,
                    ''
                )
            )

            IN
            (
                'CHECKED',
                'RECEIVED'
            )

            AND

            COALESCE(
                prd.received_qty,
                0
            ) > 0

        GROUP BY

            pod.purchase_order_id

    ) actual_receiving

        ON
        actual_receiving.purchase_order_id =
        ordered.purchase_order_id


    LEFT JOIN
    (

        SELECT

            q.source_transaction_id
                AS purchase_order_id,

            SUM(
                COALESCE(
                    q.delivered_quantity,
                    0
                )
            ) AS received_qty

        FROM
            qa_incoming_goods q

        WHERE

            q.source_transaction_type =
            'PO_RECEIVING'

            AND

            q.source_transaction_id IS NOT NULL

            AND

            UPPER(
                COALESCE(
                    q.approval_status,
                    ''
                )
            ) <> 'CANCELLED'

            AND

            COALESCE(
                q.delivered_quantity,
                0
            ) > 0

        GROUP BY

            q.source_transaction_id

    ) qa_receiving

        ON
        qa_receiving.purchase_order_id =
        ordered.purchase_order_id

";



/* =========================================================
   7. KPI - PR SUBMITTED
   ========================================================= */

$row =
    procDashOne("

        SELECT

            COUNT(*) AS total

        FROM
            purchaserequest

        WHERE

            DATE(
                COALESCE(
                    date,
                    createdAt,
                    updatedAt
                )
            )

            BETWEEN

                '" . $fromDate . "'

            AND

                '" . $toDate . "'

    ");


$prSubmitted =
    isset($row["total"])
        ? intval($row["total"])
        : 0;



/* =========================================================
   8. KPI - PR CONVERTED
   ========================================================= */

$row =
    procDashOne("

        SELECT

            COUNT(*) AS total

        FROM
            purchaserequest

        WHERE

            po_status IN
            (
                'CONVERTED_TO_PO',
                'PARTIAL_PO'
            )

            AND

            DATE(
                COALESCE(
                    date,
                    createdAt,
                    updatedAt
                )
            )

            BETWEEN

                '" . $fromDate . "'

            AND

                '" . $toDate . "'

    ");


$prConverted =
    isset($row["total"])
        ? intval($row["total"])
        : 0;



/* =========================================================
   9. KPI - ONGOING DELIVERY
   ========================================================= */

$row =
    procDashOne("

        SELECT

            COUNT(*) AS total

        FROM
            purchaseorder po

        INNER JOIN
        (

            "
            . $deliveryAggregateSql
            . "

        ) d

            ON
            d.purchase_order_id =
            po.id

        WHERE

            COALESCE(
                d.received_qty,
                0
            ) > 0

            AND

            COALESCE(
                d.received_qty,
                0
            )

            <

            COALESCE(
                d.ordered_qty,
                0
            )

            AND

            DATE(
                COALESCE(
                    po.date,
                    po.ord_date,
                    po.createdAt
                )
            )

            BETWEEN

                '" . $fromDate . "'

            AND

                '" . $toDate . "'

    ");


$poOngoing =
    isset($row["total"])
        ? intval($row["total"])
        : 0;



/* =========================================================
   10. KPI - DELIVERED
   ========================================================= */

$row =
    procDashOne("

        SELECT

            COUNT(*) AS total

        FROM
            purchaseorder po

        INNER JOIN
        (

            "
            . $deliveryAggregateSql
            . "

        ) d

            ON
            d.purchase_order_id =
            po.id

        WHERE

            COALESCE(
                d.ordered_qty,
                0
            ) > 0

            AND

            COALESCE(
                d.received_qty,
                0
            )

            >=

            COALESCE(
                d.ordered_qty,
                0
            )

            AND

            DATE(
                COALESCE(
                    po.date,
                    po.ord_date,
                    po.createdAt
                )
            )

            BETWEEN

                '" . $fromDate . "'

            AND

                '" . $toDate . "'

    ");


$poDelivered =
    isset($row["total"])
        ? intval($row["total"])
        : 0;



/* =========================================================
   11. CONVERSION RATE
   ========================================================= */

$conversionRate =
    0;


if ($prSubmitted > 0) {

    $conversionRate =
        round(
            (
                $prConverted
                /
                $prSubmitted
            )
            * 100
        );
}



/* =========================================================
   12. PR ITEM FILTER METADATA

   This does NOT filter SQL records.

   Instead, it marks each dashboard row so JavaScript
   can filter WITHOUT navigating away.
   ========================================================= */

$prItemMetaSql = "

    SELECT

        prd.pr_id,

        MAX(

            CASE

                WHEN
                    i.category_id = 1

                    AND
                    i.subcategory_id = 8

                    AND
                    i.item_classification =
                    'RAW_MATERIAL'

                THEN 1

                ELSE 0

            END

        ) AS has_raw,


        GROUP_CONCAT(

            DISTINCT

            CASE

                WHEN
                    i.category_id = 1

                    AND
                    i.subcategory_id = 8

                    AND
                    i.item_classification =
                    'RAW_MATERIAL'

                THEN

                    COALESCE(
                        NULLIF(
                            i.parent_item_id,
                            0
                        ),
                        i.id
                    )

                ELSE NULL

            END

        ) AS raw_parent_ids,


        MAX(

            CASE

                WHEN
                    i.food_classification_id = 2

                THEN 1

                ELSE 0

            END

        ) AS has_rtef,


        MAX(

            CASE

                WHEN
                    i.food_classification_id = 3

                THEN 1

                ELSE 0

            END

        ) AS has_prepack_ffp,


        MAX(

            CASE

                WHEN
                    i.category_id = 2

                THEN 1

                ELSE 0

            END

        ) AS has_nfi,


        GROUP_CONCAT(

            DISTINCT

            CASE

                WHEN
                    i.category_id = 2

                THEN

                    COALESCE(
                        NULLIF(
                            i.parent_item_id,
                            0
                        ),
                        i.id
                    )

                ELSE NULL

            END

        ) AS nfi_parent_ids


    FROM
        purchaserequestdetail prd

    LEFT JOIN
        item i

        ON
        i.id =
        prd.item_id

    GROUP BY

        prd.pr_id

";



/* =========================================================
   13. PO ITEM FILTER METADATA
   ========================================================= */

$poItemMetaSql = "

    SELECT

        pod.purchase_order_id,

        MAX(

            CASE

                WHEN
                    i.category_id = 1

                    AND
                    i.subcategory_id = 8

                    AND
                    i.item_classification =
                    'RAW_MATERIAL'

                THEN 1

                ELSE 0

            END

        ) AS has_raw,


        GROUP_CONCAT(

            DISTINCT

            CASE

                WHEN
                    i.category_id = 1

                    AND
                    i.subcategory_id = 8

                    AND
                    i.item_classification =
                    'RAW_MATERIAL'

                THEN

                    COALESCE(
                        NULLIF(
                            i.parent_item_id,
                            0
                        ),
                        i.id
                    )

                ELSE NULL

            END

        ) AS raw_parent_ids,


        MAX(

            CASE

                WHEN
                    i.food_classification_id = 2

                THEN 1

                ELSE 0

            END

        ) AS has_rtef,


        MAX(

            CASE

                WHEN
                    i.food_classification_id = 3

                THEN 1

                ELSE 0

            END

        ) AS has_prepack_ffp,


        MAX(

            CASE

                WHEN
                    i.category_id = 2

                THEN 1

                ELSE 0

            END

        ) AS has_nfi,


        GROUP_CONCAT(

            DISTINCT

            CASE

                WHEN
                    i.category_id = 2

                THEN

                    COALESCE(
                        NULLIF(
                            i.parent_item_id,
                            0
                        ),
                        i.id
                    )

                ELSE NULL

            END

        ) AS nfi_parent_ids


    FROM
        purchaseorderdetail pod

    LEFT JOIN
        item i

        ON
        i.id =
        COALESCE(
            pod.item_id,
            pod.parent_item_id
        )

    GROUP BY

        pod.purchase_order_id

";



/* =========================================================
   14. TRANSACTION LIST

   IMPORTANT:
   THERE IS NO CATEGORY WHERE CONDITION.

   We load transactions once.

   Browser-side filters hide/show rows instantly.
   ========================================================= */

$sqlTransactions = "

    SELECT

        transactions.*

    FROM
    (

        /* =================================================
           PURCHASE REQUEST
           ================================================= */

        SELECT

            'PR'
                AS record_type,

            pr.id
                AS record_id,

            pr.reference_number,

            DATE(
                COALESCE(
                    pr.date,
                    pr.createdAt,
                    pr.updatedAt
                )
            )
                AS record_date,

            COALESCE(
                pr.approved_file,
                ''
            )
                AS approved_file,

            COALESCE(
                pr.approved_by,
                ''
            )
                AS approved_by,

            COALESCE(
                pr.po_status,
                'NO_PO'
            )
                AS pr_po_status,

            ''
                AS po_status,

            0
                AS ordered_qty,

            0
                AS received_qty,

            COALESCE(
                meta.has_raw,
                0
            )
                AS has_raw,

            COALESCE(
                meta.raw_parent_ids,
                ''
            )
                AS raw_parent_ids,

            COALESCE(
                meta.has_rtef,
                0
            )
                AS has_rtef,

            COALESCE(
                meta.has_prepack_ffp,
                0
            )
                AS has_prepack_ffp,

            COALESCE(
                meta.has_nfi,
                0
            )
                AS has_nfi,

            COALESCE(
                meta.nfi_parent_ids,
                ''
            )
                AS nfi_parent_ids,

            COALESCE(
                pr.purpose,
                ''
            )
                AS description_text,

            ''
                AS supplier_name


        FROM
            purchaserequest pr


        LEFT JOIN
        (

            "
            . $prItemMetaSql
            . "

        ) meta

            ON
            meta.pr_id =
            pr.id


        WHERE

            pr.po_status IN
            (
                'NO_PO',
                'PARTIAL_PO'
            )


        UNION ALL


        /* =================================================
           PURCHASE ORDER
           ================================================= */

        SELECT

            'PO'
                AS record_type,

            po.id
                AS record_id,

            po.reference_number,

            DATE(
                COALESCE(
                    po.date,
                    po.ord_date,
                    po.createdAt
                )
            )
                AS record_date,

            COALESCE(
                parent_pr.approved_file,
                ''
            )
                AS approved_file,

            ''
                AS approved_by,

            ''
                AS pr_po_status,

            COALESCE(
                po.status,
                'Pending'
            )
                AS po_status,

            COALESCE(
                delivery.ordered_qty,
                0
            )
                AS ordered_qty,

            COALESCE(
                delivery.received_qty,
                0
            )
                AS received_qty,

            COALESCE(
                meta.has_raw,
                0
            )
                AS has_raw,

            COALESCE(
                meta.raw_parent_ids,
                ''
            )
                AS raw_parent_ids,

            COALESCE(
                meta.has_rtef,
                0
            )
                AS has_rtef,

            COALESCE(
                meta.has_prepack_ffp,
                0
            )
                AS has_prepack_ffp,

            COALESCE(
                meta.has_nfi,
                0
            )
                AS has_nfi,

            COALESCE(
                meta.nfi_parent_ids,
                ''
            )
                AS nfi_parent_ids,

            COALESCE(
                po.note,
                ''
            )
                AS description_text,

            COALESCE(
                po.supplier_name,
                ''
            )
                AS supplier_name


        FROM
            purchaseorder po


        LEFT JOIN
            purchaserequest parent_pr

            ON
            parent_pr.id =
            po.pr_id


        LEFT JOIN
        (

            "
            . $deliveryAggregateSql
            . "

        ) delivery

            ON
            delivery.purchase_order_id =
            po.id


        LEFT JOIN
        (

            "
            . $poItemMetaSql
            . "

        ) meta

            ON
            meta.purchase_order_id =
            po.id

    ) transactions


    ORDER BY

        transactions.record_date DESC,

        transactions.record_id DESC

    LIMIT 3000

";


$rsTransactions =
    DB::Query(
        $sqlTransactions
    );



/* =========================================================
   15. BUILD TABLE
   ========================================================= */

$tableRows =
    "";


$originalIndex =
    0;


if ($rsTransactions) {

    while (
        $transaction =
            $rsTransactions->fetchAssoc()
    ) {

        $originalIndex++;


        $recordType =
            strtoupper(
                trim(
                    $transaction["record_type"]
                )
            );


        $recordId =
            intval(
                $transaction["record_id"]
            );


        $reference =
            trim(
                $transaction["reference_number"]
            );


        $recordDate =
            trim(
                $transaction["record_date"]
            );


        $displayDate =
            "-";


        if ($recordDate !== "") {

            $timestamp =
                strtotime(
                    $recordDate
                );


            if ($timestamp !== false) {

                $displayDate =
                    date(
                        "n/j/Y",
                        $timestamp
                    );
            }
        }



        /* =================================================
           STATUS + ACTION
           ================================================= */

        $displayStatus =
            "";

        $statusClass =
            "";

        $actionHtml =
            "";


        if ($recordType === "PR") {

            $approvedBy =
                trim(
                    $transaction["approved_by"]
                );


            $prPoStatus =
                strtoupper(
                    trim(
                        $transaction["pr_po_status"]
                    )
                );


            $isApproved =

                (
                    $approvedBy !==
                    ""
                )

                ||

                (
                    $prPoStatus ===
                    "PARTIAL_PO"
                );


            /* =============================================
               PENDING
               ============================================= */

            if (!$isApproved) {

                $displayStatus =
                    "Pending";


                $statusClass =
                    "proc-status-pending";


                $actionUrl =
                    procDashActionUrl(
                        $PROC_PR_APPROVE_URL,
                        $recordId
                    );


                $actionHtml = "

                    <a
                        href='"
                        . procDashHtml(
                            $actionUrl
                        )
                        . "'

                        class='
                            proc-action-button
                            proc-action-approve
                        '
                    >

                        Approve

                    </a>

                ";
            }


            /* =============================================
               APPROVED
               ============================================= */

            else {

                $displayStatus =
                    "Approved";


                $statusClass =
                    "proc-status-approved";


                $actionUrl =
                    procDashActionUrl(
                        $PROC_CONVERT_TO_PO_URL,
                        $recordId
                    );


                $actionHtml = "

                    <a
                        href='"
                        . procDashHtml(
                            $actionUrl
                        )
                        . "'

                        class='
                            proc-action-button
                            proc-action-convert
                        '
                    >

                        Convert to PO

                    </a>

                ";
            }

        } else {


            $orderedQty =
                floatval(
                    $transaction["ordered_qty"]
                );


            $receivedQty =
                floatval(
                    $transaction["received_qty"]
                );


            /* =============================================
               DELIVERED
               ============================================= */

            if (

                $orderedQty > 0

                &&

                $receivedQty >=
                $orderedQty

            ) {

                $displayStatus =
                    "Delivered";


                $statusClass =
                    "proc-status-delivered";


                $actionHtml =
                    "";
            }


            /* =============================================
               ONGOING DELIVERY
               ============================================= */

            elseif (
                $receivedQty > 0
            ) {

                $displayStatus =
                    "Ongoing Delivery";


                $statusClass =
                    "proc-status-ongoing";


                $actionHtml =
                    "";
            }


            /* =============================================
               CONVERTED TO PO
               ============================================= */

            else {

                $displayStatus =
                    "Converted to PO";


                $statusClass =
                    "proc-status-converted";


                $actionUrl =
                    procDashActionUrl(
                        $PROC_PO_APPROVE_URL,
                        $recordId
                    );


                $actionHtml = "

                    <a
                        href='"
                        . procDashHtml(
                            $actionUrl
                        )
                        . "'

                        class='
                            proc-action-button
                            proc-action-approve
                        '
                    >

                        Approve

                    </a>

                ";
            }
        }



        /* =================================================
           LINKS
           ================================================= */

        if ($recordType === "PR") {

            $viewUrl =
                "purchaserequest_view.php"
                . "?editid1="
                . $recordId;


            $editUrl =
                "purchaserequest_edit.php"
                . "?editid1="
                . $recordId;

        } else {

            $viewUrl =
                "purchaseorder_view.php"
                . "?editid1="
                . $recordId;


            $editUrl =
                "purchaseorder_edit.php"
                . "?editid1="
                . $recordId;
        }



        /* =================================================
           APPROVED FILE
           ================================================= */

        $approvedFileHtml =
            "<span class='proc-empty'>—</span>";


        $approvedRaw =
            trim(
                $transaction["approved_file"]
            );


        if ($approvedRaw !== "") {

            $approvedPath =
                "";


            $decoded =
                json_decode(
                    $approvedRaw,
                    true
                );


            if (

                is_array($decoded)

                &&

                isset(
                    $decoded[0]["name"]
                )

            ) {

                $approvedPath =
                    $decoded[0]["name"];

            } elseif (

                preg_match(

                    '/"name"\s*:\s*"([^"]+)"/',

                    $approvedRaw,

                    $match

                )

            ) {

                $approvedPath =
                    str_replace(
                        '\\/',
                        '/',
                        $match[1]
                    );
            }


            if ($approvedPath !== "") {

                $approvedFileHtml = "

                    <a
                        href='"
                        . procDashHtml(
                            $approvedPath
                        )
                        . "'

                        target='_blank'

                        class='proc-approved-file'
                    >

                        Approved File

                    </a>

                ";
            }
        }



        /* =================================================
           FILTER METADATA
           ================================================= */

        $hasRaw =
            intval(
                $transaction["has_raw"]
            );


        $hasRtef =
            intval(
                $transaction["has_rtef"]
            );


        $hasFfp =
            intval(
                $transaction["has_prepack_ffp"]
            );


        $hasNfi =
            intval(
                $transaction["has_nfi"]
            );


        $rawIds =
            trim(
                $transaction["raw_parent_ids"]
            );


        $nfiIds =
            trim(
                $transaction["nfi_parent_ids"]
            );


        /*
         * Pad IDs with commas.
         *
         * Example:
         *
         * ,20,22,
         *
         * prevents:
         *
         * 2 matching 22 accidentally.
         */

        $rawIdsPadded =
            $rawIds !== ""
                ? "," . $rawIds . ","
                : ",";


        $nfiIdsPadded =
            $nfiIds !== ""
                ? "," . $nfiIds . ","
                : ",";



        /* =================================================
           SEARCH DATA
           ================================================= */

        $searchData =
            strtolower(

                $displayStatus
                . " "

                . $reference
                . " "

                . $displayDate
                . " "

                . $transaction["description_text"]
                . " "

                . $transaction["supplier_name"]

            );



        /* =================================================
           STATUS SORT ORDER
           ================================================= */

        $statusSort =
            99;


        switch ($displayStatus) {

            case "Pending":
                $statusSort = 1;
                break;

            case "Approved":
                $statusSort = 2;
                break;

            case "Converted to PO":
                $statusSort = 3;
                break;

            case "Ongoing Delivery":
                $statusSort = 4;
                break;

            case "Delivered":
                $statusSort = 5;
                break;
        }



        /* =================================================
           ROW
           ================================================= */

        $tableRows .= "

            <tr

                class='proc-dashboard-row'

                data-original='"
                . $originalIndex
                . "'

                data-status-sort='"
                . $statusSort
                . "'

                data-status='"
                . procDashHtml(
                    strtolower(
                        $displayStatus
                    )
                )
                . "'

                data-reference='"
                . procDashHtml(
                    strtolower(
                        $reference
                    )
                )
                . "'

                data-date='"
                . procDashHtml(
                    $recordDate
                )
                . "'

                data-search='"
                . procDashHtml(
                    $searchData
                )
                . "'

                data-has-raw='"
                . $hasRaw
                . "'

                data-raw-ids='"
                . procDashHtml(
                    $rawIdsPadded
                )
                . "'

                data-rtef='"
                . $hasRtef
                . "'

                data-ffp='"
                . $hasFfp
                . "'

                data-has-nfi='"
                . $hasNfi
                . "'

                data-nfi-ids='"
                . procDashHtml(
                    $nfiIdsPadded
                )
                . "'

            >


                <td class='proc-checkbox-cell'>

                    <input
                        type='checkbox'
                        class='proc-row-checkbox'
                    >

                </td>


                <td class='proc-icon-cell'>

                    <a
                        href='"
                        . procDashHtml(
                            $viewUrl
                        )
                        . "'

                        class='
                            proc-small-icon
                            proc-view-icon
                        '

                        title='View'
                    >

                        <svg
                            viewBox='0 0 24 24'
                            fill='none'
                            stroke='currentColor'
                            stroke-width='1.8'
                        >

                            <path
                                d='M2 12s3.5-6 10-6 10 6 10 6-3.5 6-10 6S2 12 2 12z'
                            />

                            <circle
                                cx='12'
                                cy='12'
                                r='2.6'
                            />

                        </svg>

                    </a>

                </td>


                <td class='proc-icon-cell'>

                    <a
                        href='"
                        . procDashHtml(
                            $editUrl
                        )
                        . "'

                        class='
                            proc-small-icon
                            proc-edit-icon
                        '

                        title='Edit'
                    >

                        <svg
                            viewBox='0 0 24 24'
                            fill='none'
                            stroke='currentColor'
                            stroke-width='1.8'
                        >

                            <path
                                d='M12 20h9'
                            />

                            <path
                                d='M16.5 3.5a2.1 2.1 0 013 3L8 18l-4 1 1-4z'
                            />

                        </svg>

                    </a>

                </td>


                <td class='proc-icon-cell'>

                    <a
                        href='"
                        . procDashHtml(
                            $viewUrl
                        )
                        . "'

                        class='
                            proc-small-icon
                            proc-doc-icon
                        '

                        title='Document'
                    >

                        <svg
                            viewBox='0 0 24 24'
                            fill='none'
                            stroke='currentColor'
                            stroke-width='1.8'
                        >

                            <rect
                                x='6'
                                y='4'
                                width='12'
                                height='16'
                            />

                            <path d='M9 8h6'/>
                            <path d='M9 12h6'/>
                            <path d='M9 16h4'/>

                        </svg>

                    </a>

                </td>


                <td class='proc-action-cell'>

                    "
                    . $actionHtml
                    . "

                </td>


                <td class='proc-status-cell'>

                    <span
                        class='
                            proc-status
                            "
                            . $statusClass
                            . "
                        '
                    >

                        "
                        . procDashHtml(
                            $displayStatus
                        )
                        . "

                    </span>

                </td>


                <td class='proc-reference-cell'>

                    "
                    . procDashHtml(
                        $reference
                    )
                    . "

                </td>


                <td class='proc-date-cell'>

                    "
                    . procDashHtml(
                        $displayDate
                    )
                    . "

                </td>


                <td class='proc-file-cell'>

                    "
                    . $approvedFileHtml
                    . "

                </td>


            </tr>

        ";
    }
}



if ($tableRows === "") {

    $tableRows = "

        <tr>

            <td colspan='9'>

                <div class='proc-no-data'>

                    No procurement records found.

                </div>

            </td>

        </tr>

    ";
}



/* =========================================================
   16. RAW MATERIAL OPTIONS
   ========================================================= */

$rawOptions = "

    <option value=''>
        Raw Materials
    </option>

";


foreach (
    $rawMaterials
    as
    $raw
) {

    $rawOptions .= "

        <option
            value='"
            . intval(
                $raw["id"]
            )
            . "'
        >

            "
            . procDashHtml(
                $raw["name"]
            )
            . "

        </option>

    ";
}



/* =========================================================
   17. NFI OPTIONS
   ========================================================= */

$nfiOptions = "

    <option value=''>
        Non-Food Items
    </option>

";


foreach (
    $nfiItems
    as
    $nfi
) {

    $nfiOptions .= "

        <option
            value='"
            . intval(
                $nfi["id"]
            )
            . "'
        >

            "
            . procDashHtml(
                $nfi["name"]
            )
            . "

        </option>

    ";
}



/* =========================================================
   18. FORMAT KPI
   ========================================================= */

$prSubmittedDisplay =
    number_format(
        $prSubmitted
    );


$prConvertedDisplay =
    number_format(
        $prConverted
    );


$poOngoingDisplay =
    number_format(
        $poOngoing
    );


$poDeliveredDisplay =
    number_format(
        $poDelivered
    );



/* =========================================================
   19. OUTPUT
   ========================================================= */

echo <<<HTML


<style>


/* =========================================================
   ROOT
   ========================================================= */

.wings-proc-dashboard {

    width:100%;

    box-sizing:border-box;

    padding:
        14px
        5px
        22px
        5px;

    font-family:
        Arial,
        Helvetica,
        sans-serif;

    color:#333333;

}


.wings-proc-dashboard * {

    box-sizing:border-box;

}



/* =========================================================
   TOP ACTIONS
   ========================================================= */

.proc-top-actions {

    display:flex;

    justify-content:flex-end;

    align-items:center;

    gap:13px;

    margin:
        12px
        12px
        17px
        0;

}


.proc-top-btn {

    height:35px;

    display:inline-flex;

    align-items:center;

    justify-content:center;

    gap:7px;

    padding:
        0
        14px;

    border-radius:6px;

    font-size:12px;

    text-decoration:none !important;

}


.proc-export-btn {

    color:#333333 !important;

    background:#ffffff;

    border:1px solid #bdbdbd;

}


.proc-add-btn {

    color:#ffffff !important;

    background:#2e3192;

    border:1px solid #2e3192;

}



/* =========================================================
   KPI
   ========================================================= */

.proc-kpi-grid {

    display:grid;

    grid-template-columns:
        repeat(
            4,
            minmax(
                0,
                1fr
            )
        );

    gap:15px;

    margin-bottom:13px;

}


.proc-kpi-card {

    min-height:82px;

    display:flex;

    gap:11px;

    padding:
        12px
        13px;

    background:#ffffff;

    border:1px solid #dedede;

    border-radius:8px;

    box-shadow:
        0
        1px
        3px
        rgba(
            0,
            0,
            0,
            .04
        );

}


.proc-kpi-icon {

    width:29px;

    height:29px;

    min-width:29px;

    display:flex;

    align-items:center;

    justify-content:center;

    border-radius:3px;

}


.proc-kpi-icon svg {

    width:17px;

    height:17px;

}


.proc-kpi-green {

    color:#56b862;

    background:#effaf1;

}


.proc-kpi-purple {

    color:#5456ba;

    background:#efefff;

}


.proc-kpi-orange {

    color:#ef9748;

    background:#fff3e9;

}


.proc-kpi-blue {

    color:#429cff;

    background:#edf7ff;

}


.proc-kpi-title {

    color:#777777;

    font-size:9px;

    margin-bottom:8px;

}


.proc-kpi-value {

    color:#222222;

    font-size:17px;

    line-height:1;

    font-weight:700;

}


.proc-kpi-note {

    margin-top:8px;

    color:#9a9a9a;

    font-size:7px;

}


.proc-green-text {

    color:#53b75d;

}



/* =========================================================
   FILTER HEADER
   ========================================================= */

.proc-filter-heading-row {

    display:flex;

    align-items:center;

    justify-content:space-between;

    gap:20px;

    margin:
        0
        0
        10px
        0;

}


.proc-filter-heading {

    color:#222222;

    font-size:11px;

    font-weight:700;

}


.proc-date-filter {

    display:flex;

    align-items:center;

    gap:6px;

}


.proc-date-label {

    color:#777777;

    font-size:9px;

}


.proc-date-input {

    height:29px;

    border:1px solid #cccccc;

    border-radius:5px;

    background:#ffffff;

    padding:
        0
        7px;

    font-size:9px;

    color:#444444;

}



/* =========================================================
   FILTER BUTTON ROW
   ========================================================= */

.proc-filter-controls {

    display:flex;

    align-items:center;

    gap:7px;

    flex-wrap:wrap;

    margin-bottom:9px;

}



/* =========================================================
   ALL CATEGORIES / SORT DROPDOWN
   ========================================================= */

.proc-sort-wrap,
.proc-select-wrap {

    position:relative;

    height:38px;

    border:
        1px
        solid
        #bdbdbd;

    border-radius:6px;

    background:#ffffff;

    display:flex;

    align-items:center;

}


.proc-sort-wrap {

    width:125px;

}


.proc-select-wrap {

    width:150px;

}


.proc-filter-select {

    width:100%;

    height:36px;

    padding:
        0
        26px
        0
        30px;

    border:0 !important;

    outline:0 !important;

    background:transparent !important;

    box-shadow:none !important;

    color:#676767;

    font-family:
        Arial,
        Helvetica,
        sans-serif;

    font-size:9px;

    cursor:pointer;

}


.proc-filter-left-icon {

    position:absolute;

    left:10px;

    top:50%;

    transform:
        translateY(-50%);

    width:12px;

    height:12px;

    color:#747474;

    pointer-events:none;

}


.proc-filter-left-icon svg {

    width:12px;

    height:12px;

}


.proc-filter-control-active {

    border-color:#2e3192;

    background:#f3f3ff;

}


.proc-filter-control-active
.proc-filter-select {

    color:#2e3192;

    font-weight:600;

}



/* =========================================================
   RTEF / FFP BUTTONS
   ========================================================= */

.proc-category-button {

    height:38px;

    min-width:115px;

    padding:
        0
        13px;

    display:inline-flex;

    align-items:center;

    justify-content:center;

    gap:6px;

    border:
        1px
        solid
        #bdbdbd;

    border-radius:6px;

    background:#ffffff;

    color:#686868;

    font-size:9px;

    cursor:pointer;

}


.proc-category-button:hover {

    border-color:#2e3192;

    color:#2e3192;

}


.proc-category-button.active {

    border-color:#2e3192;

    background:#2e3192;

    color:#ffffff;

}


.proc-category-button svg {

    width:12px;

    height:12px;

}



/* =========================================================
   FILTERED BY BAR
   ========================================================= */

.proc-filtered-bar {

    min-height:28px;

    display:none;

    align-items:center;

    gap:9px;

    margin-bottom:7px;

    color:#686868;

    font-size:9px;

}


.proc-filtered-bar.visible {

    display:flex;

}


.proc-filter-check {

    width:14px;

    height:14px;

    display:inline-flex;

    align-items:center;

    justify-content:center;

    border:
        1px
        solid
        #50b65c;

    border-radius:50%;

    color:#50b65c;

    font-size:9px;

}


.proc-filtered-name {

    color:#333333;

    font-weight:700;

}


.proc-filtered-count {

    color:#8b8b8b;

}


.proc-clear-filter {

    padding:0;

    border:0;

    background:transparent;

    color:#0878e7;

    font-size:9px;

    font-weight:600;

    cursor:pointer;

}



/* =========================================================
   SEARCH
   ========================================================= */

.proc-search-row {

    display:flex;

    justify-content:flex-end;

    margin-bottom:8px;

}


.proc-search-box {

    width:178px;

    height:28px;

    display:flex;

    align-items:center;

    border:1px solid #aaaaaa;

    border-radius:4px;

    background:#ffffff;

    padding:
        0
        8px;

}


.proc-search-box svg {

    width:11px;

    height:11px;

    color:#2e3192;

}


.proc-search-input {

    width:100%;

    height:25px;

    border:0 !important;

    outline:0 !important;

    background:transparent !important;

    box-shadow:none !important;

    padding-left:6px;

    font-size:9px;

}



/* =========================================================
   TABLE
   ========================================================= */

.proc-table-scroll {

    width:100%;

    overflow-x:auto;

}


.proc-table {

    width:100%;

    min-width:820px;

    border-collapse:separate;

    border-spacing:
        0
        8px;

}


.proc-table thead th {

    height:36px;

    padding:
        0
        9px;

    background:#f6f6f6;

    color:#777777;

    font-size:10px;

    font-weight:400;

    vertical-align:middle;

}


.proc-table thead th:first-child {

    border-radius:
        7px
        0
        0
        7px;

}


.proc-table thead th:last-child {

    border-radius:
        0
        7px
        7px
        0;

}


.proc-table tbody td {

    height:26px;

    padding:
        3px
        9px;

    background:#f9f9f9;

    color:#333333;

    font-size:10px;

    vertical-align:middle;

}


.proc-table tbody
.proc-dashboard-row:hover td {

    background:#f2f2f6;

}


.proc-table tbody td:first-child {

    border-radius:
        7px
        0
        0
        7px;

}


.proc-table tbody td:last-child {

    border-radius:
        0
        7px
        7px
        0;

}


.proc-checkbox-cell {

    width:28px;

}


.proc-icon-cell {

    width:27px;

    padding:
        2px !important;

    text-align:center;

}


.proc-action-cell {

    width:110px;

    text-align:center;

}


.proc-status-cell {

    width:145px;

}


.proc-reference-cell {

    width:150px;

}


.proc-date-cell {

    width:110px;

}


.proc-file-cell {

    width:135px;

}



/* =========================================================
   ICONS
   ========================================================= */

.proc-small-icon {

    width:20px;

    height:20px;

    display:inline-flex;

    align-items:center;

    justify-content:center;

}


.proc-small-icon svg {

    width:13px;

    height:13px;

}


.proc-view-icon {

    color:#5153ce;

}


.proc-edit-icon {

    color:#4fb45a;

}


.proc-doc-icon {

    color:#222222;

}



/* =========================================================
   ACTIONS
   ========================================================= */

.proc-action-button {

    height:22px;

    min-width:72px;

    display:inline-flex;

    align-items:center;

    justify-content:center;

    padding:
        0
        7px;

    border-radius:2px;

    color:#ffffff !important;

    text-decoration:none !important;

    font-size:8px;

}


.proc-action-approve {

    background:#55b85e;

}


.proc-action-convert {

    min-width:88px;

    background:#2e3192;

}



/* =========================================================
   STATUS
   ========================================================= */

.proc-status {

    white-space:nowrap;

    font-size:10px;

}


.proc-status-pending {

    color:#ef6d00;

}


.proc-status-approved {

    color:#53af59;

}


.proc-status-converted {

    color:#2e3192;

}


.proc-status-ongoing {

    color:#e96800;

}


.proc-status-delivered {

    color:#0075ed;

}



/* =========================================================
   APPROVED FILE
   ========================================================= */

.proc-approved-file {

    color:#333333 !important;

    text-decoration:none !important;

}


.proc-empty {

    color:#aaaaaa;

}



/* =========================================================
   FOOTER
   ========================================================= */

.proc-table-footer {

    display:flex;

    justify-content:space-between;

    align-items:center;

    margin-top:15px;

}


.proc-record-count {

    font-size:9px;

    font-weight:600;

}


.proc-page-size {

    height:29px;

    margin-left:8px;

    border:1px solid #c6c6c6;

    border-radius:5px;

    background:#ffffff;

    color:#2e3192;

}


.proc-pagination {

    display:flex;

    gap:5px;

}


.proc-page-btn {

    height:30px;

    border:1px solid #c6c6c6;

    border-radius:5px;

    background:#ffffff;

    padding:
        0
        10px;

    font-size:9px;

}


.proc-current-page {

    background:#2e3192;

    border-color:#2e3192;

    color:#ffffff;

}



/* =========================================================
   RESPONSIVE
   ========================================================= */

@media
(
    max-width:1050px
) {

    .proc-kpi-grid {

        grid-template-columns:
            repeat(
                2,
                1fr
            );

    }

}


@media
(
    max-width:650px
) {

    .proc-kpi-grid {

        grid-template-columns:
            1fr;

    }


    .proc-filter-heading-row {

        align-items:flex-start;

        flex-direction:column;

    }


    .proc-date-filter {

        flex-wrap:wrap;

    }


    .proc-search-box {

        width:100%;

    }


    .proc-search-row {

        justify-content:stretch;

    }

}


</style>



<div

    class="wings-proc-dashboard"

    id="wingsProcDashboard"

>


    <!-- ==================================================
         TOP ACTIONS
         ================================================== -->

    <div class="proc-top-actions">


        <button

            type="button"

            id="procExportButton"

            class="
                proc-top-btn
                proc-export-btn
            "

        >

            ▣

            Export

        </button>


        <a

            href="purchaserequest_add.php"

            class="
                proc-top-btn
                proc-add-btn
            "

        >

            ＋

            Add new

        </a>


    </div>



    <!-- ==================================================
         KPI
         ================================================== -->

    <div class="proc-kpi-grid">


        <div class="proc-kpi-card">

            <div
                class="
                    proc-kpi-icon
                    proc-kpi-green
                "
            >

                <svg
                    viewBox="0 0 24 24"
                    fill="none"
                    stroke="currentColor"
                    stroke-width="1.5"
                >
                    <path d="M6 2h8l4 4v16H6z"/>
                    <path d="M14 2v5h5"/>
                </svg>

            </div>


            <div>

                <div class="proc-kpi-title">

                    PR Submitted

                </div>

                <div class="proc-kpi-value">

                    {$prSubmittedDisplay}

                </div>

                <div class="proc-kpi-note">

                    Purchase requests submitted

                </div>

            </div>

        </div>



        <div class="proc-kpi-card">

            <div
                class="
                    proc-kpi-icon
                    proc-kpi-purple
                "
            >

                <svg
                    viewBox="0 0 24 24"
                    fill="none"
                    stroke="currentColor"
                    stroke-width="1.5"
                >
                    <rect x="3" y="4" width="7" height="16"/>
                    <rect x="14" y="4" width="7" height="16"/>
                    <path d="M10 9h4"/>
                    <path d="M12 7l2 2-2 2"/>
                </svg>

            </div>


            <div>

                <div class="proc-kpi-title">

                    PR Converted to PO

                </div>

                <div class="proc-kpi-value">

                    {$prConvertedDisplay}

                </div>

                <div class="proc-kpi-note">

                    <span class="proc-green-text">
                        {$conversionRate}%
                    </span>

                    of submitted PRs

                </div>

            </div>

        </div>



        <div class="proc-kpi-card">

            <div
                class="
                    proc-kpi-icon
                    proc-kpi-orange
                "
            >

                <svg
                    viewBox="0 0 24 24"
                    fill="none"
                    stroke="currentColor"
                    stroke-width="1.5"
                >
                    <path d="M3 7l9-4 9 4-9 4z"/>
                    <path d="M3 7v10l9 4 9-4V7"/>
                    <path d="M12 11v10"/>
                </svg>

            </div>


            <div>

                <div class="proc-kpi-title">

                    PO with Ongoing Delivery

                </div>

                <div class="proc-kpi-value">

                    {$poOngoingDisplay}

                </div>

                <div class="proc-kpi-note">

                    Partially delivered POs

                </div>

            </div>

        </div>



        <div class="proc-kpi-card">

            <div
                class="
                    proc-kpi-icon
                    proc-kpi-blue
                "
            >

                <svg
                    viewBox="0 0 24 24"
                    fill="none"
                    stroke="currentColor"
                    stroke-width="1.5"
                >
                    <path d="M3 7l9-4 9 4-9 4z"/>
                    <path d="M3 7v10l9 4 9-4V7"/>
                    <path d="M12 11v10"/>
                    <path d="M8 15l2 2 5-5"/>
                </svg>

            </div>


            <div>

                <div class="proc-kpi-title">

                    PO Completely Delivered

                </div>

                <div class="proc-kpi-value">

                    {$poDeliveredDisplay}

                </div>

                <div class="proc-kpi-note">

                    Fully delivered POs

                </div>

            </div>

        </div>


    </div>



    <!-- ==================================================
         FILTER HEADING
         ================================================== -->

    <div class="proc-filter-heading-row">


        <div class="proc-filter-heading">

            Filter by Category

        </div>


        <div class="proc-date-filter">

            <span class="proc-date-label">

                Date Range:

            </span>


            <input

                type="date"

                id="procDateFrom"

                class="proc-date-input"

                value="{$fromDate}"

            >


            <span class="proc-date-label">

                -

            </span>


            <input

                type="date"

                id="procDateTo"

                class="proc-date-input"

                value="{$toDate}"

            >

        </div>


    </div>



    <!-- ==================================================
         FILTER CONTROLS

         NONE OF THESE NAVIGATE AWAY
         ================================================== -->

    <div class="proc-filter-controls">


        <!-- ALL CATEGORIES / SORT -->

        <div
            class="proc-sort-wrap"
            id="procSortWrap"
        >

            <span class="proc-filter-left-icon">

                <svg
                    viewBox="0 0 24 24"
                    fill="none"
                    stroke="currentColor"
                    stroke-width="1.7"
                >
                    <path d="M4 6h16"/>
                    <path d="M4 12h16"/>
                    <path d="M4 18h16"/>
                </svg>

            </span>


            <select
                id="procSortSelect"
                class="proc-filter-select"
            >

                <option value="default">
                    All Categories
                </option>

                <option value="status">
                    Sort by Status
                </option>

                <option value="reference">
                    Sort by Reference Number
                </option>

                <option value="date_desc">
                    Sort by Date - Newest
                </option>

                <option value="date_asc">
                    Sort by Date - Oldest
                </option>

            </select>

        </div>



        <!-- RAW MATERIAL -->

        <div
            class="proc-select-wrap"
            id="procRawWrap"
        >

            <span class="proc-filter-left-icon">

                <svg
                    viewBox="0 0 24 24"
                    fill="none"
                    stroke="currentColor"
                    stroke-width="1.6"
                >
                    <path d="M4 7l8-4 8 4-8 4z"/>
                    <path d="M4 7v10l8 4 8-4V7"/>
                </svg>

            </span>


            <select
                id="procRawSelect"
                class="proc-filter-select"
            >

                {$rawOptions}

            </select>

        </div>



        <!-- RTEF -->

        <button

            type="button"

            id="procRtefButton"

            class="proc-category-button"

        >

            <svg
                viewBox="0 0 24 24"
                fill="none"
                stroke="currentColor"
                stroke-width="1.6"
            >
                <rect
                    x="5"
                    y="4"
                    width="14"
                    height="16"
                />
                <path d="M8 8h8"/>
                <path d="M8 12h8"/>
            </svg>


            Pre-packed RTEF

        </button>



        <!-- PREPACK FFP -->

        <button

            type="button"

            id="procFfpButton"

            class="proc-category-button"

        >

            <svg
                viewBox="0 0 24 24"
                fill="none"
                stroke="currentColor"
                stroke-width="1.6"
            >
                <path d="M4 7l8-4 8 4-8 4z"/>
                <path d="M4 7v10l8 4 8-4V7"/>
            </svg>


            Pre-packed FFPs

        </button>



        <!-- NFI -->

        <div
            class="proc-select-wrap"
            id="procNfiWrap"
        >

            <span class="proc-filter-left-icon">

                <svg
                    viewBox="0 0 24 24"
                    fill="none"
                    stroke="currentColor"
                    stroke-width="1.6"
                >
                    <path d="M5 8h14v11H5z"/>
                    <path d="M8 8V5h8v3"/>
                </svg>

            </span>


            <select
                id="procNfiSelect"
                class="proc-filter-select"
            >

                {$nfiOptions}

            </select>

        </div>


    </div>



    <!-- ==================================================
         FILTERED BY MESSAGE
         ================================================== -->

    <div
        id="procFilteredBar"
        class="proc-filtered-bar"
    >

        <span class="proc-filter-check">

            ✓

        </span>


        <span>

            Filtered by:

        </span>


        <span
            id="procFilteredName"
            class="proc-filtered-name"
        ></span>


        <span
            id="procFilteredCount"
            class="proc-filtered-count"
        ></span>


        <button
            type="button"
            id="procClearFilter"
            class="proc-clear-filter"
        >

            Clear filter

        </button>

    </div>



    <!-- ==================================================
         SEARCH
         ================================================== -->

    <div class="proc-search-row">


        <div class="proc-search-box">

            <svg
                viewBox="0 0 24 24"
                fill="none"
                stroke="currentColor"
                stroke-width="1.8"
            >
                <circle
                    cx="11"
                    cy="11"
                    r="7"
                />
                <path d="M20 20l-4-4"/>
            </svg>


            <input

                type="text"

                id="procSearch"

                class="proc-search-input"

                placeholder="Search"

                autocomplete="off"

            >

        </div>


    </div>



    <!-- ==================================================
         TABLE
         ================================================== -->

    <div class="proc-table-scroll">


        <table
            id="procTable"
            class="proc-table"
        >


            <thead>


                <tr>


                    <th>

                        <input
                            type="checkbox"
                            id="procCheckAll"
                        >

                    </th>


                    <th></th>

                    <th></th>

                    <th></th>

                    <th></th>


                    <th>

                        Status

                    </th>


                    <th>

                        Reference Number

                    </th>


                    <th>

                        Date

                    </th>


                    <th>

                        Approved File

                    </th>


                </tr>


            </thead>


            <tbody>

                {$tableRows}

            </tbody>


        </table>


    </div>



    <!-- ==================================================
         FOOTER
         ================================================== -->

    <div class="proc-table-footer">


        <div>

            <span
                id="procRecordCount"
                class="proc-record-count"
            >

                Displaying records

            </span>


            <select
                id="procPageSize"
                class="proc-page-size"
            >

                <option value="10">
                    10
                </option>

                <option value="25">
                    25
                </option>

                <option value="50">
                    50
                </option>

                <option value="100">
                    100
                </option>

            </select>

        </div>



        <div class="proc-pagination">


            <button
                type="button"
                id="procPrev"
                class="proc-page-btn"
            >

                ‹ Previous

            </button>


            <button
                type="button"
                id="procCurrent"
                class="
                    proc-page-btn
                    proc-current-page
                "
            >

                1

            </button>


            <button
                type="button"
                id="procNext"
                class="proc-page-btn"
            >

                Next ›

            </button>


        </div>


    </div>


</div>



<script>

(function () {


    /* =====================================================
       IMPORTANT

       This script does NOT change window.location when
       applying category filters.

       Therefore the dashboard stays on:

       PROCUREMENT DASHBOARD

       instead of returning to:

       EXECUTIVE DASHBOARD
       ===================================================== */


    var table =
        document.getElementById(
            "procTable"
        );


    if (!table) {

        return;
    }



    var tbody =
        table.querySelector(
            "tbody"
        );


    var rawSelect =
        document.getElementById(
            "procRawSelect"
        );


    var rawWrap =
        document.getElementById(
            "procRawWrap"
        );


    var rtefButton =
        document.getElementById(
            "procRtefButton"
        );


    var ffpButton =
        document.getElementById(
            "procFfpButton"
        );


    var nfiSelect =
        document.getElementById(
            "procNfiSelect"
        );


    var nfiWrap =
        document.getElementById(
            "procNfiWrap"
        );


    var sortSelect =
        document.getElementById(
            "procSortSelect"
        );


    var sortWrap =
        document.getElementById(
            "procSortWrap"
        );


    var searchInput =
        document.getElementById(
            "procSearch"
        );


    var filteredBar =
        document.getElementById(
            "procFilteredBar"
        );


    var filteredName =
        document.getElementById(
            "procFilteredName"
        );


    var filteredCount =
        document.getElementById(
            "procFilteredCount"
        );


    var clearFilterButton =
        document.getElementById(
            "procClearFilter"
        );


    var dateFrom =
        document.getElementById(
            "procDateFrom"
        );


    var dateTo =
        document.getElementById(
            "procDateTo"
        );


    var pageSize =
        document.getElementById(
            "procPageSize"
        );


    var previous =
        document.getElementById(
            "procPrev"
        );


    var next =
        document.getElementById(
            "procNext"
        );


    var current =
        document.getElementById(
            "procCurrent"
        );


    var recordCount =
        document.getElementById(
            "procRecordCount"
        );


    var checkAll =
        document.getElementById(
            "procCheckAll"
        );


    var exportButton =
        document.getElementById(
            "procExportButton"
        );



    /* =====================================================
       FILTER STATE
       ===================================================== */

    var activeCategory =
        "all";


    var activeRawId =
        "";


    var activeNfiId =
        "";


    var activeLabel =
        "";


    var currentPage =
        1;



    /* =====================================================
       ROWS
       ===================================================== */

    function getRows()
    {

        return Array.prototype.slice.call(

            table.querySelectorAll(
                "tbody tr.proc-dashboard-row"
            )

        );
    }



    /* =====================================================
       RESET CATEGORY CONTROL APPEARANCE
       ===================================================== */

    function resetCategoryAppearance()
    {

        rawWrap
            .classList
            .remove(
                "proc-filter-control-active"
            );


        nfiWrap
            .classList
            .remove(
                "proc-filter-control-active"
            );


        rtefButton
            .classList
            .remove(
                "active"
            );


        ffpButton
            .classList
            .remove(
                "active"
            );
    }



    /* =====================================================
       ALL CATEGORIES

       This does NOT reload the page.
       ===================================================== */

    function clearCategoryFilter()
    {

        activeCategory =
            "all";


        activeRawId =
            "";


        activeNfiId =
            "";


        activeLabel =
            "";


        rawSelect.selectedIndex =
            0;


        nfiSelect.selectedIndex =
            0;


        resetCategoryAppearance();


        filteredBar
            .classList
            .remove(
                "visible"
            );


        currentPage =
            1;


        render();
    }



    /* =====================================================
       RAW MATERIAL FILTER
       ===================================================== */

    rawSelect.addEventListener(

        "change",

        function () {


            resetCategoryAppearance();


            /*
             * Selecting Raw Materials header itself
             * filters all raw materials.
             */

            activeCategory =
                "raw";


            activeRawId =
                rawSelect.value;


            activeNfiId =
                "";


            nfiSelect.selectedIndex =
                0;


            activeLabel =

                rawSelect.options[
                    rawSelect.selectedIndex
                ].text;


            rawWrap
                .classList
                .add(
                    "proc-filter-control-active"
                );


            sortSelect.value =
                "default";


            currentPage =
                1;


            render();

        }

    );



    /* =====================================================
       RTEF
       ===================================================== */

    rtefButton.addEventListener(

        "click",

        function () {


            resetCategoryAppearance();


            activeCategory =
                "rtef";


            activeRawId =
                "";


            activeNfiId =
                "";


            rawSelect.selectedIndex =
                0;


            nfiSelect.selectedIndex =
                0;


            activeLabel =
                "Pre-packed RTEF";


            rtefButton
                .classList
                .add(
                    "active"
                );


            sortSelect.value =
                "default";


            currentPage =
                1;


            render();

        }

    );



    /* =====================================================
       PREPACK FFP
       ===================================================== */

    ffpButton.addEventListener(

        "click",

        function () {


            resetCategoryAppearance();


            activeCategory =
                "ffp";


            activeRawId =
                "";


            activeNfiId =
                "";


            rawSelect.selectedIndex =
                0;


            nfiSelect.selectedIndex =
                0;


            activeLabel =
                "Pre-packed FFPs";


            ffpButton
                .classList
                .add(
                    "active"
                );


            sortSelect.value =
                "default";


            currentPage =
                1;


            render();

        }

    );



    /* =====================================================
       NON FOOD ITEMS
       ===================================================== */

    nfiSelect.addEventListener(

        "change",

        function () {


            resetCategoryAppearance();


            activeCategory =
                "nfi";


            activeNfiId =
                nfiSelect.value;


            activeRawId =
                "";


            rawSelect.selectedIndex =
                0;


            activeLabel =

                nfiSelect.options[
                    nfiSelect.selectedIndex
                ].text;


            nfiWrap
                .classList
                .add(
                    "proc-filter-control-active"
                );


            sortSelect.value =
                "default";


            currentPage =
                1;


            render();

        }

    );



    /* =====================================================
       ALL CATEGORIES / SORT

       Selecting anything here returns category filtering
       to ALL records and applies only sorting.
       ===================================================== */

    sortSelect.addEventListener(

        "change",

        function () {


            activeCategory =
                "all";


            activeRawId =
                "";


            activeNfiId =
                "";


            activeLabel =
                "";


            rawSelect.selectedIndex =
                0;


            nfiSelect.selectedIndex =
                0;


            resetCategoryAppearance();


            filteredBar
                .classList
                .remove(
                    "visible"
                );


            if (
                sortSelect.value !==
                "default"
            ) {

                sortWrap
                    .classList
                    .add(
                        "proc-filter-control-active"
                    );

            } else {

                sortWrap
                    .classList
                    .remove(
                        "proc-filter-control-active"
                    );
            }


            currentPage =
                1;


            render();

        }

    );



    /* =====================================================
       CLEAR FILTER
       ===================================================== */

    clearFilterButton.addEventListener(

        "click",

        function () {


            sortSelect.value =
                "default";


            sortWrap
                .classList
                .remove(
                    "proc-filter-control-active"
                );


            clearCategoryFilter();

        }

    );



    /* =====================================================
       CATEGORY MATCH
       ===================================================== */

    function categoryMatches(row)
    {

        if (
            activeCategory ===
            "all"
        ) {

            return true;
        }


        /* ===============================================
           RAW MATERIAL
           =============================================== */

        if (
            activeCategory ===
            "raw"
        ) {

            if (
                row.getAttribute(
                    "data-has-raw"
                )
                !==
                "1"
            ) {

                return false;
            }


            /*
             * Raw Materials header:
             * show ALL raw materials.
             */

            if (!activeRawId) {

                return true;
            }


            var rawIds =
                row.getAttribute(
                    "data-raw-ids"
                )
                ||
                ",";


            return (

                rawIds.indexOf(

                    ","
                    +
                    activeRawId
                    +
                    ","

                )
                !==
                -1

            );
        }


        /* ===============================================
           RTEF
           =============================================== */

        if (
            activeCategory ===
            "rtef"
        ) {

            return (

                row.getAttribute(
                    "data-rtef"
                )
                ===
                "1"

            );
        }


        /* ===============================================
           PREPACK FFP
           =============================================== */

        if (
            activeCategory ===
            "ffp"
        ) {

            return (

                row.getAttribute(
                    "data-ffp"
                )
                ===
                "1"

            );
        }


        /* ===============================================
           NON FOOD ITEM
           =============================================== */

        if (
            activeCategory ===
            "nfi"
        ) {

            if (
                row.getAttribute(
                    "data-has-nfi"
                )
                !==
                "1"
            ) {

                return false;
            }


            if (!activeNfiId) {

                return true;
            }


            var nfiIds =
                row.getAttribute(
                    "data-nfi-ids"
                )
                ||
                ",";


            return (

                nfiIds.indexOf(

                    ","
                    +
                    activeNfiId
                    +
                    ","

                )
                !==
                -1

            );
        }


        return true;
    }



    /* =====================================================
       DATE MATCH
       ===================================================== */

    function dateMatches(row)
    {

        var rowDate =
            row.getAttribute(
                "data-date"
            );


        if (!rowDate) {

            return true;
        }


        var from =
            dateFrom.value;


        var to =
            dateTo.value;


        if (
            from

            &&

            rowDate <
            from
        ) {

            return false;
        }


        if (
            to

            &&

            rowDate >
            to
        ) {

            return false;
        }


        return true;
    }



    /* =====================================================
       SEARCH MATCH
       ===================================================== */

    function searchMatches(row)
    {

        var term =

            searchInput.value
                .trim()
                .toLowerCase();


        if (!term) {

            return true;
        }


        var data =

            (
                row.getAttribute(
                    "data-search"
                )
                ||
                ""
            )
            .toLowerCase();


        return (

            data.indexOf(
                term
            )

            !==

            -1

        );
    }



    /* =====================================================
       FILTERED ROWS
       ===================================================== */

    function getFilteredRows()
    {

        return getRows().filter(

            function (row) {

                return (

                    categoryMatches(row)

                    &&

                    dateMatches(row)

                    &&

                    searchMatches(row)

                );
            }

        );
    }



    /* =====================================================
       SORTING
       ===================================================== */

    function sortRows(rows)
    {

        var sortBy =
            sortSelect.value;


        rows.sort(

            function (a, b) {


                /* =======================================
                   STATUS WORKFLOW ORDER
                   ======================================= */

                if (
                    sortBy ===
                    "status"
                ) {

                    return (

                        parseInt(
                            a.getAttribute(
                                "data-status-sort"
                            ),
                            10
                        )

                        -

                        parseInt(
                            b.getAttribute(
                                "data-status-sort"
                            ),
                            10
                        )

                    );
                }



                /* =======================================
                   REFERENCE NUMBER
                   ======================================= */

                if (
                    sortBy ===
                    "reference"
                ) {

                    return (

                        (
                            a.getAttribute(
                                "data-reference"
                            )
                            ||
                            ""
                        )
                        .localeCompare(

                            b.getAttribute(
                                "data-reference"
                            )
                            ||
                            "",

                            undefined,

                            {
                                numeric:true
                            }

                        )

                    );
                }



                /* =======================================
                   DATE NEWEST
                   ======================================= */

                if (
                    sortBy ===
                    "date_desc"
                ) {

                    return (

                        (
                            b.getAttribute(
                                "data-date"
                            )
                            ||
                            ""
                        )
                        .localeCompare(

                            a.getAttribute(
                                "data-date"
                            )
                            ||
                            ""

                        )

                    );
                }



                /* =======================================
                   DATE OLDEST
                   ======================================= */

                if (
                    sortBy ===
                    "date_asc"
                ) {

                    return (

                        (
                            a.getAttribute(
                                "data-date"
                            )
                            ||
                            ""
                        )
                        .localeCompare(

                            b.getAttribute(
                                "data-date"
                            )
                            ||
                            ""

                        )

                    );
                }



                /* =======================================
                   ORIGINAL DATABASE ORDER
                   ======================================= */

                return (

                    parseInt(
                        a.getAttribute(
                            "data-original"
                        ),
                        10
                    )

                    -

                    parseInt(
                        b.getAttribute(
                            "data-original"
                        ),
                        10
                    )

                );
            }

        );


        return rows;
    }



    /* =====================================================
       FILTERED MESSAGE
       ===================================================== */

    function updateFilterMessage(
        total
    )
    {

        if (
            activeCategory ===
            "all"
        ) {

            filteredBar
                .classList
                .remove(
                    "visible"
                );


            return;
        }


        filteredName.textContent =
            activeLabel;


        filteredCount.textContent =

            total
            +
            (
                total === 1
                    ? " Item found"
                    : " Items found"
            );


        filteredBar
            .classList
            .add(
                "visible"
            );
    }



    /* =====================================================
       RENDER
       ===================================================== */

    function render()
    {

        var allRows =
            getRows();


        var filtered =
            getFilteredRows();


        /*
         * Sort only affects display.
         */

        var sorted =
            sortRows(
                filtered.slice()
            );


        /*
         * Reorder the matched rows in DOM.
         */

        sorted.forEach(

            function (row) {

                tbody.appendChild(
                    row
                );
            }

        );


        /*
         * Hide everything.
         */

        allRows.forEach(

            function (row) {

                row.style.display =
                    "none";
            }

        );


        var size =

            parseInt(
                pageSize.value,
                10
            )
            ||
            10;


        var total =
            sorted.length;


        var pages =

            Math.max(

                1,

                Math.ceil(
                    total
                    /
                    size
                )

            );


        if (
            currentPage >
            pages
        ) {

            currentPage =
                pages;
        }


        if (
            currentPage <
            1
        ) {

            currentPage =
                1;
        }


        var start =

            (
                currentPage
                -
                1
            )

            *

            size;


        var end =

            Math.min(

                start
                +
                size,

                total

            );


        for (

            var i = start;

            i < end;

            i++

        ) {

            sorted[i]
                .style.display =
                    "";
        }



        /* ===============================================
           COUNT
           =============================================== */

        if (
            total ===
            0
        ) {

            recordCount.textContent =

                "Displaying 0 records";

        } else {

            recordCount.textContent =

                "Displaying "
                +
                (
                    start
                    +
                    1
                )
                +
                "-"
                +
                end
                +
                " of "
                +
                total;

        }



        /* ===============================================
           FILTER MESSAGE
           =============================================== */

        updateFilterMessage(
            total
        );



        /* ===============================================
           PAGE
           =============================================== */

        current.textContent =
            currentPage;


        previous.disabled =

            currentPage <=
            1;


        next.disabled =

            currentPage >=
            pages;


        previous.style.opacity =

            previous.disabled
                ? ".45"
                : "1";


        next.style.opacity =

            next.disabled
                ? ".45"
                : "1";

    }



    /* =====================================================
       SEARCH
       ===================================================== */

    searchInput.addEventListener(

        "input",

        function () {

            currentPage =
                1;


            render();

        }

    );



    /* =====================================================
       DATE

       NO PAGE SUBMISSION.
       ===================================================== */

    dateFrom.addEventListener(

        "change",

        function () {

            currentPage =
                1;


            render();

        }

    );


    dateTo.addEventListener(

        "change",

        function () {

            currentPage =
                1;


            render();

        }

    );



    /* =====================================================
       PAGE SIZE
       ===================================================== */

    pageSize.addEventListener(

        "change",

        function () {

            currentPage =
                1;


            render();

        }

    );



    /* =====================================================
       PREVIOUS
       ===================================================== */

    previous.addEventListener(

        "click",

        function () {

            if (
                currentPage >
                1
            ) {

                currentPage--;


                render();
            }

        }

    );



    /* =====================================================
       NEXT
       ===================================================== */

    next.addEventListener(

        "click",

        function () {

            currentPage++;


            render();

        }

    );



    /* =====================================================
       SELECT ALL VISIBLE
       ===================================================== */

    checkAll.addEventListener(

        "change",

        function () {


            table
                .querySelectorAll(
                    ".proc-row-checkbox"
                )
                .forEach(

                    function (checkbox) {


                        var row =
                            checkbox.closest(
                                "tr"
                            );


                        if (

                            row

                            &&

                            row.style.display !==
                            "none"

                        ) {

                            checkbox.checked =

                                checkAll.checked;
                        }

                    }

                );

        }

    );



    /* =====================================================
       EXPORT FILTERED RESULT
       ===================================================== */

    exportButton.addEventListener(

        "click",

        function () {


            var rows =
                sortRows(
                    getFilteredRows()
                );


            var csv = [

                [
                    "Status",
                    "Reference Number",
                    "Date",
                    "Approved File"
                ]

            ];


            rows.forEach(

                function (row) {


                    var cells =
                        row.querySelectorAll(
                            "td"
                        );


                    csv.push(

                        [

                            cells[5]
                                .innerText
                                .trim(),

                            cells[6]
                                .innerText
                                .trim(),

                            cells[7]
                                .innerText
                                .trim(),

                            cells[8]
                                .innerText
                                .trim()

                        ]

                    );

                }

            );


            var text =

                csv.map(

                    function (row) {

                        return row.map(

                            function (value) {

                                value =

                                    String(
                                        value
                                    )
                                    .replace(
                                        /"/g,
                                        '""'
                                    );


                                return (

                                    '"'
                                    +
                                    value
                                    +
                                    '"'

                                );

                            }

                        ).join(",");

                    }

                ).join("\\n");


            var blob =

                new Blob(

                    [
                        text
                    ],

                    {
                        type:
                            "text/csv;charset=utf-8;"
                    }

                );


            var url =

                URL.createObjectURL(
                    blob
                );


            var link =

                document.createElement(
                    "a"
                );


            link.href =
                url;


            link.download =

                "procurement-dashboard.csv";


            document.body
                .appendChild(
                    link
                );


            link.click();


            document.body
                .removeChild(
                    link
                );


            URL.revokeObjectURL(
                url
            );

        }

    );



    /* =====================================================
       INITIAL
       ===================================================== */

    render();


})();

</script>


HTML;
		;
		
	}

	// code snippet - production
	function event_64289(  ) {
		
		/* =========================================================
   WINGS PRODUCTION DASHBOARD
   PHPRUNNER 11.3

   LIVE DATABASE SAFE VERSION
   DASHBOARD QUERIES = SELECT ONLY
   ========================================================= */


/* =========================================================
   1. ROUTES
   ========================================================= */

$forecastListUrl =
    "production_suggestion_run_list.php";

$addNewUrl =
    "production_suggestion_run_add.php";

$exportUrl =
    "production_suggestion_run_export.php";


/* =========================================================
   2. SETTINGS
   ========================================================= */

$facilityCodes = array(
    "LDRC",
    "VDRC",
    "MDRC"
);

$topStatusRate = 15000;


/* =========================================================
   3. HELPERS
   ========================================================= */

$esc = function ($value) {

    return htmlspecialchars(
        (string)$value,
        ENT_QUOTES,
        "UTF-8"
    );

};


$num = function (
    $value,
    $decimals = 0
) {

    return number_format(
        (float)$value,
        $decimals
    );

};


$trimNumber = function (
    $value,
    $decimals = 4
) {

    $value =
        number_format(
            (float)$value,
            $decimals,
            ".",
            ""
        );

    $value =
        rtrim(
            $value,
            "0"
        );

    $value =
        rtrim(
            $value,
            "."
        );

    return $value === ""
        ? "0"
        : $value;

};


$daysClass = function ($days) {

    $days =
        intval($days);


    if ($days <= 30) {

        return "wprod-days-red";

    }


    if ($days <= 60) {

        return "wprod-days-orange";

    }


    return "wprod-days-green";

};


/* =========================================================
   4. GET MOTHER FACILITY IDS
   ========================================================= */

$facilityIds = array(

    "LDRC" => 0,

    "VDRC" => 0,

    "MDRC" => 0

);


$rsFacility =
    DB::Query("

        SELECT

            id,

            UPPER(
                TRIM(
                    facility_code
                )
            ) AS facility_code

        FROM
            mother_facility

        WHERE

            UPPER(
                TRIM(
                    facility_code
                )
            ) IN (
                'LDRC',
                'VDRC',
                'MDRC'
            )

            AND status = 'ACTIVE'

    ");


if ($rsFacility) {

    while (
        $row =
        $rsFacility->fetchAssoc()
    ) {

        $code =
            strtoupper(
                trim(
                    $row["facility_code"]
                )
            );


        if (
            isset(
                $facilityIds[$code]
            )
        ) {

            $facilityIds[$code] =
                intval(
                    $row["id"]
                );

        }

    }

}


/* =========================================================
   5. PRODUCTION SOURCE

   SOURCE 1:
   production_output_details.quantity_produced

   SOURCE 2:
   completed production_work_order_details.actual_qty
   only when no Production Output exists yet.

   FACILITY RESOLUTION:
   - production_plan mother facility
   - warehouse mother facility
   - NROC -> LDRC
   - VDRC
   - MDRC
   - warehouse name
   - production area
   ========================================================= */

$productionSourceSql = "

SELECT

    po.report_date
        AS production_date,


    CASE

        /* PLAN MOTHER FACILITY */

        WHEN UPPER(
            COALESCE(
                mf_plan.facility_code,
                ''
            )
        ) = 'LDRC'
        THEN 'LDRC'


        WHEN UPPER(
            COALESCE(
                mf_plan.facility_code,
                ''
            )
        ) = 'VDRC'
        THEN 'VDRC'


        WHEN UPPER(
            COALESCE(
                mf_plan.facility_code,
                ''
            )
        ) = 'MDRC'
        THEN 'MDRC'


        /* WAREHOUSE MOTHER FACILITY */

        WHEN UPPER(
            COALESCE(
                mf_wh.facility_code,
                ''
            )
        ) = 'LDRC'
        THEN 'LDRC'


        WHEN UPPER(
            COALESCE(
                mf_wh.facility_code,
                ''
            )
        ) = 'VDRC'
        THEN 'VDRC'


        WHEN UPPER(
            COALESCE(
                mf_wh.facility_code,
                ''
            )
        ) = 'MDRC'
        THEN 'MDRC'


        /* LEGACY WAREHOUSE CODE */

        WHEN UPPER(
            COALESCE(
                w.warehouse_code,
                ''
            )
        ) IN (
            'NROC',
            'LDRC'
        )
        THEN 'LDRC'


        WHEN UPPER(
            COALESCE(
                w.warehouse_code,
                ''
            )
        ) = 'VDRC'
        THEN 'VDRC'


        WHEN UPPER(
            COALESCE(
                w.warehouse_code,
                ''
            )
        ) = 'MDRC'
        THEN 'MDRC'


        /* WAREHOUSE NAME */

        WHEN UPPER(
            COALESCE(
                w.name,
                ''
            )
        ) LIKE '%NROC%'
        THEN 'LDRC'


        WHEN UPPER(
            COALESCE(
                w.name,
                ''
            )
        ) LIKE '%LDRC%'
        THEN 'LDRC'


        WHEN UPPER(
            COALESCE(
                w.name,
                ''
            )
        ) LIKE '%VDRC%'
        THEN 'VDRC'


        WHEN UPPER(
            COALESCE(
                w.name,
                ''
            )
        ) LIKE '%MDRC%'
        THEN 'MDRC'


        /* PRODUCTION AREA */

        WHEN UPPER(
            CONCAT_WS(
                ' ',
                pp.production_area,
                pwo.production_area,
                po.production_area
            )
        ) LIKE '%NROC%'
        THEN 'LDRC'


        WHEN UPPER(
            CONCAT_WS(
                ' ',
                pp.production_area,
                pwo.production_area,
                po.production_area
            )
        ) LIKE '%LDRC%'
        THEN 'LDRC'


        WHEN UPPER(
            CONCAT_WS(
                ' ',
                pp.production_area,
                pwo.production_area,
                po.production_area
            )
        ) LIKE '%VDRC%'
        THEN 'VDRC'


        WHEN UPPER(
            CONCAT_WS(
                ' ',
                pp.production_area,
                pwo.production_area,
                po.production_area
            )
        ) LIKE '%MDRC%'
        THEN 'MDRC'


        ELSE NULL

    END AS facility_code,


    pod.finished_good_id,


    COALESCE(
        pod.quantity_produced,
        0
    ) AS production_qty


FROM
    production_output po


INNER JOIN production_output_details pod

    ON pod.production_output_id =
       po.id


INNER JOIN production_work_order pwo

    ON pwo.id =
       po.production_work_order_id


LEFT JOIN production_plan_details ppd

    ON ppd.id =
       pwo.production_plan_detail_id


LEFT JOIN production_plan pp

    ON pp.id =
       COALESCE(
           pwo.production_plan_id,
           ppd.production_plan_id
       )


LEFT JOIN warehouse w

    ON w.id =
       pp.warehouse_id


LEFT JOIN mother_facility mf_plan

    ON mf_plan.id =
       pp.mother_facility_id


LEFT JOIN mother_facility mf_wh

    ON mf_wh.id =
       w.mother_facility_id


WHERE

    UPPER(
        COALESCE(
            po.status,
            ''
        )
    ) <> 'CANCELLED'


    AND COALESCE(
        pod.quantity_produced,
        0
    ) <> 0



UNION ALL



SELECT

    COALESCE(
        pwo.date_end,
        pwo.work_order_date
    ) AS production_date,


    CASE

        /* PLAN MOTHER FACILITY */

        WHEN UPPER(
            COALESCE(
                mf_plan.facility_code,
                ''
            )
        ) = 'LDRC'
        THEN 'LDRC'


        WHEN UPPER(
            COALESCE(
                mf_plan.facility_code,
                ''
            )
        ) = 'VDRC'
        THEN 'VDRC'


        WHEN UPPER(
            COALESCE(
                mf_plan.facility_code,
                ''
            )
        ) = 'MDRC'
        THEN 'MDRC'


        /* WAREHOUSE MOTHER FACILITY */

        WHEN UPPER(
            COALESCE(
                mf_wh.facility_code,
                ''
            )
        ) = 'LDRC'
        THEN 'LDRC'


        WHEN UPPER(
            COALESCE(
                mf_wh.facility_code,
                ''
            )
        ) = 'VDRC'
        THEN 'VDRC'


        WHEN UPPER(
            COALESCE(
                mf_wh.facility_code,
                ''
            )
        ) = 'MDRC'
        THEN 'MDRC'


        /* LEGACY CODE */

        WHEN UPPER(
            COALESCE(
                w.warehouse_code,
                ''
            )
        ) IN (
            'NROC',
            'LDRC'
        )
        THEN 'LDRC'


        WHEN UPPER(
            COALESCE(
                w.warehouse_code,
                ''
            )
        ) = 'VDRC'
        THEN 'VDRC'


        WHEN UPPER(
            COALESCE(
                w.warehouse_code,
                ''
            )
        ) = 'MDRC'
        THEN 'MDRC'


        /* WAREHOUSE NAME */

        WHEN UPPER(
            COALESCE(
                w.name,
                ''
            )
        ) LIKE '%NROC%'
        THEN 'LDRC'


        WHEN UPPER(
            COALESCE(
                w.name,
                ''
            )
        ) LIKE '%LDRC%'
        THEN 'LDRC'


        WHEN UPPER(
            COALESCE(
                w.name,
                ''
            )
        ) LIKE '%VDRC%'
        THEN 'VDRC'


        WHEN UPPER(
            COALESCE(
                w.name,
                ''
            )
        ) LIKE '%MDRC%'
        THEN 'MDRC'


        /* PRODUCTION AREA */

        WHEN UPPER(
            CONCAT_WS(
                ' ',
                pp.production_area,
                pwo.production_area
            )
        ) LIKE '%NROC%'
        THEN 'LDRC'


        WHEN UPPER(
            CONCAT_WS(
                ' ',
                pp.production_area,
                pwo.production_area
            )
        ) LIKE '%LDRC%'
        THEN 'LDRC'


        WHEN UPPER(
            CONCAT_WS(
                ' ',
                pp.production_area,
                pwo.production_area
            )
        ) LIKE '%VDRC%'
        THEN 'VDRC'


        WHEN UPPER(
            CONCAT_WS(
                ' ',
                pp.production_area,
                pwo.production_area
            )
        ) LIKE '%MDRC%'
        THEN 'MDRC'


        ELSE NULL

    END AS facility_code,


    pwod.finished_good_id,


    COALESCE(
        pwod.actual_qty,
        0
    ) AS production_qty


FROM
    production_work_order pwo


INNER JOIN production_work_order_details pwod

    ON pwod.production_work_order_id =
       pwo.id


LEFT JOIN production_plan_details ppd

    ON ppd.id =
       pwo.production_plan_detail_id


LEFT JOIN production_plan pp

    ON pp.id =
       COALESCE(
           pwo.production_plan_id,
           ppd.production_plan_id
       )


LEFT JOIN warehouse w

    ON w.id =
       pp.warehouse_id


LEFT JOIN mother_facility mf_plan

    ON mf_plan.id =
       pp.mother_facility_id


LEFT JOIN mother_facility mf_wh

    ON mf_wh.id =
       w.mother_facility_id


WHERE

    UPPER(
        COALESCE(
            pwo.status,
            ''
        )
    ) = 'COMPLETED'


    AND COALESCE(
        pwod.actual_qty,
        0
    ) <> 0


    AND NOT EXISTS
    (

        SELECT
            1

        FROM
            production_output po2

        INNER JOIN production_output_details pod2

            ON pod2.production_output_id =
               po2.id

        WHERE

            po2.production_work_order_id =
                pwo.id

            AND pod2.finished_good_id =
                pwod.finished_good_id

            AND UPPER(
                COALESCE(
                    po2.status,
                    ''
                )
            ) <> 'CANCELLED'

            AND COALESCE(
                pod2.quantity_produced,
                0
            ) <> 0

    )

";


/* =========================================================
   6. FIND LATEST PRODUCTION DATE

   IMPORTANT:
   We keep your existing operational production logic.

   We also include MANUAL Production Reports only for:
   - the dashboard As Of date
   - the monthly Subtotal
   - the overall Total

   Manual reports are NOT assigned to LDRC / VDRC / MDRC
   because the manual report does not store a DRC.
   ========================================================= */

$dashboardYear =
    intval(
        date("Y")
    );


$productionAsOf =
    null;


/* ---------------------------------------------------------
   6A. Latest operational production date
   --------------------------------------------------------- */

$operationalAsOf =
    null;


$rsProdDate =
    DB::Query("

        SELECT

            MAX(
                production_date
            ) AS production_date

        FROM
        (
            " . $productionSourceSql . "
        ) src

        WHERE

            facility_code IN (
                'LDRC',
                'VDRC',
                'MDRC'
            )

    ");


if ($rsProdDate) {

    $row =
        $rsProdDate->fetchAssoc();


    if (
        $row
        &&
        !empty(
            $row["production_date"]
        )
    ) {

        $operationalAsOf =
            $row["production_date"];

    }

}


/* ---------------------------------------------------------
   6B. Latest manual Production Report date
   --------------------------------------------------------- */

$manualAsOf =
    null;


$rsManualDate =
    DB::Query("

        SELECT

            MAX(
                h.report_date
            ) AS report_date

        FROM
            production_report_form_header h

        WHERE

            h.active_flag = 1

    ");


if ($rsManualDate) {

    $row =
        $rsManualDate->fetchAssoc();


    if (
        $row
        &&
        !empty(
            $row["report_date"]
        )
    ) {

        $manualAsOf =
            $row["report_date"];

    }

}


/* ---------------------------------------------------------
   6C. Use whichever production source has the latest date
   --------------------------------------------------------- */

if (
    $operationalAsOf
    &&
    $manualAsOf
) {

    $productionAsOf =

        strtotime(
            $operationalAsOf
        )
        >=
        strtotime(
            $manualAsOf
        )

        ? $operationalAsOf

        : $manualAsOf;

}
elseif (
    $operationalAsOf
) {

    $productionAsOf =
        $operationalAsOf;

}
elseif (
    $manualAsOf
) {

    $productionAsOf =
        $manualAsOf;

}


if (
    $productionAsOf
) {

    $dashboardYear =
        intval(
            date(
                "Y",
                strtotime(
                    $productionAsOf
                )
            )
        );

}


$productionAsOfDisplay =

    $productionAsOf

    ? date(
        "F j, Y",
        strtotime(
            $productionAsOf
        )
    )

    : date(
        "F j, Y"
    );


/* =========================================================
   7. MONTH ARRAYS
   ========================================================= */

$monthNames = array(

    1  => "January",
    2  => "February",
    3  => "March",
    4  => "April",
    5  => "May",
    6  => "June",
    7  => "July",
    8  => "August",
    9  => "September",
    10 => "October",
    11 => "November",
    12 => "December"

);


$monthly =
    array();


/*
 * Manual Production Report totals.
 *
 * These are added to the monthly Subtotal only because
 * production_report_form_header has no DRC assignment.
 */

$monthlyManual =
    array();


$facilityTotals = array(

    "LDRC" => 0,
    "VDRC" => 0,
    "MDRC" => 0

);


$facilityHasProduction = array(

    "LDRC" => false,
    "VDRC" => false,
    "MDRC" => false

);


for (
    $m = 1;
    $m <= 12;
    $m++
) {

    $monthly[$m] = array(

        "LDRC" => 0,
        "VDRC" => 0,
        "MDRC" => 0

    );


    $monthlyManual[$m] =
        0;

}


/* =========================================================
   8. MONTHLY PRODUCTION
   ========================================================= */


/* ---------------------------------------------------------
   8A. Operational production assigned to a DRC
   --------------------------------------------------------- */

$rsProduction =
    DB::Query("

        SELECT

            MONTH(
                production_date
            ) AS month_no,

            facility_code,

            SUM(
                production_qty
            ) AS produced_qty

        FROM
        (
            " . $productionSourceSql . "
        ) src

        WHERE

            YEAR(
                production_date
            ) = " . intval($dashboardYear) . "

            AND facility_code IN (
                'LDRC',
                'VDRC',
                'MDRC'
            )

        GROUP BY

            MONTH(
                production_date
            ),

            facility_code

        ORDER BY

            month_no,

            facility_code

    ");


if ($rsProduction) {

    while (
        $row =
        $rsProduction->fetchAssoc()
    ) {

        $month =
            intval(
                $row["month_no"]
            );


        $code =
            strtoupper(
                trim(
                    $row["facility_code"]
                )
            );


        $qty =
            floatval(
                $row["produced_qty"]
            );


        if (
            isset(
                $monthly[$month][$code]
            )
        ) {

            $monthly[$month][$code] +=
                $qty;


            $facilityTotals[$code] +=
                $qty;


            $facilityHasProduction[$code] =
                true;

        }

    }

}


/* ---------------------------------------------------------
   8B. Manual production report

   Confirmed live result:
   2026-03-23 / PR-MEV-2026-03-023 / 3,000

   This will make March Subtotal = 3,000 when there is no
   facility-assigned operational production for that month.
   --------------------------------------------------------- */

$rsManualProduction =
    DB::Query("

        SELECT

            MONTH(
                h.report_date
            ) AS month_no,

            SUM(
                COALESCE(
                    l.quantity,
                    0
                )
            ) AS produced_qty

        FROM
            production_report_form_header h

        INNER JOIN production_report_form_line l

            ON l.production_report_form_id =
               h.id

        WHERE

            h.active_flag = 1

            AND YEAR(
                h.report_date
            ) = " . intval($dashboardYear) . "

        GROUP BY

            MONTH(
                h.report_date
            )

        ORDER BY

            month_no

    ");


if ($rsManualProduction) {

    while (
        $row =
        $rsManualProduction->fetchAssoc()
    ) {

        $month =
            intval(
                $row["month_no"]
            );


        if (
            $month >= 1
            &&
            $month <= 12
        ) {

            $monthlyManual[$month] +=
                floatval(
                    $row["produced_qty"]
                );

        }

    }

}


$manualProductionTotal =
    array_sum(
        $monthlyManual
    );


$facilityProductionTotal =

    $facilityTotals["LDRC"]

    +

    $facilityTotals["VDRC"]

    +

    $facilityTotals["MDRC"];


$grandProductionTotal =

    $facilityProductionTotal

    +

    $manualProductionTotal;


$hasAnyProduction =
    $grandProductionTotal > 0;


/* =========================================================
   9. INVENTORY AS OF DATE

   Legacy facilities included.
   ========================================================= */

$stockAsOf =
    null;


$rsStockDate =
    DB::Query("

        SELECT

            MAX(`Date`)
                AS stock_date

        FROM
            vw_inventory_ledger_complete

        WHERE

            (
                UPPER(
                    COALESCE(
                        mother_facility_code,
                        ''
                    )
                ) IN (
                    'LDRC',
                    'VDRC',
                    'MDRC'
                )

                OR

                UPPER(
                    COALESCE(
                        warehouse_code,
                        ''
                    )
                ) IN (
                    'NROC',
                    'LDRC',
                    'VDRC',
                    'MDRC'
                )

                OR

                UPPER(
                    COALESCE(
                        Warehouse,
                        ''
                    )
                ) LIKE '%NROC%'

                OR

                UPPER(
                    COALESCE(
                        Warehouse,
                        ''
                    )
                ) LIKE '%LDRC%'

                OR

                UPPER(
                    COALESCE(
                        Warehouse,
                        ''
                    )
                ) LIKE '%VDRC%'

                OR

                UPPER(
                    COALESCE(
                        Warehouse,
                        ''
                    )
                ) LIKE '%MDRC%'
            )

    ");


if ($rsStockDate) {

    $row =
        $rsStockDate->fetchAssoc();


    if (
        $row
        &&
        !empty(
            $row["stock_date"]
        )
    ) {

        $stockAsOf =
            $row["stock_date"];

    }

}


$stockAsOfDisplay =

    $stockAsOf

    ? date(
        "F j, Y",
        strtotime(
            $stockAsOf
        )
    )

    : date(
        "F j, Y"
    );


/* =========================================================
   10. QUANTITY PER FFP

   IMPORTANT:
   Use the same roll-up rule used by inventory.

   Branded RAW_MATERIAL child:
       Tuna, Fresca -> Canned Tuna

   KIT child:
       VRP NFA 3Kls remains VRP NFA 3Kls
   ========================================================= */

$qtyPerFfp =
    array();


$rsBom =
    DB::Query("

        SELECT

            CASE

                WHEN
                    ci.parent_item_id IS NOT NULL

                    AND ci.item_classification =
                        'RAW_MATERIAL'

                    AND pi.item_classification =
                        'RAW_MATERIAL'

                THEN
                    pi.id

                ELSE
                    ci.id

            END AS dashboard_item_id,


            ic.qty,


            IFNULL(
                fg.priority,
                999
            ) AS fg_priority,


            fg.id
                AS finished_good_id


        FROM
            item_component ic


        INNER JOIN item ci

            ON ci.id =
               ic.component_item_id


        LEFT JOIN item pi

            ON pi.id =
               ci.parent_item_id


        INNER JOIN item fg

            ON fg.id =
               ic.parent_item_id


        WHERE

            COALESCE(
                ic.qty,
                0
            ) > 0


        ORDER BY

            dashboard_item_id,

            IFNULL(
                fg.priority,
                999
            ),

            fg.id,

            ic.sort_order,

            ic.id

    ");


if ($rsBom) {

    while (
        $row =
        $rsBom->fetchAssoc()
    ) {

        $dashboardItemId =
            intval(
                $row[
                    "dashboard_item_id"
                ]
            );


        if (
            !isset(
                $qtyPerFfp[
                    $dashboardItemId
                ]
            )
        ) {

            $qtyPerFfp[
                $dashboardItemId
            ] =
                floatval(
                    $row["qty"]
                );

        }

    }

}


/* =========================================================
   11. RAW MATERIAL INVENTORY

   Uses inventory ledger directly.

   LEGACY:
   NROC -> LDRC

   ROLLUP:
   branded RAW_MATERIAL child -> parent raw material

   Example:
   Tuna, Fresca
   Tuna, 555
   Tuna, Sea Quest
        ↓
   Canned Tuna

   But KIT components stay separate.
   ========================================================= */

$rawByFacility = array(

    "LDRC" => array(),

    "VDRC" => array(),

    "MDRC" => array()

);


$sqlRaw = "

SELECT

    q.facility_code,

    q.dashboard_item_id,

    MAX(
        q.item_name
    ) AS item_name,

    MAX(
        q.uom
    ) AS uom,

    SUM(
        q.qty_effect
    ) AS available_qty


FROM
(

    SELECT


        /* =============================================
           FACILITY
           ============================================= */

        CASE


            WHEN UPPER(
                COALESCE(
                    l.mother_facility_code,
                    ''
                )
            ) = 'LDRC'

            THEN 'LDRC'


            WHEN UPPER(
                COALESCE(
                    l.mother_facility_code,
                    ''
                )
            ) = 'VDRC'

            THEN 'VDRC'


            WHEN UPPER(
                COALESCE(
                    l.mother_facility_code,
                    ''
                )
            ) = 'MDRC'

            THEN 'MDRC'



            WHEN UPPER(
                COALESCE(
                    l.warehouse_code,
                    ''
                )
            ) IN (
                'NROC',
                'LDRC'
            )

            THEN 'LDRC'


            WHEN UPPER(
                COALESCE(
                    l.warehouse_code,
                    ''
                )
            ) = 'VDRC'

            THEN 'VDRC'


            WHEN UPPER(
                COALESCE(
                    l.warehouse_code,
                    ''
                )
            ) = 'MDRC'

            THEN 'MDRC'



            WHEN UPPER(
                COALESCE(
                    l.Warehouse,
                    ''
                )
            ) LIKE '%NROC%'

            THEN 'LDRC'


            WHEN UPPER(
                COALESCE(
                    l.Warehouse,
                    ''
                )
            ) LIKE '%LDRC%'

            THEN 'LDRC'


            WHEN UPPER(
                COALESCE(
                    l.Warehouse,
                    ''
                )
            ) LIKE '%VDRC%'

            THEN 'VDRC'


            WHEN UPPER(
                COALESCE(
                    l.Warehouse,
                    ''
                )
            ) LIKE '%MDRC%'

            THEN 'MDRC'


            ELSE NULL

        END AS facility_code,



        /* =============================================
           ORIGINAL ITEM ID
           ============================================= */

        i.id
            AS original_item_id,



        /* =============================================
           DASHBOARD ITEM ID

           Only roll parent/child when BOTH
           are RAW_MATERIAL.
           ============================================= */

        CASE

            WHEN

                i.parent_item_id IS NOT NULL

                AND i.item_classification =
                    'RAW_MATERIAL'

                AND pi.item_classification =
                    'RAW_MATERIAL'

            THEN
                pi.id

            ELSE
                i.id

        END AS dashboard_item_id,



        /* =============================================
           DISPLAY NAME
           ============================================= */

        CASE

            WHEN

                i.parent_item_id IS NOT NULL

                AND i.item_classification =
                    'RAW_MATERIAL'

                AND pi.item_classification =
                    'RAW_MATERIAL'

            THEN

                COALESCE(

                    NULLIF(
                        TRIM(
                            pi.description
                        ),
                        ''
                    ),

                    NULLIF(
                        TRIM(
                            pi.name
                        ),
                        ''
                    ),

                    CONCAT(
                        'Item ',
                        pi.id
                    )

                )


            ELSE

                COALESCE(

                    NULLIF(
                        TRIM(
                            i.description
                        ),
                        ''
                    ),

                    NULLIF(
                        TRIM(
                            i.name
                        ),
                        ''
                    ),

                    l.description,

                    CONCAT(
                        'Item ',
                        i.id
                    )

                )

        END AS item_name,



        /* =============================================
           UOM
           ============================================= */

        CASE

            WHEN

                i.parent_item_id IS NOT NULL

                AND i.item_classification =
                    'RAW_MATERIAL'

                AND pi.item_classification =
                    'RAW_MATERIAL'

            THEN

                COALESCE(
                    iup.name,
                    iu.name,
                    ''
                )

            ELSE

                COALESCE(
                    iu.name,
                    ''
                )

        END AS uom,



        /* =============================================
           GOOD INVENTORY ONLY
           ============================================= */

        CASE

            WHEN UPPER(
                COALESCE(
                    l.Quality,
                    'GOOD'
                )
            ) = 'GOOD'

            THEN

                COALESCE(
                    l.`Qty Effect`,
                    0
                )

            ELSE
                0

        END AS qty_effect


    FROM
        vw_inventory_ledger_complete l


    INNER JOIN item i

        ON i.id =
           l.item_id


    LEFT JOIN item pi

        ON pi.id =
           i.parent_item_id


    LEFT JOIN itemunit iu

        ON iu.id =
           i.unit_id


    LEFT JOIN itemunit iup

        ON iup.id =
           pi.unit_id


    WHERE

        l.item_id IS NOT NULL

) q


WHERE

    q.facility_code IN (
        'LDRC',
        'VDRC',
        'MDRC'
    )


    /* =============================================
       ONLY MATERIALS THAT PARTICIPATE IN A BOM

       Either the original item itself is a component
       or its rolled-up parent is a component.
       ============================================= */

    AND
    (

        q.original_item_id IN
        (
            SELECT DISTINCT

                component_item_id

            FROM
                item_component
        )


        OR


        q.dashboard_item_id IN
        (
            SELECT DISTINCT

                component_item_id

            FROM
                item_component
        )

    )


GROUP BY

    q.facility_code,

    q.dashboard_item_id


HAVING

    SUM(
        q.qty_effect
    ) > 0


ORDER BY

    q.facility_code,

    item_name

";


$rsRaw =
    DB::Query(
        $sqlRaw
    );


if ($rsRaw) {

    while (
        $row =
        $rsRaw->fetchAssoc()
    ) {

        $code =
            strtoupper(
                trim(
                    $row[
                        "facility_code"
                    ]
                )
            );


        if (
            !isset(
                $rawByFacility[$code]
            )
        ) {

            continue;

        }


        $itemId =
            intval(
                $row[
                    "dashboard_item_id"
                ]
            );


        $rawByFacility[
            $code
        ][$itemId] = array(

            "item_id" =>
                $itemId,

            "item" =>
                $row["item_name"],

            "uom" =>
                $row["uom"],

            "available_qty" =>
                floatval(
                    $row[
                        "available_qty"
                    ]
                )

        );

    }

}


/* =========================================================
   12. TOP RAW MATERIAL STATUS
   ========================================================= */

$rawStatus = array(

    "LDRC" => array(
        "minimum" => null,
        "maximum" => null
    ),

    "VDRC" => array(
        "minimum" => null,
        "maximum" => null
    ),

    "MDRC" => array(
        "minimum" => null,
        "maximum" => null
    )

);


$overallLowest =
    null;


$overallHighest =
    null;


foreach (
    $facilityCodes
    as $code
) {

    foreach (
        $rawByFacility[$code]
        as $itemId => $material
    ) {

        $available =
            floatval(
                $material[
                    "available_qty"
                ]
            );


        $days =
            intval(
                floor(
                    $available
                    /
                    $topStatusRate
                )
            );


        $entry = array(

            "item_id" =>
                $itemId,

            "item" =>
                $material["item"],

            "qty" =>
                $available,

            "days" =>
                $days

        );


        /* MINIMUM */

        if (

            $rawStatus[
                $code
            ]["minimum"] === null

            ||

            $days <
            $rawStatus[
                $code
            ]["minimum"]["days"]

        ) {

            $rawStatus[
                $code
            ]["minimum"] =
                $entry;

        }


        /* MAXIMUM */

        if (

            $rawStatus[
                $code
            ]["maximum"] === null

            ||

            $days >
            $rawStatus[
                $code
            ]["maximum"]["days"]

        ) {

            $rawStatus[
                $code
            ]["maximum"] =
                $entry;

        }

    }


    if (
        $rawStatus[
            $code
        ]["minimum"] !== null
    ) {

        $d =
            intval(
                $rawStatus[
                    $code
                ]["minimum"]["days"]
            );


        if (

            $overallLowest === null

            ||

            $d <
            $overallLowest

        ) {

            $overallLowest =
                $d;

        }

    }


    if (
        $rawStatus[
            $code
        ]["maximum"] !== null
    ) {

        $d =
            intval(
                $rawStatus[
                    $code
                ]["maximum"]["days"]
            );


        if (

            $overallHighest === null

            ||

            $d >
            $overallHighest

        ) {

            $overallHighest =
                $d;

        }

    }

}


/* =========================================================
   13. CONSOLIDATED BOTTOM RAW MATERIAL TABLE

   Combine LDRC + VDRC + MDRC
   ========================================================= */

$materialMap =
    array();


foreach (
    $facilityCodes
    as $code
) {

    foreach (
        $rawByFacility[$code]
        as $itemId => $material
    ) {

        if (
            !isset(
                $materialMap[
                    $itemId
                ]
            )
        ) {

            $materialMap[
                $itemId
            ] = array(

                "item_id" =>
                    $itemId,

                "item" =>
                    $material["item"],

                "uom" =>
                    $material["uom"],

                "qty_per_ffp" =>

                    isset(
                        $qtyPerFfp[
                            $itemId
                        ]
                    )

                    ? floatval(
                        $qtyPerFfp[
                            $itemId
                        ]
                    )

                    : 0,

                "available_qty" =>
                    0

            );

        }


        $materialMap[
            $itemId
        ]["available_qty"] +=

            floatval(
                $material[
                    "available_qty"
                ]
            );

    }

}


$materials =
    array_values(
        $materialMap
    );


usort(

    $materials,

    function (
        $a,
        $b
    ) {

        return strcasecmp(
            $a["item"],
            $b["item"]
        );

    }

);


foreach (
    $materials
    as $index => $material
) {

    $available =
        floatval(
            $material[
                "available_qty"
            ]
        );


    $materials[
        $index
    ]["days_15000"] =

        intval(
            floor(
                $available / 15000
            )
        );


    $materials[
        $index
    ]["days_18000"] =

        intval(
            floor(
                $available / 18000
            )
        );


    $materials[
        $index
    ]["days_22000"] =

        intval(
            floor(
                $available / 22000
            )
        );

}


/* =========================================================
   14. CSS
   ========================================================= */

echo "

<style>


/* =========================================================
   GLOBAL
   ========================================================= */

html body .wprod-dashboard,
html body .wprod-dashboard * {

    box-sizing:border-box !important;

    font-family:
        Arial,
        Helvetica,
        sans-serif !important;

}


html body .wprod-dashboard {

    width:100% !important;

    color:#252525 !important;

    padding:
        0 0 95px 0 !important;

}


/* =========================================================
   TOOLBAR
   ========================================================= */

html body .wprod-toolbar {

    display:flex !important;

    justify-content:flex-end !important;

    align-items:center !important;

    gap:8px !important;

    margin:
        0 0 12px 0 !important;

}


html body .wprod-toolbar-btn {

    display:inline-flex !important;

    align-items:center !important;

    justify-content:center !important;

    height:32px !important;

    padding:
        0 13px !important;

    border-radius:4px !important;

    font-size:11px !important;

    text-decoration:none !important;

    white-space:nowrap !important;

}


html body .wprod-toolbar-export {

    background:#ffffff !important;

    color:#333333 !important;

    border:
        1px solid #cccccc !important;

}


html body .wprod-toolbar-add {

    background:#2e3192 !important;

    color:#ffffff !important;

    border:
        1px solid #2e3192 !important;

}


/* =========================================================
   TOP GRID
   ========================================================= */

html body .wprod-top-grid {

    display:grid !important;

    grid-template-columns:
        minmax(300px,34%)
        minmax(570px,66%) !important;

    gap:12px !important;

    width:100% !important;

    margin-bottom:12px !important;

}


/* =========================================================
   CARDS
   ========================================================= */

html body .wprod-card,
html body .wprod-section {

    background:#f7f7f7 !important;

    border:
        1px solid #ededed !important;

    border-radius:7px !important;

    box-shadow:none !important;

}


html body .wprod-card {

    padding:
        14px 16px !important;

}


html body .wprod-section {

    padding:
        14px 16px !important;

    margin-bottom:12px !important;

}


html body .wprod-title {

    color:#1d1d1d !important;

    font-size:12px !important;

    font-weight:700 !important;

    margin:
        0 0 10px 0 !important;

}


html body .wprod-scroll {

    width:100% !important;

    overflow-x:auto !important;

    overflow-y:hidden !important;

}


/* =========================================================
   STANDARD TABLE
   ========================================================= */

html body table.wprod-table {

    width:100% !important;

    border-collapse:
        separate !important;

    border-spacing:
        0 3px !important;

    margin:0 !important;

    background:
        transparent !important;

    font-size:10px !important;

}


html body table.wprod-table
thead th {

    background:#2e3192 !important;

    background-image:none !important;

    color:#ffffff !important;

    border:0 !important;

    padding:
        7px 9px !important;

    font-size:9px !important;

    font-weight:500 !important;

    line-height:12px !important;

    text-align:center !important;

    vertical-align:middle !important;

    white-space:nowrap !important;

}


html body table.wprod-table
thead th:first-child {

    border-radius:
        4px 0 0 4px !important;

}


html body table.wprod-table
thead th:last-child {

    border-radius:
        0 4px 4px 0 !important;

}


html body table.wprod-table
tbody td {

    background:#ffffff !important;

    background-image:none !important;

    border:0 !important;

    color:#333333 !important;

    padding:
        6px 9px !important;

    font-size:9px !important;

    line-height:13px !important;

    vertical-align:middle !important;

}


html body table.wprod-table
tbody tr:nth-child(even)
:not(.wprod-total-row)
td {

    background:#eeeeee !important;

}


html body table.wprod-table
tbody td:first-child {

    text-align:left !important;

}


html body table.wprod-table
tbody td:not(:first-child) {

    text-align:right !important;

}


/* =========================================================
   BLUE TOTAL OUTLINE
   ========================================================= */

html body table.wprod-table
tbody tr.wprod-total-row td {

    background:#ffffff !important;

    color:#2e3192 !important;

    font-weight:700 !important;

    border:0 !important;

    box-shadow:

        inset 0 1px 0 #2e3192,

        inset 0 -1px 0 #2e3192 !important;

}


html body table.wprod-table
tbody tr.wprod-total-row
td:first-child {

    box-shadow:

        inset 1px 0 0 #2e3192,

        inset 0 1px 0 #2e3192,

        inset 0 -1px 0 #2e3192 !important;

}


html body table.wprod-table
tbody tr.wprod-total-row
td:last-child {

    box-shadow:

        inset -1px 0 0 #2e3192,

        inset 0 1px 0 #2e3192,

        inset 0 -1px 0 #2e3192 !important;

}


html body table.wprod-drc-table {

    min-width:0 !important;

}


html body table.wprod-drc-table
th:first-child,

html body table.wprod-drc-table
td:first-child {

    width:38% !important;

}


/* =========================================================
   RAW MATERIAL STATUS TABLE
   ========================================================= */

html body table.wprod-status-table {

    width:100% !important;

    border-collapse:
        separate !important;

    border-spacing:0 !important;

    margin:0 !important;

    background:
        transparent !important;

    font-size:9px !important;

}


html body table.wprod-status-table
th,

html body table.wprod-status-table
td {

    padding:
        5px 7px !important;

    font-size:9px !important;

    line-height:12px !important;

    vertical-align:middle !important;

}


/* =========================================================
   BLUE DRC HEADER
   ========================================================= */

html body table.wprod-status-table
th.wprod-head-drc {

    width:12% !important;

    background:#2e3192 !important;

    color:#ffffff !important;

    text-align:center !important;

    font-weight:500 !important;

    border:0 !important;

    box-shadow:

        inset 1px 0 0 #2e3192,

        inset -1px 0 0 #2e3192,

        inset 0 1px 0 #2e3192,

        inset 0 -1px 0 #2e3192 !important;

}


/* =========================================================
   RED MINIMUM HEADER
   ========================================================= */

html body table.wprod-status-table
th.wprod-head-min-title {

    background:#ee1c25 !important;

    color:#ffffff !important;

    text-align:center !important;

    font-weight:500 !important;

    border:0 !important;

    box-shadow:

        inset 1px 0 0 #ee1c25,

        inset -1px 0 0 #ee1c25,

        inset 0 1px 0 #ee1c25 !important;

}


html body table.wprod-status-table
th.wprod-head-min-item {

    background:#ffffff !important;

    color:#333333 !important;

    text-align:center !important;

    font-weight:500 !important;

    border:0 !important;

    box-shadow:

        inset 1px 0 0 #ee1c25,

        inset 0 -1px 0 #ee1c25 !important;

}


html body table.wprod-status-table
th.wprod-head-min-days {

    background:#ffffff !important;

    color:#333333 !important;

    text-align:center !important;

    font-weight:500 !important;

    border:0 !important;

    box-shadow:

        inset -1px 0 0 #ee1c25,

        inset 0 -1px 0 #ee1c25 !important;

}


/* =========================================================
   GREEN MAXIMUM HEADER
   ========================================================= */

html body table.wprod-status-table
th.wprod-head-max-title {

    background:#4caf50 !important;

    color:#ffffff !important;

    text-align:center !important;

    font-weight:500 !important;

    border:0 !important;

    box-shadow:

        inset 1px 0 0 #4caf50,

        inset -1px 0 0 #4caf50,

        inset 0 1px 0 #4caf50 !important;

}


html body table.wprod-status-table
th.wprod-head-max-item {

    background:#ffffff !important;

    color:#333333 !important;

    text-align:center !important;

    font-weight:500 !important;

    border:0 !important;

    box-shadow:

        inset 1px 0 0 #4caf50,

        inset 0 -1px 0 #4caf50 !important;

}


html body table.wprod-status-table
th.wprod-head-max-days {

    background:#ffffff !important;

    color:#333333 !important;

    text-align:center !important;

    font-weight:500 !important;

    border:0 !important;

    box-shadow:

        inset -1px 0 0 #4caf50,

        inset 0 -1px 0 #4caf50 !important;

}


/* =========================================================
   EMPTY ACTION HEADER
   ========================================================= */

html body table.wprod-status-table
th.wprod-head-action {

    width:112px !important;

    background:
        transparent !important;

    border:0 !important;

    box-shadow:none !important;

}


/* =========================================================
   RAW STATUS BODY
   ========================================================= */

html body table.wprod-status-table
tbody td {

    background:#ffffff !important;

    border:0 !important;

    border-bottom:
        1px solid #ededed !important;

    color:#333333 !important;

}


html body table.wprod-status-table
tbody tr:nth-child(even)
:not(.wprod-raw-total)
td {

    background:#f4f4f4 !important;

}


html body table.wprod-status-table
td.wprod-min-text {

    color:#ee1c25 !important;

}


html body table.wprod-status-table
td.wprod-max-text {

    color:#43a047 !important;

}


html body table.wprod-status-table
td.wprod-days-cell {

    width:45px !important;

    text-align:center !important;

}


html body table.wprod-status-table
td.wprod-action-cell {

    width:112px !important;

    text-align:right !important;

}


html body .wprod-item-clip {

    display:block !important;

    max-width:165px !important;

    white-space:nowrap !important;

    overflow:hidden !important;

    text-overflow:ellipsis !important;

}


/* =========================================================
   GENERATE FORECAST
   ========================================================= */

html body .wprod-forecast-btn {

    display:inline-flex !important;

    align-items:center !important;

    justify-content:center !important;

    min-width:100px !important;

    height:24px !important;

    padding:
        0 8px !important;

    background:#2e3192 !important;

    color:#ffffff !important;

    border:
        1px solid #2e3192 !important;

    border-radius:3px !important;

    font-size:8px !important;

    line-height:22px !important;

    white-space:nowrap !important;

    text-decoration:none !important;

}


html body .wprod-forecast-btn:hover {

    background:#242678 !important;

    color:#ffffff !important;

}


/* =========================================================
   RAW MATERIAL TOTAL
   FORCE COMPLETE BLUE OUTLINE
   ========================================================= */

html body table.wprod-status-table
tbody tr.wprod-raw-total td {

    background:#ffffff !important;

    border:0 !important;

    border-bottom:0 !important;

    position:relative !important;

    font-weight:700 !important;

    box-shadow:

        inset 0 1px 0 #2e3192,

        inset 0 -1px 0 #2e3192 !important;

}


html body table.wprod-status-table
tbody tr.wprod-raw-total
td:first-child {

    color:#2e3192 !important;

    box-shadow:

        inset 1px 0 0 #2e3192,

        inset 0 1px 0 #2e3192,

        inset 0 -1px 0 #2e3192 !important;

}


html body table.wprod-status-table
tbody tr.wprod-raw-total
td:last-child {

    box-shadow:

        inset -1px 0 0 #2e3192,

        inset 0 1px 0 #2e3192,

        inset 0 -1px 0 #2e3192 !important;

}


/* LOWEST MUST BE RED */

html body table.wprod-status-table
tbody tr.wprod-raw-total
td.wprod-total-low,

html body table.wprod-status-table
tbody tr.wprod-raw-total
td.wprod-total-low strong,

html body table.wprod-status-table
tbody tr.wprod-raw-total
td.wprod-total-low small {

    color:#ee1c25 !important;

}


/* HIGHEST MUST BE GREEN */

html body table.wprod-status-table
tbody tr.wprod-raw-total
td.wprod-total-high,

html body table.wprod-status-table
tbody tr.wprod-raw-total
td.wprod-total-high strong,

html body table.wprod-status-table
tbody tr.wprod-raw-total
td.wprod-total-high small {

    color:#43a047 !important;

}


html body table.wprod-status-table
tbody tr.wprod-raw-total small {

    display:block !important;

    margin-top:1px !important;

    font-size:7px !important;

    font-weight:400 !important;

    line-height:8px !important;

}


/* =========================================================
   AS OF
   ========================================================= */

html body .wprod-asof {

    display:flex !important;

    justify-content:flex-end !important;

    align-items:center !important;

    gap:4px !important;

    margin:
        0 2px 6px 0 !important;

    color:#777777 !important;

    font-size:8px !important;

}


html body .wprod-asof strong {

    color:#2e3192 !important;

    font-weight:500 !important;

}


/* =========================================================
   MONTHLY / MATERIAL TABLE
   ========================================================= */

html body table.wprod-month-table,
html body table.wprod-material-table {

    min-width:680px !important;

}


html body table.wprod-material-table
thead th {

    white-space:normal !important;

}


html body table.wprod-material-table
td:first-child {

    min-width:170px !important;

}


/* =========================================================
   DAYS
   ========================================================= */

html body .wprod-days-red {

    color:#ee1c25 !important;

    font-weight:500 !important;

}


html body .wprod-days-orange {

    color:#e67e00 !important;

    font-weight:500 !important;

}


html body .wprod-days-green {

    color:#43a047 !important;

    font-weight:500 !important;

}


/* =========================================================
   LEGEND
   ========================================================= */

html body .wprod-legend {

    display:flex !important;

    justify-content:center !important;

    align-items:center !important;

    flex-wrap:wrap !important;

    gap:5px !important;

    margin-top:9px !important;

    font-size:8px !important;

}


html body .wprod-legend-label {

    font-weight:700 !important;

}


html body .wprod-legend-chip {

    color:#ffffff !important;

    padding:
        4px 7px !important;

    border-radius:2px !important;

}


html body .wprod-legend-red {

    background:#ee1c25 !important;

}


html body .wprod-legend-orange {

    background:#e67e00 !important;

}


html body .wprod-legend-green {

    background:#4caf50 !important;

}


/* =========================================================
   NO DATA
   ========================================================= */

html body .wprod-no-data {

    padding:18px !important;

    background:#ffffff !important;

    color:#777777 !important;

    border-radius:4px !important;

    text-align:center !important;

    font-size:10px !important;

}


/* =========================================================
   RESPONSIVE
   ========================================================= */

@media (max-width:900px) {

    html body .wprod-top-grid {

        grid-template-columns:
            1fr !important;

    }

}



/* =========================================================
   FINAL ALIGNMENT + DAY COLOR UPGRADES
   IMPORTANT:
   These rules DO NOT change the existing red/green
   Minimum/Maximum outlines in Raw Material Status.
   ========================================================= */


/* =========================================================
   AS-OF DATE COLOR
   ========================================================= */

html body .wprod-asof {

    color:#777777 !important;

}


html body .wprod-asof strong {

    color:#2e3192 !important;

    font-weight:500 !important;

}


/* =========================================================
   TOP DRC PRODUCTION ALIGNMENT
   ========================================================= */

html body table.wprod-drc-table {

    width:100% !important;

    table-layout:fixed !important;

}


html body table.wprod-drc-table
thead th:first-child,

html body table.wprod-drc-table
tbody td:first-child {

    width:38% !important;

    text-align:left !important;

}


html body table.wprod-drc-table
thead th:nth-child(2),

html body table.wprod-drc-table
tbody td:nth-child(2) {

    width:62% !important;

    text-align:center !important;

    font-variant-numeric:
        tabular-nums !important;

}


/* =========================================================
   MONTHLY PRODUCTION ALIGNMENT
   ========================================================= */

html body table.wprod-month-table {

    width:100% !important;

    table-layout:fixed !important;

}


html body table.wprod-month-table
thead th:first-child,

html body table.wprod-month-table
tbody td:first-child {

    width:18% !important;

    text-align:left !important;

}


html body table.wprod-month-table
thead th:nth-child(2),

html body table.wprod-month-table
thead th:nth-child(3),

html body table.wprod-month-table
thead th:nth-child(4),

html body table.wprod-month-table
thead th:nth-child(5),

html body table.wprod-month-table
tbody td:nth-child(2),

html body table.wprod-month-table
tbody td:nth-child(3),

html body table.wprod-month-table
tbody td:nth-child(4),

html body table.wprod-month-table
tbody td:nth-child(5) {

    width:20.5% !important;

    text-align:center !important;

    font-variant-numeric:
        tabular-nums !important;

}


/* =========================================================
   BOTTOM RAW MATERIAL TABLE ALIGNMENT
   ========================================================= */

html body table.wprod-material-table {

    width:100% !important;

    min-width:760px !important;

    table-layout:fixed !important;

}


/* ITEM */

html body table.wprod-material-table
thead th:nth-child(1),

html body table.wprod-material-table
tbody td:nth-child(1) {

    width:25% !important;

    text-align:left !important;

}


/* UOM */

html body table.wprod-material-table
thead th:nth-child(2),

html body table.wprod-material-table
tbody td:nth-child(2) {

    width:9% !important;

    text-align:center !important;

}


/* QTY / FFP */

html body table.wprod-material-table
thead th:nth-child(3),

html body table.wprod-material-table
tbody td:nth-child(3) {

    width:13% !important;

    text-align:center !important;

}


/* AVAILABLE QTY */

html body table.wprod-material-table
thead th:nth-child(4),

html body table.wprod-material-table
tbody td:nth-child(4) {

    width:17% !important;

    text-align:center !important;

}


/* 15K / 18K / 22K */

html body table.wprod-material-table
thead th:nth-child(5),

html body table.wprod-material-table
thead th:nth-child(6),

html body table.wprod-material-table
thead th:nth-child(7),

html body table.wprod-material-table
tbody td:nth-child(5),

html body table.wprod-material-table
tbody td:nth-child(6),

html body table.wprod-material-table
tbody td:nth-child(7) {

    width:12% !important;

    text-align:center !important;

    font-variant-numeric:
        tabular-nums !important;

}


/* =========================================================
   DAY COLOR CODING

   <= 30 DAYS = RED
   31 - 60 DAYS = ORANGE
   > 60 DAYS = GREEN

   Strong selectors override PHPRunner's generic TD color.
   ========================================================= */

html body table.wprod-material-table
tbody td.wprod-days-red {

    color:#ee1c25 !important;

    font-weight:500 !important;

    text-align:center !important;

}


html body table.wprod-material-table
tbody td.wprod-days-orange {

    color:#e67e00 !important;

    font-weight:500 !important;

    text-align:center !important;

}


html body table.wprod-material-table
tbody td.wprod-days-green {

    color:#43a047 !important;

    font-weight:500 !important;

    text-align:center !important;

}

</style>

";


/* =========================================================
   15. PAGE START
   ========================================================= */

echo "

<div class='wprod-dashboard'>


    <!-- ================================================
         TOOLBAR
         ================================================ -->

    <div class='wprod-toolbar'>


        <a

            href='" .
            $esc(
                $exportUrl
            )
            . "'

            class='
                wprod-toolbar-btn
                wprod-toolbar-export
            '

        >

            &#8681;&nbsp;
            Export

        </a>


        <a

            href='" .
            $esc(
                $addNewUrl
            )
            . "'

            class='
                wprod-toolbar-btn
                wprod-toolbar-add
            '

        >

            +&nbsp;
            Add new

        </a>


    </div>


    <div class='wprod-top-grid'>


        <!-- ============================================
             STATUS OF DRCS PRODUCTION
             ============================================ -->

        <div class='wprod-card'>


            <div class='wprod-title'>

                Status of DRCs Production

            </div>


            <div class='wprod-scroll'>


                <table
                    class='
                        wprod-table
                        wprod-drc-table
                    '
                >


                    <thead>

                        <tr>

                            <th>
                                DRCs
                            </th>

                            <th>

                                Product Output

                                <br>

                                (" .
                                $esc(
                                    $productionAsOfDisplay
                                )
                                . ")

                            </th>

                        </tr>

                    </thead>


                    <tbody>

";


foreach (
    $facilityCodes
    as $code
) {

    $productionText =

        $facilityHasProduction[
            $code
        ]

        ? $num(
            $facilityTotals[
                $code
            ]
        )

        : "-";


    echo "

        <tr>

            <td>

                " .
                $esc(
                    $code
                )
                . "

            </td>


            <td>

                " .
                $productionText
                . "

            </td>

        </tr>

    ";

}


echo "

        <tr class='wprod-total-row'>

            <td>

                Total

            </td>


            <td>

                " .
                (
                    $hasAnyProduction

                    ? $num(
                        $grandProductionTotal
                    )

                    : "-"
                )
                . "

            </td>

        </tr>


                    </tbody>

                </table>

            </div>

        </div>


        <!-- ============================================
             STATUS OF RAW MATERIALS
             ============================================ -->

        <div class='wprod-card'>


            <div class='wprod-title'>

                Status of Raw Materials
                for Production

            </div>


            <div class='wprod-scroll'>


                <table
                    class='wprod-status-table'
                >


                    <thead>


                        <tr>


                            <th

                                rowspan='2'

                                class='wprod-head-drc'

                            >

                                DRCs

                            </th>


                            <th

                                colspan='2'

                                class='wprod-head-min-title'

                            >

                                Minimum

                            </th>


                            <th

                                colspan='2'

                                class='wprod-head-max-title'

                            >

                                Maximum

                            </th>


                            <th

                                rowspan='2'

                                class='wprod-head-action'

                            >

                            </th>


                        </tr>


                        <tr>


                            <th
                                class='wprod-head-min-item'
                            >

                                Item

                            </th>


                            <th
                                class='wprod-head-min-days'
                            >

                                Days

                            </th>


                            <th
                                class='wprod-head-max-item'
                            >

                                Item

                            </th>


                            <th
                                class='wprod-head-max-days'
                            >

                                Days

                            </th>


                        </tr>


                    </thead>


                    <tbody>

";


foreach (
    $facilityCodes
    as $code
) {

    $minimum =
        $rawStatus[
            $code
        ]["minimum"];


    $maximum =
        $rawStatus[
            $code
        ]["maximum"];


    $minimumItem =

        $minimum

        ? $minimum["item"]

        : "No stock data";


    $minimumDays =

        $minimum

        ? intval(
            $minimum["days"]
        )

        : "-";


    $maximumItem =

        $maximum

        ? $maximum["item"]

        : "No stock data";


    $maximumDays =

        $maximum

        ? intval(
            $maximum["days"]
        )

        : "-";


    $facilityId =

        isset(
            $facilityIds[
                $code
            ]
        )

        ? intval(
            $facilityIds[
                $code
            ]
        )

        : 0;


    $forecastUrl =

        $forecastListUrl

        .

        "?mother_facility_id="

        .

        $facilityId

        .

        "&mother_facility_code="

        .

        urlencode(
            $code
        );


    echo "

        <tr>


            <td>

                " .
                $esc(
                    $code
                )
                . "

            </td>


            <td
                class='wprod-min-text'
            >

                <span

                    class='wprod-item-clip'

                    title='" .
                    $esc(
                        $minimumItem
                    )
                    . "'

                >

                    " .
                    $esc(
                        $minimumItem
                    )
                    . "

                </span>

            </td>


            <td
                class='
                    wprod-min-text
                    wprod-days-cell
                '
            >

                " .
                $minimumDays
                . "

            </td>


            <td
                class='wprod-max-text'
            >

                <span

                    class='wprod-item-clip'

                    title='" .
                    $esc(
                        $maximumItem
                    )
                    . "'

                >

                    " .
                    $esc(
                        $maximumItem
                    )
                    . "

                </span>

            </td>


            <td
                class='
                    wprod-max-text
                    wprod-days-cell
                '
            >

                " .
                $maximumDays
                . "

            </td>


            <td
                class='wprod-action-cell'
            >

                <a

                    href='" .
                    $esc(
                        $forecastUrl
                    )
                    . "'

                    class='wprod-forecast-btn'

                >

                    Generate Forecast

                </a>

            </td>


        </tr>

    ";

}


/* =========================================================
   RAW MATERIAL TOTAL
   ========================================================= */

$lowestHtml =

    $overallLowest !== null

    ?

    "<strong>"
    .
    intval(
        $overallLowest
    )
    .
    " Days</strong>
     <small>(Lowest)</small>"

    :

    "-";


$highestHtml =

    $overallHighest !== null

    ?

    "<strong>"
    .
    intval(
        $overallHighest
    )
    .
    " Days</strong>
     <small>(Highest)</small>"

    :

    "-";


echo "

        <tr
            class='wprod-raw-total'
        >


            <td>

                Total

            </td>


            <td>

            </td>


            <td
                class='wprod-total-low'
            >

                " .
                $lowestHtml
                . "

            </td>


            <td>

            </td>


            <td
                class='wprod-total-high'
            >

                " .
                $highestHtml
                . "

            </td>


            <td>

            </td>


        </tr>


                    </tbody>


                </table>


            </div>


        </div>


    </div>

";


/* =========================================================
   16. MONTHLY PRODUCTION TABLE

   IMPORTANT:
   Manual Production Reports are added to Subtotal only.
   They are not assigned to LDRC / VDRC / MDRC because the
   manual report source has no mother-facility field.

   Confirmed manual production:
   March 2026 = 3,000
   ========================================================= */

echo "

    <div class='wprod-section'>


        <div class='wprod-asof'>

            As of

            <strong>

                " .
                $esc(
                    $productionAsOfDisplay
                )
                . "

            </strong>

        </div>


        <div class='wprod-scroll'>


            <table
                class='
                    wprod-table
                    wprod-month-table
                '
            >


                <thead>


                    <tr>


                        <th>
                            Dates
                        </th>


                        <th>
                            LDRC
                        </th>


                        <th>
                            VDRC
                        </th>


                        <th>
                            MDRC
                        </th>


                        <th>
                            Subtotal
                        </th>


                    </tr>


                </thead>


                <tbody>

";


for (
    $month = 1;
    $month <= 12;
    $month++
) {

    $ldrc =
        floatval(
            $monthly[
                $month
            ]["LDRC"]
        );


    $vdrc =
        floatval(
            $monthly[
                $month
            ]["VDRC"]
        );


    $mdrc =
        floatval(
            $monthly[
                $month
            ]["MDRC"]
        );


    /*
     * Manual Production Report quantity for the month.
     * This is included only in Subtotal.
     */

    $manualQty =
        isset(
            $monthlyManual[
                $month
            ]
        )

        ? floatval(
            $monthlyManual[
                $month
            ]
        )

        : 0;


    $subtotal =
        $ldrc
        +
        $vdrc
        +
        $mdrc
        +
        $manualQty;


    $ldrcText =
        $ldrc != 0

        ? $num($ldrc)

        : "-";


    $vdrcText =
        $vdrc != 0

        ? $num($vdrc)

        : "-";


    $mdrcText =
        $mdrc != 0

        ? $num($mdrc)

        : "-";


    $subtotalText =
        $subtotal != 0

        ? $num($subtotal)

        : "-";


    echo "

        <tr>


            <td>

                " .
                $esc(
                    $monthNames[
                        $month
                    ]
                )
                . "

            </td>


            <td>

                " .
                $ldrcText
                . "

            </td>


            <td>

                " .
                $vdrcText
                . "

            </td>


            <td>

                " .
                $mdrcText
                . "

            </td>


            <td>

                " .
                $subtotalText
                . "

            </td>


        </tr>

    ";

}


echo "

        <tr
            class='wprod-total-row'
        >


            <td>

                Total

            </td>


            <td>

                " .
                (
                    $facilityHasProduction[
                        "LDRC"
                    ]

                    ? $num(
                        $facilityTotals[
                            "LDRC"
                        ]
                    )

                    : "-"
                )
                . "

            </td>


            <td>

                " .
                (
                    $facilityHasProduction[
                        "VDRC"
                    ]

                    ? $num(
                        $facilityTotals[
                            "VDRC"
                        ]
                    )

                    : "-"
                )
                . "

            </td>


            <td>

                " .
                (
                    $facilityHasProduction[
                        "MDRC"
                    ]

                    ? $num(
                        $facilityTotals[
                            "MDRC"
                        ]
                    )

                    : "-"
                )
                . "

            </td>


            <td>

                " .
                (
                    $hasAnyProduction

                    ? $num(
                        $grandProductionTotal
                    )

                    : "-"
                )
                . "

            </td>


        </tr>


                </tbody>


            </table>


        </div>


    </div>

";


/* =========================================================
   17. BOTTOM RAW MATERIAL TABLE
   ========================================================= */

echo "

    <div class='wprod-section'>


        <div class='wprod-asof'>

            Inventory as of

            <strong>

                " .
                $esc(
                    $stockAsOfDisplay
                )
                . "

            </strong>

        </div>

";


if (
    count(
        $materials
    ) === 0
) {

    echo "

        <div class='wprod-no-data'>

            No positive production raw-material
            inventory was found for
            LDRC, VDRC or MDRC.

        </div>

    ";

} else {


    echo "

        <div class='wprod-scroll'>


            <table
                class='
                    wprod-table
                    wprod-material-table
                '
            >


                <thead>


                    <tr>


                        <th>

                            Items

                        </th>


                        <th>

                            UoM

                        </th>


                        <th>

                            Quantity per FFP

                        </th>


                        <th>

                            Quantity as of

                            <br>

                            " .
                            $esc(
                                $stockAsOfDisplay
                            )
                            . "

                        </th>


                        <th>

                            Days to Produce

                            <br>

                            @ 15,000 FFPs

                        </th>


                        <th>

                            Days to Produce

                            <br>

                            @ 18,000 FFPs

                        </th>


                        <th>

                            Days to Produce

                            <br>

                            @ 22,000 FFPs

                        </th>


                    </tr>


                </thead>


                <tbody>

    ";


    foreach (
        $materials
        as $material
    ) {

        $class15000 =
            $daysClass(
                $material[
                    "days_15000"
                ]
            );


        $class18000 =
            $daysClass(
                $material[
                    "days_18000"
                ]
            );


        $class22000 =
            $daysClass(
                $material[
                    "days_22000"
                ]
            );


        $qtyPerFfpText =

            floatval(
                $material[
                    "qty_per_ffp"
                ]
            ) > 0

            ?

            $trimNumber(
                $material[
                    "qty_per_ffp"
                ],
                4
            )

            :

            "-";


        echo "

            <tr>


                <td>

                    " .
                    $esc(
                        $material[
                            "item"
                        ]
                    )
                    . "

                </td>


                <td>

                    " .
                    $esc(
                        $material[
                            "uom"
                        ]
                    )
                    . "

                </td>


                <td>

                    " .
                    $esc(
                        $qtyPerFfpText
                    )
                    . "

                </td>


                <td>

                    " .
                    $num(
                        $material[
                            "available_qty"
                        ]
                    )
                    . "

                </td>


                <td
                    class='" .
                    $class15000 .
                    "'
                >

                    " .
                    intval(
                        $material[
                            "days_15000"
                        ]
                    )
                    . "
                    Days

                </td>


                <td
                    class='" .
                    $class18000 .
                    "'
                >

                    " .
                    intval(
                        $material[
                            "days_18000"
                        ]
                    )
                    . "
                    Days

                </td>


                <td
                    class='" .
                    $class22000 .
                    "'
                >

                    " .
                    intval(
                        $material[
                            "days_22000"
                        ]
                    )
                    . "
                    Days

                </td>


            </tr>

        ";

    }


    echo "

                </tbody>


            </table>


        </div>


        <div class='wprod-legend'>


            <span
                class='wprod-legend-label'
            >

                Legend:

            </span>


            <span
                class='
                    wprod-legend-chip
                    wprod-legend-red
                '
            >

                less than 30 Days

            </span>


            <span
                class='
                    wprod-legend-chip
                    wprod-legend-orange
                '
            >

                31 to 60 Days

            </span>


            <span
                class='
                    wprod-legend-chip
                    wprod-legend-green
                '
            >

                more than 61 Days

            </span>


        </div>

    ";

}


echo "

    </div>


</div>

";
		;
		
	}

	// code snippet - header k
	function event_64515(  ) {
		
		/* =========================================================
   WINGS / DSWD DYNAMIC CUSTOM HEADER
   PHPRUNNER 11.3

   UPDATED VERSION

   LEFT:
   - DYNAMIC PAGE TITLE
   - SHORT DYNAMIC BREADCRUMB
   - MOVES WITH EXPANDED/COLLAPSED SIDEBAR
   - DOES NOT OVERLAP HAMBURGER/HIDE BUTTON
   - DOES NOT FOLLOW PAGE WHEN SCROLLING

   RIGHT:
   - SEARCH
   - SETTINGS
   - NOTIFICATION
   - CURRENT LOGGED-IN USER
   - DOES NOT FOLLOW PAGE WHEN SCROLLING

   USER:
   - NO HARDCODED NAME
   - NO HARDCODED ADMIN ROLE

   ALSO:
   - REMOVES PENDING APPROVAL BADGE

   DO NOT ADD <?php OR ?>
   ========================================================= */


/* =========================================================
   1. CURRENT LOGGED-IN USER
   ========================================================= */

$headerUserName = "";
$headerUserRole = "";


/* ---------------------------------------------------------
   TRY FIRST NAME + LAST NAME
   --------------------------------------------------------- */

$firstName = "";
$lastName = "";


if (
    isset($_SESSION["FirstName"])
    &&
    trim($_SESSION["FirstName"]) != ""
) {

    $firstName =
        trim(
            $_SESSION["FirstName"]
        );
}


if (
    isset($_SESSION["LastName"])
    &&
    trim($_SESSION["LastName"]) != ""
) {

    $lastName =
        trim(
            $_SESSION["LastName"]
        );
}


if (
    $firstName != ""
    ||
    $lastName != ""
) {

    $headerUserName =
        trim(
            $firstName . " " . $lastName
        );

}


/* ---------------------------------------------------------
   TRY COMMON SESSION FIELDS
   --------------------------------------------------------- */

if ($headerUserName == "") {

    $userNameCandidates = array(

        "FullName",
        "full_name",
        "fullname",

        "DisplayName",
        "display_name",

        "UserFullName",
        "user_full_name",

        "Name",
        "name",

        "UserName",
        "username"

    );


    foreach (
        $userNameCandidates
        as $candidate
    ) {

        if (
            isset($_SESSION[$candidate])
            &&
            trim(
                (string)$_SESSION[$candidate]
            ) != ""
        ) {

            $headerUserName =
                trim(
                    (string)$_SESSION[$candidate]
                );

            break;

        }

    }

}


/* ---------------------------------------------------------
   PHPRUNNER SECURITY FALLBACK
   --------------------------------------------------------- */

if (
    $headerUserName == ""
    &&
    class_exists("Security")
    &&
    method_exists(
        "Security",
        "getUserName"
    )
) {

    try {

        $securityUserName =
            Security::getUserName();


        if (
            $securityUserName !== null
            &&
            trim(
                (string)$securityUserName
            ) != ""
        ) {

            $headerUserName =
                trim(
                    (string)$securityUserName
                );

        }

    } catch (Throwable $e) {

        /* ignore */

    }

}


/* ---------------------------------------------------------
   ROLE
   --------------------------------------------------------- */

$roleCandidates = array(

    "role_name",
    "RoleName",

    "role",
    "Role",

    "user_role",
    "UserRole",

    "group_name",
    "GroupName",

    "group",
    "Group",

    "UserGroup"

);


foreach (
    $roleCandidates
    as $candidate
) {

    if (
        isset($_SESSION[$candidate])
        &&
        trim(
            (string)$_SESSION[$candidate]
        ) != ""
    ) {

        $headerUserRole =
            trim(
                (string)$_SESSION[$candidate]
            );

        break;

    }

}


/* ---------------------------------------------------------
   REAL ADMIN CHECK
   --------------------------------------------------------- */

if (
    $headerUserRole == ""
    &&
    class_exists("Security")
    &&
    method_exists(
        "Security",
        "isAdmin"
    )
) {

    try {

        if (
            Security::isAdmin()
        ) {

            $headerUserRole =
                "Administrator";

        }

    } catch (Throwable $e) {

        /* leave blank */

    }

}


/* ---------------------------------------------------------
   SAFE USER FALLBACK
   --------------------------------------------------------- */

if ($headerUserName == "") {

    $headerUserName = "User";

}


/* ---------------------------------------------------------
   ESCAPE
   --------------------------------------------------------- */

$headerUserName =
    htmlspecialchars(
        $headerUserName,
        ENT_QUOTES,
        "UTF-8"
    );


$headerUserRole =
    htmlspecialchars(
        $headerUserRole,
        ENT_QUOTES,
        "UTF-8"
    );



/* =========================================================
   2. CSS
   ========================================================= */

echo "

<style>


/* =========================================================
   CUSTOM HEADER HOLDER
   ========================================================= */

#wingsCustomHeader {

    display: block !important;

    width: 0 !important;

    height: 0 !important;

    min-width: 0 !important;

    min-height: 0 !important;

    padding: 0 !important;

    margin: 0 !important;

    border: 0 !important;

    background: transparent !important;

    overflow: visible !important;

    position: static !important;

    font-family:
        Arial,
        sans-serif !important;

}



/* =========================================================
   TITLE AREA

   IMPORTANT:
   ABSOLUTE = WILL NOT FOLLOW USER WHILE SCROLLING
   ========================================================= */

#wingsCustomHeader
.wings-header-title-area {

    position: absolute !important;

    top: 13px !important;

    left:
        var(
            --wings-title-left,
            350px
        ) !important;

    width:
        var(
            --wings-title-width,
            480px
        ) !important;

    max-width:
        var(
            --wings-title-width,
            480px
        ) !important;

    height: 45px !important;

    display: flex !important;

    flex-direction: column !important;

    align-items: flex-start !important;

    justify-content: center !important;

    box-sizing: border-box !important;

    padding: 0 !important;

    margin: 0 !important;

    color: #ffffff !important;

    font-family:
        Arial,
        sans-serif !important;

    pointer-events: none !important;

    overflow: hidden !important;

    z-index: 999990 !important;

}



/* =========================================================
   BIG TITLE
   ========================================================= */

#wingsCustomHeader
.wings-page-title {

    display: block !important;

    width: 100% !important;

    max-width: 100% !important;

    min-width: 0 !important;

    padding: 0 !important;

    margin: 0 !important;

    color: #ffffff !important;

    font-family:
        Arial,
        sans-serif !important;

    font-size: 25px !important;

    line-height: 27px !important;

    font-weight: 700 !important;

    letter-spacing: 0 !important;

    white-space: nowrap !important;

    overflow: hidden !important;

    text-overflow: ellipsis !important;

}



/* =========================================================
   BREADCRUMB
   ========================================================= */

#wingsCustomHeader
.wings-breadcrumb {

    display: block !important;

    width: 100% !important;

    max-width: 100% !important;

    padding: 0 !important;

    margin:
        3px
        0
        0
        0 !important;

    color: #ffffff !important;

    font-family:
        Arial,
        sans-serif !important;

    font-size: 8px !important;

    line-height: 10px !important;

    font-weight: 600 !important;

    white-space: nowrap !important;

    overflow: hidden !important;

    text-overflow: ellipsis !important;

}



/* =========================================================
   RIGHT SIDE

   IMPORTANT:
   ABSOLUTE = WILL NOT FOLLOW USER WHILE SCROLLING
   ========================================================= */

#wingsCustomHeader
.wings-header-right {

    position: absolute !important;

    top: 17px !important;

    right: 38px !important;

    left: auto !important;

    bottom: auto !important;

    display: flex !important;

    flex-direction: row !important;

    align-items: center !important;

    justify-content: flex-end !important;

    flex-wrap: nowrap !important;

    gap: 10px !important;

    width: auto !important;

    height: 34px !important;

    padding: 0 !important;

    margin: 0 !important;

    background: transparent !important;

    box-sizing: border-box !important;

    z-index: 999999 !important;

}



/* =========================================================
   SEARCH BOX
   ========================================================= */

#wingsCustomHeader
.wings-search-box {

    display: flex !important;

    flex-direction: row !important;

    align-items: center !important;

    width: 220px !important;

    height: 28px !important;

    min-width: 0 !important;

    padding: 0 !important;

    margin: 0 !important;

    box-sizing: border-box !important;

    background: #ffffff !important;

    border:
        1px
        solid
        rgba(
            255,
            255,
            255,
            .75
        ) !important;

    border-radius: 4px !important;

    overflow: hidden !important;

}



/* =========================================================
   SEARCH BUTTON
   ========================================================= */

#wingsCustomHeader
.wings-search-button {

    display: flex !important;

    align-items: center !important;

    justify-content: center !important;

    width: 30px !important;

    min-width: 30px !important;

    height: 28px !important;

    padding: 0 !important;

    margin: 0 !important;

    border: 0 !important;

    outline: 0 !important;

    box-shadow: none !important;

    background: #ffffff !important;

    color: #2e3192 !important;

    cursor: pointer !important;

}


#wingsCustomHeader
.wings-search-button
svg {

    width: 12px !important;

    height: 12px !important;

    display: block !important;

    fill: none !important;

    stroke: #2e3192 !important;

    stroke-width: 2 !important;

    stroke-linecap: round !important;

    stroke-linejoin: round !important;

}



/* =========================================================
   SEARCH INPUT
   ========================================================= */

#wingsCustomHeader
.wings-search-input {

    display: block !important;

    width:
        calc(
            100% - 30px
        ) !important;

    min-width: 0 !important;

    height: 28px !important;

    line-height: 28px !important;

    padding:
        0
        9px
        0
        0 !important;

    margin: 0 !important;

    box-sizing: border-box !important;

    border: 0 !important;

    border-radius: 0 !important;

    outline: 0 !important;

    box-shadow: none !important;

    background: #ffffff !important;

    color: #444444 !important;

    font-family:
        Arial,
        sans-serif !important;

    font-size: 9px !important;

}


#wingsCustomHeader
.wings-search-input::placeholder {

    color: #aaaaaa !important;

    opacity: 1 !important;

}



/* =========================================================
   ACTION HOLDER
   ========================================================= */

#wingsCustomHeader
.wings-action-area {

    display: block !important;

    position: relative !important;

    width: auto !important;

    height: auto !important;

    padding: 0 !important;

    margin: 0 !important;

}



/* =========================================================
   ICON BUTTON
   ========================================================= */

#wingsCustomHeader
.wings-icon-button {

    display: flex !important;

    align-items: center !important;

    justify-content: center !important;

    width: 28px !important;

    min-width: 28px !important;

    height: 28px !important;

    min-height: 28px !important;

    padding: 0 !important;

    margin: 0 !important;

    box-sizing: border-box !important;

    border: 0 !important;

    outline: 0 !important;

    box-shadow: none !important;

    background: #ffffff !important;

    color: #2e3192 !important;

    cursor: pointer !important;

}


#wingsCustomHeader
.wings-icon-button:hover {

    background: #f4f4f5 !important;

}



/* SETTINGS */

#wingsCustomHeader
.wings-settings-button {

    border-radius: 4px !important;

}



/* NOTIFICATIONS */

#wingsCustomHeader
.wings-notification-button {

    position: relative !important;

    border-radius: 50% !important;

}


#wingsCustomHeader
.wings-icon-button
svg {

    display: block !important;

    width: 15px !important;

    height: 15px !important;

    fill: none !important;

    stroke: #2e3192 !important;

    stroke-width: 1.7 !important;

    stroke-linecap: round !important;

    stroke-linejoin: round !important;

}



/* =========================================================
   NOTIFICATION DOT
   ========================================================= */

#wingsCustomHeader
.wings-notification-dot {

    display: none !important;

    position: absolute !important;

    top: 4px !important;

    right: 4px !important;

    width: 6px !important;

    height: 6px !important;

    border-radius: 50% !important;

    background: #ee1c25 !important;

    border:
        1px
        solid
        #ffffff !important;

}



/* =========================================================
   DROPDOWNS
   ========================================================= */

#wingsCustomHeader
.wings-action-menu,

#wingsCustomHeader
.wings-user-menu {

    display: none !important;

    position: absolute !important;

    top: 40px !important;

    right: 0 !important;

    left: auto !important;

    width: 205px !important;

    min-width: 205px !important;

    padding:
        6px
        0 !important;

    margin: 0 !important;

    box-sizing: border-box !important;

    background: #ffffff !important;

    border:
        1px
        solid
        #dddddd !important;

    border-radius: 7px !important;

    box-shadow:
        0
        8px
        24px
        rgba(
            0,
            0,
            0,
            .16
        ) !important;

    z-index: 1000000 !important;

}


#wingsCustomHeader
.wings-action-menu.wings-open,

#wingsCustomHeader
.wings-user-menu.wings-open {

    display: block !important;

}



/* =========================================================
   POPUP TITLE
   ========================================================= */

#wingsCustomHeader
.wings-popup-title {

    display: block !important;

    padding:
        8px
        14px !important;

    margin: 0 !important;

    color: #222222 !important;

    font-family:
        Arial,
        sans-serif !important;

    font-size: 11px !important;

    line-height: 15px !important;

    font-weight: 700 !important;

}



/* =========================================================
   LINKS
   ========================================================= */

#wingsCustomHeader
.wings-action-menu
a,

#wingsCustomHeader
.wings-user-menu
a {

    display: block !important;

    width: 100% !important;

    box-sizing: border-box !important;

    padding:
        9px
        14px !important;

    margin: 0 !important;

    background: transparent !important;

    color: #333333 !important;

    font-family:
        Arial,
        sans-serif !important;

    font-size: 11px !important;

    line-height: 15px !important;

    text-decoration: none !important;

}


#wingsCustomHeader
.wings-action-menu
a:hover,

#wingsCustomHeader
.wings-user-menu
a:hover {

    background: #f4f4f6 !important;

    color: #2e3192 !important;

}



/* =========================================================
   DIVIDER
   ========================================================= */

#wingsCustomHeader
.wings-menu-divider {

    display: block !important;

    width: 100% !important;

    height: 1px !important;

    margin:
        5px
        0 !important;

    padding: 0 !important;

    background: #eeeeee !important;

}



/* =========================================================
   EMPTY NOTIFICATION
   ========================================================= */

#wingsCustomHeader
.wings-notification-empty {

    padding: 14px !important;

    color: #777777 !important;

    font-family:
        Arial,
        sans-serif !important;

    font-size: 10px !important;

    line-height: 15px !important;

    text-align: center !important;

}



/* =========================================================
   USER AREA
   ========================================================= */

#wingsCustomHeader
.wings-user-area {

    display: block !important;

    position: relative !important;

    margin:
        0
        0
        0
        1px !important;

    padding: 0 !important;

}



/* =========================================================
   USER BUTTON
   ========================================================= */

#wingsCustomHeader
.wings-user-button {

    display: flex !important;

    flex-direction: row !important;

    align-items: center !important;

    justify-content: flex-start !important;

    gap: 8px !important;

    height: 32px !important;

    min-height: 32px !important;

    padding: 0 !important;

    margin: 0 !important;

    border: 0 !important;

    outline: 0 !important;

    box-shadow: none !important;

    background: transparent !important;

    color: #ffffff !important;

    cursor: pointer !important;

}



/* =========================================================
   USER AVATAR
   ========================================================= */

#wingsCustomHeader
.wings-user-avatar {

    display: flex !important;

    align-items: center !important;

    justify-content: center !important;

    width: 28px !important;

    min-width: 28px !important;

    height: 28px !important;

    padding: 0 !important;

    margin: 0 !important;

    border-radius: 50% !important;

    background: #ffffff !important;

}


#wingsCustomHeader
.wings-user-avatar
svg {

    display: block !important;

    width: 16px !important;

    height: 16px !important;

    fill: none !important;

    stroke: #2e3192 !important;

    stroke-width: 1.6 !important;

    stroke-linecap: round !important;

    stroke-linejoin: round !important;

}



/* =========================================================
   USER INFORMATION
   ========================================================= */

#wingsCustomHeader
.wings-user-information {

    display: flex !important;

    flex-direction: column !important;

    align-items: flex-start !important;

    justify-content: center !important;

    min-width: 0 !important;

    max-width: 140px !important;

    overflow: hidden !important;

}



/* USER NAME */

#wingsCustomHeader
.wings-user-name {

    display: block !important;

    max-width: 140px !important;

    color: #ffffff !important;

    font-family:
        Arial,
        sans-serif !important;

    font-size: 12px !important;

    line-height: 14px !important;

    font-weight: 400 !important;

    white-space: nowrap !important;

    overflow: hidden !important;

    text-overflow: ellipsis !important;

}



/* USER ROLE */

#wingsCustomHeader
.wings-user-role {

    display: block !important;

    max-width: 140px !important;

    margin-top: 1px !important;

    color:
        rgba(
            255,
            255,
            255,
            .85
        ) !important;

    font-family:
        Arial,
        sans-serif !important;

    font-size: 9px !important;

    line-height: 11px !important;

    white-space: nowrap !important;

    overflow: hidden !important;

    text-overflow: ellipsis !important;

}


#wingsCustomHeader
.wings-user-role:empty {

    display: none !important;

}



/* =========================================================
   USER ARROW
   ========================================================= */

#wingsCustomHeader
.wings-user-arrow {

    display: flex !important;

    align-items: center !important;

    justify-content: center !important;

    width: 14px !important;

    min-width: 14px !important;

    height: 28px !important;

    transition:
        transform
        .15s
        ease !important;

}


#wingsCustomHeader
.wings-user-button[aria-expanded='true']
.wings-user-arrow {

    transform:
        rotate(
            180deg
        ) !important;

}


#wingsCustomHeader
.wings-user-arrow
svg {

    width: 10px !important;

    height: 10px !important;

    fill: none !important;

    stroke: #ffffff !important;

    stroke-width: 2 !important;

    stroke-linecap: round !important;

    stroke-linejoin: round !important;

}



/* =========================================================
   SIGN OUT
   ========================================================= */

#wingsCustomHeader
.wings-user-menu
a.wings-signout {

    color: #ee1c25 !important;

}



/* =========================================================
   SEARCH MESSAGE

   ABSOLUTE SO IT DOES NOT FOLLOW SCROLL
   ========================================================= */

#wingsSearchMessage {

    display: none !important;

    position: absolute !important;

    top: 58px !important;

    right: 38px !important;

    min-width: 180px !important;

    max-width: 320px !important;

    padding:
        7px
        11px !important;

    box-sizing: border-box !important;

    background: #ffffff !important;

    border:
        1px
        solid
        #dddddd !important;

    border-radius: 5px !important;

    box-shadow:
        0
        5px
        15px
        rgba(
            0,
            0,
            0,
            .12
        ) !important;

    color: #555555 !important;

    font-family:
        Arial,
        sans-serif !important;

    font-size: 10px !important;

    line-height: 14px !important;

    z-index: 1000001 !important;

}


#wingsSearchMessage.wings-show {

    display: block !important;

}



/* =========================================================
   RESPONSIVE
   ========================================================= */

@media screen and (max-width: 1250px) {

    #wingsCustomHeader
    .wings-search-box {

        width: 180px !important;

    }


    #wingsCustomHeader
    .wings-page-title {

        font-size: 23px !important;

    }

}



@media screen and (max-width: 1050px) {

    #wingsCustomHeader
    .wings-search-box {

        width: 150px !important;

    }


    #wingsCustomHeader
    .wings-user-information {

        max-width: 100px !important;

    }


    #wingsCustomHeader
    .wings-user-name,

    #wingsCustomHeader
    .wings-user-role {

        max-width: 100px !important;

    }


    #wingsCustomHeader
    .wings-page-title {

        font-size: 21px !important;

        line-height: 24px !important;

    }

}



@media screen and (max-width: 850px) {

    #wingsCustomHeader
    .wings-header-right {

        right: 18px !important;

        gap: 7px !important;

    }


    #wingsSearchMessage {

        right: 18px !important;

    }


    #wingsCustomHeader
    .wings-search-box {

        width: 130px !important;

    }


    #wingsCustomHeader
    .wings-user-information {

        display: none !important;

    }


    #wingsCustomHeader
    .wings-user-arrow {

        display: none !important;

    }


    #wingsCustomHeader
    .wings-page-title {

        font-size: 19px !important;

        line-height: 22px !important;

    }

}



@media screen and (max-width: 650px) {

    #wingsCustomHeader
    .wings-search-box {

        display: none !important;

    }

}



/* =========================================================
   REMOVE PENDING APPROVAL
   ========================================================= */

#wingsPendingApproval,

.wings-pending-approval,

.pending-approval,

.pending-approvals,

.pending-approval-badge {

    display: none !important;

}

</style>

";



/* =========================================================
   3. HTML
   ========================================================= */

echo "

<div id='wingsCustomHeader'>


    <!-- =================================================
         DYNAMIC TITLE
         ================================================= -->

    <div
        class='wings-header-title-area'
        id='wingsHeaderTitleArea'
    >


        <div
            class='wings-page-title'
            id='wingsDynamicPageTitle'
        >

            Dashboard

        </div>


        <div
            class='wings-breadcrumb'
            id='wingsDynamicBreadcrumb'
        >

            Dashboard

        </div>


    </div>



    <!-- =================================================
         RIGHT CONTROLS
         ================================================= -->

    <div
        class='wings-header-right'
        id='wingsHeaderRight'
    >


        <!-- SEARCH -->

        <div class='wings-search-box'>


            <button
                type='button'
                class='wings-search-button'
                id='wingsSearchButton'
                title='Search'
                aria-label='Search'
            >


                <svg viewBox='0 0 24 24'>


                    <circle
                        cx='10.5'
                        cy='10.5'
                        r='6.5'
                    ></circle>


                    <line
                        x1='15.5'
                        y1='15.5'
                        x2='21'
                        y2='21'
                    ></line>


                </svg>


            </button>


            <input
                type='text'
                class='wings-search-input'
                id='wingsGlobalSearch'
                placeholder='Search'
                autocomplete='off'
                aria-label='Search'
            >


        </div>



        <!-- SETTINGS -->

        <div class='wings-action-area'>


            <button
                type='button'
                class='wings-icon-button wings-settings-button'
                id='wingsSettingsButton'
                title='Settings'
                aria-label='Settings'
                aria-expanded='false'
            >


                <svg viewBox='0 0 24 24'>


                    <circle
                        cx='12'
                        cy='12'
                        r='3'
                    ></circle>


                    <path
                        d='
                        M12 2v3
                        M12 19v3
                        M4.9 4.9l2.1 2.1
                        M17 17l2.1 2.1
                        M2 12h3
                        M19 12h3
                        M4.9 19.1l2.1-2.1
                        M17 7l2.1-2.1
                        '
                    ></path>


                </svg>


            </button>


            <div
                class='wings-action-menu'
                id='wingsSettingsMenu'
            >


                <span class='wings-popup-title'>

                    Settings

                </span>


                <div class='wings-menu-divider'>
                </div>


                <a href='userinfo.php'>

                    My Profile

                </a>


                <a href='changepwd.php'>

                    Change Password

                </a>


            </div>


        </div>



        <!-- NOTIFICATIONS -->

        <div class='wings-action-area'>


            <button
                type='button'
                class='wings-icon-button wings-notification-button'
                id='wingsNotificationButton'
                title='Notifications'
                aria-label='Notifications'
                aria-expanded='false'
            >


                <svg viewBox='0 0 24 24'>


                    <path
                        d='
                        M18 8
                        a6 6 0 0 0-12 0
                        c0 7-3 7-3 9
                        h18
                        c0-2-3-2-3-9
                        '
                    ></path>


                    <path
                        d='
                        M10 20
                        a2.4 2.4 0 0 0 4 0
                        '
                    ></path>


                </svg>


                <span
                    class='wings-notification-dot'
                    id='wingsNotificationDot'
                >
                </span>


            </button>


            <div
                class='wings-action-menu'
                id='wingsNotificationMenu'
            >


                <span class='wings-popup-title'>

                    Notifications

                </span>


                <div class='wings-menu-divider'>
                </div>


                <div class='wings-notification-empty'>

                    No new notifications.

                </div>


            </div>


        </div>



        <!-- USER -->

        <div class='wings-user-area'>


            <button
                type='button'
                class='wings-user-button'
                id='wingsUserButton'
                aria-label='User menu'
                aria-expanded='false'
            >


                <span class='wings-user-avatar'>


                    <svg viewBox='0 0 24 24'>


                        <circle
                            cx='12'
                            cy='8'
                            r='4'
                        ></circle>


                        <path
                            d='
                            M4 21
                            c0-4.4 3.6-7 8-7
                            s8 2.6 8 7
                            '
                        ></path>


                    </svg>


                </span>


                <span class='wings-user-information'>


                    <span class='wings-user-name'>

                        {$headerUserName}

                    </span>


                    <span class='wings-user-role'>

                        {$headerUserRole}

                    </span>


                </span>


                <span class='wings-user-arrow'>


                    <svg viewBox='0 0 24 24'>


                        <path
                            d='M7 9l5 5 5-5'
                        ></path>


                    </svg>


                </span>


            </button>


            <div
                class='wings-user-menu'
                id='wingsUserMenu'
            >


                <a href='userinfo.php'>

                    My Profile

                </a>


                <a href='changepwd.php'>

                    Change Password

                </a>


                <div class='wings-menu-divider'>
                </div>


                <a
                    href='login.php?a=logout'
                    class='wings-signout'
                >

                    Sign Out

                </a>


            </div>


        </div>


    </div>


    <div id='wingsSearchMessage'>
    </div>


</div>

";



/* =========================================================
   4. JAVASCRIPT
   ========================================================= */

echo "

<script>

(function () {


    /* =====================================================
       MOVE CUSTOM HEADER DIRECTLY UNDER BODY

       IMPORTANT:
       This allows position:absolute to use the page itself
       instead of a PHPRunner sidebar/content container.

       RESULT:
       - Header scrolls away normally with page
       - Header still moves horizontally when sidebar toggles
       ===================================================== */

    var customHeader =
        document.getElementById(
            'wingsCustomHeader'
        );


    if (
        customHeader
        &&
        customHeader.parentElement !==
            document.body
    ) {

        document.body.appendChild(
            customHeader
        );

    }



    /* =====================================================
       ELEMENTS
       ===================================================== */

    var titleArea =
        document.getElementById(
            'wingsHeaderTitleArea'
        );


    var titleElement =
        document.getElementById(
            'wingsDynamicPageTitle'
        );


    var breadcrumbElement =
        document.getElementById(
            'wingsDynamicBreadcrumb'
        );


    var rightHeader =
        document.getElementById(
            'wingsHeaderRight'
        );


    var searchInput =
        document.getElementById(
            'wingsGlobalSearch'
        );


    var searchButton =
        document.getElementById(
            'wingsSearchButton'
        );


    var searchMessage =
        document.getElementById(
            'wingsSearchMessage'
        );


    var settingsButton =
        document.getElementById(
            'wingsSettingsButton'
        );


    var settingsMenu =
        document.getElementById(
            'wingsSettingsMenu'
        );


    var notificationButton =
        document.getElementById(
            'wingsNotificationButton'
        );


    var notificationMenu =
        document.getElementById(
            'wingsNotificationMenu'
        );


    var userButton =
        document.getElementById(
            'wingsUserButton'
        );


    var userMenu =
        document.getElementById(
            'wingsUserMenu'
        );



    /* =====================================================
       CLEAN TEXT
       ===================================================== */

    function cleanMenuText(text) {


        if (!text) {

            return '';

        }


        return text
            .replace(
                /\\s+/g,
                ' '
            )
            .trim();


    }



    /* =====================================================
       NORMALIZE URL
       ===================================================== */

    function normalizePath(url) {


        try {


            var parsed =
                new URL(
                    url,
                    window.location.href
                );


            return parsed.pathname
                .replace(
                    /\\/+$/,
                    ''
                )
                .toLowerCase();


        } catch (error) {


            return '';


        }


    }



    /* =====================================================
       CURRENT MENU TITLE
       ===================================================== */

    function findCurrentMenuTitle() {


        var currentPath =
            normalizePath(
                window.location.href
            );


        var currentFile =
            currentPath
                .split('/')
                .pop();


        var selectors = [

            '.r-left a[href]',

            '.r-sidebar a[href]',

            '.sidebar a[href]',

            '.r-vmenu a[href]',

            '[data-location=left] a[href]'

        ];


        var links = [];


        for (
            var s = 0;
            s < selectors.length;
            s++
        ) {


            var found =
                document.querySelectorAll(
                    selectors[s]
                );


            for (
                var f = 0;
                f < found.length;
                f++
            ) {


                if (
                    links.indexOf(
                        found[f]
                    ) === -1
                ) {

                    links.push(
                        found[f]
                    );

                }


            }


        }



        /* EXACT PATH */

        for (
            var i = 0;
            i < links.length;
            i++
        ) {


            var href =
                links[i].getAttribute(
                    'href'
                );


            if (
                !href
                ||
                href === '#'
                ||
                href.indexOf(
                    'javascript:'
                ) === 0
            ) {

                continue;

            }


            if (
                normalizePath(
                    href
                ) === currentPath
            ) {


                var exactText =
                    cleanMenuText(
                        links[i].textContent
                    );


                if (exactText) {

                    return exactText;

                }


            }


        }



        /* FILE MATCH */

        if (currentFile) {


            for (
                var j = 0;
                j < links.length;
                j++
            ) {


                var href2 =
                    links[j].getAttribute(
                        'href'
                    );


                if (!href2) {

                    continue;

                }


                var file2 =
                    normalizePath(
                        href2
                    )
                    .split('/')
                    .pop();


                if (
                    file2
                    &&
                    file2 === currentFile
                ) {


                    var fileText =
                        cleanMenuText(
                            links[j].textContent
                        );


                    if (fileText) {

                        return fileText;

                    }


                }


            }


        }


        return '';


    }



    /* =====================================================
       ACTIVE MENU
       ===================================================== */

    function findActiveMenuTitle() {


        var selectors = [

            '.r-left a.active',

            '.r-left .active > a',

            '.r-left li.active > a',

            '.r-left a[aria-current=page]',

            '.r-sidebar a.active',

            '.r-sidebar .active > a',

            '.sidebar a.active',

            '.sidebar .active > a',

            '.r-vmenu a.active',

            '.r-vmenu .active > a'

        ];


        for (
            var i = 0;
            i < selectors.length;
            i++
        ) {


            var element =
                document.querySelector(
                    selectors[i]
                );


            if (element) {


                var text =
                    cleanMenuText(
                        element.textContent
                    );


                if (text) {

                    return text;

                }


            }


        }


        return '';


    }



    /* =====================================================
       ORIGINAL PHPRUNNER TITLE
       ===================================================== */

    function findOriginalPageTitle() {


        var selectors = [

            '.r-page-title',

            '.pagetitle',

            '.page-title',

            '[data-itemtype=page_title]',

            '.r-content h1'

        ];


        for (
            var i = 0;
            i < selectors.length;
            i++
        ) {


            var elements =
                document.querySelectorAll(
                    selectors[i]
                );


            for (
                var j = 0;
                j < elements.length;
                j++
            ) {


                if (
                    elements[j].closest(
                        '#wingsCustomHeader'
                    )
                ) {

                    continue;

                }


                var text =
                    cleanMenuText(
                        elements[j].textContent
                    );


                if (
                    text
                    &&
                    text.length < 100
                ) {

                    return text;

                }


            }


        }


        return '';


    }



    /* =====================================================
       DOCUMENT TITLE
       ===================================================== */

    function getDocumentTitle() {


        var text =
            cleanMenuText(
                document.title
            );


        if (!text) {

            return '';

        }


        text =
            text.replace(
                /^WINGS\\s*[-|:]\\s*/i,
                ''
            );


        text =
            text.replace(
                /\\s*[-|:]\\s*WINGS$/i,
                ''
            );


        return text;


    }



    /* =====================================================
       SHORT BREADCRUMB
       ===================================================== */

    function getBreadcrumbLabel(title) {


        if (!title) {

            return '';

        }


        var text =
            title
                .toLowerCase()
                .trim();


        if (
            text.indexOf(
                'dashboard'
            ) !== -1
        ) {

            return 'Dashboard';

        }


        if (
            text.indexOf(
                'mapping'
            ) !== -1
            ||
            text.indexOf(
                ' map'
            ) !== -1
        ) {

            return 'Map';

        }


        if (
            text.indexOf(
                'work order'
            ) !== -1
        ) {

            return 'Work Order';

        }


        if (
            text.indexOf(
                'report'
            ) !== -1
        ) {

            return 'Report';

        }


        if (
            text.indexOf(
                'forecast'
            ) !== -1
        ) {

            return 'Forecast';

        }


        if (
            text.indexOf(
                'inspection'
            ) !== -1
        ) {

            return 'Inspection';

        }


        if (
            text.indexOf(
                'plan'
            ) !== -1
        ) {

            return 'Plan';

        }


        if (
            text.indexOf(
                'request'
            ) !== -1
            ||
            text.indexOf(
                'requisition'
            ) !== -1
        ) {

            return 'Request';

        }


        if (
            text.indexOf(
                'receiving'
            ) !== -1
        ) {

            return 'Receiving';

        }


        if (
            text.indexOf(
                'delivery'
            ) !== -1
        ) {

            return 'Delivery';

        }


        if (
            text.indexOf(
                'transfer'
            ) !== -1
        ) {

            return 'Transfer';

        }


        if (
            text.indexOf(
                'inventory'
            ) !== -1
        ) {

            return 'Inventory';

        }


        if (
            text.indexOf(
                'approval'
            ) !== -1
            ||
            text.indexOf(
                'approve'
            ) !== -1
        ) {

            return 'Approval';

        }


        if (
            text.indexOf(
                'edit '
            ) === 0
            ||
            text.indexOf(
                'update '
            ) === 0
        ) {

            return 'Edit';

        }


        if (
            text.indexOf(
                'add '
            ) === 0
            ||
            text.indexOf(
                'new '
            ) === 0
            ||
            text.indexOf(
                'create '
            ) === 0
        ) {

            return 'Add';

        }


        if (
            text.indexOf(
                'view '
            ) === 0
            ||
            text.indexOf(
                'detail'
            ) !== -1
        ) {

            return 'View';

        }


        if (
            text.indexOf(
                'list'
            ) !== -1
        ) {

            return 'List';

        }


        if (
            text.indexOf(
                'setting'
            ) !== -1
            ||
            text.indexOf(
                'setup'
            ) !== -1
        ) {

            return 'Setup';

        }


        return title;


    }



    /* =====================================================
       UPDATE TITLE
       ===================================================== */

    function updateDynamicPageTitle() {


        var title =
            findCurrentMenuTitle();


        if (!title) {

            title =
                findActiveMenuTitle();

        }


        if (!title) {

            title =
                findOriginalPageTitle();

        }


        if (!title) {

            title =
                getDocumentTitle();

        }


        if (!title) {

            title =
                'Dashboard';

        }


        if (titleElement) {

            titleElement.textContent =
                title;

        }


        if (breadcrumbElement) {

            breadcrumbElement.textContent =
                getBreadcrumbLabel(
                    title
                );

        }


    }



    /* =====================================================
       FIND SIDEBAR
       ===================================================== */

    function getWingsSidebar() {


        var selectors = [

            '.r-left',

            '.r-sidebar',

            '.sidebar',

            '[data-location=left]'

        ];


        for (
            var i = 0;
            i < selectors.length;
            i++
        ) {


            var candidate =
                document.querySelector(
                    selectors[i]
                );


            if (!candidate) {

                continue;

            }


            var rect =
                candidate
                    .getBoundingClientRect();


            if (
                rect.width >= 35
                &&
                rect.height > 100
            ) {

                return candidate;

            }


        }


        return null;


    }



    /* =====================================================
       FIND SIDEBAR HIDE / TOGGLE BUTTON
       ===================================================== */

    function getMenuToggleRight() {


        var selectors = [

            '.r-left-toggle',

            '.sidebar-toggle',

            '.navbar-toggle',

            '.menu-toggler',

            '.r-menu-button',

            '[data-action=collapse]',

            '[data-toggle=collapse]',

            '[aria-label*=menu]',

            '[aria-label*=Menu]',

            '[title*=menu]',

            '[title*=Menu]'

        ];


        var bestRight = 0;


        for (
            var i = 0;
            i < selectors.length;
            i++
        ) {


            var elements =
                document.querySelectorAll(
                    selectors[i]
                );


            for (
                var j = 0;
                j < elements.length;
                j++
            ) {


                var rect =
                    elements[j]
                        .getBoundingClientRect();


                if (
                    rect.width <= 0
                    ||
                    rect.height <= 0
                ) {

                    continue;

                }


                if (
                    rect.top < 85
                    &&
                    rect.left < 450
                ) {


                    if (
                        rect.right >
                        bestRight
                    ) {

                        bestRight =
                            rect.right;

                    }


                }


            }


        }


        return bestRight;


    }



    /* =====================================================
       POSITION HEADER HORIZONTALLY

       NOTE:
       THIS FUNCTION DOES NOT CHANGE TOP/Y POSITION.

       IT ONLY CHANGES:
       - left
       - width

       Therefore scrolling does not reposition the header.
       ===================================================== */

    function positionWingsHeader() {


        var sidebar =
            getWingsSidebar();


        var leftPosition =
            83;


        if (sidebar) {


            var sidebarRect =
                sidebar
                    .getBoundingClientRect();


            /*
             * 26px clearance from sidebar edge.
             */

            leftPosition =
                Math.round(
                    sidebarRect.right +
                    28
                );


        }



        /* -------------------------------------------------
           CLEAR SIDEBAR ARROW / TOGGLE
           ------------------------------------------------- */

        var toggleRight =
            getMenuToggleRight();


        if (
            toggleRight > 0
        ) {


            leftPosition =
                Math.max(
                    leftPosition,
                    Math.round(
                        toggleRight +
                        28
                    )
                );


        }



        /* -------------------------------------------------
           RIGHT BOUNDARY
           ------------------------------------------------- */

        var rightBoundary =
            window.innerWidth -
            30;


        if (rightHeader) {


            var rightRect =
                rightHeader
                    .getBoundingClientRect();


            if (
                rightRect.left > 0
            ) {


                rightBoundary =
                    Math.round(
                        rightRect.left -
                        24
                    );


            }


        }



        /* -------------------------------------------------
           TITLE WIDTH
           ------------------------------------------------- */

        var availableWidth =
            rightBoundary -
            leftPosition;


        if (
            availableWidth <
            100
        ) {

            availableWidth =
                100;

        }


        if (
            availableWidth >
            600
        ) {

            availableWidth =
                600;

        }



        /* -------------------------------------------------
           APPLY LEFT POSITION
           ------------------------------------------------- */

        document.documentElement
            .style
            .setProperty(

                '--wings-title-left',

                leftPosition +
                'px'

            );



        /* -------------------------------------------------
           APPLY WIDTH
           ------------------------------------------------- */

        document.documentElement
            .style
            .setProperty(

                '--wings-title-width',

                availableWidth +
                'px'

            );


    }



    /* =====================================================
       REQUEST HEADER POSITION
       ===================================================== */

    var positionFrame =
        null;


    function requestHeaderPosition() {


        if (positionFrame) {

            cancelAnimationFrame(
                positionFrame
            );

        }


        positionFrame =
            requestAnimationFrame(
                function () {


                    positionWingsHeader();


                    positionFrame =
                        null;


                }
            );


    }



    /* =====================================================
       WATCH SIDEBAR RESIZE
       ===================================================== */

    function watchSidebarResize() {


        var sidebar =
            getWingsSidebar();


        if (
            !sidebar
            ||
            typeof ResizeObserver ===
            'undefined'
        ) {

            return;

        }


        var resizeObserver =
            new ResizeObserver(
                function () {


                    requestHeaderPosition();


                }
            );


        resizeObserver.observe(
            sidebar
        );


    }



    /* =====================================================
       WATCH SIDEBAR CLASS
       ===================================================== */

    function watchSidebarMutation() {


        if (
            typeof MutationObserver ===
            'undefined'
        ) {

            return;

        }


        var sidebar =
            getWingsSidebar();


        if (!sidebar) {

            return;

        }


        var observer =
            new MutationObserver(
                function () {


                    requestHeaderPosition();


                    setTimeout(
                        positionWingsHeader,
                        50
                    );


                    setTimeout(
                        positionWingsHeader,
                        150
                    );


                    setTimeout(
                        positionWingsHeader,
                        300
                    );


                    setTimeout(
                        positionWingsHeader,
                        500
                    );


                }
            );


        observer.observe(
            sidebar,
            {

                attributes: true,

                attributeFilter: [

                    'class',

                    'style'

                ]

            }
        );


        if (
            sidebar.parentElement
        ) {


            observer.observe(
                sidebar.parentElement,
                {

                    attributes: true,

                    attributeFilter: [

                        'class',

                        'style'

                    ]

                }
            );


        }


    }



    /* =====================================================
       REMOVE PENDING APPROVAL
       ===================================================== */

    function removePendingApproval() {


        var elements =
            document.querySelectorAll(
                'a,button,div,span'
            );


        for (
            var i = 0;
            i < elements.length;
            i++
        ) {


            var element =
                elements[i];


            if (
                element.closest(
                    '#wingsCustomHeader'
                )
            ) {

                continue;

            }


            var text =
                cleanMenuText(
                    element.textContent
                );


            if (
                !text
                ||
                text.length > 70
            ) {

                continue;

            }


            if (
                /pending\\s+approval/i
                    .test(
                        text
                    )
            ) {


                var target =
                    element;


                var possibleTarget =
                    element.closest(
                        '.alert,' +
                        '.badge,' +
                        '.btn,' +
                        '[class*=pending],' +
                        '[class*=approval]'
                    );


                if (
                    possibleTarget
                    &&
                    cleanMenuText(
                        possibleTarget
                            .textContent
                    ).length < 100
                ) {

                    target =
                        possibleTarget;

                }


                target.style.setProperty(
                    'display',
                    'none',
                    'important'
                );


            }


        }


    }



    /* =====================================================
       SIDEBAR TOGGLE CLICK

       ONLY RECALCULATES HORIZONTAL POSITION
       ===================================================== */

    document.addEventListener(
        'click',
        function (event) {


            var button =
                event.target
                    ? event.target.closest(
                        'button,a'
                    )
                    : null;


            if (!button) {

                return;

            }


            var rect =
                button
                    .getBoundingClientRect();


            if (
                rect.top < 90
                &&
                rect.left < 450
            ) {


                requestHeaderPosition();


                setTimeout(
                    positionWingsHeader,
                    25
                );


                setTimeout(
                    positionWingsHeader,
                    75
                );


                setTimeout(
                    positionWingsHeader,
                    150
                );


                setTimeout(
                    positionWingsHeader,
                    250
                );


                setTimeout(
                    positionWingsHeader,
                    400
                );


                setTimeout(
                    positionWingsHeader,
                    600
                );


            }


        },
        true
    );



    /* =====================================================
       WINDOW RESIZE
       ===================================================== */

    window.addEventListener(
        'resize',
        function () {


            requestHeaderPosition();


        }
    );



    /* =====================================================
       CLOSE MENUS
       ===================================================== */

    function closeAllMenus() {


        if (settingsMenu) {

            settingsMenu.classList.remove(
                'wings-open'
            );

        }


        if (notificationMenu) {

            notificationMenu.classList.remove(
                'wings-open'
            );

        }


        if (userMenu) {

            userMenu.classList.remove(
                'wings-open'
            );

        }


        if (settingsButton) {

            settingsButton.setAttribute(
                'aria-expanded',
                'false'
            );

        }


        if (notificationButton) {

            notificationButton.setAttribute(
                'aria-expanded',
                'false'
            );

        }


        if (userButton) {

            userButton.setAttribute(
                'aria-expanded',
                'false'
            );

        }


    }



    /* =====================================================
       SEARCH MESSAGE
       ===================================================== */

    var searchMessageTimer =
        null;


    function hideSearchMessage() {


        if (searchMessage) {


            searchMessage.classList.remove(
                'wings-show'
            );


        }


    }


    function showSearchMessage(
        message
    ) {


        if (!searchMessage) {

            return;

        }


        if (searchMessageTimer) {


            clearTimeout(
                searchMessageTimer
            );


        }


        searchMessage.textContent =
            message;


        searchMessage.classList.add(
            'wings-show'
        );


        searchMessageTimer =
            setTimeout(
                hideSearchMessage,
                2200
            );


    }



    /* =====================================================
       SEARCH
       ===================================================== */

    function runPageSearch() {


        if (!searchInput) {

            return;

        }


        var term =
            searchInput
                .value
                .trim();


        if (!term) {


            showSearchMessage(
                'Enter a word to search.'
            );


            searchInput.focus();


            return;

        }


        closeAllMenus();


        var found =
            false;


        if (
            typeof window.find ===
            'function'
        ) {


            try {


                found =
                    window.find(
                        term,
                        false,
                        false,
                        true,
                        false,
                        false,
                        false
                    );


            } catch (error) {


                found =
                    false;


            }


        }


        if (!found) {


            var pageText =
                document.body
                    ? document.body.innerText
                    : '';


            found =
                pageText
                    .toLowerCase()
                    .indexOf(
                        term
                            .toLowerCase()
                    )
                !== -1;


        }


        if (found) {


            showSearchMessage(
                'Found: ' +
                term
            );


        } else {


            showSearchMessage(
                'No result found for: ' +
                term
            );


        }


    }



    /* =====================================================
       SEARCH EVENTS
       ===================================================== */

    if (searchButton) {


        searchButton.addEventListener(
            'click',
            function (event) {


                event.preventDefault();

                event.stopPropagation();


                runPageSearch();


            }
        );


    }


    if (searchInput) {


        searchInput.addEventListener(
            'click',
            function (event) {


                event.stopPropagation();


            }
        );


        searchInput.addEventListener(
            'keydown',
            function (event) {


                if (
                    event.key ===
                    'Enter'
                ) {


                    event.preventDefault();


                    runPageSearch();


                }


                if (
                    event.key ===
                    'Escape'
                ) {


                    searchInput.value =
                        '';


                    hideSearchMessage();


                    searchInput.blur();


                }


            }
        );


    }



    /* =====================================================
       SETTINGS
       ===================================================== */

    if (
        settingsButton
        &&
        settingsMenu
    ) {


        settingsButton.addEventListener(
            'click',
            function (event) {


                event.preventDefault();

                event.stopPropagation();


                var shouldOpen =
                    !settingsMenu
                        .classList
                        .contains(
                            'wings-open'
                        );


                closeAllMenus();


                if (shouldOpen) {


                    settingsMenu
                        .classList
                        .add(
                            'wings-open'
                        );


                    settingsButton
                        .setAttribute(
                            'aria-expanded',
                            'true'
                        );


                }


            }
        );


        settingsMenu.addEventListener(
            'click',
            function (event) {


                event.stopPropagation();


            }
        );


    }



    /* =====================================================
       NOTIFICATION
       ===================================================== */

    if (
        notificationButton
        &&
        notificationMenu
    ) {


        notificationButton.addEventListener(
            'click',
            function (event) {


                event.preventDefault();

                event.stopPropagation();


                var shouldOpen =
                    !notificationMenu
                        .classList
                        .contains(
                            'wings-open'
                        );


                closeAllMenus();


                if (shouldOpen) {


                    notificationMenu
                        .classList
                        .add(
                            'wings-open'
                        );


                    notificationButton
                        .setAttribute(
                            'aria-expanded',
                            'true'
                        );


                }


            }
        );


        notificationMenu.addEventListener(
            'click',
            function (event) {


                event.stopPropagation();


            }
        );


    }



    /* =====================================================
       USER MENU
       ===================================================== */

    if (
        userButton
        &&
        userMenu
    ) {


        userButton.addEventListener(
            'click',
            function (event) {


                event.preventDefault();

                event.stopPropagation();


                var shouldOpen =
                    !userMenu
                        .classList
                        .contains(
                            'wings-open'
                        );


                closeAllMenus();


                if (shouldOpen) {


                    userMenu
                        .classList
                        .add(
                            'wings-open'
                        );


                    userButton
                        .setAttribute(
                            'aria-expanded',
                            'true'
                        );


                }


            }
        );


        userMenu.addEventListener(
            'click',
            function (event) {


                event.stopPropagation();


            }
        );


    }



    /* =====================================================
       OUTSIDE CLICK
       ===================================================== */

    document.addEventListener(
        'click',
        function () {


            closeAllMenus();


            hideSearchMessage();


        }
    );



    /* =====================================================
       ESCAPE
       ===================================================== */

    document.addEventListener(
        'keydown',
        function (event) {


            if (
                event.key ===
                'Escape'
            ) {


                closeAllMenus();


                hideSearchMessage();


            }


        }
    );



    /* =====================================================
       INITIALIZE
       ===================================================== */

    updateDynamicPageTitle();


    removePendingApproval();


    positionWingsHeader();



    setTimeout(
        function () {


            updateDynamicPageTitle();

            removePendingApproval();

            positionWingsHeader();


        },
        100
    );


    setTimeout(
        function () {


            updateDynamicPageTitle();

            removePendingApproval();

            positionWingsHeader();


        },
        300
    );


    setTimeout(
        function () {


            updateDynamicPageTitle();

            removePendingApproval();

            positionWingsHeader();


            watchSidebarResize();

            watchSidebarMutation();


        },
        600
    );



    /* =====================================================
       WATCH LATE PHPRUNNER LAYOUT CHANGES

       ONLY RECALCULATES HORIZONTAL HEADER POSITION.
       DOES NOT TRACK WINDOW SCROLL.
       ===================================================== */

    if (
        typeof MutationObserver !==
        'undefined'
    ) {


        var layoutTimer =
            null;


        var layoutObserver =
            new MutationObserver(
                function () {


                    if (layoutTimer) {


                        clearTimeout(
                            layoutTimer
                        );


                    }


                    layoutTimer =
                        setTimeout(
                            function () {


                                removePendingApproval();


                                requestHeaderPosition();


                            },
                            30
                        );


                }
            );


        layoutObserver.observe(
            document.body,
            {

                childList: true,

                subtree: true,

                attributes: true,

                attributeFilter: [

                    'class',

                    'style'

                ]

            }
        );


    }


})();

</script>

";
		;
		
	}




	// code snippet - Approvals
	function event_64877(  ) {
		
		// ======================================================
// PURCHASE REQUEST APPROVALS + FILE
// ======================================================


$id = $_GET["editid"];


// GET DATA

$rsApproval = DB::Query("

SELECT

    requested_by,
    requested_by_designation,

    approved_by,
    approved_by_designation,

    approved_file

FROM purchaserequest

WHERE id=".$id."

");



if(!$rsApproval)
{
    echo DB::LastError();
    exit();
}



$data = $rsApproval->fetchAssoc();




// DEFAULT VALUES

$requestedBy = !empty($data["requested_by"])
?
$data["requested_by"]
:
"-";


$requestedDesignation = !empty($data["requested_by_designation"])
?
$data["requested_by_designation"]
:
"-";



$approvedBy = !empty($data["approved_by"])
?
$data["approved_by"]
:
"-";


$approvedDesignation = !empty($data["approved_by_designation"])
?
$data["approved_by_designation"]
:
"-";





// ======================================================
// APPROVED FILE
// ======================================================


$fileHTML = "-";


if(!empty($data["approved_file"]))
{

$fileName = basename($data["approved_file"]);



$fileHTML = '

<div class="pr-file-box">


<div class="pr-file-icon">

<i class="fa fa-file-pdf-o"></i>

</div>


<div>

<div class="pr-file-name">

'.$fileName.'

</div>


<div class="pr-file-size">

Approved File

</div>


</div>



</div>

';

}




// ======================================================
// OUTPUT
// ======================================================


echo '

<style>


.pr-section{


background:#f7f7f7;

padding:15px;

border-radius:8px;

margin-top:20px;

}



.pr-section-title{


background:#302f92;

color:white;

padding:14px;

font-size:14px;

font-weight:bold;

border-radius:4px;

margin-bottom:15px;


}



.pr-grid{


display:grid;

grid-template-columns:1fr 1fr;

gap:15px;


}



.pr-label{


font-size:12px;

font-weight:bold;

margin-bottom:6px;


}



.pr-value{


background:white;

padding:14px;

border-radius:4px;

font-size:13px;

}




.pr-file-box{


background:white;

padding:18px;

border-radius:4px;

display:flex;

align-items:center;

gap:15px;


}



.pr-file-icon{


font-size:28px;

color:red;


}



.pr-file-name{


font-size:14px;

font-weight:500;


}



.pr-file-size{


font-size:12px;

color:#777;


}



</style>






<div class="pr-section">


<div class="pr-section-title">

Approvals

</div>



<div class="pr-grid">


<div>

<div class="pr-label">

Requested By

</div>


<div class="pr-value">

'.$requestedBy.'

</div>


</div>




<div>

<div class="pr-label">

Approved By

</div>


<div class="pr-value">

'.$approvedBy.'

</div>


</div>





<div>

<div class="pr-label">

Requested By Designation

</div>


<div class="pr-value">

'.$requestedDesignation.'

</div>


</div>





<div>

<div class="pr-label">

Approved By Designation

</div>


<div class="pr-value">

'.$approvedDesignation.'

</div>


</div>



</div>


</div>






<div class="pr-section">


<div class="pr-section-title">

File Uploaded

</div>



'.$fileHTML.'



</div>


';
		;
		
	}

	// code snippet - Activity Logs
	function event_64883(  ) {
		
		// ======================================================
// PURCHASE REQUEST VIEW
// ACTIVITY LOGS
// ======================================================


// GET CURRENT ID

$id = 0;


if(isset($keys["id"]))
{
    $id = intval($keys["id"]);
}
elseif(isset($_GET["editid"]))
{
    $id = intval($_GET["editid"]);
}


if($id <= 0)
{
    return;
}





// ======================================================
// GET ACTIVITY LOG DATA
// ======================================================


$rsLogs = DB::Query("

SELECT

    action_label,
    actor_name,
    actor_username,
    action_at


FROM transaction_history_log


WHERE module_code='PURCHASE_REQUEST'

AND record_id=".$id."


ORDER BY action_at DESC


LIMIT 5


");





// ======================================================
// CSS
// ======================================================


echo '

<style>


.pr-log-section{


background:#f7f7f7!important;

padding:15px!important;

border-radius:8px!important;

margin-top:20px!important;

width:100%!important;


}





.pr-log-header{


background:#302f92!important;

color:white!important;

padding:14px!important;

font-size:14px!important;

font-weight:bold!important;

border-radius:4px!important;

display:flex!important;

justify-content:space-between!important;

align-items:center!important;

margin-bottom:15px!important;


}





.pr-log-viewall{


background:white!important;

color:#302f92!important;

padding:8px 14px!important;

border-radius:4px!important;

font-size:12px!important;

text-decoration:none!important;

font-weight:600!important;


}





.pr-log-table{


width:100%!important;

border-collapse:collapse!important;


}





.pr-log-table th{


text-align:left!important;

font-size:12px!important;

font-weight:500!important;

color:#777!important;

padding:10px!important;


}





.pr-log-table td{


padding:10px!important;

font-size:13px!important;

color:#333!important;


}





.pr-log-status{


color:#45a85b!important;

font-weight:500!important;


}





</style>


';





// ======================================================
// DISPLAY
// ======================================================


echo '


<div class="pr-log-section">



<div class="pr-log-header">


<span>

Activity Logs

</span>



<a href="#" class="pr-log-viewall">

<i class="fa fa-history"></i>

&nbsp; View All

</a>



</div>





<table class="pr-log-table">


<thead>


<tr>


<th>

Activity

</th>


<th>

Name

</th>


<th>

Time

</th>


<th>

Performed By

</th>


</tr>


</thead>



<tbody>


';



if($rsLogs)
{


while($log=$rsLogs->fetchAssoc())

{


echo '


<tr>


<td class="pr-log-status">


'.$log["action_label"].'


</td>



<td>


'.$log["actor_name"].'


</td>



<td>


'.date("M d, Y | h:i A",strtotime($log["action_at"])).'


</td>



<td>


'.$log["actor_username"].'


</td>



</tr>


';



}



}
else
{


echo '

<tr>

<td colspan="4">

No activity logs found.

</td>

</tr>

';


}



echo '


</tbody>


</table>



</div>


';
		;
		
	}




	// code snippet - pr
	function event_66058(  ) {
		
		// ======================================================
// PURCHASE REQUEST VIEW
// PART 1 - HEADER INFORMATION
// ======================================================


// ======================================================
// GET CURRENT RECORD ID
// ======================================================


$id = 0;


// PHPRUNNER VIEW PAGE ID HANDLING

if(isset($data["id"]) && $data["id"]!="")
{

    $id = intval($data["id"]);

}
elseif(isset($keys["id"]) && $keys["id"]!="")
{

    $id = intval($keys["id"]);

}
elseif(isset($_GET["editid"]) && $_GET["editid"]!="")
{

    $id = intval($_GET["editid"]);

}




if($id <= 0)
{

    echo "Cannot detect Purchase Request ID.";

    return;

}






// ======================================================
// GET PURCHASE REQUEST HEADER DATA
// ======================================================


$rs = DB::Query("

SELECT

    id,
    date,
    reference_number,
    office_section,
    fund_cluster_id,
    responsibility_center_code_id

FROM purchaserequest

WHERE id=".$id."

");





if(!$rs)
{

    echo DB::LastError();

    return;

}





$pr = $rs->fetchAssoc();





if(!$pr)
{

    echo "Purchase Request record not found.";

    return;

}









// ======================================================
// CSS - MATCH REFERENCE DESIGN
// ======================================================


echo '

<style>


/* MAIN CARD */

.pr-info-card{


background:#f7f7f7!important;

border-radius:8px!important;

padding:20px!important;

margin-bottom:20px!important;

width:100%!important;


}






/* GRID */


.pr-info-grid{


display:grid!important;

grid-template-columns:1fr 1fr!important;

gap:16px 30px!important;


}






/* FIELD */


.pr-info-item{


width:100%!important;


}






.pr-info-item label{


display:block!important;

font-size:12px!important;

font-weight:600!important;

color:#333!important;

margin-bottom:7px!important;


}







/* VALUE BOX */


.pr-info-value{


background:#ffffff!important;

border-radius:4px!important;

height:45px!important;

display:flex!important;

align-items:center!important;

padding:0 15px!important;

font-size:13px!important;

color:#333!important;


}







/* FULL WIDTH */


.pr-full-width{


grid-column:1 / span 2!important;


}





</style>


';









// ======================================================
// DISPLAY HEADER
// ======================================================


echo '


<div class="pr-info-card">



<div class="pr-info-grid">







<div class="pr-info-item">


<label>

Date

</label>


<div class="pr-info-value">

'.$pr["date"].'

</div>


</div>








<div class="pr-info-item">


<label>

Fund Cluster

</label>


<div class="pr-info-value">

'.$pr["fund_cluster_id"].'

</div>


</div>








<div class="pr-info-item">


<label>

Reference Number

</label>


<div class="pr-info-value">

'.$pr["reference_number"].'

</div>


</div>








<div class="pr-info-item">


<label>

Responsibility Center Code

</label>


<div class="pr-info-value">

'.$pr["responsibility_center_code_id"].'

</div>


</div>








<div class="pr-info-item pr-full-width">


<label>

Office Section

</label>


<div class="pr-info-value">

'.$pr["office_section"].'

</div>


</div>







</div>



</div>



';
		;
		
	}

	// code snippet - PR
	function event_66064(  ) {
		
		// ======================================================
// PURCHASE REQUEST CUSTOM LIST
// PART 1/4
// ======================================================


// ======================================================
// APPROVE PURCHASE REQUEST
// ======================================================


if(isset($_GET["approve_pr"]))
{


$id = intval($_GET["approve_pr"]);



// GET PURCHASE REQUEST

$rsApprove = DB::Query("

SELECT

reference_number,
status

FROM purchaserequest

WHERE id=".$id."

");



if($rsApprove)
{


$pr=$rsApprove->fetchAssoc();



if($pr)
{


$referenceNumber=$pr["reference_number"];

$oldStatus=$pr["status"];





// UPDATE STATUS


DB::Exec("

UPDATE purchaserequest

SET status='APPROVED'

WHERE id=".$id."

");






// USER INFO


$username=$_SESSION["UserID"] ?? "";

$actorName=$_SESSION["UserName"] ?? "";





$userID=0;



$rsUser=DB::Query("

SELECT ID

FROM users

WHERE username='".addslashes($username)."'

LIMIT 1

");



if($rsUser)
{


$user=$rsUser->fetchAssoc();


if($user)

{

$userID=$user["ID"];

}

}






// HISTORY LOG


DB::Exec("

INSERT INTO transaction_history_log

(

module_code,

record_id,

record_no,

action_code,

action_label,

from_status,

to_status,

acted_by,

actor_username,

actor_name,

action_at

)


VALUES

(

'PURCHASE_REQUEST',

".$id.",

'".addslashes($referenceNumber)."',

'APPROVE_PR',

'Approved Purchase Request',

'".addslashes($oldStatus)."',

'APPROVED',

".$userID.",

'".addslashes($username)."',

'".addslashes($actorName)."',

NOW()

)

");



}



}


$_SESSION["PR_ALERT"] = array(
"type"=>"success",
"title"=>"Purchase Request Approved",
"message"=>"This Purchase Request has been approved and will proceed to Procurement and Budget for further processing."
);


echo "
<script>

window.location.href=window.location.pathname;

</script>
";

exit();





}


// ======================================================
// CONVERT PURCHASE REQUEST TO PO
// ======================================================


if(isset($_GET["convert_po"]))
{


$id=intval($_GET["convert_po"]);





$rsPO=DB::Query("

SELECT

reference_number

FROM purchaserequest

WHERE id=".$id."

");





if($rsPO)

{


$pr=$rsPO->fetchAssoc();






DB::Exec("

UPDATE purchaserequest

SET

po_status='CONVERTED_TO_PO',

po_created_at=NOW()

WHERE id=".$id."

");






$username=$_SESSION["UserID"] ?? "";

$actorName=$_SESSION["UserName"] ?? "";







DB::Exec("

INSERT INTO transaction_history_log

(

module_code,

record_id,

record_no,

action_code,

action_label,

from_status,

to_status,

actor_username,

actor_name,

action_at

)


VALUES

(

'PURCHASE_REQUEST',

".$id.",

'".addslashes($pr["reference_number"])."',

'CONVERT_TO_PO',

'Converted Purchase Request to PO',

'APPROVED',

'CONVERTED_TO_PO',

'".addslashes($username)."',

'".addslashes($actorName)."',

NOW()

)

");



}

$_SESSION["PR_ALERT"] = array(
"type"=>"success",
"title"=>"Converted to Purchase Order",
"message"=>"This Purchase Request has been successfully converted to a Purchase Order."
);


echo "

<script>

window.location.href=window.location.pathname;

</script>

";

exit();
}








// ======================================================
// GET LIST DATA
// ======================================================


$rs = DB::Query("


SELECT


pr.id,

pr.reference_number,

pr.date,

pr.purpose,

pr.approved_file,



COALESCE(

(

SELECT

to_status


FROM transaction_history_log


WHERE module_code='PURCHASE_REQUEST'


AND record_id=pr.id


ORDER BY action_at DESC


LIMIT 1


),

'PENDING'

) AS status



FROM purchaserequest pr



ORDER BY pr.id DESC



");

// ======================================================
// SWEET ALERT SESSION MESSAGE
// ======================================================


if(isset($_SESSION["PR_ALERT"]))
{

$alert=$_SESSION["PR_ALERT"];

unset($_SESSION["PR_ALERT"]);


echo '

<script>

setTimeout(function(){


Swal.fire({

icon:"'.$alert["type"].'",

title:"'.$alert["title"].'",

html:"'.$alert["message"].'",

confirmButtonText:"Done",

confirmButtonColor:"#4caf50"


});


},500);


</script>

';

}
// ======================================================
// CSS OVERRIDE
// ======================================================


echo '

<style>


/* ==========================================
   MAIN CONTAINER
========================================== */


.pr-wrapper{

width:100%!important;

max-width:100%!important;

}





/* ==========================================
   TOOLBAR
========================================== */


.pr-toolbar{

width:100%!important;

display:flex!important;

justify-content:flex-end!important;

margin-bottom:12px!important;

}



.pr-toolbar-right{

display:flex!important;

flex-direction:column!important;

align-items:flex-end!important;

gap:8px!important;

}



.pr-buttons{

display:flex!important;

gap:8px!important;

}






/* EXPORT / SORT / FILTER */


.pr-btn{

height:28px!important;

font-size:11px!important;

padding:0 10px!important;

border:1px solid #ddd!important;

border-radius:5px!important;

background:white!important;

cursor:pointer!important;

width:auto!important;

min-width:85px!important;

}





select.pr-btn{

width:120px!important;

min-width:120px!important;

}





/* ADD NEW */


.pr-add{

height:28px!important;

padding:0 16px!important;

display:flex!important;

align-items:center!important;

justify-content:center!important;

background:#302f92!important;

color:white!important;

border-radius:5px!important;

font-size:11px!important;

text-decoration:none!important;

}






/* ==========================================
   TABLE
========================================== */


.pr-table{

width:100%!important;

border-collapse:collapse!important;

table-layout:auto!important;

}





.pr-table th{


background:#f5f5f7!important;

padding:10px!important;

font-size:12px!important;

font-weight:500!important;

color:#666!important;

text-decoration:underline!important;

white-space:nowrap!important;


}




.pr-table td{


padding:9px 10px!important;

font-size:12px!important;

border-bottom:1px solid #eeeeee!important;


}







/* CHECKBOX */


.pr-check{


width:40px!important;


}







/* ACTIONS */


.pr-actions{


width:180px!important;

white-space:nowrap!important;


}






/* STATUS */


.pr-status-col{


width:100px!important;


}






/* REFERENCE */


.pr-ref-col{


width:150px!important;


}







/* DATE */


.pr-date-col{


width:110px!important;


}







/* PURPOSE */


.pr-purpose-col{


width:220px!important;


}






/* FILE */


.pr-file-col{


width:auto!important;

max-width:none!important;

overflow:hidden!important;

text-overflow:ellipsis!important;

white-space:nowrap!important;


}






/* ==========================================
   ICONS
========================================== */


.pr-icon{


font-size:15px!important;

margin-right:10px!important;

text-decoration:none!important;

cursor:pointer!important;


}




.pr-view{


color:#3036a5!important;


}




.pr-edit{


color:#45a85b!important;


}




.pr-log{


color:#333!important;


}







/* ==========================================
   ACTION BUTTONS
========================================== */


.pr-approve{

display:inline-flex!important;

align-items:center!important;

justify-content:center!important;

height:30px!important;

padding:0 22px!important;

border-radius:5px!important;

font-size:12px!important;

font-weight:500!important;

line-height:30px!important;

white-space:nowrap!important;

cursor:pointer!important;

text-decoration:none!important;

background:#4caf50!important;

color:white!important;

}

.pr-convert{


display:inline-flex!important;

align-items:center!important;

justify-content:center!important;

height:25px!important;

padding:0 12px!important;

border-radius:3px!important;

font-size:11px!important;

line-height:25px!important;

white-space:nowrap!important;

cursor:pointer!important;

text-decoration:none!important;

}





.pr-approve{


background:#4caf50!important;

color:white!important;


}






.pr-convert{


background:#302f92!important;

color:white!important;


}







.pending{


color:#ff8800!important;


}






.approved{


color:#198754!important;


}





</style>


';

// ======================================================
// TOOLBAR
// ======================================================


echo '

<div class="pr-toolbar">


<div class="pr-toolbar-right">


<div class="pr-buttons">


<button class="pr-btn">

⬇ Export

</button>



<a href="purchaserequest_add.php"

class="pr-add">

+ Add new

</a>


</div>





<div class="pr-buttons">



<select class="pr-btn"

onchange="sortPR(this.value)">


<option value="">

Sort by

</option>


<option value="status">

Status

</option>



<option value="reference">

Reference Number

</option>



<option value="date">

Date

</option>



</select>







<select class="pr-btn"

onchange="filterPR(this.value)">



<option value="">

Filter by

</option>



<option value="PENDING">

Pending

</option>



<option value="APPROVED">

Approved

</option>



<option value="CONVERTED_TO_PO">

Converted to PO

</option>



<option value="RETURNED">

Returned

</option>



<option value="CANCELLED">

Cancelled

</option>



</select>



</div>



</div>


</div>


';






// ======================================================
// TABLE
// ======================================================


echo '

<table class="pr-table">


<thead>


<tr>


<th class="pr-check">


<input type="checkbox" id="checkAllPR">


</th>




<th class="pr-actions">


</th>





<th class="pr-status-col">

Status

</th>




<th class="pr-ref-col">

Reference Number

</th>




<th class="pr-date-col">

Date

</th>




<th class="pr-purpose-col">

Purpose

</th>




<th class="pr-file-col">

Approved File

</th>




</tr>


</thead>



<tbody>


';







// ======================================================
// ROWS
// ======================================================


while($row=$rs->fetchAssoc())

{


$status=strtoupper($row["status"]);




// STATUS


if($status=="APPROVED")

{


$statusHTML='

<span class="approved">

APPROVED

</span>';



}

elseif($status=="CONVERTED_TO_PO")

{


$statusHTML='

<span class="approved">

CONVERTED TO PO

</span>';



}

else

{


$statusHTML='

<span class="pending">

'.$status.'

</span>';



}





// FILE


$file="-";


if(!empty($row["approved_file"]))

{


$json=json_decode(

$row["approved_file"],

true

);



if(is_array($json) && isset($json[0]["name"]))

{

$file=$json[0]["name"];

}

else

{

$file=$row["approved_file"];

}



}






echo '


<tr>



<td>

<input type="checkbox">

</td>






<td class="pr-actions">





<a class="pr-icon pr-view"

href="purchaserequest_view.php?editid='.$row["id"].'">


<i class="fa fa-eye"></i>


</a>






<a class="pr-icon pr-edit"

href="purchaserequest_edit.php?editid='.$row["id"].'">


<i class="fa fa-pencil"></i>


</a>






<a class="pr-icon pr-log"

href="#">


<i class="fa fa-list"></i>


</a>



';






// ==========================
// APPROVE
// ==========================

if($status=="PENDING")
{

echo '

<a href="javascript:void(0)"
class="pr-approve"
onclick="confirmApprove('.$row["id"].');return false;">


Approve


</a>


';


}







// ==========================
// CONVERT TO PO
// ==========================

if($status=="APPROVED")
{


echo '


<a href="javascript:void(0)"
class="pr-convert"
onclick="confirmConvert('.$row["id"].');return false;">


Convert to PO


</a>


';


}




echo '


</td>





<td>


'.$statusHTML.'


</td>






<td>


'.$row["reference_number"].'


</td>






<td>


'.$row["date"].'


</td>






<td>


'.$row["purpose"].'


</td>






<td class="pr-file-col">


'.$file.'


</td>






</tr>


';


}



echo '


</tbody>


</table>


';

// ======================================================
// JAVASCRIPT
// ======================================================


echo '

<script>


// ==========================================
// APPROVE CONFIRMATION
// ==========================================


function confirmApprove(id)

{


Swal.fire({


icon:"question",


title:"Approve Purchase Request?",



html:

"Are you sure you want to approve this Purchase Request?<br><br>The request will be marked as Approved and proceed to the next stage of the procurement process.",




showCancelButton:true,



confirmButtonText:"Approve",



cancelButtonText:"Cancel",



confirmButtonColor:"#4caf50",



cancelButtonColor:"#999",



reverseButtons:true



}).then(function(result){



if(result.isConfirmed)

{
window.location.href=window.location.pathname+"?approve_pr="+id;



}



});



}







// ==========================================
// CONVERT TO PO CONFIRMATION
// ==========================================


function confirmConvert(id)

{


Swal.fire({


icon:"question",



title:"Convert to PO?",




html:

"This Purchase Request will be converted into a Purchase Order and sent to Procurement.<br><br>This action cannot be undone.",





showCancelButton:true,



confirmButtonText:"Confirm",



cancelButtonText:"Cancel",



confirmButtonColor:"#302f92",



cancelButtonColor:"#999",



reverseButtons:true



}).then(function(result){



if(result.isConfirmed)

{

window.location.href=window.location.pathname+"?convert_po="+id;



}



});



}







// ==========================================
// FILTER
// ==========================================


function filterPR(value)

{


let rows=document.querySelectorAll(

".pr-table tbody tr"

);




rows.forEach(function(row){



let status=row.cells[2].innerText.trim();





if(value=="" || status==value)

{


row.style.display="";

}

else

{


row.style.display="none";


}



});



}







// ==========================================
// SORT
// ==========================================


function sortPR(value)

{


let tbody=document.querySelector(

".pr-table tbody"

);



if(!tbody)

return;



let rows=Array.from(tbody.rows);




if(value=="status")

{


rows.sort(function(a,b){


return a.cells[2].innerText.localeCompare(

b.cells[2].innerText

);


});


}




if(value=="reference")

{


rows.sort(function(a,b){


return a.cells[3].innerText.localeCompare(

b.cells[3].innerText

);


});


}




if(value=="date")

{


rows.sort(function(a,b){


return a.cells[4].innerText.localeCompare(

b.cells[4].innerText

);


});


}





rows.forEach(function(row){


tbody.appendChild(row);


});



}








// ==========================================
// CHECK ALL
// ==========================================


let checkAll=document.getElementById(

"checkAllPR"

);



if(checkAll)

{


checkAll.addEventListener(

"change",

function(){



document

.querySelectorAll(

".pr-table tbody input[type=checkbox]"

)

.forEach(function(cb){


cb.checked=checkAll.checked;


});



}

);



}



</script>


';
		;
		
	}

	// code snippet - purpose
	function event_66154(  ) {
		
		// ======================================================
// PURCHASE REQUEST VIEW
// PART 3 - PURPOSE
// ======================================================


// ======================================================
// GET CURRENT RECORD ID
// ======================================================


$id = 0;


if(isset($keys["id"]))
{

    $id = intval($keys["id"]);

}
elseif(isset($_GET["editid"]))
{

    $id = intval($_GET["editid"]);

}




if($id <= 0)
{

    echo "Invalid Purchase Request ID.";

    return;

}





// ======================================================
// GET PURPOSE DATA
// ======================================================


$rsPurpose = DB::Query("

SELECT

    purpose

FROM purchaserequest

WHERE id=".$id."


");




if(!$rsPurpose)
{

    echo DB::LastError();

    return;

}





$purpose = $rsPurpose->fetchAssoc();




// ======================================================
// CSS - PURPOSE STYLE MATCH HEADER
// ======================================================


echo '

<style>


.pr-purpose-card{


background:#f7f7f7!important;

border-radius:8px!important;

padding:20px!important;

margin-top:20px!important;

width:100%!important;


}






.pr-purpose-title{


font-size:12px!important;

font-weight:600!important;

color:#333!important;

margin-bottom:8px!important;


}






.pr-purpose-content{


background:#ffffff!important;

border-radius:5px!important;

padding:15px!important;

font-size:14px!important;

color:#333!important;

line-height:1.5!important;

min-height:140px!important;

white-space:normal!important;


}




</style>


';








// ======================================================
// DISPLAY PURPOSE
// ======================================================


echo '


<div class="pr-purpose-card">





<div class="pr-purpose-title">

Purpose

</div>






<div class="pr-purpose-content">

';


if($purpose && !empty($purpose["purpose"]))
{

    echo nl2br($purpose["purpose"]);

}
else
{

    echo "-";

}




echo '


</div>



</div>


';
		;
		
	}

	// code snippet - app_configuration_panel
	function event_66715(  ) {
		
		// ============================================================
// WINGS SYSTEM CONFIGURATION
// APPLICATION TAB
// PHPRUNNER SAFE CODE SNIPPET
//

// ============================================================


// ============================================================
// 1. DEFAULT VALUES
// ============================================================

$environment = "STAGING";
$baseUrl = "";
$appIsActive = "1";

$lastUpdatedBy = "-";
$lastUpdatedRole = "-";
$lastUpdatedDate = "-";


// ============================================================
// 2. LOAD APPLICATION SETTINGS
// ============================================================

$sqlSettings = "
    SELECT
        setting_key,
        setting_value
    FROM system_setting
    WHERE setting_group = 'APPLICATION'
      AND setting_key IN
      (
          'APP_ENVIRONMENT',
          'APP_BASE_URL',
          'APP_IS_ACTIVE'
      )
";

$rsSettings = DB::Query($sqlSettings);

if ($rsSettings)
{
    while ($settingRow = $rsSettings->fetchAssoc())
    {
        $settingKey = "";

        if (isset($settingRow["setting_key"]))
        {
            $settingKey =
                trim(
                    (string)$settingRow["setting_key"]
                );
        }


        $settingValue = "";

        if (isset($settingRow["setting_value"]))
        {
            $settingValue =
                trim(
                    (string)$settingRow["setting_value"]
                );
        }


        if ($settingKey == "APP_ENVIRONMENT")
        {
            $environment =
                strtoupper(
                    $settingValue
                );
        }


        if ($settingKey == "APP_BASE_URL")
        {
            $baseUrl =
                $settingValue;
        }


        if ($settingKey == "APP_IS_ACTIVE")
        {
            $appIsActive =
                $settingValue;
        }
    }
}


// ============================================================
// 3. NORMALIZE VALUES
// ============================================================

if (
    $environment != "STAGING" &&
    $environment != "PRODUCTION"
)
{
    $environment = "STAGING";
}


if (
    $appIsActive != "1"
)
{
    $appIsActive = "0";
}


// ============================================================
// 4. CHECK AUDIT TABLE
// ============================================================

$hasAuditTable = false;

$rsAuditCheck =
    DB::Query(
        "SHOW TABLES LIKE 'system_setting_audit'"
    );

if ($rsAuditCheck)
{
    $auditCheck =
        $rsAuditCheck->fetchAssoc();

    if ($auditCheck)
    {
        $hasAuditTable = true;
    }
}


// ============================================================
// 5. LOAD LAST UPDATED
// ============================================================

if ($hasAuditTable)
{
    $sqlAudit = "
        SELECT
            changed_by_name,
            changed_by_username,
            changed_by_role,
            changed_at
        FROM system_setting_audit
        WHERE setting_area = 'APPLICATION'
        ORDER BY
            log_id DESC
        LIMIT 1
    ";

    $rsAudit =
        DB::Query(
            $sqlAudit
        );


    if ($rsAudit)
    {
        $auditRow =
            $rsAudit->fetchAssoc();


        if ($auditRow)
        {
            // ------------------------------------------------
            // Updated By
            // ------------------------------------------------

            if (
                isset(
                    $auditRow[
                        "changed_by_name"
                    ]
                ) &&
                trim(
                    (string)$auditRow[
                        "changed_by_name"
                    ]
                ) != ""
            )
            {
                $lastUpdatedBy =
                    trim(
                        (string)$auditRow[
                            "changed_by_name"
                        ]
                    );
            }
            elseif (
                isset(
                    $auditRow[
                        "changed_by_username"
                    ]
                ) &&
                trim(
                    (string)$auditRow[
                        "changed_by_username"
                    ]
                ) != ""
            )
            {
                $lastUpdatedBy =
                    trim(
                        (string)$auditRow[
                            "changed_by_username"
                        ]
                    );
            }


            // ------------------------------------------------
            // Role
            // ------------------------------------------------

            if (
                isset(
                    $auditRow[
                        "changed_by_role"
                    ]
                ) &&
                trim(
                    (string)$auditRow[
                        "changed_by_role"
                    ]
                ) != ""
            )
            {
                $lastUpdatedRole =
                    trim(
                        (string)$auditRow[
                            "changed_by_role"
                        ]
                    );
            }


            // ------------------------------------------------
            // Date
            // ------------------------------------------------

            if (
                isset(
                    $auditRow[
                        "changed_at"
                    ]
                ) &&
                trim(
                    (string)$auditRow[
                        "changed_at"
                    ]
                ) != ""
            )
            {
                $auditTime =
                    strtotime(
                        $auditRow[
                            "changed_at"
                        ]
                    );

                if (
                    $auditTime !== false
                )
                {
                    $lastUpdatedDate =
                        date(
                            "M d, Y h:i A",
                            $auditTime
                        );
                }
            }
        }
    }
}


// ============================================================
// 6. ESCAPE DISPLAY VALUES
// ============================================================

$baseUrlHtml =
    htmlspecialchars(
        $baseUrl,
        ENT_QUOTES,
        "UTF-8"
    );


$updatedByHtml =
    htmlspecialchars(
        $lastUpdatedBy,
        ENT_QUOTES,
        "UTF-8"
    );


$updatedRoleHtml =
    htmlspecialchars(
        $lastUpdatedRole,
        ENT_QUOTES,
        "UTF-8"
    );


$updatedDateHtml =
    htmlspecialchars(
        $lastUpdatedDate,
        ENT_QUOTES,
        "UTF-8"
    );


// ============================================================
// 7. CSS
// ============================================================

echo '

<style>

/* ============================================================
   PAGE
   ============================================================ */

.wings-settings-page
{
    width:100%;
    box-sizing:border-box;
    padding:4px 16px 25px 16px;
    font-family:Arial, sans-serif;
}


/* ============================================================
   TITLE AREA
   ============================================================ */

.wings-settings-header
{
    display:flex;
    justify-content:space-between;
    align-items:flex-start;
    margin-bottom:30px;
}


.wings-settings-title
{
    color:#2e3192;
    font-size:22px;
    font-weight:700;
    line-height:1.2;
    margin-bottom:4px;
}


.wings-settings-subtitle
{
    color:#666666;
    font-size:13px;
    line-height:1.4;
}


/* ============================================================
   TAB MENU
   ============================================================ */

.wings-settings-tabs
{
    display:flex;
    align-items:center;
    gap:24px;
    border-bottom:1px solid #eeeeee;
    margin-bottom:14px;
    min-height:42px;
}


.wings-settings-tab
{
    display:inline-flex;
    align-items:center;
    gap:7px;
    height:42px;
    padding:0 4px;

    color:#666666 !important;
    text-decoration:none !important;

    font-size:13px;
    font-weight:400;

    border-bottom:
        3px solid transparent;
}


.wings-settings-tab:hover
{
    color:#2e3192 !important;
}


.wings-settings-tab.active
{
    color:#2e3192 !important;
    font-weight:600;
    border-bottom-color:#2e3192;
}


.wings-tab-icon
{
    font-size:14px;
}


/* ============================================================
   APPLICATION CARD
   ============================================================ */

.wings-config-card
{
    width:100%;
    box-sizing:border-box;

    background:#f7f7f7;

    border-radius:8px;

    padding:
        18px 18px 20px 18px;
}


.wings-config-card-header
{
    display:flex;
    align-items:center;
    justify-content:space-between;

    margin-bottom:25px;
}


.wings-config-title
{
    color:#2e3192;
    font-size:13px;
    font-weight:600;
}


/* ============================================================
   STATUS
   ============================================================ */

.wings-status-area
{
    display:flex;
    align-items:center;
    gap:14px;

    font-size:11px;
    font-weight:600;
    color:#333333;
}


/* ============================================================
   FORM GRID
   ============================================================ */

.wings-config-fields
{
    display:grid;

    grid-template-columns:
        minmax(320px, 1fr)
        minmax(420px, 1.7fr);

    gap:45px;

    align-items:center;
}


.wings-field
{
    display:grid;

    grid-template-columns:
        105px
        minmax(0,1fr);

    align-items:center;

    column-gap:12px;
}


.wings-field label
{
    margin:0;

    color:#333333;

    font-size:11px;

    font-weight:400;
}


.wings-field select,
.wings-field input
{
    width:100%;

    height:36px;

    box-sizing:border-box;

    padding:
        7px 11px;

    border:
        1px solid #eeeeee;

    border-radius:4px;

    background:#ffffff;

    color:#333333;

    font-size:12px;
}


.wings-field select:focus,
.wings-field input:focus
{
    outline:none;

    border-color:#2e3192;

    box-shadow:
        0 0 0 1px
        rgba(
            46,
            49,
            146,
            0.08
        );
}


/* ============================================================
   TOGGLE
   ============================================================ */

.wings-switch
{
    position:relative;

    display:inline-block;

    width:34px;
    height:18px;

    margin:0;
}


.wings-switch input
{
    opacity:0;

    width:0;
    height:0;
}


.wings-slider
{
    position:absolute;

    cursor:pointer;

    top:0;
    left:0;
    right:0;
    bottom:0;

    background:#bcbcbc;

    border-radius:20px;

    transition:0.2s;
}


.wings-slider:before
{
    position:absolute;

    content:"";

    height:14px;
    width:14px;

    left:2px;
    top:2px;

    background:#ffffff;

    border-radius:50%;

    transition:0.2s;
}


.wings-switch
input:checked
+
.wings-slider
{
    background:#50b863;
}


.wings-switch
input:checked
+
.wings-slider:before
{
    transform:
        translateX(16px);
}


/* ============================================================
   LAST UPDATED
   ============================================================ */

.wings-last-updated
{
    width:100%;

    box-sizing:border-box;

    background:#f7f7f7;

    border-radius:8px;

    padding:20px;

    margin-top:28px;
}


.wings-last-title
{
    color:#2e3192;

    font-size:13px;

    font-weight:600;

    margin-bottom:20px;
}


.wings-last-grid
{
    display:grid;

    grid-template-columns:
        1fr
        1fr
        1fr;

    gap:45px;
}


.wings-last-item
{
    display:flex;

    flex-direction:column;

    gap:12px;
}


.wings-last-label
{
    color:#666666;

    font-size:12px;
}


.wings-last-value
{
    color:#222222;

    font-size:12px;
}


/* ============================================================
   RESPONSIVE
   ============================================================ */

@media
(
    max-width:950px
)
{

    .wings-config-fields
    {
        grid-template-columns:1fr;
    }


    .wings-last-grid
    {
        grid-template-columns:1fr;
    }


    .wings-settings-tabs
    {
        flex-wrap:wrap;
    }

}

</style>

';


// ============================================================
// 8. START PAGE
// ============================================================

echo '
<div class="wings-settings-page">
';


// ============================================================
// 9. PAGE TITLE
// ============================================================

echo '

<div class="wings-settings-header">

    <div>

        <div class="wings-settings-title">
            Application Configuration
        </div>

        <div class="wings-settings-subtitle">
            Manage the application environment,
            base URL, and system availability settings.
        </div>

    </div>

</div>

';


// ============================================================
// 10. TABS
//
// Change URLs later if your generated PHPRunner page names
// are different.
// ============================================================

echo '

<div class="wings-settings-tabs">

    <a
        href="#"
        class="wings-settings-tab active"
        onclick="return false;"
    >
        <span class="wings-tab-icon">
            &#9633;
        </span>

        Application
    </a>


    <a
        href="#"
        class="wings-settings-tab"
        onclick="
            alert(
                \'Integrations tab will be connected next.\'
            );
            return false;
        "
    >
        <span class="wings-tab-icon">
            &#10022;
        </span>

        Integrations
    </a>


    <a
        href="#"
        class="wings-settings-tab"
        onclick="
            alert(
                \'Security & PNPKI tab will be connected next.\'
            );
            return false;
        "
    >
        <span class="wings-tab-icon">
            &#9432;
        </span>

        Security &amp; PNPKI
    </a>

</div>

';


// ============================================================
// 11. APPLICATION CONFIGURATION CARD
// ============================================================

echo '

<div class="wings-config-card">


    <div class="wings-config-card-header">


        <div class="wings-config-title">
            Application Configuration
        </div>


        <div class="wings-status-area">

            <span>
                Application Status
            </span>


            <label
                class="wings-switch"
                title="Application Status"
            >

                <input
                    type="checkbox"
                    id="app_is_active"
';


// ============================================================
// CHECKBOX STATE
// ============================================================

if ($appIsActive == "1")
{
    echo ' checked';
}


echo '

                >

                <span
                    class="wings-slider"
                ></span>

            </label>

        </div>


    </div>


    <div class="wings-config-fields">

';


// ============================================================
// 12. ENVIRONMENT FIELD
// ============================================================

echo '

<div class="wings-field">

    <label
        for="app_environment"
    >
        Environment
    </label>


    <select
        id="app_environment"
    >

';


echo '
<option value="STAGING"
';

if ($environment == "STAGING")
{
    echo ' selected';
}

echo '
>
Staging
</option>
';


echo '
<option value="PRODUCTION"
';

if ($environment == "PRODUCTION")
{
    echo ' selected';
}

echo '
>
Production
</option>
';


echo '

    </select>

</div>

';


// ============================================================
// 13. BASE URL
// ============================================================

echo '

<div class="wings-field">

    <label
        for="app_base_url"
    >
        Base URL
    </label>


    <input
        type="text"
        id="app_base_url"
        value="' .
        $baseUrlHtml .
        '"
        placeholder="https://"
        autocomplete="off"
    >

</div>

';


// ============================================================
// CLOSE CONFIG FIELD / CARD
// ============================================================

echo '

    </div>

</div>

';


// ============================================================
// 14. LAST UPDATED CARD
// ============================================================

echo '

<div class="wings-last-updated">


    <div class="wings-last-title">
        Last Updated
    </div>


    <div class="wings-last-grid">


        <div class="wings-last-item">

            <span class="wings-last-label">
                Updated By:
            </span>

            <span
                class="wings-last-value"
                id="app_updated_by"
            >' .
                $updatedByHtml .
            '</span>

        </div>


        <div class="wings-last-item">

            <span class="wings-last-label">
                Roles
            </span>

            <span
                class="wings-last-value"
                id="app_updated_role"
            >' .
                $updatedRoleHtml .
            '</span>

        </div>


        <div class="wings-last-item">

            <span class="wings-last-label">
                Date and Time
            </span>

            <span
                class="wings-last-value"
                id="app_updated_date"
            >' .
                $updatedDateHtml .
            '</span>

        </div>


    </div>

</div>

';


// ============================================================
// 15. END PAGE
// ============================================================

echo '
</div>
';
		;
		
	}


}
?>
