feat(webstatement): tambahkan fitur eksport dan download statement
Penambahan fitur untuk mendukung proses eksport dan download statement secara dinamis. Fitur ini mencakup: - Penambahan `ExportStatementJob` untuk menjadwalkan proses eksport statement dalam bentuk file CSV ke dalam queue. - Penambahan endpoint untuk: 1. `index`: Menjadwalkan pekerjaan eksport ke dalam queue. 2. `generateAndDownload`: Proses pembuatan statement secara langsung dan mengunduh hasilnya. 3. `downloadStatement`: Mendukung pengunduhan file statement yang telah dibuat sebelumnya. 4. `queueExport`: Menambahkan job eksport ke queue dengan ID job yang dirilis. 5. `checkExportStatus`: Memastikan status job apakah sedang berjalan, selesai, atau tidak ditemukan. - Refactoring fitur narrative generator untuk mendukung format dinamis berdasarkan konfigurasi database dengan parsing format. - Refactoring data transformation untuk memastikan urutan dan perhitungan running balance sebelum dieksport. - Penggunaan storage lokal untuk menyimpan hasil file CSV, dan implementasi header respons yang benar untuk file unduhan. Signed-off-by: Daeng Deni Mardaeni <ddeni05@gmail.com>
This commit is contained in:
@@ -1,226 +1,295 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Webstatement\Http\Controllers;
|
||||
namespace Modules\Webstatement\Http\Controllers;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
use Modules\Webstatement\Models\StmtEntry;
|
||||
use Modules\Webstatement\Models\TempFundsTransfer;
|
||||
use Modules\Webstatement\Models\TempStmtNarrFormat;
|
||||
use Modules\Webstatement\Models\TempStmtNarrParam;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Contracts\Bus\Dispatcher;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Modules\Webstatement\Jobs\ExportStatementJob;
|
||||
use Modules\Webstatement\Models\StmtEntry;
|
||||
use Modules\Webstatement\Models\TempFundsTransfer;
|
||||
use Modules\Webstatement\Models\TempStmtNarrFormat;
|
||||
use Modules\Webstatement\Models\TempStmtNarrParam;
|
||||
|
||||
class WebstatementController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index()
|
||||
class WebstatementController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$account_number = '1080425781';
|
||||
$period = '20250512';
|
||||
$saldo = '23984352604';
|
||||
|
||||
$account_number = '1080425781';
|
||||
$period = '20250512';
|
||||
// Dispatch the job to export the statement
|
||||
ExportStatementJob::dispatch($account_number, $period, $saldo);
|
||||
|
||||
$stmt = StmtEntry::with(['ft','transaction'])->where('account_number',$account_number)->where('booking_date',$period)->get();
|
||||
$saldo = '23984352604';
|
||||
$runningBalance = (float) $saldo;
|
||||
return response()->json([
|
||||
'message' => 'Statement export job has been queued',
|
||||
'account_number' => $account_number,
|
||||
'period' => $period,
|
||||
'file_name' => "{$account_number}_{$period}.csv"
|
||||
]);
|
||||
}
|
||||
|
||||
// Map the data to transform or format specific fields
|
||||
$mappedData = $stmt->sortBy(['ACTUAL.DATE', 'REFERENCE.NUMBER'])->map(function ($item, $index) use (&$runningBalance) {
|
||||
$runningBalance += (float) $item->amount_lcy;
|
||||
return [
|
||||
'NO' => 0, // Use $index instead of $item->count()
|
||||
'TRANSACTION.DATE' => \Carbon\Carbon::createFromFormat('YmdHi', $item->booking_date . substr($item->ft?->date_time ?? '0000000000', 6, 4))->format('d/m/Y H:i'),
|
||||
'REFERENCE.NUMBER' => $item->trans_reference,
|
||||
'TRANSACTION.AMOUNT' => $item->amount_lcy,
|
||||
'TRANSACTION.TYPE' => $item->amount_lcy < 0 ? 'D' : 'C',
|
||||
'DESCRIPTION' => $this->generateNarative($item),
|
||||
'END.BALANCE' => $runningBalance,
|
||||
'ACTUAL.DATE' => \Carbon\Carbon::createFromFormat('ymdHi', $item->ft?->date_time ?? '2505120000')
|
||||
->format('d/m/Y H:i'),
|
||||
/**
|
||||
* Download a previously exported statement
|
||||
*/
|
||||
public function downloadStatement(Request $request)
|
||||
{
|
||||
$account_number = $request->input('account_number', '1080425781');
|
||||
$period = $request->input('period', '20250512');
|
||||
$fileName = "{$account_number}_{$period}.csv";
|
||||
$filePath = "statements/{$fileName}";
|
||||
|
||||
if (!Storage::disk('local')->exists($filePath)) {
|
||||
return response()->json([
|
||||
'message' => 'Statement file not found. It may still be processing.'
|
||||
], 404);
|
||||
}
|
||||
|
||||
return Storage::disk('local')->download($filePath, $fileName, [
|
||||
"Content-Type" => "text/csv",
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate statement on-demand and return as download
|
||||
*/
|
||||
public function generateAndDownload(Request $request)
|
||||
{
|
||||
$account_number = $request->input('account_number', '1080425781');
|
||||
$period = $request->input('period', '20250512');
|
||||
$saldo = $request->input('saldo', '23984352604');
|
||||
|
||||
$stmt = StmtEntry::with(['ft', 'transaction'])
|
||||
->where('account_number', $account_number)
|
||||
->where('booking_date', $period)
|
||||
->orderBy('date_time', 'ASC')
|
||||
->orderBy('trans_reference', 'ASC')
|
||||
->get();
|
||||
|
||||
if ($stmt->isEmpty()) {
|
||||
return response()->json([
|
||||
'message' => 'No statement data found for the specified account and period.'
|
||||
], 404);
|
||||
}
|
||||
|
||||
$runningBalance = (float) $saldo;
|
||||
// Map the data to transform or format specific fields
|
||||
$mappedData = $stmt->sortBy(['ACTUAL.DATE', 'REFERENCE.NUMBER'])
|
||||
->map(function ($item, $index) use (&$runningBalance) {
|
||||
$runningBalance += (float) $item->amount_lcy;
|
||||
return [
|
||||
'NO' => 0, // Will be updated later
|
||||
'TRANSACTION.DATE' => Carbon::createFromFormat('YmdHi', $item->booking_date . substr($item->ft?->date_time ?? '0000000000', 6, 4))
|
||||
->format('d/m/Y H:i'),
|
||||
'REFERENCE.NUMBER' => $item->trans_reference,
|
||||
'TRANSACTION.AMOUNT' => $item->amount_lcy,
|
||||
'TRANSACTION.TYPE' => $item->amount_lcy < 0 ? 'D' : 'C',
|
||||
'DESCRIPTION' => $this->generateNarrative($item),
|
||||
'END.BALANCE' => $runningBalance,
|
||||
'ACTUAL.DATE' => Carbon::createFromFormat('ymdHi', $item->ft?->date_time ?? '2505120000')
|
||||
->format('d/m/Y H:i'),
|
||||
];
|
||||
})
|
||||
->values();
|
||||
|
||||
// Then apply the sequential numbers
|
||||
$mappedData = $mappedData->map(function ($item, $index) {
|
||||
$item['NO'] = $index + 1;
|
||||
return $item;
|
||||
});
|
||||
|
||||
$csvFileName = $account_number . "_" . $period . ".csv";
|
||||
$headers = [
|
||||
"Content-Type" => "text/csv",
|
||||
"Content-Disposition" => "attachment; filename={$csvFileName}"
|
||||
];
|
||||
})->values();
|
||||
|
||||
|
||||
// Then apply the sequential numbers
|
||||
$mappedData = $mappedData->map(function ($item, $index) {
|
||||
$item['NO'] = $index + 1;
|
||||
return $item;
|
||||
});
|
||||
|
||||
|
||||
return response()->json($mappedData);
|
||||
|
||||
$csvFileName = $account_number."_".$period.".csv";
|
||||
$headers = [
|
||||
"Content-Type" => "text/csv",
|
||||
"Content-Disposition" => "attachment; filename={$csvFileName}"
|
||||
];
|
||||
|
||||
$callback = function () use ($mappedData) {
|
||||
$file = fopen('php://output', 'w');
|
||||
// Write headers without quotes, using pipe separator
|
||||
fputs($file, implode('|', array_keys($mappedData[0])) . "\n");
|
||||
// Write data rows without quotes, using pipe separator
|
||||
foreach ($mappedData as $row) {
|
||||
fputs($file, implode('|', $row) . "\n");
|
||||
}
|
||||
fclose($file);
|
||||
};
|
||||
|
||||
|
||||
return response()->stream($callback, 200, $headers);
|
||||
}
|
||||
|
||||
|
||||
function generateNarative($item){
|
||||
$narr = '';
|
||||
if($item->transaction->narr_type){
|
||||
$narr .= $item->transaction->stmt_narr.' ';
|
||||
$narr .= $this->getFormatNarrative($item->transaction->narr_type,$item);
|
||||
} else {
|
||||
$narr .= $item->transaction->stmt_narr.' ';
|
||||
}
|
||||
|
||||
if($item->ft?->recipt_no) {
|
||||
$narr .= 'Receipt No: ' . $item->ft->recipt_no;
|
||||
}
|
||||
return $narr;
|
||||
}
|
||||
|
||||
|
||||
function getFormatNarrative($narr,$item){
|
||||
$narrParam = TempStmtNarrParam::where('_id', $narr)->first();
|
||||
|
||||
if (!$narrParam) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$fmt = '';
|
||||
if($narrParam->_id=='FTIN'){
|
||||
$fmt = 'FT.IN';
|
||||
}elseif($narrParam->_id=='FTOUT'){
|
||||
$fmt = 'FT.IN';
|
||||
} else {
|
||||
$fmt = $narrParam->_id;
|
||||
}
|
||||
|
||||
$narrFormat = TempStmtNarrFormat::where('_id', $fmt)->first();
|
||||
|
||||
if (!$narrFormat) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// Get the format string from the database
|
||||
$formatString = $narrFormat->text_data ?? '';
|
||||
|
||||
// Parse the format string
|
||||
// Split by the separator ']'
|
||||
$parts = explode(']', $formatString);
|
||||
|
||||
$result = '';
|
||||
|
||||
foreach ($parts as $index => $part) {
|
||||
if (empty($part)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($index === 0) {
|
||||
// For the first part, take only what's before the '!'
|
||||
$splitPart = explode('!', $part);
|
||||
if (count($splitPart) > 0) {
|
||||
// Remove quotes, backslashes, and other escape characters
|
||||
$cleanPart = trim($splitPart[0]);
|
||||
// Remove quotes at the beginning and end
|
||||
$cleanPart = preg_replace('/^["\'\\\\]+|["\'\\\\]+$/', '', $cleanPart);
|
||||
// Remove any remaining backslashes
|
||||
$cleanPart = str_replace('\\', '', $cleanPart);
|
||||
// Remove any remaining quotes
|
||||
$cleanPart = str_replace('"', '', $cleanPart);
|
||||
$result .= $cleanPart;
|
||||
$callback = function () use ($mappedData) {
|
||||
$file = fopen('php://output', 'w');
|
||||
// Write headers without quotes, using pipe separator
|
||||
fputs($file, implode('|', array_keys($mappedData[0])) . "\n");
|
||||
// Write data rows without quotes, using pipe separator
|
||||
foreach ($mappedData as $row) {
|
||||
fputs($file, implode('|', $row) . "\n");
|
||||
}
|
||||
fclose($file);
|
||||
};
|
||||
|
||||
return response()->stream($callback, 200, $headers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate narrative for a statement entry
|
||||
*/
|
||||
private function generateNarrative($item)
|
||||
{
|
||||
$narr = '';
|
||||
if ($item->transaction && $item->transaction->narr_type) {
|
||||
$narr .= $item->transaction->stmt_narr . ' ';
|
||||
$narr .= $this->getFormatNarrative($item->transaction->narr_type, $item);
|
||||
} else if ($item->transaction) {
|
||||
$narr .= $item->transaction->stmt_narr . ' ';
|
||||
}
|
||||
|
||||
if ($item->ft && $item->ft->recipt_no) {
|
||||
$narr .= 'Receipt No: ' . $item->ft->recipt_no;
|
||||
}
|
||||
return $narr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get formatted narrative based on narrative type
|
||||
*/
|
||||
private function getFormatNarrative($narr, $item)
|
||||
{
|
||||
$narrParam = TempStmtNarrParam::where('_id', $narr)->first();
|
||||
|
||||
if (!$narrParam) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$fmt = '';
|
||||
if ($narrParam->_id == 'FTIN') {
|
||||
$fmt = 'FT.IN';
|
||||
} else if ($narrParam->_id == 'FTOUT') {
|
||||
$fmt = 'FT.IN';
|
||||
} else {
|
||||
// For other parts, these are field placeholders
|
||||
$fieldName = strtolower(str_replace('.', '_', $part));
|
||||
$fmt = $narrParam->_id;
|
||||
}
|
||||
|
||||
// Get the corresponding parameter value from narrParam
|
||||
$paramValue = null;
|
||||
$narrFormat = TempStmtNarrFormat::where('_id', $fmt)->first();
|
||||
|
||||
// Check if the field exists as a property in narrParam
|
||||
if (property_exists($narrParam, $fieldName)) {
|
||||
$paramValue = $narrParam->$fieldName;
|
||||
} elseif (isset($narrParam->$fieldName)) {
|
||||
$paramValue = $narrParam->$fieldName;
|
||||
if (!$narrFormat) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// Get the format string from the database
|
||||
$formatString = $narrFormat->text_data ?? '';
|
||||
|
||||
// Parse the format string
|
||||
// Split by the separator ']'
|
||||
$parts = explode(']', $formatString);
|
||||
|
||||
$result = '';
|
||||
|
||||
foreach ($parts as $index => $part) {
|
||||
if (empty($part)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If we found a value, add it to the result
|
||||
if ($paramValue !== null) {
|
||||
$result .= $paramValue;
|
||||
if ($index === 0) {
|
||||
// For the first part, take only what's before the '!'
|
||||
$splitPart = explode('!', $part);
|
||||
if (count($splitPart) > 0) {
|
||||
// Remove quotes, backslashes, and other escape characters
|
||||
$cleanPart = trim($splitPart[0]);
|
||||
// Remove quotes at the beginning and end
|
||||
$cleanPart = preg_replace('/^["\'\\\\]+|["\'\\\\]+$/', '', $cleanPart);
|
||||
// Remove any remaining backslashes
|
||||
$cleanPart = str_replace('\\', '', $cleanPart);
|
||||
// Remove any remaining quotes
|
||||
$cleanPart = str_replace('"', '', $cleanPart);
|
||||
$result .= $cleanPart;
|
||||
}
|
||||
} else {
|
||||
// For other parts, these are field placeholders
|
||||
$fieldName = strtolower(str_replace('.', '_', $part));
|
||||
|
||||
// If no value found, try to use the original field name as a fallback
|
||||
if($fieldName!='recipt_no') {
|
||||
$result .= $this->getTransaction($item->trans_reference, $fieldName).' ';
|
||||
// $result .= "[$fieldName]";
|
||||
// Get the corresponding parameter value from narrParam
|
||||
$paramValue = null;
|
||||
|
||||
// Check if the field exists as a property in narrParam
|
||||
if (property_exists($narrParam, $fieldName)) {
|
||||
$paramValue = $narrParam->$fieldName;
|
||||
} else if (isset($narrParam->$fieldName)) {
|
||||
$paramValue = $narrParam->$fieldName;
|
||||
}
|
||||
|
||||
// If we found a value, add it to the result
|
||||
if ($paramValue !== null) {
|
||||
$result .= $paramValue;
|
||||
} else {
|
||||
// If no value found, try to use the original field name as a fallback
|
||||
if ($fieldName != 'recipt_no') {
|
||||
$result .= $this->getTransaction($item->trans_reference, $fieldName) . ' ';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
return $result;
|
||||
/**
|
||||
* Get transaction data by reference and field
|
||||
*/
|
||||
private function getTransaction($ref, $field)
|
||||
{
|
||||
$trans = TempFundsTransfer::where('ref_no', $ref)->first();
|
||||
return $trans ? ($trans->$field ?? "") : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Queue a statement export job and return job ID
|
||||
*/
|
||||
public function queueExport(Request $request)
|
||||
{
|
||||
$account_number = $request->input('account_number', '1080425781');
|
||||
$period = $request->input('period', '20250512');
|
||||
$saldo = $request->input('saldo', '23984352604');
|
||||
|
||||
// Dispatch the job and get the job ID
|
||||
$job = new ExportStatementJob($account_number, $period, $saldo);
|
||||
$jobId = app(Dispatcher::class)->dispatch($job);
|
||||
|
||||
return response()->json([
|
||||
'message' => 'Statement export job has been queued',
|
||||
'job_id' => $jobId,
|
||||
'account_number' => $account_number,
|
||||
'period' => $period,
|
||||
'file_name' => "{$account_number}_{$period}.csv"
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the status of an export job
|
||||
*/
|
||||
public function checkExportStatus(Request $request, $jobId)
|
||||
{
|
||||
// Get job status from the queue
|
||||
$job = DB::table('jobs')
|
||||
->where('id', $jobId)
|
||||
->first();
|
||||
|
||||
if (!$job) {
|
||||
// Check if job is completed
|
||||
$completedJob = DB::table('job_batches')
|
||||
->where('id', $jobId)
|
||||
->first();
|
||||
|
||||
if ($completedJob) {
|
||||
return response()->json([
|
||||
'status' => 'completed',
|
||||
'message' => 'Export job has been completed'
|
||||
]);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'status' => 'not_found',
|
||||
'message' => 'Export job not found'
|
||||
], 404);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'status' => 'pending',
|
||||
'message' => 'Export job is still processing'
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function getTransaction($ref, $field){
|
||||
$trans = TempFundsTransfer::where('ref_no', $ref)->first();
|
||||
|
||||
return $trans->$field ?? "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
return view('webstatement::create');
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the specified resource.
|
||||
*/
|
||||
public function show($id)
|
||||
{
|
||||
return view('webstatement::show');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*/
|
||||
public function edit($id)
|
||||
{
|
||||
return view('webstatement::edit');
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*/
|
||||
public function update(Request $request, $id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*/
|
||||
public function destroy($id)
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
|
||||
243
app/Jobs/ExportStatementJob.php
Normal file
243
app/Jobs/ExportStatementJob.php
Normal file
@@ -0,0 +1,243 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Webstatement\Jobs;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Exception;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Modules\Webstatement\Models\StmtEntry;
|
||||
use Modules\Webstatement\Models\TempFundsTransfer;
|
||||
use Modules\Webstatement\Models\TempStmtNarrFormat;
|
||||
use Modules\Webstatement\Models\TempStmtNarrParam;
|
||||
|
||||
class ExportStatementJob implements ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
|
||||
protected $account_number;
|
||||
protected $period;
|
||||
protected $saldo;
|
||||
protected $disk;
|
||||
protected $fileName;
|
||||
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*
|
||||
* @param string $account_number
|
||||
* @param string $period
|
||||
* @param string $saldo
|
||||
* @param string $disk
|
||||
*/
|
||||
public function __construct(string $account_number, string $period, string $saldo, string $disk = 'local')
|
||||
{
|
||||
$this->account_number = $account_number;
|
||||
$this->period = $period;
|
||||
$this->saldo = $saldo;
|
||||
$this->disk = $disk;
|
||||
$this->fileName = "{$account_number}_{$period}.csv";
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
*/
|
||||
public function handle()
|
||||
: void
|
||||
{
|
||||
try {
|
||||
Log::info("Starting export statement job for account: {$this->account_number}, period: {$this->period}");
|
||||
|
||||
$stmt = $this->getStatementData();
|
||||
$mappedData = $this->mapStatementData($stmt);
|
||||
$this->exportToCsv($mappedData);
|
||||
|
||||
Log::info("Export statement job completed successfully for account: {$this->account_number}, period: {$this->period}");
|
||||
} catch (Exception $e) {
|
||||
Log::error("Error in ExportStatementJob: " . $e->getMessage());
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get statement data from database
|
||||
*/
|
||||
private function getStatementData()
|
||||
{
|
||||
return StmtEntry::with(['ft', 'transaction'])
|
||||
->where('account_number', $this->account_number)
|
||||
->where('booking_date', $this->period)
|
||||
->orderBy('date_time', 'ASC')
|
||||
->orderBy('trans_reference', 'ASC')
|
||||
->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Map statement data to the required format
|
||||
*/
|
||||
private function mapStatementData($stmt)
|
||||
{
|
||||
$runningBalance = (float) $this->saldo;
|
||||
|
||||
// Map the data to transform or format specific fields
|
||||
$mappedData = $stmt->sortBy(['ACTUAL.DATE', 'REFERENCE.NUMBER'])
|
||||
->map(function ($item, $index) use (&$runningBalance) {
|
||||
$runningBalance += (float) $item->amount_lcy;
|
||||
return [
|
||||
'NO' => 0, // Will be updated later
|
||||
'TRANSACTION.DATE' => Carbon::createFromFormat('YmdHi', $item->booking_date . substr($item->ft?->date_time ?? '0000000000', 6, 4))
|
||||
->format('d/m/Y H:i'),
|
||||
'REFERENCE.NUMBER' => $item->trans_reference,
|
||||
'TRANSACTION.AMOUNT' => $item->amount_lcy,
|
||||
'TRANSACTION.TYPE' => $item->amount_lcy < 0 ? 'D' : 'C',
|
||||
'DESCRIPTION' => $this->generateNarrative($item),
|
||||
'END.BALANCE' => $runningBalance,
|
||||
'ACTUAL.DATE' => Carbon::createFromFormat('ymdHi', $item->ft?->date_time ?? '2505120000')
|
||||
->format('d/m/Y H:i'),
|
||||
];
|
||||
})
|
||||
->values();
|
||||
|
||||
// Apply sequential numbers
|
||||
return $mappedData->map(function ($item, $index) {
|
||||
$item['NO'] = $index + 1;
|
||||
return $item;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate narrative for a statement entry
|
||||
*/
|
||||
private function generateNarrative($item)
|
||||
{
|
||||
$narr = '';
|
||||
if ($item->transaction->narr_type) {
|
||||
$narr .= $item->transaction->stmt_narr . ' ';
|
||||
$narr .= $this->getFormatNarrative($item->transaction->narr_type, $item);
|
||||
} else {
|
||||
$narr .= $item->transaction->stmt_narr . ' ';
|
||||
}
|
||||
|
||||
if ($item->ft?->recipt_no) {
|
||||
$narr .= 'Receipt No: ' . $item->ft->recipt_no;
|
||||
}
|
||||
return $narr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get formatted narrative based on narrative type
|
||||
*/
|
||||
private function getFormatNarrative($narr, $item)
|
||||
{
|
||||
$narrParam = TempStmtNarrParam::where('_id', $narr)->first();
|
||||
|
||||
if (!$narrParam) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$fmt = '';
|
||||
if ($narrParam->_id == 'FTIN') {
|
||||
$fmt = 'FT.IN';
|
||||
} else if ($narrParam->_id == 'FTOUT') {
|
||||
$fmt = 'FT.IN';
|
||||
} else {
|
||||
$fmt = $narrParam->_id;
|
||||
}
|
||||
|
||||
$narrFormat = TempStmtNarrFormat::where('_id', $fmt)->first();
|
||||
|
||||
if (!$narrFormat) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// Get the format string from the database
|
||||
$formatString = $narrFormat->text_data ?? '';
|
||||
|
||||
// Parse the format string
|
||||
// Split by the separator ']'
|
||||
$parts = explode(']', $formatString);
|
||||
|
||||
$result = '';
|
||||
|
||||
foreach ($parts as $index => $part) {
|
||||
if (empty($part)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($index === 0) {
|
||||
// For the first part, take only what's before the '!'
|
||||
$splitPart = explode('!', $part);
|
||||
if (count($splitPart) > 0) {
|
||||
// Remove quotes, backslashes, and other escape characters
|
||||
$cleanPart = trim($splitPart[0]);
|
||||
// Remove quotes at the beginning and end
|
||||
$cleanPart = preg_replace('/^["\'\\\\]+|["\'\\\\]+$/', '', $cleanPart);
|
||||
// Remove any remaining backslashes
|
||||
$cleanPart = str_replace('\\', '', $cleanPart);
|
||||
// Remove any remaining quotes
|
||||
$cleanPart = str_replace('"', '', $cleanPart);
|
||||
$result .= $cleanPart;
|
||||
}
|
||||
} else {
|
||||
// For other parts, these are field placeholders
|
||||
$fieldName = strtolower(str_replace('.', '_', $part));
|
||||
|
||||
// Get the corresponding parameter value from narrParam
|
||||
$paramValue = null;
|
||||
|
||||
// Check if the field exists as a property in narrParam
|
||||
if (property_exists($narrParam, $fieldName)) {
|
||||
$paramValue = $narrParam->$fieldName;
|
||||
} else if (isset($narrParam->$fieldName)) {
|
||||
$paramValue = $narrParam->$fieldName;
|
||||
}
|
||||
|
||||
// If we found a value, add it to the result
|
||||
if ($paramValue !== null) {
|
||||
$result .= $paramValue;
|
||||
} else {
|
||||
// If no value found, try to use the original field name as a fallback
|
||||
if ($fieldName != 'recipt_no') {
|
||||
$result .= $this->getTransaction($item->trans_reference, $fieldName) . ' ';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get transaction data by reference and field
|
||||
*/
|
||||
private function getTransaction($ref, $field)
|
||||
{
|
||||
$trans = TempFundsTransfer::where('ref_no', $ref)->first();
|
||||
return $trans->$field ?? "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Export data to CSV file
|
||||
*/
|
||||
private function exportToCsv($mappedData)
|
||||
{
|
||||
$csvContent = '';
|
||||
|
||||
// Add headers
|
||||
$csvContent .= implode('|', array_keys($mappedData[0])) . "\n";
|
||||
|
||||
// Add data rows
|
||||
foreach ($mappedData as $row) {
|
||||
$csvContent .= implode('|', $row) . "\n";
|
||||
}
|
||||
|
||||
// Save to storage
|
||||
Storage::disk($this->disk)->put("statements/{$this->fileName}", $csvContent);
|
||||
|
||||
Log::info("Statement exported to {$this->disk} disk: statements/{$this->fileName}");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user