Files
webstatement/app/Services/AccountBalanceService.php
Daeng Deni Mardaeni 1ff4035b98 feat(balance): implementasi service layer untuk balance management
- Menambahkan `AccountBalanceService` dengan transaksi PostgreSQL dan proper error handling.
- Implementasi `BalanceServiceProvider` untuk mendukung dependency injection pattern.
- Registrasi `BalanceServiceProvider` dalam `WebstatementServiceProvider`.
- Penambahan `CAST` ke `DECIMAL(15,2)` untuk kompatibilitas PostgreSQL.
- Perhitungan balance summary mencakup opening balance dan closing balance.
- Agregasi transaksi dengan type casting yang aman.
- Implementasi database transaction handling dengan mekanisme rollback dan commit.
- Logging komprehensif untuk debugging dan audit trail.
- Mendukung balance inquiry berdasarkan tanggal maupun periode tertentu.
- Validasi akun dengan pengecekan `exists` untuk memastikan data valid.
2025-08-27 16:22:06 +07:00

131 lines
4.5 KiB
PHP

<?php
namespace Modules\Webstatement\Services;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Carbon\Carbon;
use Modules\Webstatement\Models\AccountBalance;
use Modules\Webstatement\Models\StmtEntry;
class AccountBalanceService
{
/**
* Get balance summary (opening and closing balance)
*
* @param string $accountNumber
* @param string $startDate
* @param string $endDate
* @return array
*/
public function getBalanceSummary(string $accountNumber, string $startDate, string $endDate): array
{
return DB::transaction(function () use ($accountNumber, $startDate, $endDate) {
Log::info('Calculating balance summary', [
'account_number' => $accountNumber,
'start_date' => $startDate,
'end_date' => $endDate
]);
// Convert dates to Carbon instances
$startDateCarbon = Carbon::parse($startDate);
$endDateCarbon = Carbon::parse($endDate);
// Get opening balance (balance from previous day)
$openingBalanceDate = $startDateCarbon->copy()->subDay();
$openingBalance = $this->getAccountBalance($accountNumber, $openingBalanceDate);
// Get closing balance date (previous day from end date)
$closingBalanceDate = $endDateCarbon->copy()->subDay();
$closingBalanceBase = $this->getAccountBalance($accountNumber, $closingBalanceDate);
// Get transactions on end date
$transactionsOnEndDate = $this->getTransactionsOnDate($accountNumber, $endDate);
// Calculate closing balance
$closingBalance = $closingBalanceBase + $transactionsOnEndDate;
$result = [
'account_number' => $accountNumber,
'period' => [
'start_date' => $startDate,
'end_date' => $endDate
],
'opening_balance' => [
'date' => $openingBalanceDate->format('Y-m-d'),
'balance' => $openingBalance,
'formatted_balance' => number_format($openingBalance, 2)
],
'closing_balance' => [
'date' => $endDate,
'balance' => $closingBalance,
'formatted_balance' => number_format($closingBalance, 2),
'base_balance' => [
'date' => $closingBalanceDate->format('Y-m-d'),
'balance' => $closingBalanceBase,
'formatted_balance' => number_format($closingBalanceBase, 2)
],
'transactions_on_end_date' => $transactionsOnEndDate,
'formatted_transactions_on_end_date' => number_format($transactionsOnEndDate, 2)
]
];
Log::info('Balance summary calculated successfully', $result);
return $result;
});
}
/**
* Get account balance for specific date
*
* @param string $accountNumber
* @param Carbon $date
* @return float
*/
private function getAccountBalance(string $accountNumber, Carbon $date): float
{
$balance = AccountBalance::where('account_number', $accountNumber)
->where('period', $date->format('Ymd'))
->value('actual_balance');
if ($balance === null) {
Log::warning('Account balance not found', [
'account_number' => $accountNumber,
'date' => $date->format('Y-m-d'),
'period' => $date->format('Ymd')
]);
return 0.00;
}
return (float) $balance;
}
/**
* Get transactions on specific date
*
* @param string $accountNumber
* @param string $date
* @return float
*/
private function getTransactionsOnDate(string $accountNumber, string $date): float
{
$total = StmtEntry::where('account_number', $accountNumber)
->whereDate('value_date', $date)
->sum(DB::raw('CAST(amount_lcy AS DECIMAL(15,2))'));
return (float) $total;
}
/**
* Validate if account exists
*
* @param string $accountNumber
* @return bool
*/
public function validateAccount(string $accountNumber): bool
{
return AccountBalance::where('account_number', $accountNumber)->exists();
}
}