<?php
class eventclass_sales_detail  extends TableEventsBase {
	
	function init() {
		$this->events = array(
	'BeforeAdd' => true,
	'BeforeEdit' => true,
	'AfterAdd' => true,
	'AfterEdit' => true,
	'AfterDelete' => true,
	'BeforeDelete' => true 
);
		$this->fieldValues = array(
	'filterLimit' => array(
		 
	),
	'mapIcon' => array(
		 
	),
	'viewCustom' => array(
		 
	),
	'lookupWhere' => array(
		 
	),
	'viewFileText' => array(
		 
	),
	'defaultValue' => array(
		 
	),
	'autoUpdateValue' => array(
		 
	),
	'uploadFolder' => array(
		 
	),
	'viewPluginInit' => array(
		 
	),
	'editPluginInit' => array(
		 
	) 
);
			}
		function BeforeAdd( &$values, &$sqlValues, &$message, $inline, $pageObject ) {
		// BuildLedger Finance - Sales Detail Before Add
// Generated-column safe version

/* ============================================================
   Required Header
   ============================================================ */

if (empty($values["sales_detail_uuid"])) {
    $rsUuid = DB::Query("SELECT UUID() AS uuid");
    $uuidData = $rsUuid->fetchAssoc();
    $values["sales_detail_uuid"] = $uuidData["uuid"];
}

if (empty($values["sales_id"])) {
    $message = "Sales header is missing.";
    return false;
}

$salesId = (int)$values["sales_id"];

/* ============================================================
   Get Sales Header and Period Status
   ============================================================ */

$rsSales = DB::Query("
    SELECT
        s.posting_status,
        COALESCE(s.exchange_rate, 1) AS exchange_rate,
        ap.period_status
    FROM sales s
    LEFT JOIN accounting_period ap
        ON ap.id = s.accounting_period_id
    WHERE s.id = " . $salesId . "
    LIMIT 1
");

$sales = $rsSales->fetchAssoc();

if (!$sales) {
    $message = "Sales header was not found.";
    return false;
}

if (strtoupper((string)$sales["posting_status"]) == "POSTED") {
    $message = "Cannot add lines to a posted sales document.";
    return false;
}

if (empty($sales["period_status"])) {
    $message = "Accounting period was not found for this sales invoice.";
    return false;
}

if (strtoupper((string)$sales["period_status"]) == "CLOSED") {
    $message = "This accounting period is already closed. You cannot add sales detail lines.";
    return false;
}

/* ============================================================
   Auto Line Number
   ============================================================ */

if (empty($values["line_no"])) {
    $rsLine = DB::Query("
        SELECT COALESCE(MAX(line_no), 0) + 1 AS next_line_no
        FROM sales_detail
        WHERE sales_id = " . $salesId
    );

    $lineData = $rsLine->fetchAssoc();
    $values["line_no"] = (int)$lineData["next_line_no"];
}

/* ============================================================
   Item Lookup
   ============================================================ */

if (empty($values["item_id"])) {
    $message = "Please select an item.";
    return false;
}

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

$rsItem = DB::Query("
    SELECT
        item_code,
        item_name,
        uom_code,
        default_sales_price
    FROM item
    WHERE id = " . $itemId . "
    LIMIT 1
");

$item = $rsItem->fetchAssoc();

if ($item) {
    if (empty($values["item_code_snapshot"])) {
        $values["item_code_snapshot"] = $item["item_code"];
    }

    if (empty($values["description"])) {
        $values["description"] = $item["item_name"];
    }

    if (empty($values["uom_code"])) {
        $values["uom_code"] = $item["uom_code"];
    }

    if (
        (empty($values["unit_price"]) || (float)$values["unit_price"] == 0)
        && $item["default_sales_price"] !== null
    ) {
        $values["unit_price"] = $item["default_sales_price"];
    }
}

/* ============================================================
   Tax Code Lookups
   ============================================================ */

if (!empty($values["vat_tax_code_id"])) {
    $vatTaxCodeId = (int)$values["vat_tax_code_id"];

    $rsVat = DB::Query("
        SELECT rate_percent
        FROM tax_code
        WHERE id = " . $vatTaxCodeId . "
        LIMIT 1
    ");

    $vat = $rsVat->fetchAssoc();

    if ($vat) {
        $values["vat_rate_snapshot"] = (float)$vat["rate_percent"];
    }
}

if (!empty($values["withholding_tax_code_id"])) {
    $withholdingTaxCodeId = (int)$values["withholding_tax_code_id"];

    $rsWh = DB::Query("
        SELECT rate_percent
        FROM tax_code
        WHERE id = " . $withholdingTaxCodeId . "
        LIMIT 1
    ");

    $wh = $rsWh->fetchAssoc();

    if ($wh) {
        $values["withholding_rate_snapshot"] = (float)$wh["rate_percent"];
    }
}

/* ============================================================
   Validate and Compute Non-Generated Values
   ============================================================ */

$qty = isset($values["quantity"]) && $values["quantity"] !== ""
    ? (float)$values["quantity"]
    : 0;

$unitPrice = isset($values["unit_price"]) && $values["unit_price"] !== ""
    ? (float)$values["unit_price"]
    : 0;

$commercialRate = isset($values["commercial_discount_rate"]) && $values["commercial_discount_rate"] !== ""
    ? (float)$values["commercial_discount_rate"]
    : 0;

$commercialAmount = isset($values["commercial_discount_amount"]) && $values["commercial_discount_amount"] !== ""
    ? (float)$values["commercial_discount_amount"]
    : 0;

$statutoryRate = isset($values["statutory_discount_rate"]) && $values["statutory_discount_rate"] !== ""
    ? (float)$values["statutory_discount_rate"]
    : 0;

$statutoryAmount = isset($values["statutory_discount_amount"]) && $values["statutory_discount_amount"] !== ""
    ? (float)$values["statutory_discount_amount"]
    : 0;

$vatRate = isset($values["vat_rate_snapshot"]) && $values["vat_rate_snapshot"] !== ""
    ? (float)$values["vat_rate_snapshot"]
    : 0;

$withholdingRate = isset($values["withholding_rate_snapshot"]) && $values["withholding_rate_snapshot"] !== ""
    ? (float)$values["withholding_rate_snapshot"]
    : 0;

if ($qty <= 0) {
    $message = "Quantity must be greater than zero.";
    return false;
}

if ($unitPrice < 0) {
    $message = "Unit price cannot be negative.";
    return false;
}

$gross = round($qty * $unitPrice, 4);

if ($commercialAmount <= 0 && $commercialRate > 0) {
    $commercialAmount = round($gross * ($commercialRate / 100), 4);
}

$afterCommercial = round($gross - $commercialAmount, 4);

if ($statutoryAmount <= 0 && $statutoryRate > 0) {
    $statutoryAmount = round($afterCommercial * ($statutoryRate / 100), 4);
}

$netBeforeTax = round($afterCommercial - $statutoryAmount, 4);

if ($netBeforeTax < 0) {
    $message = "Discounts cannot exceed the line amount.";
    return false;
}

$vatAmount = round($netBeforeTax * ($vatRate / 100), 4);
$withholdingAmount = round($netBeforeTax * ($withholdingRate / 100), 4);

$lineTotal = round($netBeforeTax + $vatAmount - $withholdingAmount, 4);

$exchangeRate = !empty($sales["exchange_rate"])
    ? (float)$sales["exchange_rate"]
    : 1;

/* ============================================================
   Save Values
   Do NOT set generated columns:
   - gross_amount
   - net_before_tax_amount
   - line_total_amount
   ============================================================ */

$values["quantity"] = $qty;
$values["unit_price"] = $unitPrice;

$values["commercial_discount_rate"] = $commercialRate;
$values["commercial_discount_amount"] = $commercialAmount;

$values["statutory_discount_rate"] = $statutoryRate;
$values["statutory_discount_amount"] = $statutoryAmount;

$values["vat_rate_snapshot"] = $vatRate;
$values["withholding_rate_snapshot"] = $withholdingRate;

$values["vatable_amount"] = $netBeforeTax;
$values["vat_exempt_amount"] = 0;
$values["zero_rated_amount"] = 0;

$values["vat_amount"] = $vatAmount;
$values["withholding_amount"] = $withholdingAmount;
$values["base_line_total_amount"] = round($lineTotal * $exchangeRate, 4);

return true;
		;
		return true;
	}

	function BeforeEdit( &$values, &$sqlValues, $where, &$oldvalues, &$keys, &$message, $inline, $pageObject ) {
		// BuildLedger Finance - Sales Detail Before Edit
// Generated-column safe version

/* ============================================================
   Preserve Key Fields
   ============================================================ */

if (!empty($oldvalues["sales_detail_uuid"])) {
    $values["sales_detail_uuid"] = $oldvalues["sales_detail_uuid"];
}

if (!empty($oldvalues["sales_id"])) {
    $values["sales_id"] = $oldvalues["sales_id"];
}

if (empty($values["sales_id"])) {
    $message = "Sales header is missing.";
    return false;
}

$salesId = (int)$values["sales_id"];

/* ============================================================
   Helper for edit values
   ============================================================ */

$getValue = function ($key, $default = "") use ($values, $oldvalues) {
    if (isset($values[$key]) && $values[$key] !== "") {
        return $values[$key];
    }

    if (isset($oldvalues[$key]) && $oldvalues[$key] !== "") {
        return $oldvalues[$key];
    }

    return $default;
};

/* ============================================================
   Get Sales Header and Period Status
   ============================================================ */

$rsSales = DB::Query("
    SELECT
        s.posting_status,
        COALESCE(s.exchange_rate, 1) AS exchange_rate,
        ap.period_status
    FROM sales s
    LEFT JOIN accounting_period ap
        ON ap.id = s.accounting_period_id
    WHERE s.id = " . $salesId . "
    LIMIT 1
");

$sales = $rsSales->fetchAssoc();

if (!$sales) {
    $message = "Sales header was not found.";
    return false;
}

if (strtoupper((string)$sales["posting_status"]) == "POSTED") {
    $message = "Cannot edit lines of a posted sales document.";
    return false;
}

if (empty($sales["period_status"])) {
    $message = "Accounting period was not found for this sales invoice.";
    return false;
}

if (strtoupper((string)$sales["period_status"]) == "CLOSED") {
    $message = "This accounting period is already closed. You cannot edit sales detail lines.";
    return false;
}

/* ============================================================
   Preserve Line Number if Missing
   ============================================================ */

if (empty($values["line_no"]) && !empty($oldvalues["line_no"])) {
    $values["line_no"] = $oldvalues["line_no"];
}

/* ============================================================
   Item Lookup
   ============================================================ */

$itemId = (int)$getValue("item_id", 0);

if ($itemId <= 0) {
    $message = "Please select an item.";
    return false;
}

$values["item_id"] = $itemId;

$rsItem = DB::Query("
    SELECT
        item_code,
        item_name,
        uom_code,
        default_sales_price
    FROM item
    WHERE id = " . $itemId . "
    LIMIT 1
");

$item = $rsItem->fetchAssoc();

if ($item) {
    if (empty($values["item_code_snapshot"])) {
        $values["item_code_snapshot"] = $item["item_code"];
    }

    if (empty($values["description"])) {
        $values["description"] = $item["item_name"];
    }

    if (empty($values["uom_code"])) {
        $values["uom_code"] = $item["uom_code"];
    }

    if (
        (empty($values["unit_price"]) || (float)$values["unit_price"] == 0)
        && $item["default_sales_price"] !== null
    ) {
        $values["unit_price"] = $item["default_sales_price"];
    }
}

/* ============================================================
   Tax Code Lookups
   ============================================================ */

$vatTaxCodeId = (int)$getValue("vat_tax_code_id", 0);

if ($vatTaxCodeId > 0) {
    $values["vat_tax_code_id"] = $vatTaxCodeId;

    $rsVat = DB::Query("
        SELECT rate_percent
        FROM tax_code
        WHERE id = " . $vatTaxCodeId . "
        LIMIT 1
    ");

    $vat = $rsVat->fetchAssoc();

    if ($vat) {
        $values["vat_rate_snapshot"] = (float)$vat["rate_percent"];
    }
}

$withholdingTaxCodeId = (int)$getValue("withholding_tax_code_id", 0);

if ($withholdingTaxCodeId > 0) {
    $values["withholding_tax_code_id"] = $withholdingTaxCodeId;

    $rsWh = DB::Query("
        SELECT rate_percent
        FROM tax_code
        WHERE id = " . $withholdingTaxCodeId . "
        LIMIT 1
    ");

    $wh = $rsWh->fetchAssoc();

    if ($wh) {
        $values["withholding_rate_snapshot"] = (float)$wh["rate_percent"];
    }
}

/* ============================================================
   Validate and Compute Non-Generated Values
   ============================================================ */

$qty = (float)$getValue("quantity", 0);
$unitPrice = (float)$getValue("unit_price", 0);

$commercialRate = (float)$getValue("commercial_discount_rate", 0);
$commercialAmount = (float)$getValue("commercial_discount_amount", 0);

$statutoryRate = (float)$getValue("statutory_discount_rate", 0);
$statutoryAmount = (float)$getValue("statutory_discount_amount", 0);

$vatRate = isset($values["vat_rate_snapshot"]) && $values["vat_rate_snapshot"] !== ""
    ? (float)$values["vat_rate_snapshot"]
    : (float)$getValue("vat_rate_snapshot", 0);

$withholdingRate = isset($values["withholding_rate_snapshot"]) && $values["withholding_rate_snapshot"] !== ""
    ? (float)$values["withholding_rate_snapshot"]
    : (float)$getValue("withholding_rate_snapshot", 0);

if ($qty <= 0) {
    $message = "Quantity must be greater than zero.";
    return false;
}

if ($unitPrice < 0) {
    $message = "Unit price cannot be negative.";
    return false;
}

$gross = round($qty * $unitPrice, 4);

if ($commercialAmount <= 0 && $commercialRate > 0) {
    $commercialAmount = round($gross * ($commercialRate / 100), 4);
}

$afterCommercial = round($gross - $commercialAmount, 4);

if ($statutoryAmount <= 0 && $statutoryRate > 0) {
    $statutoryAmount = round($afterCommercial * ($statutoryRate / 100), 4);
}

$netBeforeTax = round($afterCommercial - $statutoryAmount, 4);

if ($netBeforeTax < 0) {
    $message = "Discounts cannot exceed the line amount.";
    return false;
}

$vatAmount = round($netBeforeTax * ($vatRate / 100), 4);
$withholdingAmount = round($netBeforeTax * ($withholdingRate / 100), 4);

$lineTotal = round($netBeforeTax + $vatAmount - $withholdingAmount, 4);

$exchangeRate = !empty($sales["exchange_rate"])
    ? (float)$sales["exchange_rate"]
    : 1;

/* ============================================================
   Save Values
   Do NOT set generated columns:
   - gross_amount
   - net_before_tax_amount
   - line_total_amount
   ============================================================ */

$values["quantity"] = $qty;
$values["unit_price"] = $unitPrice;

$values["commercial_discount_rate"] = $commercialRate;
$values["commercial_discount_amount"] = $commercialAmount;

$values["statutory_discount_rate"] = $statutoryRate;
$values["statutory_discount_amount"] = $statutoryAmount;

$values["vat_rate_snapshot"] = $vatRate;
$values["withholding_rate_snapshot"] = $withholdingRate;

$values["vatable_amount"] = $netBeforeTax;
$values["vat_exempt_amount"] = 0;
$values["zero_rated_amount"] = 0;

$values["vat_amount"] = $vatAmount;
$values["withholding_amount"] = $withholdingAmount;
$values["base_line_total_amount"] = round($lineTotal * $exchangeRate, 4);

return true;
		;
		return true;
	}

	function AfterAdd( &$values, &$keys, $inline, $pageObject ) {
		/* ============================================================
   BuildLedger Finance - Recalculate Sales Header Totals
   Use this same code for:
   1. sales_detail Add page  → After record added
   2. sales_detail Edit page → After record updated
   3. sales_detail List page → After record deleted
   ============================================================ */

$salesIds = array();

if (isset($values["sales_id"]) && (int)$values["sales_id"] > 0) {
    $salesIds[] = (int)$values["sales_id"];
}

if (isset($oldvalues["sales_id"]) && (int)$oldvalues["sales_id"] > 0) {
    $salesIds[] = (int)$oldvalues["sales_id"];
}

if (isset($deleted_values["sales_id"]) && (int)$deleted_values["sales_id"] > 0) {
    $salesIds[] = (int)$deleted_values["sales_id"];
}

$salesIds = array_unique($salesIds);

$fmt = function ($value) {
    return number_format((float)$value, 4, ".", "");
};

foreach ($salesIds as $salesId) {

    $salesId = (int)$salesId;

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

    /* ============================================================
       Get Detail Totals
       ============================================================ */

    $rsTotals = DB::Query("
        SELECT
            COUNT(*) AS line_count,

            COALESCE(SUM(gross_amount), 0) AS gross_amount,
            COALESCE(SUM(commercial_discount_amount), 0) AS commercial_discount_amount,
            COALESCE(SUM(statutory_discount_amount), 0) AS statutory_discount_amount,

            COALESCE(SUM(net_before_tax_amount), 0) AS net_before_tax_amount,
            COALESCE(SUM(vatable_amount), 0) AS vatable_amount,
            COALESCE(SUM(vat_exempt_amount), 0) AS vat_exempt_amount,
            COALESCE(SUM(zero_rated_amount), 0) AS zero_rated_amount,

            COALESCE(SUM(vat_amount), 0) AS vat_amount,
            COALESCE(SUM(withholding_amount), 0) AS withholding_amount,

            COALESCE(SUM(line_total_amount), 0) AS line_total_amount,
            COALESCE(SUM(base_line_total_amount), 0) AS base_line_total_amount
        FROM sales_detail
        WHERE sales_id = " . $salesId
    );

    $totals = $rsTotals->fetchAssoc();

    $lineCount = 0;

    $subtotalAmount = 0;
    $commercialDiscountAmount = 0;
    $statutoryDiscountAmount = 0;

    $netBeforeTaxAmount = 0;
    $vatableAmount = 0;
    $vatExemptAmount = 0;
    $zeroRatedAmount = 0;

    $vatAmount = 0;
    $withholdingAmount = 0;

    $grandTotalAmount = 0;
    $baseGrandTotalAmount = 0;

    if ($totals) {
        $lineCount = (int)$totals["line_count"];

        $subtotalAmount = round((float)$totals["gross_amount"], 4);
        $commercialDiscountAmount = round((float)$totals["commercial_discount_amount"], 4);
        $statutoryDiscountAmount = round((float)$totals["statutory_discount_amount"], 4);

        $netBeforeTaxAmount = round((float)$totals["net_before_tax_amount"], 4);
        $vatableAmount = round((float)$totals["vatable_amount"], 4);
        $vatExemptAmount = round((float)$totals["vat_exempt_amount"], 4);
        $zeroRatedAmount = round((float)$totals["zero_rated_amount"], 4);

        $vatAmount = round((float)$totals["vat_amount"], 4);
        $withholdingAmount = round((float)$totals["withholding_amount"], 4);

        $grandTotalAmount = round((float)$totals["line_total_amount"], 4);
        $baseGrandTotalAmount = round((float)$totals["base_line_total_amount"], 4);
    }

    /* ============================================================
       Fallback if generated line total is not populated
       ============================================================ */

    if ($grandTotalAmount <= 0 && $lineCount > 0) {
        $grandTotalAmount = round($netBeforeTaxAmount + $vatAmount - $withholdingAmount, 4);
    }

    if ($grandTotalAmount <= 0 && $lineCount > 0) {
        $grandTotalAmount = round(
            $subtotalAmount
            - $commercialDiscountAmount
            - $statutoryDiscountAmount
            + $vatAmount
            - $withholdingAmount,
            4
        );
    }

    if ($baseGrandTotalAmount <= 0 && $grandTotalAmount > 0) {
        $baseGrandTotalAmount = $grandTotalAmount;
    }

    /* ============================================================
       If all detail lines were deleted, reset header totals
       ============================================================ */

    if ($lineCount <= 0) {
        $subtotalAmount = 0;
        $commercialDiscountAmount = 0;
        $statutoryDiscountAmount = 0;

        $vatableAmount = 0;
        $vatExemptAmount = 0;
        $zeroRatedAmount = 0;

        $vatAmount = 0;
        $withholdingAmount = 0;

        $grandTotalAmount = 0;
        $baseGrandTotalAmount = 0;
    }

    /* ============================================================
       Update Sales Header
       ============================================================ */

    DB::Query("
        UPDATE sales
        SET
            subtotal_amount = " . $fmt($subtotalAmount) . ",
            commercial_discount_amount = " . $fmt($commercialDiscountAmount) . ",
            statutory_discount_amount = " . $fmt($statutoryDiscountAmount) . ",

            vatable_amount = " . $fmt($vatableAmount) . ",
            vat_exempt_amount = " . $fmt($vatExemptAmount) . ",
            zero_rated_amount = " . $fmt($zeroRatedAmount) . ",

            vat_amount = " . $fmt($vatAmount) . ",
            withholding_amount = " . $fmt($withholdingAmount) . ",

            grand_total_amount = " . $fmt($grandTotalAmount) . ",
            base_grand_total_amount = " . $fmt($baseGrandTotalAmount) . ",
            updated_at = CURRENT_TIMESTAMP(6)
        WHERE id = " . $salesId . "
        LIMIT 1
    ");
}
		;
		
	}

	function AfterEdit( &$values, $where, &$oldvalues, &$keys, $inline, $pageObject ) {
		/* ============================================================
   BuildLedger Finance - Recalculate Sales Header Totals
   Event:
   sales_detail → List page → After record updated

   Purpose:
   This is required for INLINE EDIT / SAVE ALL inside Sales Detail.
   ============================================================ */

$salesId = 0;

if (isset($values["sales_id"]) && (int)$values["sales_id"] > 0) {
    $salesId = (int)$values["sales_id"];
} elseif (isset($oldvalues["sales_id"]) && (int)$oldvalues["sales_id"] > 0) {
    $salesId = (int)$oldvalues["sales_id"];
}

if ($salesId <= 0) {
    return;
}

$rs = DB::Query("
    SELECT
        COUNT(*) AS line_count,

        COALESCE(SUM(gross_amount), 0) AS subtotal_amount,
        COALESCE(SUM(commercial_discount_amount), 0) AS commercial_discount_amount,
        COALESCE(SUM(statutory_discount_amount), 0) AS statutory_discount_amount,

        COALESCE(SUM(vatable_amount), 0) AS vatable_amount,
        COALESCE(SUM(vat_exempt_amount), 0) AS vat_exempt_amount,
        COALESCE(SUM(zero_rated_amount), 0) AS zero_rated_amount,
        COALESCE(SUM(vat_amount), 0) AS vat_amount,
        COALESCE(SUM(withholding_amount), 0) AS withholding_amount,

        COALESCE(SUM(line_total_amount), 0) AS grand_total_amount,
        COALESCE(SUM(base_line_total_amount), 0) AS base_grand_total_amount
    FROM sales_detail
    WHERE sales_id = " . $salesId
);

$totals = $rs->fetchAssoc();

$lineCount = $totals ? (int)$totals["line_count"] : 0;

$subtotalAmount = 0;
$commercialDiscountAmount = 0;
$statutoryDiscountAmount = 0;
$vatableAmount = 0;
$vatExemptAmount = 0;
$zeroRatedAmount = 0;
$vatAmount = 0;
$withholdingAmount = 0;
$grandTotalAmount = 0;
$baseGrandTotalAmount = 0;

if ($lineCount > 0) {
    $subtotalAmount = round((float)$totals["subtotal_amount"], 4);
    $commercialDiscountAmount = round((float)$totals["commercial_discount_amount"], 4);
    $statutoryDiscountAmount = round((float)$totals["statutory_discount_amount"], 4);

    $vatableAmount = round((float)$totals["vatable_amount"], 4);
    $vatExemptAmount = round((float)$totals["vat_exempt_amount"], 4);
    $zeroRatedAmount = round((float)$totals["zero_rated_amount"], 4);
    $vatAmount = round((float)$totals["vat_amount"], 4);
    $withholdingAmount = round((float)$totals["withholding_amount"], 4);

    $grandTotalAmount = round((float)$totals["grand_total_amount"], 4);
    $baseGrandTotalAmount = round((float)$totals["base_grand_total_amount"], 4);

    if ($grandTotalAmount <= 0 && $subtotalAmount > 0) {
        $grandTotalAmount = $subtotalAmount + $vatAmount - $withholdingAmount;
    }

    if ($baseGrandTotalAmount <= 0 && $grandTotalAmount > 0) {
        $baseGrandTotalAmount = $grandTotalAmount;
    }
}

function bl_sales_money_sql($value) {
    return number_format((float)$value, 4, ".", "");
}

DB::Exec("
    UPDATE sales
    SET
        subtotal_amount = " . bl_sales_money_sql($subtotalAmount) . ",
        commercial_discount_amount = " . bl_sales_money_sql($commercialDiscountAmount) . ",
        statutory_discount_amount = " . bl_sales_money_sql($statutoryDiscountAmount) . ",

        vatable_amount = " . bl_sales_money_sql($vatableAmount) . ",
        vat_exempt_amount = " . bl_sales_money_sql($vatExemptAmount) . ",
        zero_rated_amount = " . bl_sales_money_sql($zeroRatedAmount) . ",
        vat_amount = " . bl_sales_money_sql($vatAmount) . ",
        withholding_amount = " . bl_sales_money_sql($withholdingAmount) . ",

        grand_total_amount = " . bl_sales_money_sql($grandTotalAmount) . ",
        base_grand_total_amount = " . bl_sales_money_sql($baseGrandTotalAmount) . ",
        updated_at = CURRENT_TIMESTAMP(6)
    WHERE id = " . $salesId . "
    LIMIT 1
");
		;
		
	}

	function AfterDelete( $where, &$deleted_values, &$message, $pageObject ) {
		/* ============================================================
   BuildLedger Finance - Recalculate Sales Header Totals
   Use this same code for:
   1. sales_detail Add page  → After record added
   2. sales_detail Edit page → After record updated
   3. sales_detail List page → After record deleted
   ============================================================ */

$salesIds = array();

if (isset($values["sales_id"]) && (int)$values["sales_id"] > 0) {
    $salesIds[] = (int)$values["sales_id"];
}

if (isset($oldvalues["sales_id"]) && (int)$oldvalues["sales_id"] > 0) {
    $salesIds[] = (int)$oldvalues["sales_id"];
}

if (isset($deleted_values["sales_id"]) && (int)$deleted_values["sales_id"] > 0) {
    $salesIds[] = (int)$deleted_values["sales_id"];
}

$salesIds = array_unique($salesIds);

$fmt = function ($value) {
    return number_format((float)$value, 4, ".", "");
};

foreach ($salesIds as $salesId) {

    $salesId = (int)$salesId;

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

    /* ============================================================
       Get Detail Totals
       ============================================================ */

    $rsTotals = DB::Query("
        SELECT
            COUNT(*) AS line_count,

            COALESCE(SUM(gross_amount), 0) AS gross_amount,
            COALESCE(SUM(commercial_discount_amount), 0) AS commercial_discount_amount,
            COALESCE(SUM(statutory_discount_amount), 0) AS statutory_discount_amount,

            COALESCE(SUM(net_before_tax_amount), 0) AS net_before_tax_amount,
            COALESCE(SUM(vatable_amount), 0) AS vatable_amount,
            COALESCE(SUM(vat_exempt_amount), 0) AS vat_exempt_amount,
            COALESCE(SUM(zero_rated_amount), 0) AS zero_rated_amount,

            COALESCE(SUM(vat_amount), 0) AS vat_amount,
            COALESCE(SUM(withholding_amount), 0) AS withholding_amount,

            COALESCE(SUM(line_total_amount), 0) AS line_total_amount,
            COALESCE(SUM(base_line_total_amount), 0) AS base_line_total_amount
        FROM sales_detail
        WHERE sales_id = " . $salesId
    );

    $totals = $rsTotals->fetchAssoc();

    $lineCount = 0;

    $subtotalAmount = 0;
    $commercialDiscountAmount = 0;
    $statutoryDiscountAmount = 0;

    $netBeforeTaxAmount = 0;
    $vatableAmount = 0;
    $vatExemptAmount = 0;
    $zeroRatedAmount = 0;

    $vatAmount = 0;
    $withholdingAmount = 0;

    $grandTotalAmount = 0;
    $baseGrandTotalAmount = 0;

    if ($totals) {
        $lineCount = (int)$totals["line_count"];

        $subtotalAmount = round((float)$totals["gross_amount"], 4);
        $commercialDiscountAmount = round((float)$totals["commercial_discount_amount"], 4);
        $statutoryDiscountAmount = round((float)$totals["statutory_discount_amount"], 4);

        $netBeforeTaxAmount = round((float)$totals["net_before_tax_amount"], 4);
        $vatableAmount = round((float)$totals["vatable_amount"], 4);
        $vatExemptAmount = round((float)$totals["vat_exempt_amount"], 4);
        $zeroRatedAmount = round((float)$totals["zero_rated_amount"], 4);

        $vatAmount = round((float)$totals["vat_amount"], 4);
        $withholdingAmount = round((float)$totals["withholding_amount"], 4);

        $grandTotalAmount = round((float)$totals["line_total_amount"], 4);
        $baseGrandTotalAmount = round((float)$totals["base_line_total_amount"], 4);
    }

    /* ============================================================
       Fallback if generated line total is not populated
       ============================================================ */

    if ($grandTotalAmount <= 0 && $lineCount > 0) {
        $grandTotalAmount = round($netBeforeTaxAmount + $vatAmount - $withholdingAmount, 4);
    }

    if ($grandTotalAmount <= 0 && $lineCount > 0) {
        $grandTotalAmount = round(
            $subtotalAmount
            - $commercialDiscountAmount
            - $statutoryDiscountAmount
            + $vatAmount
            - $withholdingAmount,
            4
        );
    }

    if ($baseGrandTotalAmount <= 0 && $grandTotalAmount > 0) {
        $baseGrandTotalAmount = $grandTotalAmount;
    }

    /* ============================================================
       If all detail lines were deleted, reset header totals
       ============================================================ */

    if ($lineCount <= 0) {
        $subtotalAmount = 0;
        $commercialDiscountAmount = 0;
        $statutoryDiscountAmount = 0;

        $vatableAmount = 0;
        $vatExemptAmount = 0;
        $zeroRatedAmount = 0;

        $vatAmount = 0;
        $withholdingAmount = 0;

        $grandTotalAmount = 0;
        $baseGrandTotalAmount = 0;
    }

    /* ============================================================
       Update Sales Header
       ============================================================ */

    DB::Query("
        UPDATE sales
        SET
            subtotal_amount = " . $fmt($subtotalAmount) . ",
            commercial_discount_amount = " . $fmt($commercialDiscountAmount) . ",
            statutory_discount_amount = " . $fmt($statutoryDiscountAmount) . ",

            vatable_amount = " . $fmt($vatableAmount) . ",
            vat_exempt_amount = " . $fmt($vatExemptAmount) . ",
            zero_rated_amount = " . $fmt($zeroRatedAmount) . ",

            vat_amount = " . $fmt($vatAmount) . ",
            withholding_amount = " . $fmt($withholdingAmount) . ",

            grand_total_amount = " . $fmt($grandTotalAmount) . ",
            base_grand_total_amount = " . $fmt($baseGrandTotalAmount) . ",
            updated_at = CURRENT_TIMESTAMP(6)
        WHERE id = " . $salesId . "
        LIMIT 1
    ");
}
		;
		
	}

	function BeforeDelete( $where, &$deleted_values, &$message, $pageObject ) {
		// BuildLedger Finance - Sales Detail Before Delete

$salesId = !empty($deleted_values["sales_id"])
    ? (int)$deleted_values["sales_id"]
    : 0;

if ($salesId <= 0) {
    $message = "Sales header is missing.";
    return false;
}

// Check parent sales invoice
$rsSales = DB::Query("
    SELECT
        s.id,
        s.posting_status,
        s.accounting_period_id,
        ap.period_status
    FROM sales s
    LEFT JOIN accounting_period ap
        ON ap.id = s.accounting_period_id
    WHERE s.id = " . $salesId . "
    LIMIT 1
");

$sales = $rsSales->fetchAssoc();

if (!$sales) {
    $message = "Sales invoice was not found.";
    return false;
}

// Block delete if parent sales invoice is posted
if (strtoupper((string)$sales["posting_status"]) == "POSTED") {
    $message = "This sales invoice is already posted. You cannot delete detail lines.";
    return false;
}

// Block delete if accounting period is missing
if (empty($sales["period_status"])) {
    $message = "Accounting period was not found for this sales invoice.";
    return false;
}

// Block delete if accounting period is closed
if (strtoupper((string)$sales["period_status"]) == "CLOSED") {
    $message = "This accounting period is already closed. You cannot delete sales detail lines.";
    return false;
}

return true;
		;
		return true;
	}
		

}


?>