<?php
class eventclass_customer_payment_application  extends TableEventsBase {
	
	function init() {
		$this->events = array(
	'BeforeAdd' => true,
	'BeforeEdit' => true,
	'AfterEdit' => true,
	'AfterAdd' => true,
	'AfterDelete' => true,
	'BeforeDelete' => true 
);
		$this->fieldValues = array(
	'filterLimit' => array(
		 
	),
	'mapIcon' => array(
		 
	),
	'viewCustom' => array(
		 
	),
	'lookupWhere' => array(
		 
	),
	'viewFileText' => array(
		 
	),
	'defaultValue' => array(
		'discount_taken_amount' => array(
			'edit' => true 
		),
		'withholding_applied_amount' => array(
			'edit' => true 
		) 
	),
	'autoUpdateValue' => array(
		 
	),
	'uploadFolder' => array(
		 
	),
	'viewPluginInit' => array(
		 
	),
	'editPluginInit' => array(
		 
	) 
);
			}
		function BeforeAdd( &$values, &$sqlValues, &$message, $inline, $pageObject ) {
		/* ============================================================
   BuildLedger Finance - Customer Payment Application Before Add
   With period lock, posted lock, and over-application validation
   ============================================================ */

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

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

if (empty($values["sales_id"])) {
    $message = "Please select the sales invoice to apply this payment to.";
    return false;
}

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

/* ============================================================
   Check Customer Payment Header
   ============================================================ */

$rsPayment = DB::Query("
    SELECT
        id,
        accounting_period_id,
        gross_amount,
        withholding_amount,
        bank_charge_amount,
        net_received_amount,
        posting_status
    FROM customer_payment
    WHERE id = " . $customerPaymentId . "
    LIMIT 1
");

$payment = $rsPayment->fetchAssoc();

if (!$payment) {
    $message = "Customer payment was not found.";
    return false;
}

if (strtoupper($payment["posting_status"]) == "POSTED") {
    $message = "Cannot add applications to a posted customer payment.";
    return false;
}

/* ============================================================
   Period Lock Check
   ============================================================ */

$accountingPeriodId = (int)$payment["accounting_period_id"];

if ($accountingPeriodId > 0) {
    $rsPeriod = DB::Query("
        SELECT period_status
        FROM accounting_period
        WHERE id = " . $accountingPeriodId . "
        LIMIT 1
    ");

    $period = $rsPeriod->fetchAssoc();

    if (!$period) {
        $message = "Accounting period was not found.";
        return false;
    }

    if (strtoupper($period["period_status"]) == "CLOSED") {
        $message = "This accounting period is already closed. You cannot add customer payment applications.";
        return false;
    }
}

/* ============================================================
   Clean and validate amounts
   ============================================================ */

$values["customer_payment_id"] = $customerPaymentId;
$values["sales_id"] = $salesId;

$values["applied_amount"] = !empty($values["applied_amount"])
    ? round((float)$values["applied_amount"], 4)
    : 0;

$values["discount_taken_amount"] = !empty($values["discount_taken_amount"])
    ? round((float)$values["discount_taken_amount"], 4)
    : 0;

$values["withholding_applied_amount"] = !empty($values["withholding_applied_amount"])
    ? round((float)$values["withholding_applied_amount"], 4)
    : 0;

if ($values["applied_amount"] < 0) {
    $message = "Applied amount cannot be negative.";
    return false;
}

if ($values["discount_taken_amount"] < 0) {
    $message = "Discount taken amount cannot be negative.";
    return false;
}

if ($values["withholding_applied_amount"] < 0) {
    $message = "Withholding applied amount cannot be negative.";
    return false;
}

$totalAppliedValue =
    $values["applied_amount"] +
    $values["discount_taken_amount"] +
    $values["withholding_applied_amount"];

if ($totalAppliedValue <= 0) {
    $message = "Applied amount, discount, or withholding must be greater than zero.";
    return false;
}

/* ============================================================
   Prevent applying more than available customer payment
   Based on net_received_amount. If empty, compute fallback.
   ============================================================ */

$paymentGross = (float)$payment["gross_amount"];
$paymentWithholding = (float)$payment["withholding_amount"];
$paymentBankCharge = (float)$payment["bank_charge_amount"];
$paymentNetReceived = (float)$payment["net_received_amount"];

if ($paymentNetReceived <= 0 && $paymentGross > 0) {
    $paymentNetReceived = $paymentGross - $paymentWithholding - $paymentBankCharge;
}

if ($paymentNetReceived < 0) {
    $paymentNetReceived = 0;
}

$rsExistingPaymentApplied = DB::Query("
    SELECT
        COALESCE(SUM(applied_amount), 0) AS existing_applied
    FROM customer_payment_application
    WHERE customer_payment_id = " . $customerPaymentId
);

$existingPaymentAppliedData = $rsExistingPaymentApplied->fetchAssoc();

$existingPaymentApplied = $existingPaymentAppliedData
    ? (float)$existingPaymentAppliedData["existing_applied"]
    : 0;

$newPaymentAppliedTotal = $existingPaymentApplied + $values["applied_amount"];

if ($newPaymentAppliedTotal > $paymentNetReceived) {
    $message = "Total applied amount cannot exceed the net received payment amount.";
    return false;
}

/* ============================================================
   Prevent applying more than invoice balance
   ============================================================ */

$rsInvoice = DB::Query("
    SELECT
        id,
        document_no,
        grand_total_amount
    FROM sales
    WHERE id = " . $salesId . "
    LIMIT 1
");

$invoice = $rsInvoice->fetchAssoc();

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

$invoiceAmount = (float)$invoice["grand_total_amount"];

$rsExistingInvoiceApplied = DB::Query("
    SELECT
        COALESCE(SUM(applied_amount + discount_taken_amount + withholding_applied_amount), 0) AS existing_invoice_applied
    FROM customer_payment_application
    WHERE sales_id = " . $salesId
);

$existingInvoiceAppliedData = $rsExistingInvoiceApplied->fetchAssoc();

$existingInvoiceApplied = $existingInvoiceAppliedData
    ? (float)$existingInvoiceAppliedData["existing_invoice_applied"]
    : 0;

$newInvoiceAppliedTotal = $existingInvoiceApplied + $totalAppliedValue;

if ($newInvoiceAppliedTotal > $invoiceAmount) {
    $message = "Total application cannot exceed the selected sales invoice amount.";
    return false;
}

if (empty($values["applied_at"])) {
    $values["applied_at"] = date("Y-m-d");
}

return true;
		;
		return true;
	}

	function BeforeEdit( &$values, &$sqlValues, $where, &$oldvalues, &$keys, &$message, $inline, $pageObject ) {
		/* ============================================================
   BuildLedger Finance - Customer Payment Application Before Edit
   With period lock, posted lock, and over-application validation
   ============================================================ */

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

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

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

$applicationId = !empty($oldvalues["id"])
    ? (int)$oldvalues["id"]
    : 0;

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

if ($customerPaymentId <= 0) {
    $message = "Customer payment header is missing.";
    return false;
}

if ($salesId <= 0) {
    $message = "Please select the sales invoice to apply this payment to.";
    return false;
}

/* ============================================================
   Check Customer Payment Header
   ============================================================ */

$rsPayment = DB::Query("
    SELECT
        id,
        accounting_period_id,
        gross_amount,
        withholding_amount,
        bank_charge_amount,
        net_received_amount,
        posting_status
    FROM customer_payment
    WHERE id = " . $customerPaymentId . "
    LIMIT 1
");

$payment = $rsPayment->fetchAssoc();

if (!$payment) {
    $message = "Customer payment was not found.";
    return false;
}

if (strtoupper($payment["posting_status"]) == "POSTED") {
    $message = "Cannot edit applications of a posted customer payment.";
    return false;
}

/* ============================================================
   Period Lock Check
   ============================================================ */

$accountingPeriodId = (int)$payment["accounting_period_id"];

if ($accountingPeriodId > 0) {
    $rsPeriod = DB::Query("
        SELECT period_status
        FROM accounting_period
        WHERE id = " . $accountingPeriodId . "
        LIMIT 1
    ");

    $period = $rsPeriod->fetchAssoc();

    if (!$period) {
        $message = "Accounting period was not found.";
        return false;
    }

    if (strtoupper($period["period_status"]) == "CLOSED") {
        $message = "This accounting period is already closed. You cannot edit customer payment applications.";
        return false;
    }
}

/* ============================================================
   Clean and validate amounts
   ============================================================ */

$values["customer_payment_id"] = $customerPaymentId;
$values["sales_id"] = $salesId;

$values["applied_amount"] = !empty($values["applied_amount"])
    ? round((float)$values["applied_amount"], 4)
    : 0;

$values["discount_taken_amount"] = !empty($values["discount_taken_amount"])
    ? round((float)$values["discount_taken_amount"], 4)
    : 0;

$values["withholding_applied_amount"] = !empty($values["withholding_applied_amount"])
    ? round((float)$values["withholding_applied_amount"], 4)
    : 0;

if ($values["applied_amount"] < 0) {
    $message = "Applied amount cannot be negative.";
    return false;
}

if ($values["discount_taken_amount"] < 0) {
    $message = "Discount taken amount cannot be negative.";
    return false;
}

if ($values["withholding_applied_amount"] < 0) {
    $message = "Withholding applied amount cannot be negative.";
    return false;
}

$totalAppliedValue =
    $values["applied_amount"] +
    $values["discount_taken_amount"] +
    $values["withholding_applied_amount"];

if ($totalAppliedValue <= 0) {
    $message = "Applied amount, discount, or withholding must be greater than zero.";
    return false;
}

/* ============================================================
   Prevent applying more than available customer payment
   Based on net_received_amount. If empty, compute fallback.
   ============================================================ */

$paymentGross = (float)$payment["gross_amount"];
$paymentWithholding = (float)$payment["withholding_amount"];
$paymentBankCharge = (float)$payment["bank_charge_amount"];
$paymentNetReceived = (float)$payment["net_received_amount"];

if ($paymentNetReceived <= 0 && $paymentGross > 0) {
    $paymentNetReceived = $paymentGross - $paymentWithholding - $paymentBankCharge;
}

if ($paymentNetReceived < 0) {
    $paymentNetReceived = 0;
}

$rsExistingPaymentApplied = DB::Query("
    SELECT
        COALESCE(SUM(applied_amount), 0) AS existing_applied
    FROM customer_payment_application
    WHERE customer_payment_id = " . $customerPaymentId . "
      AND id <> " . $applicationId
);

$existingPaymentAppliedData = $rsExistingPaymentApplied->fetchAssoc();

$existingPaymentApplied = $existingPaymentAppliedData
    ? (float)$existingPaymentAppliedData["existing_applied"]
    : 0;

$newPaymentAppliedTotal = $existingPaymentApplied + $values["applied_amount"];

if ($newPaymentAppliedTotal > $paymentNetReceived) {
    $message = "Total applied amount cannot exceed the net received payment amount.";
    return false;
}

/* ============================================================
   Prevent applying more than invoice balance
   ============================================================ */

$rsInvoice = DB::Query("
    SELECT
        id,
        document_no,
        grand_total_amount
    FROM sales
    WHERE id = " . $salesId . "
    LIMIT 1
");

$invoice = $rsInvoice->fetchAssoc();

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

$invoiceAmount = (float)$invoice["grand_total_amount"];

$rsExistingInvoiceApplied = DB::Query("
    SELECT
        COALESCE(SUM(applied_amount + discount_taken_amount + withholding_applied_amount), 0) AS existing_invoice_applied
    FROM customer_payment_application
    WHERE sales_id = " . $salesId . "
      AND id <> " . $applicationId
);

$existingInvoiceAppliedData = $rsExistingInvoiceApplied->fetchAssoc();

$existingInvoiceApplied = $existingInvoiceAppliedData
    ? (float)$existingInvoiceAppliedData["existing_invoice_applied"]
    : 0;

$newInvoiceAppliedTotal = $existingInvoiceApplied + $totalAppliedValue;

if ($newInvoiceAppliedTotal > $invoiceAmount) {
    $message = "Total application cannot exceed the selected sales invoice amount.";
    return false;
}

if (empty($values["applied_at"])) {
    $values["applied_at"] = !empty($oldvalues["applied_at"])
        ? $oldvalues["applied_at"]
        : date("Y-m-d");
}

return true;
		;
		return true;
	}

	function AfterEdit( &$values, $where, &$oldvalues, &$keys, $inline, $pageObject ) {
		/* ============================================================
   Recompute Customer Payment Header - After Application Edit
   ============================================================ */

$customerPaymentIds = array();

if (!empty($values["customer_payment_id"])) {
    $customerPaymentIds[] = (int)$values["customer_payment_id"];
}

if (!empty($oldvalues["customer_payment_id"])) {
    $customerPaymentIds[] = (int)$oldvalues["customer_payment_id"];
}

$customerPaymentIds = array_unique($customerPaymentIds);

foreach ($customerPaymentIds as $customerPaymentId) {

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

    DB::Exec("
        UPDATE customer_payment cp
        LEFT JOIN (
            SELECT
                customer_payment_id,
                COALESCE(SUM(applied_amount), 0) AS applied_amount,
                COALESCE(SUM(withholding_applied_amount), 0) AS withholding_amount
            FROM customer_payment_application
            WHERE customer_payment_id = " . $customerPaymentId . "
            GROUP BY customer_payment_id
        ) app
            ON app.customer_payment_id = cp.id
        SET
            cp.applied_amount = COALESCE(app.applied_amount, 0),
            cp.withholding_amount = COALESCE(app.withholding_amount, 0),
            cp.net_received_amount =
                ROUND(
                    COALESCE(cp.gross_amount, 0)
                    - COALESCE(app.withholding_amount, 0)
                    - COALESCE(cp.bank_charge_amount, 0),
                    4
                ),
            cp.unapplied_amount =
                ROUND(
                    (
                        COALESCE(cp.gross_amount, 0)
                        - COALESCE(app.withholding_amount, 0)
                        - COALESCE(cp.bank_charge_amount, 0)
                    )
                    - COALESCE(app.applied_amount, 0),
                    4
                )
        WHERE cp.id = " . $customerPaymentId . "
    ");
}
		;
		
	}

	function AfterAdd( &$values, &$keys, $inline, $pageObject ) {
		/* ============================================================
   Recompute Customer Payment Header - After Application Add
   ============================================================ */

$customerPaymentId = 0;

if (!empty($values["customer_payment_id"])) {
    $customerPaymentId = (int)$values["customer_payment_id"];
}

if ($customerPaymentId > 0) {
    DB::Exec("
        UPDATE customer_payment cp
        LEFT JOIN (
            SELECT
                customer_payment_id,
                COALESCE(SUM(applied_amount), 0) AS applied_amount,
                COALESCE(SUM(withholding_applied_amount), 0) AS withholding_amount
            FROM customer_payment_application
            WHERE customer_payment_id = " . $customerPaymentId . "
            GROUP BY customer_payment_id
        ) app
            ON app.customer_payment_id = cp.id
        SET
            cp.applied_amount = COALESCE(app.applied_amount, 0),
            cp.withholding_amount = COALESCE(app.withholding_amount, 0),
            cp.net_received_amount =
                ROUND(
                    COALESCE(cp.gross_amount, 0)
                    - COALESCE(app.withholding_amount, 0)
                    - COALESCE(cp.bank_charge_amount, 0),
                    4
                ),
            cp.unapplied_amount =
                ROUND(
                    (
                        COALESCE(cp.gross_amount, 0)
                        - COALESCE(app.withholding_amount, 0)
                        - COALESCE(cp.bank_charge_amount, 0)
                    )
                    - COALESCE(app.applied_amount, 0),
                    4
                )
        WHERE cp.id = " . $customerPaymentId . "
    ");
}
		;
		
	}

	function AfterDelete( $where, &$deleted_values, &$message, $pageObject ) {
		/* ============================================================
   Recompute Customer Payment Header - After Application Delete
   ============================================================ */

$customerPaymentId = 0;

if (!empty($deleted_values["customer_payment_id"])) {
    $customerPaymentId = (int)$deleted_values["customer_payment_id"];
}

if ($customerPaymentId > 0) {
    DB::Exec("
        UPDATE customer_payment cp
        LEFT JOIN (
            SELECT
                customer_payment_id,
                COALESCE(SUM(applied_amount), 0) AS applied_amount,
                COALESCE(SUM(withholding_applied_amount), 0) AS withholding_amount
            FROM customer_payment_application
            WHERE customer_payment_id = " . $customerPaymentId . "
            GROUP BY customer_payment_id
        ) app
            ON app.customer_payment_id = cp.id
        SET
            cp.applied_amount = COALESCE(app.applied_amount, 0),
            cp.withholding_amount = COALESCE(app.withholding_amount, 0),
            cp.net_received_amount =
                ROUND(
                    COALESCE(cp.gross_amount, 0)
                    - COALESCE(app.withholding_amount, 0)
                    - COALESCE(cp.bank_charge_amount, 0),
                    4
                ),
            cp.unapplied_amount =
                ROUND(
                    (
                        COALESCE(cp.gross_amount, 0)
                        - COALESCE(app.withholding_amount, 0)
                        - COALESCE(cp.bank_charge_amount, 0)
                    )
                    - COALESCE(app.applied_amount, 0),
                    4
                )
        WHERE cp.id = " . $customerPaymentId . "
    ");
}
		;
		
	}

	function BeforeDelete( $where, &$deleted_values, &$message, $pageObject ) {
		/* ============================================================
   BuildLedger Finance - Customer Payment Application Before Delete
   ============================================================ */

if (empty($deleted_values["customer_payment_id"])) {
    $message = "Customer payment header is missing.";
    return false;
}

$customerPaymentId = (int)$deleted_values["customer_payment_id"];

/* ============================================================
   Check Customer Payment Header
   ============================================================ */

$rsPayment = DB::Query("
    SELECT
        id,
        accounting_period_id,
        posting_status
    FROM customer_payment
    WHERE id = " . $customerPaymentId . "
    LIMIT 1
");

$payment = $rsPayment->fetchAssoc();

if (!$payment) {
    $message = "Customer payment was not found.";
    return false;
}

if (strtoupper($payment["posting_status"]) == "POSTED") {
    $message = "Cannot delete applications of a posted customer payment.";
    return false;
}

/* ============================================================
   Period Lock Check
   ============================================================ */

$accountingPeriodId = (int)$payment["accounting_period_id"];

if ($accountingPeriodId > 0) {
    $rsPeriod = DB::Query("
        SELECT period_status
        FROM accounting_period
        WHERE id = " . $accountingPeriodId . "
        LIMIT 1
    ");

    $period = $rsPeriod->fetchAssoc();

    if (!$period) {
        $message = "Accounting period was not found.";
        return false;
    }

    if (strtoupper($period["period_status"]) == "CLOSED") {
        $message = "This accounting period is already closed. You cannot delete customer payment applications.";
        return false;
    }
}

return true;
		;
		return true;
	}
	public function default_discount_taken_amount_efedit(  ) {
	$defaultValue = 0;
return $defaultValue;
}

public function default_withholding_applied_amount_efedit(  ) {
	$defaultValue = 0;
return $defaultValue;
}	

}


?>