diff --git a/app/Http/Controllers/PrintStatementController.php b/app/Http/Controllers/PrintStatementController.php index 1b90d12..d5d71ef 100644 --- a/app/Http/Controllers/PrintStatementController.php +++ b/app/Http/Controllers/PrintStatementController.php @@ -3,13 +3,18 @@ namespace Modules\Webstatement\Http\Controllers; use App\Http\Controllers\Controller; + use Carbon\Carbon; + use Exception; use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; + use Illuminate\Support\Facades\Mail; use Illuminate\Support\Facades\Storage; - use Modules\Webstatement\Http\Requests\PrintStatementRequest; - use Modules\Webstatement\Models\PrintStatementLog; + use Log; use Modules\Basicdata\Models\Branch; - use phpseclib3\Net\SFTP; + use Modules\Webstatement\Http\Requests\PrintStatementRequest; + use Modules\Webstatement\Mail\StatementEmail; + use Modules\Webstatement\Models\PrintStatementLog; + use ZipArchive; class PrintStatementController extends Controller { @@ -23,15 +28,6 @@ return view('webstatement::statements.index', compact('branches')); } - /** - * Show the form for creating a new statement request. - */ - public function create() - { - $branches = Branch::orderBy('name')->get(); - return view('webstatement::statements.create', compact('branches',)); - } - /** * Store a newly created statement request. */ @@ -40,7 +36,7 @@ $validated = $request->validated(); // Add user tracking data - $validated['user_id'] = Auth::id(); + $validated['user_id'] = Auth::id(); $validated['created_by'] = Auth::id(); $validated['ip_address'] = $request->ip(); $validated['user_agent'] = $request->userAgent(); @@ -55,6 +51,81 @@ ->with('success', 'Statement request has been created successfully.'); } + /** + * Show the form for creating a new statement request. + */ + public function create() + { + $branches = Branch::orderBy('name')->get(); + return view('webstatement::statements.create', compact('branches')); + } + + /** + * Check if the statement is available in the system. + * This is a placeholder method - implement according to your system. + */ + protected function checkStatementAvailability(PrintStatementLog $statement) + { + // This would be implemented based on your system's logic + // For example, checking an API or database for statement availability + $disk = Storage::disk('sftpStatement'); + + //format folder /periode/Print/branch_code/account_number.pdf + $filePath = "{$statement->period_from}/Print/{$statement->branch_code}/{$statement->account_number}.pdf"; + + // Check if the statement exists in the storage + if ($statement->is_period_range && $statement->period_to) { + $periodFrom = Carbon::createFromFormat('Ym', $statement->period_from); + $periodTo = Carbon::createFromFormat('Ym', $statement->period_to); + + // Loop through each month in the range + $missingPeriods = []; + $availablePeriods = []; + + for ($period = clone $periodFrom; $period->lte($periodTo); $period->addMonth()) { + $periodFormatted = $period->format('Ym'); + $periodPath = $periodFormatted . "/Print/{$statement->branch_code}/{$statement->account_number}.pdf"; + + if ($disk->exists($periodPath)) { + $availablePeriods[] = $periodFormatted; + } else { + $missingPeriods[] = $periodFormatted; + } + } + + + // If any period is missing, the statement is not available + if (count($missingPeriods) > 0) { + $notes = "Missing periods: " . implode(', ', $missingPeriods); + $statement->update([ + 'is_available' => false, + 'remarks' => $notes, + 'updated_by' => Auth::id() + ]); + return; + } else { + // All periods are available + $statement->update([ + 'is_available' => true, + 'updated_by' => Auth::id() + ]); + return; + } + } else if ($disk->exists($filePath)) { + $statement->update([ + 'is_available' => true, + 'updated_by' => Auth::id() + ]); + return; + } + + $statement->update([ + 'is_available' => false, + 'updated_by' => Auth::id() + ]); + return; + } + /** * Display the specified statement. */ @@ -74,32 +145,32 @@ return back()->with('error', 'Statement is not available for download.'); } - /* if ($statement->authorization_status !== 'approved') { - return back()->with('error', 'Statement download requires authorization.'); - }*/ + /* if ($statement->authorization_status !== 'approved') { + return back()->with('error', 'Statement download requires authorization.'); + }*/ // Update download status $statement->update([ 'is_downloaded' => true, 'downloaded_at' => now(), - 'updated_by' => Auth::id() + 'updated_by' => Auth::id() ]); // Generate or fetch the statement file (implementation depends on your system) - $disk = Storage::disk('sftpStatement'); + $disk = Storage::disk('sftpStatement'); $filePath = "{$statement->period_from}/Print/{$statement->branch_code}/{$statement->account_number}.pdf"; if ($statement->is_period_range && $statement->period_to) { - $periodFrom = \Carbon\Carbon::createFromFormat('Ym', $statement->period_from); - $periodTo = \Carbon\Carbon::createFromFormat('Ym', $statement->period_to); + $periodFrom = Carbon::createFromFormat('Ym', $statement->period_from); + $periodTo = Carbon::createFromFormat('Ym', $statement->period_to); // Loop through each month in the range - $missingPeriods = []; + $missingPeriods = []; $availablePeriods = []; for ($period = clone $periodFrom; $period->lte($periodTo); $period->addMonth()) { $periodFormatted = $period->format('Ym'); - $periodPath = $periodFormatted . "/Print/{$statement->branch_code}/{$statement->account_number}.pdf"; + $periodPath = $periodFormatted . "/Print/{$statement->branch_code}/{$statement->account_number}.pdf"; if ($disk->exists($periodPath)) { $availablePeriods[] = $periodFormatted; @@ -120,11 +191,11 @@ } // Create a new zip archive - $zip = new \ZipArchive(); - if ($zip->open($zipFilePath, \ZipArchive::CREATE | \ZipArchive::OVERWRITE) === TRUE) { + $zip = new ZipArchive(); + if ($zip->open($zipFilePath, ZipArchive::CREATE | ZipArchive::OVERWRITE) === true) { // Add each available statement to the zip foreach ($availablePeriods as $period) { - $filePath = "{$period}/Print/{$statement->branch_code}/{$statement->account_number}.pdf"; + $filePath = "{$period}/Print/{$statement->branch_code}/{$statement->account_number}.pdf"; $localFilePath = storage_path("app/temp/{$statement->account_number}_{$period}.pdf"); // Download the file from SFTP to local storage temporarily @@ -152,7 +223,7 @@ } else { return back()->with('error', 'No statements available for download.'); } - } else if($disk->exists($filePath)) { + } else if ($disk->exists($filePath)) { return $disk->download($filePath, "{$statement->account_number}_{$statement->period_from}.pdf"); } } @@ -164,16 +235,16 @@ { $request->validate([ 'authorization_status' => ['required', Rule::in(['approved', 'rejected'])], - 'remarks' => ['nullable', 'string', 'max:255'], + 'remarks' => ['nullable', 'string', 'max:255'], ]); // Update authorization status $statement->update([ 'authorization_status' => $request->authorization_status, - 'authorized_by' => Auth::id(), - 'authorized_at' => now(), - 'remarks' => $request->remarks, - 'updated_by' => Auth::id() + 'authorized_by' => Auth::id(), + 'authorized_at' => now(), + 'remarks' => $request->remarks, + 'updated_by' => Auth::id() ]); $statusText = $request->authorization_status === 'approved' ? 'approved' : 'rejected'; @@ -183,99 +254,6 @@ } - /** - * Check if the statement is available in the system. - * This is a placeholder method - implement according to your system. - */ - protected function checkStatementAvailability(PrintStatementLog $statement) - { - // This would be implemented based on your system's logic - // For example, checking an API or database for statement availability - $disk = Storage::disk('sftpStatement'); - - //format folder /periode/Print/branch_code/account_number.pdf - $filePath = "{$statement->period_from}/Print/{$statement->branch_code}/{$statement->account_number}.pdf"; - - // Check if the statement exists in the storage - if ($statement->is_period_range && $statement->period_to) { - $periodFrom = \Carbon\Carbon::createFromFormat('Ym', $statement->period_from); - $periodTo = \Carbon\Carbon::createFromFormat('Ym', $statement->period_to); - - // Loop through each month in the range - $missingPeriods = []; - $availablePeriods = []; - - for ($period = clone $periodFrom; $period->lte($periodTo); $period->addMonth()) { - $periodFormatted = $period->format('Ym'); - $periodPath = $periodFormatted . "/Print/{$statement->branch_code}/{$statement->account_number}.pdf"; - - if ($disk->exists($periodPath)) { - $availablePeriods[] = $periodFormatted; - } else { - $missingPeriods[] = $periodFormatted; - } - } - - // If any period is missing, the statement is not available - if (count($missingPeriods) > 0) { - $notes = "Missing periods: " . implode(', ', $missingPeriods); - $statement->update([ - 'is_available' => false, - 'remarks' => $notes, - 'updated_by' => Auth::id() - ]); - return; - } else { - // All periods are available - $statement->update([ - 'is_available' => true, - 'updated_by' => Auth::id() - ]); - } - } else if($disk->exists($filePath)) { - $statement->update([ - 'is_available' => true, - 'updated_by' => Auth::id() - ]); - return; - } - - $statement->update([ - 'is_available' => false, - 'updated_by' => Auth::id() - ]); - return; - } - - /** - * Generate or fetch the statement file. - * This is a placeholder method - implement according to your system. - */ - protected function generateStatementFile(PrintStatementLog $statement) - { - // This would be implemented based on your system's logic - // For example, calling an API to generate a PDF or fetching from storage - - // Placeholder implementation - return a dummy path - $tempFile = tempnam(sys_get_temp_dir(), 'statement_'); - file_put_contents($tempFile, 'Statement content would go here'); - return $tempFile; - } - - /** - * Generate a filename for the statement download. - */ - protected function generateFileName(PrintStatementLog $statement) - { - $accountNumber = $statement->account_number; - - if ($statement->is_period_range) { - return "statement_{$accountNumber}_{$statement->period_from}_to_{$statement->period_to}.pdf"; - } - - return "statement_{$accountNumber}_{$statement->period_from}.pdf"; - } - /** * Provide data for datatables. */ @@ -309,9 +287,9 @@ if (!empty($filter['value'])) { if ($filter['column'] === 'branch_code') { $query->where('branch_code', $filter['value']); - } elseif ($filter['column'] === 'authorization_status') { + } else if ($filter['column'] === 'authorization_status') { $query->where('authorization_status', $filter['value']); - } elseif ($filter['column'] === 'is_downloaded') { + } else if ($filter['column'] === 'is_downloaded') { $query->where('is_downloaded', filter_var($filter['value'], FILTER_VALIDATE_BOOLEAN)); } } @@ -320,16 +298,16 @@ // Apply sorting if provided if ($request->has('sortOrder') && !empty($request->get('sortOrder'))) { - $order = $request->get('sortOrder'); + $order = $request->get('sortOrder'); $column = $request->get('sortField'); // Map frontend column names to database column names if needed $columnMap = [ - 'branch' => 'branch_code', + 'branch' => 'branch_code', 'account' => 'account_number', - 'period' => 'period_from', - 'status' => 'authorization_status', - 'remarks' =>'remarks', + 'period' => 'period_from', + 'status' => 'authorization_status', + 'remarks' => 'remarks', // Add more mappings as needed ]; @@ -345,8 +323,8 @@ // Apply pagination if provided if ($request->has('page') && $request->has('size')) { - $page = $request->get('page'); - $size = $request->get('size'); + $page = $request->get('page'); + $size = $request->get('size'); $offset = ($page - 1) * $size; // Calculate the offset $query->skip($offset)->take($size); @@ -362,20 +340,20 @@ $data = $query->get()->map(function ($item) { // Transform data for frontend if needed return [ - 'id' => $item->id, - 'branch_code' => $item->branch_code, - 'branch_name' => $item->branch->name ?? 'N/A', - 'account_number' => $item->account_number, - 'period_from' => $item->period_from, - 'period_to' => $item->is_period_range ? $item->period_to : null, + 'id' => $item->id, + 'branch_code' => $item->branch_code, + 'branch_name' => $item->branch->name ?? 'N/A', + 'account_number' => $item->account_number, + 'period_from' => $item->period_from, + 'period_to' => $item->is_period_range ? $item->period_to : null, 'authorization_status' => $item->authorization_status, - 'is_available' => $item->is_available, - 'is_downloaded' => $item->is_downloaded, - 'created_at' => dateFormat($item->created_at,1,1), - 'created_by' => $item->user->name ?? 'N/A', - 'authorized_by' => $item->authorizer ? $item->authorizer->name : null, - 'authorized_at' => $item->authorized_at ? $item->authorized_at->format('Y-m-d H:i:s') : null, - 'remarks' => $item->remarks, + 'is_available' => $item->is_available, + 'is_downloaded' => $item->is_downloaded, + 'created_at' => dateFormat($item->created_at, 1, 1), + 'created_by' => $item->user->name ?? 'N/A', + 'authorized_by' => $item->authorizer ? $item->authorizer->name : null, + 'authorized_at' => $item->authorized_at ? $item->authorized_at->format('Y-m-d H:i:s') : null, + 'remarks' => $item->remarks, ]; }); @@ -387,22 +365,184 @@ // Return the response data as a JSON object return response()->json([ - 'draw' => $request->get('draw'), - 'recordsTotal' => $totalRecords, + 'draw' => $request->get('draw'), + 'recordsTotal' => $totalRecords, 'recordsFiltered' => $filteredRecords, - 'pageCount' => $pageCount, - 'page' => $currentPage, - 'totalCount' => $totalRecords, - 'data' => $data, + 'pageCount' => $pageCount, + 'page' => $currentPage, + 'totalCount' => $totalRecords, + 'data' => $data, ]); } - public function destroy(PrintStatementLog $statement){ + public function destroy(PrintStatementLog $statement) + { // Delete the statement $statement->delete(); return response()->json([ - 'message' => 'Statement deleted successfully.', + 'message' => 'Statement deleted successfully.', ]); } + + /** + * Send statement to email + */ + public function sendEmail($id) + { + $statement = PrintStatementLog::findOrFail($id); + // Check if statement has email + if (empty($statement->email)) { + return redirect()->back()->with('error', 'No email address provided for this statement.'); + } + + // Check if statement is available + if (!$statement->is_available) { + return redirect()->back()->with('error', 'Statement is not available for sending.'); + } + + try { + $disk = Storage::disk('sftpStatement'); + $filePath = "{$statement->period_from}/Print/{$statement->branch_code}/{$statement->account_number}.pdf"; + + if ($statement->is_period_range && $statement->period_to) { + $periodFrom = Carbon::createFromFormat('Ym', $statement->period_from); + $periodTo = Carbon::createFromFormat('Ym', $statement->period_to); + + // Loop through each month in the range + $missingPeriods = []; + $availablePeriods = []; + + for ($period = clone $periodFrom; $period->lte($periodTo); $period->addMonth()) { + $periodFormatted = $period->format('Ym'); + $periodPath = $periodFormatted . "/Print/{$statement->branch_code}/{$statement->account_number}.pdf"; + + if ($disk->exists($periodPath)) { + $availablePeriods[] = $periodFormatted; + } else { + $missingPeriods[] = $periodFormatted; + } + } + + // If any period is available, create a zip and send it + if (count($availablePeriods) > 0) { + // Create a temporary zip file + $zipFileName = "{$statement->account_number}_{$statement->period_from}_to_{$statement->period_to}.zip"; + $zipFilePath = storage_path("app/temp/{$zipFileName}"); + + // Ensure the temp directory exists + if (!file_exists(storage_path('app/temp'))) { + mkdir(storage_path('app/temp'), 0755, true); + } + + // Create a new zip archive + $zip = new ZipArchive(); + if ($zip->open($zipFilePath, ZipArchive::CREATE | ZipArchive::OVERWRITE) === true) { + // Add each available statement to the zip + foreach ($availablePeriods as $period) { + $filePath = "{$period}/Print/{$statement->branch_code}/{$statement->account_number}.pdf"; + $localFilePath = storage_path("app/temp/{$statement->account_number}_{$period}.pdf"); + + // Download the file from SFTP to local storage temporarily + file_put_contents($localFilePath, $disk->get($filePath)); + + // Add the file to the zip + $zip->addFile($localFilePath, "{$statement->account_number}_{$period}.pdf"); + } + + $zip->close(); + + // Send email with zip attachment + Mail::to($statement->email) + ->send(new StatementEmail($statement, $zipFilePath, true)); + + // Clean up temporary files + foreach ($availablePeriods as $period) { + $localFilePath = storage_path("app/temp/{$statement->account_number}_{$period}.pdf"); + if (file_exists($localFilePath)) { + unlink($localFilePath); + } + } + + // Delete the zip file after sending + if (file_exists($zipFilePath)) { + unlink($zipFilePath); + } + } else { + return redirect()->back()->with('error', 'Failed to create zip archive for email.'); + } + } else { + return redirect()->back()->with('error', 'No statements available for sending.'); + } + } else if ($disk->exists($filePath)) { + // For single period statements + $localFilePath = storage_path("app/temp/{$statement->account_number}_{$statement->period_from}.pdf"); + + // Ensure the temp directory exists + if (!file_exists(storage_path('app/temp'))) { + mkdir(storage_path('app/temp'), 0755, true); + } + + // Download the file from SFTP to local storage temporarily + file_put_contents($localFilePath, $disk->get($filePath)); + + // Send email with PDF attachment + Mail::to($statement->email) + ->send(new StatementEmail($statement, $localFilePath, false)); + + // Delete the temporary file + if (file_exists($localFilePath)) { + unlink($localFilePath); + } + } else { + return redirect()->back()->with('error', 'Statement file not found.'); + } + + // Update statement record to mark as emailed + $statement->update([ + 'email_sent_at' => now(), + 'updated_by' => Auth::id() + ]); + + return redirect()->back()->with('success', 'Statement has been sent to ' . $statement->email); + } catch (Exception $e) { + // Log the error + Log::error('Failed to send statement email: ' . $e->getMessage()); + + return redirect()->back()->with('error', 'Failed to send email: ' . $e->getMessage()); + } + } + + /** + * Generate or fetch the statement file. + * This is a placeholder method - implement according to your system. + */ + protected function generateStatementFile(PrintStatementLog $statement) + { + // This would be implemented based on your system's logic + // For example, calling an API to generate a PDF or fetching from storage + + // Placeholder implementation - return a dummy path + $tempFile = tempnam(sys_get_temp_dir(), 'statement_'); + file_put_contents($tempFile, 'Statement content would go here'); + return $tempFile; + } + + /** + * Send statement to email + */ + + /** + * Generate a filename for the statement download. + */ + protected function generateFileName(PrintStatementLog $statement) + { + $accountNumber = $statement->account_number; + + if ($statement->is_period_range) { + return "statement_{$accountNumber}_{$statement->period_from}_to_{$statement->period_to}.pdf"; + } + + return "statement_{$accountNumber}_{$statement->period_from}.pdf"; + } } diff --git a/app/Http/Requests/PrintStatementRequest.php b/app/Http/Requests/PrintStatementRequest.php index 0537fc1..051b5ec 100644 --- a/app/Http/Requests/PrintStatementRequest.php +++ b/app/Http/Requests/PrintStatementRequest.php @@ -3,7 +3,6 @@ namespace Modules\Webstatement\Http\Requests; use Illuminate\Foundation\Http\FormRequest; - use Illuminate\Validation\Rule; use Modules\Webstatement\Models\PrintStatementLog as Statement; class PrintStatementRequest extends FormRequest @@ -29,6 +28,8 @@ 'branch_code' => ['required', 'string', 'exists:branches,code'], 'account_number' => ['required', 'string'], 'is_period_range' => ['sometimes', 'boolean'], + 'email' => ['nullable', 'email'], + 'email_sent_at' => ['nullable', 'timestamp'], 'period_from' => [ 'required', 'string', @@ -36,8 +37,8 @@ // Prevent duplicate requests with same account number and period function ($attribute, $value, $fail) { $query = Statement::where('account_number', $this->input('account_number')) - ->where('authorization_status', '!=', 'rejected') - ->where('period_from', $value); + ->where('authorization_status', '!=', 'rejected') + ->where('period_from', $value); // If this is an update request, exclude the current record if ($this->route('statement')) { @@ -100,17 +101,17 @@ protected function prepareForValidation() : void { - if($this->has('period_from')){ + if ($this->has('period_from')) { //conver to YYYYMM format $this->merge([ - 'period_from' => substr($this->period_from, 0, 4).substr($this->period_from, 5, 2), + 'period_from' => substr($this->period_from, 0, 4) . substr($this->period_from, 5, 2), ]); } - if($this->has('period_to')){ + if ($this->has('period_to')) { //conver to YYYYMM format $this->merge([ - 'period_to' => substr($this->period_to, 0, 4).substr($this->period_to, 5, 2), + 'period_to' => substr($this->period_to, 0, 4) . substr($this->period_to, 5, 2), ]); } diff --git a/app/Mail/StatementEmail.php b/app/Mail/StatementEmail.php new file mode 100644 index 0000000..f6cbe5b --- /dev/null +++ b/app/Mail/StatementEmail.php @@ -0,0 +1,73 @@ +statement = $statement; + $this->filePath = $filePath; + $this->isZip = $isZip; + } + + /** + * Build the message. + * + * @return $this + */ + public function build() + { + $subject = 'Your Account Statement'; + + if ($this->statement->is_period_range) { + $subject .= " - {$this->statement->period_from} to {$this->statement->period_to}"; + } else { + $subject .= " - {$this->statement->period_from}"; + } + + $email = $this->subject($subject) + ->view('webstatement::statements.email') + ->with([ + 'statement' => $this->statement, + 'accountNumber' => $this->statement->account_number, + 'periodFrom' => $this->statement->period_from, + 'periodTo' => $this->statement->period_to, + 'isRange' => $this->statement->is_period_range, + ]); + + if ($this->isZip) { + $fileName = "{$this->statement->account_number}_{$this->statement->period_from}_to_{$this->statement->period_to}.zip"; + $email->attach($this->filePath, [ + 'as' => $fileName, + 'mime' => 'application/zip', + ]); + } else { + $fileName = "{$this->statement->account_number}_{$this->statement->period_from}.pdf"; + $email->attach($this->filePath, [ + 'as' => $fileName, + 'mime' => 'application/pdf', + ]); + } + + return $email; + } + } diff --git a/app/Models/PrintStatementLog.php b/app/Models/PrintStatementLog.php index ec1630a..06ea5d3 100644 --- a/app/Models/PrintStatementLog.php +++ b/app/Models/PrintStatementLog.php @@ -31,6 +31,8 @@ 'authorized_by', 'authorized_at', 'remarks', + 'email', + 'email_sent_at', ]; protected $casts = [ diff --git a/database/migrations/2025_05_11_172635_create_print_statement_logs_table.php b/database/migrations/2025_05_11_172635_create_print_statement_logs_table.php index 33a60d1..5275886 100644 --- a/database/migrations/2025_05_11_172635_create_print_statement_logs_table.php +++ b/database/migrations/2025_05_11_172635_create_print_statement_logs_table.php @@ -25,6 +25,8 @@ $table->string('user_agent')->nullable()->comment('User agent of requester'); $table->timestamp('downloaded_at')->nullable()->comment('When the statement was downloaded'); $table->string('remarks')->nullable()->comment('Remarks for the statement'); + $table->string('email')->nullable()->comment('Email address of customer'); + $table->timestamp('email_sent_at')->nullable()->comment('When the email was sent'); $table->enum('authorization_status', ['pending', 'approved', 'rejected'])->default('pending'); diff --git a/module.json b/module.json index 1c375d3..9ac9e25 100644 --- a/module.json +++ b/module.json @@ -12,7 +12,7 @@ "menu": { "main": [ { - "title": "Periode Statement", + "title": "Create Periode", "path": "periode-statements", "icon": "ki-filled ki-calendar text-lg text-primary", "classes": "", @@ -23,7 +23,7 @@ ] }, { - "title": "Print Statement", + "title": "Statement", "path": "statements", "icon": "ki-filled ki-printer text-lg text-primary", "classes": "", diff --git a/resources/views/emails/statement.blade.php b/resources/views/emails/statement.blade.php new file mode 100644 index 0000000..e69de29 diff --git a/resources/views/statements/email.blade.php b/resources/views/statements/email.blade.php new file mode 100644 index 0000000..76e274e --- /dev/null +++ b/resources/views/statements/email.blade.php @@ -0,0 +1,143 @@ + + + + + + + + + +
+
+
+ Yang Terhormat Bapak/Ibu Daeng Deni Mardaeni,

+ + Terlampir adalah Electronic Statement Rekening Anda.
+ Silahkan gunakan password Electronic Statement Anda untuk membukanya.

+ Password standar Elektronic Statement ini adalah ddMonyyyyxx (contoh: 01Aug1970xx) dimana : +
    +
  • dd : 2 digit tanggal lahir anda, contoh: 01
  • +
  • Mon : + 3 huruf pertama bulan lahir anda dalam bahasa Ingris. Huruf pertama adalah huruf besar dan selanjutnya huruf kecil, contoh : Aug +
  • +
  • yyyy : 4 digit tahun kelahiran anda, contoh : 1970
  • +
  • xx : 2 digit terakhir dari nomer rekening anda, contoh : 12
  • +
+
+ + Terima Kasih,

+ + Bank Artha Graha Internasional
+ ------------------------------ + + ------------------------------ + + --------
+ Kami sangat menghargai masukan dan saran Anda untuk meningkatkan layanan dan produk kami.
+ Untuk memberikan masukan, silakan hubungi GrahaCall 24 Jam kami di + 0-800-191-8880.


+ + Dear Mr/Mrs/Ms Daeng Deni Mardaeni,

+ + Attached is your Electronic Account Statement.
+ Please use your Electronic Statement password to open it.

+ + The Electronic Statement standard password is ddMonyyyyxx (example: 01Aug1970xx) where: +
    +
  • dd : The first 2 digits of your birthdate, example: 01
  • +
  • Mon : + The first 3 letters of your birth month in English. The first letter is uppercase and the rest are lowercase, example: Aug +
  • +
  • yyyy : 4 digit of your birth year, example: 1970
  • +
  • xx : The last 2 digits of your account number, example: 12.
  • +
+
+ + Regards,

+ + Bank Artha Graha Internasional
+ ------------------------------ + + ------------------------------ + + --------
+ We welcome any feedback or suggestions to improve our product and services.
+ If you have any feedback, please contact our GrahaCall 24 Hours at + 0-800-191-8880. +
+

+
+
+
+ +
+ + diff --git a/resources/views/statements/index.blade.php b/resources/views/statements/index.blade.php index afe577a..88a380d 100644 --- a/resources/views/statements/index.blade.php +++ b/resources/views/statements/index.blade.php @@ -41,6 +41,14 @@ @enderror +
+ + + @error('email') +
{{ $message }}
+ @enderror +
+
@@ -284,6 +292,13 @@ `; } + // Show send email button if email is not empty and statement is available + if (data.is_available) { + buttons += ` + + `; + } + // Only show delete button if status is pending if (data.authorization_status === 'pending') { buttons += ` diff --git a/routes/web.php b/routes/web.php index 2906f34..f29d572 100644 --- a/routes/web.php +++ b/routes/web.php @@ -83,6 +83,7 @@ Route::middleware(['auth'])->group(function () { Route::get('/datatables', [PrintStatementController::class, 'dataForDatatables'])->name('datatables'); Route::get('/{statement}/download', [PrintStatementController::class, 'download'])->name('download'); Route::post('/{statement}/authorize', [PrintStatementController::class, 'authorize'])->name('authorize'); + Route::get('/{statement}/send-email', [PrintStatementController::class, 'sendEmail'])->name('send-email'); }); Route::resource('statements', PrintStatementController::class);