✨ 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.
This commit is contained in:
31
app/Providers/BalanceServiceProvider.php
Normal file
31
app/Providers/BalanceServiceProvider.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Webstatement\Providers;
|
||||
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Modules\Webstatement\Services\AccountBalanceService;
|
||||
|
||||
class BalanceServiceProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* Register the service provider.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register(): void
|
||||
{
|
||||
$this->app->singleton(AccountBalanceService::class, function ($app) {
|
||||
return new AccountBalanceService();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the services provided by the provider.
|
||||
*
|
||||
* @return array<string>
|
||||
*/
|
||||
public function provides(): array
|
||||
{
|
||||
return [AccountBalanceService::class];
|
||||
}
|
||||
}
|
||||
@@ -57,6 +57,7 @@ class WebstatementServiceProvider extends ServiceProvider
|
||||
{
|
||||
$this->app->register(EventServiceProvider::class);
|
||||
$this->app->register(RouteServiceProvider::class);
|
||||
$this->app->register(BalanceServiceProvider::class);
|
||||
$this->app->bind(UpdateAtmCardBranchCurrencyJob::class);
|
||||
}
|
||||
|
||||
|
||||
130
app/Services/AccountBalanceService.php
Normal file
130
app/Services/AccountBalanceService.php
Normal file
@@ -0,0 +1,130 @@
|
||||
<?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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user