Files
alrahma_sunday_school/app/Models/PaymentModel.php
T
2026-02-10 22:11:06 -05:00

212 lines
6.5 KiB
PHP

<?php
namespace App\Models;
use CodeIgniter\Model;
class PaymentModel extends Model
{
protected $table = 'payments';
protected $primaryKey = 'id';
protected $returnType = 'array';
protected $allowedFields = [
'parent_id',
'invoice_id',
'total_amount',
'paid_amount',
'balance',
'number_of_installments',
'transaction_id',
'check_file',
'check_number',
'payment_method',
'payment_date',
'school_year',
'semester',
'status',
'updated_by'
];
protected $useTimestamps = false;
// ❗ Your DB handles created_at / updated_at with default CURRENT_TIMESTAMP
// Remove CI4 auto timestamp management unless you modify your DB schema
protected $validationRules = [
'parent_id' => 'required|integer',
'invoice_id' => 'required|integer',
'total_amount' => 'required|decimal',
'paid_amount' => 'required|decimal',
'balance' => 'required|decimal',
'number_of_installments' => 'required|integer',
'payment_method' => 'required|max_length[50]', // ✅ Removed 'string'
'payment_date' => 'required|valid_date[Y-m-d H:i:s]',
'status' => 'required|max_length[50]', // ✅ Removed 'string'
'check_number' => 'permit_empty|max_length[100]',
];
protected $validationMessages = [
'parent_id' => [
'required' => 'Parent ID is required.',
'integer' => 'Parent ID must be an integer.',
],
'invoice_id' => [
'required' => 'Invoice ID is required.',
'integer' => 'Invoice ID must be an integer.',
],
'total_amount' => [
'required' => 'Total amount is required.',
'decimal' => 'Total amount must be a valid decimal.',
],
'paid_amount' => [
'required' => 'Paid amount is required.',
'decimal' => 'Paid amount must be a valid decimal.',
],
'balance' => [
'required' => 'Balance is required.',
'decimal' => 'Balance must be a valid decimal.',
],
'payment_date' => [
'required' => 'Payment date is required.',
'valid_date' => 'Payment date must be a valid date (Y-m-d H:i:s).',
],
'payment_method' => [
'required' => 'Payment method is required.',
'max_length' => 'Payment method must not exceed 50 characters.',
],
'status' => [
'required' => 'Status is required.',
'max_length' => 'Status must not exceed 50 characters.',
],
'number_of_installments' => [
'required' => 'Number of installments is required.',
'integer' => 'Number of installments must be an integer.',
],
'check_number' => [
'max_length' => 'Check number must not exceed 100 characters.',
]
];
/**
* Get payments by parent ID.
*
* @param int $parentId
* @return array
*/
public function getPaymentsByParentId(int $parentId): array
{
return $this->where('parent_id', $parentId)
->orderBy('payment_date', 'DESC')
->findAll();
}
/**
* Calculate the total paid amount for a specific parent.
*
* @param int $parentId
* @return float
*/
public function getTotalPaidByParentId(int $parentId, string $schoolYear): float
{
$db = \Config\Database::connect();
$result = $db->table('payments')
->selectSum('paid_amount', 'total_paid')
->where('parent_id', $parentId)
->where('school_year', $schoolYear)
->get()
->getRowArray();
return $result && isset($result['total_paid']) ? (float) $result['total_paid'] : 0.00;
}
/**
* Update balance for a specific payment.
*
* @param int $paymentId
* @param float $amountPaid
* @return bool
*/
public function updateBalance(int $paymentId, float $amountPaid): bool
{
$payment = $this->find($paymentId);
if (!$payment) {
return false;
}
$newBalance = $payment['balance'] - $amountPaid;
return $this->update($paymentId, [
'paid_amount' => $payment['paid_amount'] + $amountPaid,
'balance' => $newBalance
]);
}
/**
* Get payments by school year.
*
* @param string $schoolYear
* @return array
*/
public function getPaymentsByYear(string $schoolYear): array
{
return $this->where('school_year', $schoolYear)
->orderBy('payment_date', 'DESC')
->findAll();
}
/**
* Generate a new transaction ID.
*
* @return string
*/
public function generateNewTransactionId(): string
{
$currentYear = date('Y');
$prefix = $currentYear . '-';
$latest = $this->like('transaction_id', $prefix, 'after')
->orderBy('transaction_id', 'DESC')
->first();
if ($latest && isset($latest['transaction_id'])) {
$lastNumber = (int) str_replace($prefix, '', $latest['transaction_id']);
$newNumber = $lastNumber + 1;
} else {
$newNumber = 1;
}
return $prefix . str_pad($newNumber, 6, '0', STR_PAD_LEFT);
}
public function getPaymentsByInvoice($invoiceIds): array
{
// Normalize input
if (!is_array($invoiceIds)) {
$invoiceIds = [$invoiceIds];
}
if (empty($invoiceIds)) {
return [];
}
// Subquery: latest payment_date per invoice (Full/Partial only)
$latestSub = $this->db->table('payments')
->select('invoice_id, MAX(payment_date) AS max_date')
->whereIn('status', ['Full', 'Paid', 'Partially Paid'])
->groupBy('invoice_id')
->getCompiledSelect();
// Main query: join payments to the latest per invoice
$rows = $this->db->table('payments p')
->select('p.invoice_id, p.paid_amount AS last_paid_amount, p.payment_date AS last_payment_date, p.status AS last_payment_status')
->join("($latestSub) latest", 'latest.invoice_id = p.invoice_id AND latest.max_date = p.payment_date', 'inner', false) // <-- escape=false
->whereIn('p.invoice_id', $invoiceIds)
->whereIn('p.status', ['Full', 'Paid', 'Partially Paid'])
->get()
->getResultArray();
return $rows;
}
}