diff --git a/app/Http/Controllers/PrintStatementController.php b/app/Http/Controllers/PrintStatementController.php index 3e82f55..1b90d12 100644 --- a/app/Http/Controllers/PrintStatementController.php +++ b/app/Http/Controllers/PrintStatementController.php @@ -5,9 +5,11 @@ use App\Http\Controllers\Controller; use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; + use Illuminate\Support\Facades\Storage; use Modules\Webstatement\Http\Requests\PrintStatementRequest; use Modules\Webstatement\Models\PrintStatementLog; use Modules\Basicdata\Models\Branch; + use phpseclib3\Net\SFTP; class PrintStatementController extends Controller { @@ -49,7 +51,7 @@ // Process statement availability check (this would be implemented based on your system) $this->checkStatementAvailability($statement); - return redirect()->route('webstatement.statements.show', $statement->id) + return redirect()->route('statements.index') ->with('success', 'Statement request has been created successfully.'); } @@ -72,9 +74,9 @@ return back()->with('error', 'Statement is not available for download.'); } - if ($statement->authorization_status !== 'approved') { + /* if ($statement->authorization_status !== 'approved') { return back()->with('error', 'Statement download requires authorization.'); - } + }*/ // Update download status $statement->update([ @@ -84,10 +86,75 @@ ]); // Generate or fetch the statement file (implementation depends on your system) - $filePath = $this->generateStatementFile($statement); + $disk = Storage::disk('sftpStatement'); + $filePath = "{$statement->period_from}/Print/{$statement->branch_code}/{$statement->account_number}.pdf"; - // Return file download response - return response()->download($filePath, $this->generateFileName($statement)); + 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($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(); + + // Clean up temporary files + foreach ($availablePeriods as $period) { + $localFilePath = storage_path("app/temp/{$statement->account_number}_{$period}.pdf"); + if (file_exists($localFilePath)) { + unlink($localFilePath); + } + } + + // Return the zip file for download + return response()->download($zipFilePath, $zipFileName)->deleteFileAfterSend(true); + } else { + return back()->with('error', 'Failed to create zip archive.'); + } + } else { + return back()->with('error', 'No statements available for download.'); + } + } else if($disk->exists($filePath)) { + return $disk->download($filePath, "{$statement->account_number}_{$statement->period_from}.pdf"); + } } /** @@ -111,8 +178,9 @@ $statusText = $request->authorization_status === 'approved' ? 'approved' : 'rejected'; - return redirect()->route('webstatement.statements.show', $statement->id) + return redirect()->route('statements.show', $statement->id) ->with('success', "Statement request has been {$statusText} successfully."); + } /** @@ -123,12 +191,60 @@ { // 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; + } - // Placeholder implementation - set to available for demo $statement->update([ - 'is_available' => true, + 'is_available' => false, 'updated_by' => Auth::id() ]); + return; } /** @@ -213,6 +329,7 @@ 'account' => 'account_number', 'period' => 'period_from', 'status' => 'authorization_status', + 'remarks' =>'remarks', // Add more mappings as needed ]; @@ -254,10 +371,11 @@ 'authorization_status' => $item->authorization_status, 'is_available' => $item->is_available, 'is_downloaded' => $item->is_downloaded, - 'created_at' => $item->created_at->format('Y-m-d H:i:s'), + '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, ]; }); @@ -278,4 +396,13 @@ 'data' => $data, ]); } + + public function destroy(PrintStatementLog $statement){ + // Delete the statement + $statement->delete(); + + return response()->json([ + 'message' => 'Statement deleted successfully.', + ]); + } } diff --git a/app/Http/Requests/PrintStatementRequest.php b/app/Http/Requests/PrintStatementRequest.php index 67701b9..0537fc1 100644 --- a/app/Http/Requests/PrintStatementRequest.php +++ b/app/Http/Requests/PrintStatementRequest.php @@ -3,6 +3,8 @@ 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 { @@ -27,11 +29,38 @@ 'branch_code' => ['required', 'string', 'exists:branches,code'], 'account_number' => ['required', 'string'], 'is_period_range' => ['sometimes', 'boolean'], - 'period_from' => ['required', 'string', 'regex:/^\d{6}$/'], // YYYYMM format + 'period_from' => [ + 'required', + 'string', + 'regex:/^\d{6}$/', // YYYYMM format + // 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); + + // If this is an update request, exclude the current record + if ($this->route('statement')) { + $query->where('id', '!=', $this->route('statement')); + } + + // If period_to is provided, check for overlapping periods + if ($this->input('period_to')) { + $query->where(function ($q) use ($value) { + $q->where('period_from', '<=', $this->input('period_to')) + ->where('period_to', '>=', $value); + }); + } + + if ($query->exists()) { + $fail('A statement request with this account number and period already exists.'); + } + } + ], ]; // If it's a period range, require period_to - if ($this->input('is_period_range')) { + if ($this->input('period_to')) { $rules['period_to'] = [ 'required', 'string', @@ -71,10 +100,24 @@ protected function prepareForValidation() : void { - // Convert is_period_range to boolean if it exists - if ($this->has('is_period_range')) { + if($this->has('period_from')){ + //conver to YYYYMM format $this->merge([ - 'is_period_range' => filter_var($this->is_period_range, FILTER_VALIDATE_BOOLEAN), + 'period_from' => substr($this->period_from, 0, 4).substr($this->period_from, 5, 2), + ]); + } + + 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), + ]); + } + + // Convert is_period_range to boolean if it exists + if ($this->has('period_to')) { + $this->merge([ + 'is_period_range' => true, ]); } } diff --git a/app/Models/PrintStatementLog.php b/app/Models/PrintStatementLog.php index 2206a08..ec1630a 100644 --- a/app/Models/PrintStatementLog.php +++ b/app/Models/PrintStatementLog.php @@ -30,6 +30,7 @@ 'deleted_by', 'authorized_by', 'authorized_at', + 'remarks', ]; 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 a78ede6..33a60d1 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 @@ -24,6 +24,7 @@ $table->string('ip_address')->nullable()->comment('IP address of requester'); $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->enum('authorization_status', ['pending', 'approved', 'rejected'])->default('pending'); diff --git a/module.json b/module.json index 664d81a..1c375d3 100644 --- a/module.json +++ b/module.json @@ -25,7 +25,7 @@ { "title": "Print Statement", "path": "statements", - "icon": "ki-filled ki-calendar text-lg text-primary", + "icon": "ki-filled ki-printer text-lg text-primary", "classes": "", "attributes": [], "permission": "", diff --git a/resources/views/statements/create.blade.php b/resources/views/statements/create.blade.php deleted file mode 100644 index f648007..0000000 --- a/resources/views/statements/create.blade.php +++ /dev/null @@ -1,38 +0,0 @@ -@extends('layouts.main') - -@section('breadcrumbs') - -@endsection - -@section('content') - -@endsection - -@push('scripts') - -@endpush diff --git a/resources/views/statements/index.blade.php b/resources/views/statements/index.blade.php index 6fd2358..afe577a 100644 --- a/resources/views/statements/index.blade.php +++ b/resources/views/statements/index.blade.php @@ -5,15 +5,10 @@ @endsection @section('content') -