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
+
+