Initial commit - WASL Digital Wallet
This commit is contained in:
83
Backend/app/Models/TransactionEntry.php
Normal file
83
Backend/app/Models/TransactionEntry.php
Normal file
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Enums\EntryType;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
|
||||
/**
|
||||
* transaction_entries — DOUBLE-ENTRY LEDGER
|
||||
*
|
||||
* Every transaction MUST have exactly 2 entries (debit + credit).
|
||||
* balance_after_minor is the wallet balance snapshot after this entry.
|
||||
* This table is the source of truth for all balance calculations.
|
||||
*
|
||||
* @property int $transaction_id
|
||||
* @property int $wallet_id
|
||||
* @property string $entry_type debit/credit
|
||||
* @property int $amount_minor BIGINT
|
||||
* @property int $balance_after_minor BIGINT — snapshot after this entry
|
||||
*/
|
||||
class TransactionEntry extends BaseModel
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $fillable = [
|
||||
'transaction_id',
|
||||
'wallet_id',
|
||||
'entry_type',
|
||||
'amount_minor',
|
||||
'balance_after_minor',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'entry_type' => EntryType::class,
|
||||
'amount_minor' => 'integer',
|
||||
'balance_after_minor' => 'integer',
|
||||
];
|
||||
|
||||
public $timestamps = false; // created_at only, set via useCurrent()
|
||||
|
||||
// ── Relationships ──
|
||||
|
||||
public function transaction()
|
||||
{
|
||||
return $this->belongsTo(Transaction::class);
|
||||
}
|
||||
|
||||
public function wallet()
|
||||
{
|
||||
return $this->belongsTo(Wallet::class);
|
||||
}
|
||||
|
||||
// ── Scopes ──
|
||||
|
||||
public function scopeDebits($query)
|
||||
{
|
||||
return $query->where('entry_type', EntryType::DEBIT);
|
||||
}
|
||||
|
||||
public function scopeCredits($query)
|
||||
{
|
||||
return $query->where('entry_type', EntryType::CREDIT);
|
||||
}
|
||||
|
||||
public function scopeForWallet($query, int $walletId)
|
||||
{
|
||||
return $query->where('wallet_id', $walletId);
|
||||
}
|
||||
|
||||
// ── Reconciliation helper ──
|
||||
|
||||
/**
|
||||
* Verify double-entry integrity: SUM(debits) must equal SUM(credits)
|
||||
* for the given transaction_id.
|
||||
*/
|
||||
public static function verifyIntegrity(int $transactionId): bool
|
||||
{
|
||||
$debits = self::where('transaction_id', $transactionId)->debits()->sum('amount_minor');
|
||||
$credits = self::where('transaction_id', $transactionId)->credits()->sum('amount_minor');
|
||||
|
||||
return $debits === $credits && $debits > 0;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user