Files
alrahma_sunday_school_api/app/Models/Refund.php
T
2026-06-09 01:03:53 -04:00

175 lines
5.6 KiB
PHP

<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Builder;
use App\Models\BaseModel;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class Refund extends BaseModel
{
protected $table = 'refunds';
protected $fillable = [
'parent_id',
'school_year',
'invoice_id',
'refund_amount',
'requested_at',
'approved_at',
'refunded_at',
'status',
'reason',
'refund_paid_amount',
'request',
'note',
'semester',
'school_year',
'approved_by',
'updated_by',
'refund_method',
'check_nbr',
'check_file',
];
public $timestamps = true;
protected $casts = [
'parent_id' => 'integer',
'invoice_id' => 'integer',
'approved_by' => 'integer',
'updated_by' => 'integer',
'refund_amount' => 'decimal:2',
'refund_paid_amount' => 'decimal:2',
'requested_at' => 'datetime',
'approved_at' => 'datetime',
'refunded_at' => 'datetime',
'created_at' => 'datetime',
'updated_at' => 'datetime',
];
/* ============================================================
* Status (enum-like)
* ============================================================
*/
public const STATUS_PENDING = 'Pending';
public const STATUS_APPROVED = 'Approved';
public const STATUS_PARTIAL = 'Partial';
public const STATUS_PAID = 'Paid';
public const STATUS_REJECTED = 'Rejected';
public const STATUS_CANCELED = 'Canceled';
public static function paidOutStatuses(): array
{
// matches your legacy whereIn(['Partial','Paid'])
return [self::STATUS_PARTIAL, self::STATUS_PAID];
}
/* ============================================================
* Relationships (optional)
* ============================================================
*/
public function parent(): BelongsTo
{
return $this->belongsTo(ParentModel::class, 'parent_id'); // rename to your real model, e.g. ParentUser/Guardian/Customer
}
public function invoice(): BelongsTo
{
return $this->belongsTo(Invoice::class, 'invoice_id');
}
/* ============================================================
* Scopes
* ============================================================
*/
public function scopeForParent(Builder $q, int $parentId): Builder
{
return $q->where('parent_id', $parentId);
}
public function scopeForSchoolYear(Builder $q, string $schoolYear): Builder
{
return $q->where('school_year', $schoolYear);
}
public function scopePaidOut(Builder $q): Builder
{
return $q->whereIn('status', self::paidOutStatuses());
}
/* ============================================================
* Business: totals
* ============================================================
*/
/**
* Total paid-out refunds for a parent in a specific school year (Partial + Paid).
* Mirrors the legacy behavior and returns 0.00 if none.
*/
public static function totalApprovedPaidOutForParentAndYear(int $parentId, string $schoolYear): float
{
$sum = static::query()
->forParent($parentId)
->forSchoolYear($schoolYear)
->paidOut()
->sum('refund_paid_amount');
return (float) $sum;
}
/**
* Instance-style method if you want to keep a similar calling style to legacy.
*/
public function getTotalApprovedRefundByParentIdAndSchoolYear(int $parentId, string $schoolYear): float
{
return static::totalApprovedPaidOutForParentAndYear($parentId, $schoolYear);
}
/* ============================================================
* Validation rules (optional helper for controllers/FormRequests)
* ============================================================
*/
public static function rules(?int $id = null): array
{
return [
'parent_id' => ['required', 'integer', 'min:1', 'exists:parents,id'], // adjust table name
'school_year' => ['required', 'string', 'max:20'],
'invoice_id' => ['nullable', 'integer', 'exists:invoices,id'],
'refund_amount' => ['required', 'numeric', 'min:0'],
'refund_paid_amount' => ['nullable', 'numeric', 'min:0'],
'requested_at' => ['nullable', 'date'],
'approved_at' => ['nullable', 'date', 'after_or_equal:requested_at'],
'refunded_at' => ['nullable', 'date', 'after_or_equal:approved_at'],
'status' => ['required', 'string', 'in:' . implode(',', [
self::STATUS_PENDING,
self::STATUS_APPROVED,
self::STATUS_PARTIAL,
self::STATUS_PAID,
self::STATUS_REJECTED,
self::STATUS_CANCELED,
])],
'reason' => ['nullable', 'string', 'max:2000'],
'request' => ['nullable', 'string'],
'note' => ['nullable', 'string', 'max:5000'],
'semester' => ['nullable', 'string', 'max:20'],
'approved_by' => ['nullable', 'integer'],
'updated_by' => ['nullable', 'integer'],
'refund_method' => ['nullable', 'string', 'max:50'], // cash/check/cc/etc.
'check_nbr' => ['nullable', 'string', 'max:80'],
'check_file' => ['nullable', 'string', 'max:255'],
];
}
}