e13df69885
API CI/CD / Validate (composer + pint) (push) Successful in 3m6s
API CI/CD / Test (PHPUnit) (push) Failing after 4m53s
API CI/CD / Build frontend assets (push) Successful in 1m2s
API CI/CD / Security audit (push) Failing after 59s
API CI/CD / Deploy to shared hosting (PHP) (push) Has been skipped
161 lines
5.3 KiB
PHP
161 lines
5.3 KiB
PHP
<?php
|
|
|
|
namespace App\Models;
|
|
|
|
use Illuminate\Database\Eloquent\Builder;
|
|
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', 'approved_by', 'updated_by', 'refund_method', 'check_nbr', 'check_file', 'created_at', 'updated_at', 'semester'];
|
|
|
|
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'],
|
|
];
|
|
}
|
|
}
|