FEAT_S3_FILE_UPLOAD

This commit is contained in:
VENKATESHWARAN 2026-07-15 15:49:13 +05:30
parent 2e3bb11c65
commit 62b5ddbeaf
48 changed files with 3428 additions and 592 deletions

View File

@ -189,3 +189,11 @@ ICICI_GRANT_TYPE =
ICICI_PRIMARY_KEY_CONSTANT = ICICI_PRIMARY_KEY_CONSTANT =
#--------------------------------------------------------------------
# File storage (S3 uploads)
#--------------------------------------------------------------------
# FILE_STORAGE_DRIVER = s3
# AWS_FILE_UPLOAD_BUCKET =
# Keep permanent local copy after S3 upload in storage_file_Upload (default false)
RETAIN_LOCAL = false

4
.gitignore vendored
View File

@ -3,6 +3,10 @@
#------------------------- #-------------------------
writable/cache/* writable/cache/*
!writable/cache/.gitkeep !writable/cache/.gitkeep
!writable/cache/storage_runtime/
!writable/cache/storage_runtime/.gitkeep
!writable/cache/claim_files_runtime/
!writable/cache/claim_files_runtime/.gitkeep
writable/logs/* writable/logs/*
!writable/logs/.gitkeep !writable/logs/.gitkeep

View File

@ -0,0 +1,217 @@
<?php
namespace App\Commands;
use CodeIgniter\CLI\BaseCommand;
use CodeIgniter\CLI\CLI;
class MigrateLocalFilesToS3 extends BaseCommand
{
protected $group = 'Storage';
protected $name = 'storage:migrate-local-to-s3';
protected $description = 'One-time phased migration of local uploaded files to S3 using FileStorageService.';
protected $usage = 'storage:migrate-local-to-s3 [--module writable_uploads|<folder_name>|insurer_claim_form|all] [--limit 500] [--offset 0] [--execute]';
protected $options = [
'--module' => 'Target module/folder (default: writable_uploads). Use writable_uploads for all writable/uploads/* folders.',
'--limit' => 'Max files per run (default: 500).',
'--offset' => 'Start offset for phased batches (default: 0).',
'--execute' => 'Actually upload files. Without this flag, command runs in dry-run mode.',
];
/**
* @var array<string, string>
*/
private array $staticPaths = [
'insurer_claim_form' => WRITEPATH . 'insurer_claim_form',
];
public function run(array $params)
{
$moduleOpt = strtolower((string) (CLI::getOption('module') ?? 'writable_uploads'));
$execute = CLI::getOption('execute') !== null;
$dryRun = !$execute;
$limit = max(1, (int) (CLI::getOption('limit') ?? 500));
$offset = max(0, (int) (CLI::getOption('offset') ?? 0));
$modulePaths = $this->buildModulePaths();
$selectedModules = $this->resolveModules($moduleOpt, $modulePaths);
if ($selectedModules === []) {
CLI::error('Invalid --module value. Allowed: writable_uploads, ' . implode(', ', array_keys($modulePaths)) . ', all');
return;
}
$storage = \Config\Services::getFileStorageService(false);
if (!$storage->usesS3()) {
CLI::error('FileStorageService is not in S3 mode. Set FILE_STORAGE_DRIVER=s3 before migration.');
return;
}
CLI::write($dryRun ? 'Running in DRY-RUN mode (no uploads).' : 'Running in EXECUTE mode (uploads enabled).', 'yellow');
CLI::write('Target bucket: ' . ($storage->getBucket() ?? 'N/A'), 'cyan');
CLI::newLine();
$totals = [
'seen' => 0,
'uploaded' => 0,
'skipped_exists' => 0,
'skipped_missing' => 0,
'failed' => 0,
];
foreach ($selectedModules as $module) {
$path = $modulePaths[$module];
CLI::write("Module: {$module}", 'green');
CLI::write("Path: {$path}");
if (!is_dir($path)) {
CLI::write(' - Skipped: folder does not exist', 'yellow');
$totals['skipped_missing']++;
CLI::newLine();
continue;
}
$files = $this->listFiles($path);
$files = array_slice($files, $offset, $limit);
CLI::write(' - Files in batch: ' . count($files));
foreach ($files as $fullPath) {
$totals['seen']++;
$fileName = basename($fullPath);
if (!is_file($fullPath)) {
$totals['skipped_missing']++;
CLI::write(" - Missing: {$fileName}", 'yellow');
continue;
}
$alreadyExists = $storage->exists($path, $fileName);
if ($alreadyExists) {
$totals['skipped_exists']++;
CLI::write(" - Exists in S3, skipped: {$fileName}", 'yellow');
continue;
}
if ($dryRun) {
CLI::write(" - [dry-run] Would upload: {$fileName}");
continue;
}
$result = $storage->upload($fullPath, $path, $fileName);
if ($result['success'] ?? false) {
$totals['uploaded']++;
CLI::write(" - Uploaded: {$fileName}", 'green');
} else {
$totals['failed']++;
CLI::write(" - Failed: {$fileName} | " . ($result['message'] ?? 'unknown error'), 'red');
}
}
CLI::newLine();
}
CLI::write('Migration summary', 'cyan');
CLI::write(' Seen: ' . $totals['seen']);
CLI::write(' Uploaded: ' . $totals['uploaded'], $totals['uploaded'] > 0 ? 'green' : 'white');
CLI::write(' Skipped (already in S3): ' . $totals['skipped_exists'], 'yellow');
CLI::write(' Skipped (missing/invalid): ' . $totals['skipped_missing'], 'yellow');
CLI::write(' Failed: ' . $totals['failed'], $totals['failed'] > 0 ? 'red' : 'white');
if ($dryRun) {
CLI::newLine();
CLI::write('Dry-run complete. Re-run with --execute to perform uploads.', 'yellow');
}
}
/**
* @return array<int, string>
*/
private function resolveModules(string $moduleOpt, array $modulePaths): array
{
if ($moduleOpt === 'all') {
return array_keys($modulePaths);
}
if ($moduleOpt === 'writable_uploads') {
$uploadRoot = rtrim(WRITEPATH, '/\\') . DIRECTORY_SEPARATOR . 'uploads' . DIRECTORY_SEPARATOR;
$modules = [];
foreach ($modulePaths as $module => $path) {
$normalized = str_replace('\\', '/', $path);
$normalizedRoot = str_replace('\\', '/', $uploadRoot);
if (strpos($normalized, rtrim($normalizedRoot, '/')) === 0) {
$modules[] = $module;
}
}
return $modules;
}
$raw = array_filter(array_map('trim', explode(',', $moduleOpt)));
$valid = [];
foreach ($raw as $module) {
if (array_key_exists($module, $modulePaths)) {
$valid[] = $module;
}
}
return array_values(array_unique($valid));
}
/**
* Build migratable paths:
* - all direct subfolders in writable/uploads
* - additional static paths (outside writable/uploads)
*
* @return array<string, string>
*/
private function buildModulePaths(): array
{
$paths = [];
$uploadRoot = rtrim(WRITEPATH, '/\\') . DIRECTORY_SEPARATOR . 'uploads';
$entries = @scandir($uploadRoot);
if (is_array($entries)) {
foreach ($entries as $entry) {
if ($entry === '.' || $entry === '..') {
continue;
}
$fullPath = $uploadRoot . DIRECTORY_SEPARATOR . $entry;
if (is_dir($fullPath)) {
$paths[strtolower($entry)] = $fullPath;
}
}
}
foreach ($this->staticPaths as $key => $path) {
$paths[$key] = $path;
}
ksort($paths);
return $paths;
}
/**
* @return array<int, string>
*/
private function listFiles(string $path): array
{
$entries = @scandir($path);
if (!is_array($entries)) {
return [];
}
$files = [];
foreach ($entries as $entry) {
if ($entry === '.' || $entry === '..') {
continue;
}
$fullPath = rtrim($path, '/\\') . DIRECTORY_SEPARATOR . $entry;
if (is_file($fullPath)) {
$files[] = $fullPath;
}
}
sort($files);
return $files;
}
}

View File

@ -0,0 +1,361 @@
<?php
namespace App\Commands;
use App\Models\ClaimFilesModel;
use CodeIgniter\CLI\BaseCommand;
use CodeIgniter\CLI\CLI;
use Mpdf\Mpdf;
use Mpdf\Output\Destination;
/**
* Dedicated smoke test for claim PDF merge with S3-backed claim_files.
*
* Usage:
* php spark storage:smoke-test-merge-pdf
* php spark storage:smoke-test-merge-pdf --list
* php spark storage:smoke-test-merge-pdf --keep # leave S3/DB artifacts (debug)
*/
class StorageMergePdfSmokeTest extends BaseCommand
{
protected $group = 'Storage';
protected $name = 'storage:smoke-test-merge-pdf';
protected $description = 'Run dedicated merge_ticket_pdfs S3 scenarios (claim_files).';
protected $usage = 'storage:smoke-test-merge-pdf [--list] [--keep]';
protected $options = [
'--list' => 'List merge scenarios without executing.',
'--keep' => 'Skip cleanup of S3 objects and claim_files rows.',
];
private int $pass = 0;
private int $fail = 0;
private int $skip = 0;
/** @var list<array{id:string,title:string}> */
private array $catalog = [
['id' => 'MERGE-01', 'title' => 'Create & upload 2 source PDFs to S3 (claim_files, no permanent local)'],
['id' => 'MERGE-02', 'title' => 'Insert claim_files DB rows for synthetic ticket'],
['id' => 'MERGE-03', 'title' => 'merge_ticket_pdfs resolves sources from S3 (temp download)'],
['id' => 'MERGE-04', 'title' => 'Merge succeeds with pages >= 2'],
['id' => 'MERGE-05', 'title' => 'Merged PDF exists on S3'],
['id' => 'MERGE-06', 'title' => 'Merged permanent local path gone when S3 enabled'],
['id' => 'MERGE-07', 'title' => 'Merged claim_files row registered (file_type=4)'],
['id' => 'MERGE-08', 'title' => 'Claim runtime temps cleaned after merge'],
['id' => 'MERGE-09', 'title' => 'Cleanup removes S3 objects + soft-deletes DB rows'],
];
public function run(array $params)
{
helper(['utility', 'merge_pdf']);
if (CLI::getOption('list') !== null) {
CLI::write('========== MERGE PDF SCENARIOS ==========', 'cyan');
foreach ($this->catalog as $row) {
CLI::write(" {$row['id']} {$row['title']}");
}
CLI::newLine();
CLI::write('Run: php spark storage:smoke-test-merge-pdf');
return EXIT_SUCCESS;
}
$storage = \Config\Services::getFileStorageService(false);
$keep = CLI::getOption('keep') !== null;
CLI::write('========== CLAIM PDF MERGE SMOKE ==========', 'cyan');
CLI::write('usesS3: ' . ($storage->usesS3() ? 'YES' : 'NO'));
CLI::write('Bucket: ' . ($storage->getBucket() ?? 'N/A'));
CLI::write('RETAIN_LOCAL: ' . (storage_env_retain_local() ? 'true' : 'false'));
CLI::newLine();
if (! $storage->usesS3()) {
foreach ($this->catalog as $row) {
$this->skip($row['id'], 'FILE_STORAGE_DRIVER must be s3');
}
$this->printResult();
return EXIT_ERROR;
}
$uploadDir = rtrim(WRITEPATH, '/\\') . DIRECTORY_SEPARATOR
. 'uploads' . DIRECTORY_SEPARATOR
. 'claim_files' . DIRECTORY_SEPARATOR;
if (! is_dir($uploadDir)) {
@mkdir($uploadDir, 0775, true);
}
$ticketId = 990000000 + random_int(1000, 999999);
$stamp = date('Ymd_His') . '_' . bin2hex(random_bytes(3));
$srcNames = [
'smoke_merge_a_' . $stamp . '.pdf',
'smoke_merge_b_' . $stamp . '.pdf',
];
$sourceIds = [];
$mergedName = null;
$mergedId = null;
$claimFiles = new ClaimFilesModel();
try {
// MERGE-01
$uploaded = 0;
foreach ($srcNames as $i => $name) {
$local = $this->makeOnePagePdf($uploadDir, $name, 'Smoke source ' . ($i + 1));
if ($local === null || ! is_file($local)) {
continue;
}
$up = $storage->upload($local, rtrim($uploadDir, '/\\'), $name);
@unlink($local);
if (($up['success'] ?? false) && $storage->exists(rtrim($uploadDir, '/\\'), $name) && ! is_file($uploadDir . $name)) {
$uploaded++;
}
}
$this->step('MERGE-01', $uploaded === 2, "uploaded={$uploaded}/2 ticket_id={$ticketId}");
if ($uploaded !== 2) {
foreach (array_slice($this->catalog, 1) as $row) {
$this->skip($row['id'], 'source upload failed');
}
$this->printResult();
return EXIT_ERROR;
}
// MERGE-02
foreach ($srcNames as $idx => $name) {
$id = $claimFiles->insert([
'ticket_id' => $ticketId,
'file_type' => 2,
'doc_name' => 'SMOKE_MERGE_SRC_' . ($idx + 1),
'file_name' => $name,
'url' => $name,
'mime_type' => 'application/pdf',
'is_active' => 1,
'created_by' => 1,
]);
if ($id) {
$sourceIds[] = (int) $id;
}
}
$this->step('MERGE-02', count($sourceIds) === 2, 'ids=' . implode(',', $sourceIds));
if (count($sourceIds) !== 2) {
foreach (array_slice($this->catalog, 2) as $row) {
$this->skip($row['id'], 'DB insert failed');
}
$this->cleanup($storage, $uploadDir, $srcNames, null, $ticketId, $sourceIds, $keep);
$this->printResult();
return EXIT_ERROR;
}
// MERGE-03..07 via merge_ticket_pdfs
$result = merge_ticket_pdfs($ticketId, [
'replace' => true,
'created_by' => 1,
'include_file_types' => [1, 2],
'include_mime_types' => ['application/pdf', 'image/jpeg', 'image/png'],
]);
$this->step(
'MERGE-03',
(bool) ($result['status'] ?? false) && (int) ($result['source_count'] ?? 0) >= 2,
(string) ($result['message'] ?? '') . ' sources=' . (int) ($result['source_count'] ?? 0)
);
$pages = (int) ($result['pages'] ?? 0);
$this->step(
'MERGE-04',
(bool) ($result['status'] ?? false) && $pages >= 2,
'pages=' . $pages
);
$mergedName = (string) ($result['file_name'] ?? '');
$mergedId = $result['merged_file_id'] ?? null;
$onS3 = $mergedName !== '' && $storage->exists(rtrim($uploadDir, '/\\'), $mergedName);
$this->step('MERGE-05', $onS3, $mergedName !== '' ? $mergedName : 'no merged name');
$localMergedGone = $mergedName === '' || ! is_file($uploadDir . $mergedName);
$this->step('MERGE-06', $localMergedGone, $mergedName !== '' ? basename($mergedName) : 'n/a');
$rowOk = false;
if ($mergedId) {
$row = $claimFiles->find((int) $mergedId);
$rowOk = is_array($row)
&& (int) ($row['file_type'] ?? 0) === MERGED_CLAIM_FILE_TYPE
&& (int) ($row['is_active'] ?? 0) === 1
&& (string) ($row['file_name'] ?? '') === $mergedName;
}
$this->step('MERGE-07', $rowOk, 'merged_file_id=' . ($mergedId ?? 'null'));
// MERGE-08: no leftover smoke temps for our source names in claim_files_runtime
$afterRuntime = $this->listClaimRuntimeFiles();
$leaked = [];
foreach ($afterRuntime as $f) {
foreach ($srcNames as $src) {
if (strpos($f, $src) !== false) {
$leaked[] = $f;
}
}
}
$this->step('MERGE-08', $leaked === [], $leaked === [] ? 'no leaks' : implode(',', $leaked));
// MERGE-09 cleanup
$cleanOk = $this->cleanup(
$storage,
$uploadDir,
$srcNames,
$mergedName !== '' ? $mergedName : null,
$ticketId,
$sourceIds,
$keep,
$mergedId ? [(int) $mergedId] : []
);
if ($keep) {
$this->skip('MERGE-09', '--keep set; left ticket_id=' . $ticketId);
} else {
$srcGone = true;
foreach ($srcNames as $name) {
if ($storage->exists(rtrim($uploadDir, '/\\'), $name)) {
$srcGone = false;
}
}
$mergedGone = $mergedName === '' || ! $storage->exists(rtrim($uploadDir, '/\\'), $mergedName);
$this->step('MERGE-09', $cleanOk && $srcGone && $mergedGone, 'ticket_id=' . $ticketId);
}
} catch (\Throwable $e) {
CLI::error('Unhandled: ' . $e->getMessage());
$this->fail++;
$this->cleanup($storage, $uploadDir, $srcNames, $mergedName, $ticketId, $sourceIds, $keep, $mergedId ? [(int) $mergedId] : []);
}
$this->printResult();
return $this->fail > 0 ? EXIT_ERROR : EXIT_SUCCESS;
}
private function makeOnePagePdf(string $uploadDir, string $fileName, string $text): ?string
{
$tempDir = rtrim(WRITEPATH, '/\\') . DIRECTORY_SEPARATOR . 'cache' . DIRECTORY_SEPARATOR . 'mpdf';
if (! is_dir($tempDir)) {
@mkdir($tempDir, 0775, true);
}
$path = $uploadDir . $fileName;
try {
$mpdf = new Mpdf(['tempDir' => $tempDir, 'mode' => 'utf-8']);
$mpdf->WriteHTML('<h1>' . htmlspecialchars($text, ENT_QUOTES, 'UTF-8') . '</h1><p>storage merge smoke</p>');
$mpdf->Output($path, Destination::FILE);
return is_file($path) ? $path : null;
} catch (\Throwable $e) {
CLI::error('PDF create failed: ' . $e->getMessage());
return null;
}
}
/** @return list<string> */
private function listClaimRuntimeFiles(): array
{
$dir = rtrim(WRITEPATH, '/\\') . DIRECTORY_SEPARATOR
. 'cache' . DIRECTORY_SEPARATOR
. 'claim_files_runtime' . DIRECTORY_SEPARATOR;
if (! is_dir($dir)) {
return [];
}
$out = [];
foreach (scandir($dir) ?: [] as $f) {
if ($f === '.' || $f === '..') {
continue;
}
if (is_file($dir . $f)) {
$out[] = $f;
}
}
return $out;
}
/**
* @param list<string> $srcNames
* @param list<int> $sourceIds
* @param list<int> $extraIds
*/
private function cleanup(
$storage,
string $uploadDir,
array $srcNames,
?string $mergedName,
int $ticketId,
array $sourceIds,
bool $keep,
array $extraIds = []
): bool {
if ($keep) {
return true;
}
$ok = true;
$dir = rtrim($uploadDir, '/\\');
foreach ($srcNames as $name) {
if ($storage->exists($dir, $name)) {
$del = $storage->delete($dir, $name);
if (! ($del['success'] ?? false)) {
$ok = false;
}
}
@unlink($uploadDir . $name);
}
if ($mergedName) {
if ($storage->exists($dir, $mergedName)) {
$del = $storage->delete($dir, $mergedName);
if (! ($del['success'] ?? false)) {
$ok = false;
}
}
@unlink($uploadDir . $mergedName);
}
try {
$claimFiles = new ClaimFilesModel();
$ids = array_values(array_unique(array_merge($sourceIds, $extraIds)));
if ($ids !== []) {
$claimFiles->whereIn('id', $ids)->set(['is_active' => 0])->update();
}
$claimFiles->where('ticket_id', $ticketId)->set(['is_active' => 0])->update();
} catch (\Throwable $e) {
CLI::write('DB cleanup warning: ' . $e->getMessage(), 'yellow');
$ok = false;
}
return $ok;
}
private function step(string $id, bool $ok, string $detail = ''): void
{
$title = $this->titleFor($id);
if ($ok) {
$this->pass++;
CLI::write("PASS {$id} {$title}" . ($detail !== '' ? "{$detail}" : ''), 'green');
} else {
$this->fail++;
CLI::write("FAIL {$id} {$title}" . ($detail !== '' ? "{$detail}" : ''), 'red');
}
}
private function skip(string $id, string $reason): void
{
$this->skip++;
CLI::write("SKIP {$id} {$this->titleFor($id)}{$reason}", 'yellow');
}
private function titleFor(string $id): string
{
foreach ($this->catalog as $row) {
if ($row['id'] === $id) {
return $row['title'];
}
}
return $id;
}
private function printResult(): void
{
CLI::newLine();
CLI::write(
sprintf('MERGE RESULT: %d passed | %d failed | %d skipped', $this->pass, $this->fail, $this->skip),
$this->fail === 0 ? 'green' : 'red'
);
}
}

View File

@ -0,0 +1,189 @@
<?php
namespace App\Commands;
use CodeIgniter\CLI\BaseCommand;
use CodeIgniter\CLI\CLI;
/**
* Purge objects under an S3 prefix that matches a storage module folder
* (e.g. claim_files keys claim_files/* in AWS_FILE_UPLOAD_BUCKET).
*
* Usage:
* php spark storage:purge-s3 --module claim_files
* php spark storage:purge-s3 --module claim_files --execute
* php spark storage:purge-s3 --module claim_files,excel --limit 100 --execute
*/
class StoragePurgeS3 extends BaseCommand
{
protected $group = 'Storage';
protected $name = 'storage:purge-s3';
protected $description = 'List/delete S3 objects under a module prefix (dry-run by default).';
protected $usage = 'storage:purge-s3 --module <folder>[,folder...] [--limit 0] [--offset 0] [--execute] [--list-modules]';
protected $options = [
'--module' => 'Required. Module folder name(s), comma-separated (e.g. claim_files).',
'--limit' => 'Max objects to delete per module (0 = all, default: 0).',
'--offset' => 'Skip first N keys per module (default: 0).',
'--execute' => 'Actually delete. Without this flag, dry-run only.',
'--list-modules' => 'List known local upload module folder names and exit.',
];
public function run(array $params)
{
if (CLI::getOption('list-modules') !== null) {
$this->printKnownModules();
return EXIT_SUCCESS;
}
$moduleOpt = trim((string) (CLI::getOption('module') ?? ($params[0] ?? '')));
if ($moduleOpt === '') {
CLI::error('Missing --module. Example: php spark storage:purge-s3 --module claim_files');
CLI::write('Tip: php spark storage:purge-s3 --list-modules');
return EXIT_ERROR;
}
$execute = CLI::getOption('execute') !== null;
$dryRun = ! $execute;
$limit = max(0, (int) (CLI::getOption('limit') ?? 0));
$offset = max(0, (int) (CLI::getOption('offset') ?? 0));
$modules = $this->parseModules($moduleOpt);
if ($modules === []) {
CLI::error('No valid module names after parsing. Use basename-only folder names (no path).');
return EXIT_ERROR;
}
$storage = \Config\Services::getFileStorageService(false);
if (! $storage->usesS3()) {
CLI::error('FileStorageService is not in S3 mode. Set FILE_STORAGE_DRIVER=s3 and AWS_FILE_UPLOAD_BUCKET.');
return EXIT_ERROR;
}
$s3 = \Config\Services::getS3Service(false);
$bucket = $storage->getBucket();
CLI::write($dryRun ? 'Running in DRY-RUN mode (no deletes).' : 'Running in EXECUTE mode (deletes enabled).', 'yellow');
CLI::write('Bucket: ' . ($bucket ?? 'N/A'), 'cyan');
CLI::write('Modules: ' . implode(', ', $modules));
CLI::newLine();
$totals = [
'listed' => 0,
'deleted' => 0,
'failed' => 0,
];
foreach ($modules as $module) {
$prefix = $module . '/';
CLI::write("Module: {$module}", 'green');
CLI::write(" Prefix: {$prefix}");
$listed = $s3->listFiles($prefix, $bucket);
if (! ($listed['success'] ?? false)) {
CLI::error(' List failed: ' . ($listed['message'] ?? 'unknown'));
$totals['failed']++;
CLI::newLine();
continue;
}
$keys = [];
foreach ($listed['files'] ?? [] as $file) {
$key = (string) ($file['key'] ?? '');
if ($key === '' || substr($key, -1) === '/') {
continue; // skip empty / folder markers
}
$keys[] = $key;
}
sort($keys);
$batch = array_slice($keys, $offset, $limit > 0 ? $limit : null);
CLI::write(' Objects under prefix: ' . count($keys));
CLI::write(' In this batch: ' . count($batch));
if ($batch === []) {
CLI::write(' Nothing to purge.', 'yellow');
CLI::newLine();
continue;
}
foreach ($batch as $key) {
$totals['listed']++;
if ($dryRun) {
CLI::write(" - [dry-run] Would delete: {$key}");
continue;
}
$result = $s3->delete($key, $bucket);
if ($result['success'] ?? false) {
$totals['deleted']++;
CLI::write(" - Deleted: {$key}", 'green');
} else {
$totals['failed']++;
CLI::write(' - Failed: ' . $key . ' | ' . ($result['message'] ?? ''), 'red');
}
}
CLI::newLine();
}
CLI::write('Purge summary', 'cyan');
CLI::write(' Listed (batch): ' . $totals['listed']);
CLI::write(' Deleted: ' . $totals['deleted'], $totals['deleted'] > 0 ? 'green' : 'white');
CLI::write(' Failed: ' . $totals['failed'], $totals['failed'] > 0 ? 'red' : 'white');
if ($dryRun) {
CLI::newLine();
CLI::write('Dry-run complete. Re-run with --execute to delete these objects.', 'yellow');
}
return $totals['failed'] > 0 ? EXIT_ERROR : EXIT_SUCCESS;
}
/**
* @return list<string>
*/
private function parseModules(string $moduleOpt): array
{
$raw = array_filter(array_map('trim', explode(',', strtolower($moduleOpt))));
$out = [];
foreach ($raw as $module) {
$module = basename(str_replace('\\', '/', $module));
if ($module === '' || $module === '.' || $module === '..') {
continue;
}
if (strpos($module, '/') !== false || preg_match('/[^a-z0-9_\-]/i', $module)) {
CLI::write(" Skipping invalid module name: {$module}", 'yellow');
continue;
}
$out[] = $module;
}
return array_values(array_unique($out));
}
private function printKnownModules(): void
{
$uploadRoot = rtrim(WRITEPATH, '/\\') . DIRECTORY_SEPARATOR . 'uploads';
CLI::write('Known local upload folders (S3 prefix = folder name):', 'cyan');
$entries = @scandir($uploadRoot);
if (! is_array($entries)) {
CLI::write(' (uploads root missing)');
return;
}
$names = [];
foreach ($entries as $entry) {
if ($entry === '.' || $entry === '..') {
continue;
}
if (is_dir($uploadRoot . DIRECTORY_SEPARATOR . $entry)) {
$names[] = $entry;
}
}
sort($names);
foreach ($names as $name) {
CLI::write(' ' . $name);
}
CLI::newLine();
CLI::write('Example: php spark storage:purge-s3 --module claim_files');
}
}

View File

@ -0,0 +1,514 @@
<?php
namespace App\Commands;
use CodeIgniter\CLI\BaseCommand;
use CodeIgniter\CLI\CLI;
/**
* Runs ALL automatable S3/storage scenarios in one command.
*
* Usage:
* php spark storage:smoke-test
* php spark storage:smoke-test --module excel
* php spark storage:smoke-test --list # list all scenarios without running
*/
class StorageSmokeTest extends BaseCommand
{
protected $group = 'Storage';
protected $name = 'storage:smoke-test';
protected $description = 'Run every automatable storage scenario (all modules) and list remaining manual ones.';
protected $usage = 'storage:smoke-test [--module all|excel|claim_files|...] [--list]';
protected $options = [
'--module' => 'One folder name, or all (default: all wired folders).',
'--list' => 'List every scenario ID without executing.',
];
private int $pass = 0;
private int $fail = 0;
private int $skip = 0;
/** @var list<array{id:string,title:string,group:string}> */
private array $catalog = [];
/** @var list<string> */
private array $wiredModules = [
'claim_files',
'client_kyc_documents',
'excel',
'import_excel',
'lead_files',
'attachments',
'claim_dump_excel',
'claims_mis',
'claims_dump',
'statements',
'bds_dump_excel',
'hr_files',
'non_eb_asset_files',
'non_eb_rack_rate',
];
public function run(array $params)
{
helper('utility');
$this->buildCatalog();
if (CLI::getOption('list') !== null) {
$this->printCatalog();
return EXIT_SUCCESS;
}
$storage = \Config\Services::getFileStorageService(false);
$moduleOpt = strtolower((string) (CLI::getOption('module') ?? 'all'));
$modules = $moduleOpt === 'all' || $moduleOpt === ''
? $this->wiredModules
: [basename($moduleOpt)];
CLI::write('========== STORAGE FULL SCENARIO RUN ==========', 'cyan');
CLI::write('usesS3: ' . ($storage->usesS3() ? 'YES' : 'NO'));
CLI::write('Bucket: ' . ($storage->getBucket() ?? 'N/A'));
CLI::write('RETAIN_LOCAL: ' . (storage_env_retain_local() ? 'true' : 'false'));
CLI::write('Modules: ' . implode(', ', $modules));
CLI::write('Total catalog scenarios: ' . count($this->catalog));
CLI::newLine();
// ENV / helper checks
$this->runEnvScenarios($storage);
// Per-module full lifecycle for every wired folder
foreach ($modules as $mod) {
$this->runModuleLifecycle($storage, $mod);
}
// Cross-cutting claim / mail / mirror / soft-delete
$this->runClaimScenarios($storage);
$this->runMailScenarios($storage);
$this->runMirrorScenario($storage);
$this->runRetainLocalSimulation($storage);
$this->runClaimsDumpResolve($storage);
CLI::newLine();
CLI::write(
sprintf('RESULT: %d passed | %d failed | %d skipped', $this->pass, $this->fail, $this->skip),
$this->fail === 0 ? 'green' : 'red'
);
CLI::newLine();
$this->printManualOnlyRemaining();
return $this->fail > 0 ? EXIT_ERROR : EXIT_SUCCESS;
}
private function buildCatalog(): void
{
$this->catalog = [
['id' => 'ENV-01', 'group' => 'ENV', 'title' => 'FILE_STORAGE / bucket / RETAIN_LOCAL readable'],
['id' => 'ENV-02', 'group' => 'ENV', 'title' => 'Runtime temp dirs writable'],
['id' => 'ENV-03', 'group' => 'ENV', 'title' => 'usesS3 matches FILE_STORAGE_DRIVER'],
];
foreach ($this->wiredModules as $mod) {
$this->catalog[] = ['id' => "MOD-{$mod}-01", 'group' => "MODULE:{$mod}", 'title' => 'Upload to S3/local'];
$this->catalog[] = ['id' => "MOD-{$mod}-02", 'group' => "MODULE:{$mod}", 'title' => 'Exists after upload'];
$this->catalog[] = ['id' => "MOD-{$mod}-03", 'group' => "MODULE:{$mod}", 'title' => 'Download content'];
$this->catalog[] = ['id' => "MOD-{$mod}-04", 'group' => "MODULE:{$mod}", 'title' => 'ensure_local from storage'];
$this->catalog[] = ['id' => "MOD-{$mod}-05", 'group' => "MODULE:{$mod}", 'title' => 'No permanent local when RETAIN_LOCAL=false (S3)'];
$this->catalog[] = ['id' => "MOD-{$mod}-06", 'group' => "MODULE:{$mod}", 'title' => 'Delete removes object'];
$this->catalog[] = ['id' => "MOD-{$mod}-07", 'group' => "MODULE:{$mod}", 'title' => 'Presigned URL (S3 only)'];
}
$extra = [
['id' => 'CLAIM-01', 'group' => 'CLAIM', 'title' => 'resolve_claim_file_path'],
['id' => 'CLAIM-02', 'group' => 'CLAIM', 'title' => 'claim_file_download_url (TPA)'],
['id' => 'CLAIM-03', 'group' => 'CLAIM', 'title' => 'soft_delete cleans S3 when unused (DB)'],
['id' => 'MERGE-PDF', 'group' => 'CLAIM', 'title' => 'Dedicated PDF merge suite — php spark storage:smoke-test-merge-pdf'],
['id' => 'MAIL-01', 'group' => 'MAIL', 'title' => 'resolve_mail_attachment_path'],
['id' => 'GEN-01', 'group' => 'GENERATED', 'title' => 'mirror_generated_file then local gone'],
['id' => 'RETAIN-01', 'group' => 'RETAIN_LOCAL', 'title' => 'Simulate retain=false (S3-only)'],
['id' => 'RETAIN-02', 'group' => 'RETAIN_LOCAL', 'title' => 'Simulate retain=true (dual-write keep local)'],
['id' => 'DUMP-01', 'group' => 'CLAIMS_DUMP', 'title' => 'resolveDumpLocalPath / ensure_local'],
];
foreach ($extra as $row) {
$this->catalog[] = $row;
}
}
private function printCatalog(): void
{
CLI::write('========== ALL SCENARIO TEST CASES ==========', 'cyan');
$current = '';
foreach ($this->catalog as $row) {
if ($row['group'] !== $current) {
$current = $row['group'];
CLI::newLine();
CLI::write("--- {$current} ---", 'yellow');
}
CLI::write(" {$row['id']} {$row['title']}");
}
CLI::newLine();
CLI::write('Manual-only (UI/TPA jobs — run by human after automated):', 'yellow');
foreach ($this->manualScenarioLines() as $line) {
CLI::write(' ' . $line);
}
CLI::newLine();
CLI::write('Run all automated: php spark storage:smoke-test');
}
private function step(string $id, bool $ok, string $detail = ''): void
{
$title = $this->titleFor($id);
if ($ok) {
$this->pass++;
CLI::write("[PASS] {$id} {$title}" . ($detail !== '' ? "{$detail}" : ''), 'green');
} else {
$this->fail++;
CLI::write("[FAIL] {$id} {$title}" . ($detail !== '' ? "{$detail}" : ''), 'red');
}
}
private function skip(string $id, string $reason): void
{
$this->skip++;
CLI::write("[SKIP] {$id} {$this->titleFor($id)}{$reason}", 'yellow');
}
private function titleFor(string $id): string
{
foreach ($this->catalog as $row) {
if ($row['id'] === $id) {
return $row['title'];
}
}
return $id;
}
private function uploadPath(string $mod): string
{
return rtrim(WRITEPATH, '/\\') . DIRECTORY_SEPARATOR . 'uploads' . DIRECTORY_SEPARATOR . $mod;
}
private function makeTmp(string $name, string $body): string
{
$dir = storage_runtime_temp_dir();
if (! is_dir($dir)) {
mkdir($dir, 0755, true);
}
$path = $dir . DIRECTORY_SEPARATOR . $name;
file_put_contents($path, $body);
return $path;
}
private function runEnvScenarios($storage): void
{
CLI::write('--- ENV ---', 'white');
$driver = strtolower((string) (getenv('FILE_STORAGE_DRIVER') ?: env('FILE_STORAGE_DRIVER') ?: ''));
$bucket = (string) (getenv('AWS_FILE_UPLOAD_BUCKET') ?: getenv('AWS_BUCKET') ?: '');
$this->step('ENV-01', true, "driver=" . ($driver !== '' ? $driver : 'default') . ", retain=" . (storage_env_retain_local() ? '1' : '0') . ", bucket=" . ($bucket !== '' ? 'set' : 'empty'));
$runtime = storage_runtime_temp_dir();
$claimRt = rtrim(WRITEPATH, '/\\') . '/cache/claim_files_runtime';
foreach ([$runtime, $claimRt] as $d) {
if (! is_dir($d)) {
@mkdir($d, 0755, true);
}
}
$probe = $runtime . DIRECTORY_SEPARATOR . 'probe_' . uniqid('', true) . '.txt';
$wrote = @file_put_contents($probe, 'ok') !== false;
if ($wrote) {
@unlink($probe);
}
$this->step('ENV-02', $wrote && is_dir($runtime));
if ($driver === 'local') {
$this->step('ENV-03', ! $storage->usesS3(), 'local driver => usesS3 false');
} elseif ($driver === 's3' || $driver === '') {
$this->step('ENV-03', $storage->usesS3(), 's3 driver => usesS3 true (bucket required)');
} else {
$this->skip('ENV-03', 'unknown FILE_STORAGE_DRIVER=' . $driver);
}
}
private function runModuleLifecycle($storage, string $mod): void
{
CLI::write("--- MODULE: {$mod} ---", 'white');
$path = $this->uploadPath($mod);
$fileName = 'smoke_' . $mod . '_' . date('Ymd_His') . '_' . bin2hex(random_bytes(2)) . '.txt';
$tmp = $this->makeTmp($fileName, "smoke-{$mod}\n" . date('c') . "\n");
$up = $storage->upload($tmp, $path, $fileName);
@unlink($tmp);
$this->step("MOD-{$mod}-01", (bool) ($up['success'] ?? false), (string) ($up['message'] ?? ''));
if (! ($up['success'] ?? false)) {
// Skip rest of module if upload failed
foreach (['02', '03', '04', '05', '06', '07'] as $n) {
$this->skip("MOD-{$mod}-{$n}", 'upload failed');
}
return;
}
$this->step("MOD-{$mod}-02", $storage->exists($path, $fileName));
$dl = $storage->download($path, $fileName);
$contentOk = ($dl['success'] ?? false) && (
((! empty($dl['content'])) && str_contains((string) $dl['content'], "smoke-{$mod}"))
|| ((! empty($dl['path'])) && is_file((string) $dl['path'])
&& str_contains((string) file_get_contents((string) $dl['path']), "smoke-{$mod}"))
);
$this->step("MOD-{$mod}-03", $contentOk, (string) ($dl['message'] ?? ''));
// Force missing permanent local then ensure_local
$permanent = $storage->resolveLocalPath($path, $fileName);
if (is_file($permanent)) {
@unlink($permanent);
}
$ensured = storage_ensure_local_file($path, $fileName);
$this->step(
"MOD-{$mod}-04",
is_string($ensured) && is_file($ensured) && str_contains((string) file_get_contents($ensured), "smoke-{$mod}"),
$ensured ? basename($ensured) : 'null'
);
if ($ensured) {
storage_cleanup_temp_file($ensured);
}
if ($storage->usesS3() && ! storage_env_retain_local()) {
$this->step("MOD-{$mod}-05", ! is_file($permanent), 'permanent path absent');
} else {
$this->skip("MOD-{$mod}-05", $storage->usesS3() ? 'RETAIN_LOCAL=true' : 'local driver');
}
$del = $storage->delete($path, $fileName);
$this->step("MOD-{$mod}-06", (bool) ($del['success'] ?? false) && ! $storage->exists($path, $fileName));
if ($storage->usesS3()) {
$tmp = $this->makeTmp($fileName, "presign-{$mod}\n");
$storage->upload($tmp, $path, $fileName);
@unlink($tmp);
$pre = $storage->getPresignedUrl($path, $fileName, 5);
$this->step("MOD-{$mod}-07", (bool) ($pre['success'] ?? false) && ! empty($pre['url']));
$storage->delete($path, $fileName);
} else {
$this->skip("MOD-{$mod}-07", 'local driver');
}
}
private function runClaimScenarios($storage): void
{
CLI::write('--- CLAIM ---', 'white');
$claimDir = $this->uploadPath('claim_files');
$fileName = 'smoke_claim_' . date('Ymd_His') . '_' . bin2hex(random_bytes(2)) . '.pdf';
$tmp = $this->makeTmp($fileName, "%PDF-1.4 smoke-claim\n");
$up = $storage->upload($tmp, $claimDir, $fileName);
@unlink($tmp);
if (! ($up['success'] ?? false)) {
$this->skip('CLAIM-01', 'upload claim sample failed');
$this->skip('CLAIM-02', 'upload claim sample failed');
$this->skip('CLAIM-03', 'upload claim sample failed');
return;
}
// Ensure no permanent leftover interferes
$permanent = $storage->resolveLocalPath($claimDir, $fileName);
if (is_file($permanent)) {
@unlink($permanent);
}
$resolved = storage_resolve_claim_file_path($claimDir, $fileName);
$this->step(
'CLAIM-01',
(bool) ($resolved['success'] ?? false) && ! empty($resolved['path']) && is_file((string) $resolved['path']),
(string) ($resolved['message'] ?? '')
);
storage_cleanup_temp_claim_file($resolved);
if ($storage->usesS3()) {
$url = storage_claim_file_download_url($fileName, null, 10);
$this->step('CLAIM-02', is_string($url) && str_starts_with($url, 'http'));
} else {
$this->skip('CLAIM-02', 'local driver');
}
// Soft-delete: insert temp claim_files row, soft delete, expect S3 gone
try {
$db = \Config\Database::connect();
$insert = [
'ticket_master_id' => 0,
'file_name' => $fileName,
'url' => $fileName,
'doc_name' => 'smoke-test',
'file_type' => 2,
'is_active' => 1,
'created_at' => date('Y-m-d H:i:s'),
];
// Only use columns that exist
$fields = $db->getFieldNames('claim_files');
$row = [];
foreach ($insert as $k => $v) {
if (in_array($k, $fields, true)) {
$row[$k] = $v;
}
}
$db->table('claim_files')->insert($row);
$id = (int) $db->insertID();
$ok = $id > 0 && storage_soft_delete_claim_file($id);
$gone = ! $storage->exists($claimDir, $fileName);
$this->step('CLAIM-03', $ok && $gone, 'id=' . $id);
// Hard cleanup leftover row
if ($id > 0) {
$db->table('claim_files')->where('id', $id)->delete();
}
} catch (\Throwable $e) {
$this->skip('CLAIM-03', 'DB soft-delete unavailable: ' . $e->getMessage());
$storage->delete($claimDir, $fileName);
}
}
private function runMailScenarios($storage): void
{
CLI::write('--- MAIL ---', 'white');
$dir = $this->uploadPath('attachments');
$fileName = 'smoke_mail_' . date('Ymd_His') . '_' . bin2hex(random_bytes(2)) . '.txt';
$tmp = $this->makeTmp($fileName, "mail\n");
$up = $storage->upload($tmp, $dir, $fileName);
@unlink($tmp);
if (! ($up['success'] ?? false)) {
$this->step('MAIL-01', false, (string) ($up['message'] ?? ''));
return;
}
$permanent = $storage->resolveLocalPath($dir, $fileName);
if (is_file($permanent)) {
@unlink($permanent);
}
$resolved = storage_resolve_mail_attachment_path('uploads/attachments/' . $fileName, $fileName);
$this->step(
'MAIL-01',
(bool) ($resolved['success'] ?? false) && ! empty($resolved['path']) && is_file((string) $resolved['path'])
);
if (! empty($resolved['path'])) {
storage_cleanup_temp_file((string) $resolved['path']);
}
$storage->delete($dir, $fileName);
}
private function runMirrorScenario($storage): void
{
CLI::write('--- GENERATED ---', 'white');
$dir = $this->uploadPath('excel');
$fileName = 'smoke_gen_' . date('Ymd_His') . '_' . bin2hex(random_bytes(2)) . '.txt';
$local = $this->makeTmp($fileName, "generated\n");
$ok = storage_mirror_generated_file($local, $dir, $fileName);
if ($storage->usesS3()) {
$this->step('GEN-01', $ok && ! is_file($local) && $storage->exists($dir, $fileName));
$storage->delete($dir, $fileName);
} else {
$this->step('GEN-01', $ok && is_file($local));
@unlink($local);
}
}
private function runRetainLocalSimulation($storage): void
{
CLI::write('--- RETAIN_LOCAL simulation ---', 'white');
if (! $storage->usesS3()) {
$this->skip('RETAIN-01', 'local driver');
$this->skip('RETAIN-02', 'local driver');
return;
}
$dir = $this->uploadPath('excel');
// retain=false behaviour: upload via temp then unlink (current default path)
$f1 = 'smoke_retain_off_' . bin2hex(random_bytes(2)) . '.txt';
$t1 = $this->makeTmp($f1, "off\n");
$storage->upload($t1, $dir, $f1);
@unlink($t1);
$p1 = $storage->resolveLocalPath($dir, $f1);
$this->step('RETAIN-01', ! is_file($p1) && $storage->exists($dir, $f1));
$storage->delete($dir, $f1);
// retain=true behaviour: keep local file after S3 upload
$f2 = 'smoke_retain_on_' . bin2hex(random_bytes(2)) . '.txt';
// Use runtime path as the "kept local" copy (CLI may lack write perms under uploads/)
$p2 = $this->makeTmp($f2, "on\n");
$up2 = $storage->upload($p2, $dir, $f2);
$this->step(
'RETAIN-02',
(bool) ($up2['success'] ?? false) && is_file($p2) && $storage->exists($dir, $f2),
'local kept + S3'
);
@unlink($p2);
$storage->delete($dir, $f2);
}
private function runClaimsDumpResolve($storage): void
{
CLI::write('--- CLAIMS_DUMP ---', 'white');
$dir = $this->uploadPath('claims_dump');
$fileName = 'smoke_cdump_' . date('Ymd_His') . '_' . bin2hex(random_bytes(2)) . '.xlsx';
$tmp = $this->makeTmp($fileName, "claims-dump\n");
$up = $storage->upload($tmp, $dir, $fileName);
@unlink($tmp);
if (! ($up['success'] ?? false)) {
$this->step('DUMP-01', false, (string) ($up['message'] ?? ''));
return;
}
$permanent = $storage->resolveLocalPath($dir, $fileName);
if (is_file($permanent)) {
@unlink($permanent);
}
$resolved = storage_ensure_local_file($dir, $fileName);
$this->step('DUMP-01', is_string($resolved) && is_file($resolved));
if ($resolved) {
storage_cleanup_temp_file($resolved);
}
$storage->delete($dir, $fileName);
}
/** @return list<string> */
private function manualScenarioLines(): array
{
return [
'UI-KYC-01 Upload KYC in browser',
'UI-KYC-02 Download download-kyc-docs/{id}',
'UI-KYC-03 Re-upload / delete KYC',
'UI-PT-01 Upload PT doc + download-pt-docs/{id}',
'UI-PT-02 REST downloadPolicyFiles',
'UI-CLAIM-01 Upload claim file in ticket UI',
'UI-CLAIM-02 downloadClaimFile / viewClaimFile',
'UI-CLAIM-03 Remove claim file in UI',
'UI-CLAIM-04 Merge PDFs in UI (core automated: php spark storage:smoke-test-merge-pdf)',
'UI-TPA-01 FHPL claim submit (base64)',
'UI-TPA-02 Vidal claim submit (base64)',
'UI-TPA-03 HealthIndia claim submit',
'UI-TPA-04 MediAssist uses presigned URL',
'UI-TPA-05 Volo uses presigned URL',
'UI-EMP-01 Employee excel upload + background job',
'UI-EMP-02 download-file-list / download_import_file',
'UI-EMP-03 HR upload + hrFileDownload',
'UI-LEAD-01 Lead member upload + demography job',
'UI-LEAD-02 downloadMemberFile / error excel',
'UI-DUMP-01 Claim dump / MIS / statements / BDS UI jobs',
'UI-MAIL-01 Compose mail with attachment send',
'UI-NEB-01 Non-EB asset + rack rate UI',
'UI-NEG-01 Invalid extension rejected in UI',
'UI-NEG-02 Toggle FILE_STORAGE_DRIVER=local and retest one upload',
'UI-NEG-03 Toggle RETAIN_LOCAL=true/false and retest one upload',
];
}
private function printManualOnlyRemaining(): void
{
CLI::write('========== MANUAL UI / TPA / JOB (not auto-runnable) ==========', 'yellow');
CLI::write('These need browser login / real TPA — tick after you test:');
foreach ($this->manualScenarioLines() as $i => $line) {
CLI::write(sprintf(' [ ] %s', $line));
}
CLI::newLine();
CLI::write('Commands:');
CLI::write(' php spark storage:smoke-test # run ALL automated scenarios');
CLI::write(' php spark storage:smoke-test --list # list every scenario ID');
CLI::write(' php spark storage:smoke-test --module claim_files');
}
}

View File

@ -90,6 +90,7 @@ $routes->get('/auth/google', 'LoginController::initiateGoogleOAuth');
$routes->get('/update-emp-policy-status', 'ClientController::updateEmpAndPolicyStatus'); $routes->get('/update-emp-policy-status', 'ClientController::updateEmpAndPolicyStatus');
$routes->get('download-e-card/(:any)', 'EmployeeController::generateIDCardForEmployee/$1'); $routes->get('download-e-card/(:any)', 'EmployeeController::generateIDCardForEmployee/$1');
$routes->get('download-kyc-docs/(:segment)', 'ClientController::downloadKYCDocument/$1'); $routes->get('download-kyc-docs/(:segment)', 'ClientController::downloadKYCDocument/$1');
$routes->get('download-pt-docs/(:segment)', 'PolicyTransactionController::downloadPtDocument/$1');
$routes->get('claim-form-download/(:any)', 'TicketController::downloadClaimForm/$1'); $routes->get('claim-form-download/(:any)', 'TicketController::downloadClaimForm/$1');
$routes->get('downloadClaimFile/(:any)', 'TicketController::downloadClaimFile/$1'); $routes->get('downloadClaimFile/(:any)', 'TicketController::downloadClaimFile/$1');
$routes->get('viewClaimFile/(:any)', 'TicketController::viewClaimFile/$1'); $routes->get('viewClaimFile/(:any)', 'TicketController::viewClaimFile/$1');
@ -446,6 +447,8 @@ $routes->group("/util", ["filter" => "authMVC"], function ($routes) {
$routes->get('getClaimDumpFileErrorData', 'TicketController::getClaimDumpFileErrorData'); $routes->get('getClaimDumpFileErrorData', 'TicketController::getClaimDumpFileErrorData');
$routes->get("claim_dump_excel_error/(:any)", "TicketController::getClaimDumpExcelFileErrors/$1"); $routes->get("claim_dump_excel_error/(:any)", "TicketController::getClaimDumpExcelFileErrors/$1");
$routes->get("download_claim_dump_file/(:any)", "TicketController::downloadClaimDumpFile/$1"); $routes->get("download_claim_dump_file/(:any)", "TicketController::downloadClaimDumpFile/$1");
$routes->post('claims-dump/upload', 'ClaimsUploadController::uploadDump');
$routes->get('claims-dump/download/(:num)', 'ClaimsUploadController::downloadDump/$1');
$routes->match(['get', 'post'], 'truncateClaimDumpFile', 'TicketController::truncateClaimDumpFile'); $routes->match(['get', 'post'], 'truncateClaimDumpFile', 'TicketController::truncateClaimDumpFile');
$routes->match(['get', 'post'], 'reprocessClaimDumpPending', 'TicketController::reprocessClaimDumpPending'); $routes->match(['get', 'post'], 'reprocessClaimDumpPending', 'TicketController::reprocessClaimDumpPending');
$routes->match(['get', 'post'], 'getClaimDumpPendingRows', 'TicketController::getClaimDumpPendingRows'); $routes->match(['get', 'post'], 'getClaimDumpPendingRows', 'TicketController::getClaimDumpPendingRows');

View File

@ -10,6 +10,7 @@ use App\Libraries\MyGoogleDrive;
use App\Libraries\RuleImportService; use App\Libraries\RuleImportService;
use App\Libraries\DataServiceSqlite; use App\Libraries\DataServiceSqlite;
use App\Libraries\S3Service; use App\Libraries\S3Service;
use App\Libraries\FileStorageService;
use App\Controllers\Home; use App\Controllers\Home;
/** /**
@ -101,4 +102,13 @@ class Services extends BaseService
return new S3Service(); return new S3Service();
} }
public static function getFileStorageService($getShared = true)
{
if ($getShared) {
return static::getSharedInstance('getFileStorageService');
}
return new FileStorageService();
}
} }

View File

@ -142,7 +142,7 @@ class NonEbClaimApiController extends BaseController
return null; return null;
} }
$uploadPath = WRITEPATH . 'uploads/non_eb_asset_files/'; $uploadPath = WRITEPATH . 'uploads/non_eb_asset_files/';
$fileName = file_Upload($file, $uploadPath, UPLOAD_EXT_ASSET_FILES); $fileName = storage_file_Upload($file, $uploadPath, UPLOAD_EXT_ASSET_FILES);
return !empty($fileName) ? $fileName : null; return !empty($fileName) ? $fileName : null;
} }
@ -323,7 +323,7 @@ class NonEbClaimApiController extends BaseController
} }
$uploadPath = WRITEPATH . 'uploads/non_eb_asset_files/'; $uploadPath = WRITEPATH . 'uploads/non_eb_asset_files/';
$assetFileName = file_Upload($assetFile, $uploadPath, $allowed); $assetFileName = storage_file_Upload($assetFile, $uploadPath, $allowed);
if (empty($assetFileName)) { if (empty($assetFileName)) {
return $this->respond(['status' => false, 'code' => 500, 'message' => 'Asset file upload failed'], 500); return $this->respond(['status' => false, 'code' => 500, 'message' => 'Asset file upload failed'], 500);
@ -675,7 +675,7 @@ class NonEbClaimApiController extends BaseController
$file_data = []; $file_data = [];
if (!empty($get_file_data)) { if (!empty($get_file_data)) {
$file_path = WRITEPATH . 'uploads/claim_files/'; $file_path = WRITEPATH . 'uploads/claim_files/';
$file_data = multi_file_Upload($get_file_data, $file_path, $get_docs_name, UPLOAD_EXT_CLAIM_DOCS); $file_data = storage_multi_file_Upload($get_file_data, $file_path, $get_docs_name, UPLOAD_EXT_CLAIM_DOCS);
} }
if (!empty($file_data) && !empty($ticket_id)) { if (!empty($file_data) && !empty($ticket_id)) {
@ -775,22 +775,25 @@ class NonEbClaimApiController extends BaseController
$db->transStart(); $db->transStart();
$upload_path = WRITEPATH . 'uploads/claim_files/'; $upload_path = WRITEPATH . 'uploads/claim_files/';
$file_name = file_Upload($file, $upload_path, UPLOAD_EXT_CLAIM_DOCS); $uploaded = storage_claim_file_Upload($file, $upload_path, UPLOAD_EXT_CLAIM_DOCS);
if (empty($file_name)) { if ($uploaded === '') {
$db->transRollback(); $db->transRollback();
return $this->respond(['status' => false, 'code' => 500, 'message' => 'File upload failed'], 500); return $this->respond(['status' => false, 'code' => 500, 'message' => 'File upload failed'], 500);
} }
$disk_name = $uploaded['disk_name'];
$display_name = $uploaded['display_name'];
// Insert into claim_files // Insert into claim_files
$this->claimFilesModel->insert([ $this->claimFilesModel->insert([
'ticket_id' => $claim_id, 'ticket_id' => $claim_id,
'ticket_type' => 2, 'ticket_type' => 2,
'doc_name' => $document_name, 'doc_name' => $document_name,
'file_name' => $file_name, 'file_name' => $display_name,
'url' => $upload_path . $file_name, 'url' => $disk_name,
'file_type' => 2, 'file_type' => 2,
'mime_type' => getMimeTypeByFileName($file_name), 'mime_type' => getMimeTypeByFileName($display_name),
'is_active' => 1, 'is_active' => 1,
'created_by' => self::API_SYSTEM_USER_ID, 'created_by' => self::API_SYSTEM_USER_ID,
]); ]);
@ -811,7 +814,7 @@ class NonEbClaimApiController extends BaseController
$file_id = $this->claimFilesModel->insertID(); $file_id = $this->claimFilesModel->insertID();
$download_url = base_url('downloadClaimFile/') . $file_id; $download_url = base_url('downloadClaimFile/') . $file_id;
$this->myLogger->logme('error', "[NON_EB_API][uploadRequiredDoc] Doc uploaded. claim_id: $claim_id, doc: $document_name, file: $file_name, user: {$authUser['id']}"); $this->myLogger->logme('error', "[NON_EB_API][uploadRequiredDoc] Doc uploaded. claim_id: $claim_id, doc: $document_name, file: $disk_name, user: {$authUser['id']}");
return $this->respond([ return $this->respond([
'status' => true, 'status' => true,

View File

@ -33,23 +33,78 @@ class ClaimsUploadController extends BaseController
], 400); ], 400);
} }
$uploadFile = storage_file_Upload($file, WRITEPATH . 'uploads/claims_dump/', UPLOAD_EXT_EXCEL);
if ($uploadFile === '') {
return $this->respond([
'status' => 'failed',
'message' => 'File upload failed'
], 500);
}
$data = [ $data = [
'client_id' => $this->request->getPost('client_id'), 'client_id' => $this->request->getPost('client_id'),
'tpa_id' => $this->request->getPost('tpa_id'), 'tpa_id' => $this->request->getPost('tpa_id'),
'client_policy_id' => $this->request->getPost('client_policy_id'), 'client_policy_id' => $this->request->getPost('client_policy_id'),
'from_date' => $this->request->getPost('from_date'), 'from_date' => $this->request->getPost('from_date'),
'to_date' => $this->request->getPost('to_date'), 'to_date' => $this->request->getPost('to_date'),
'upload_file' => $file->getRandomName(), 'upload_file' => $uploadFile,
// 'uploaded_by' => user_id() // 'uploaded_by' => user_id()
]; ];
$file->move(WRITEPATH . 'uploads/claims_dump', $data['upload_file']);
$this->db->table('claims_dump_uploads')->insert($data); $this->db->table('claims_dump_uploads')->insert($data);
$insertId = $this->db->insertID();
return $this->respond([ return $this->respond([
'status' => 'success', 'status' => 'success',
'message' => 'Claims dump uploaded' 'message' => 'Claims dump uploaded',
'id' => $insertId,
'upload_file' => $uploadFile,
]); ]);
} }
/**
* Download a claims_dump upload by claims_dump_uploads.id (local or S3).
*/
public function downloadDump($id = null)
{
$id = (int) ($id ?? $this->request->getGet('id'));
if ($id <= 0) {
$data['message'] = 'Invalid file id';
return view('errors/404', $data);
}
$record = $this->db->table('claims_dump_uploads')->where('id', $id)->get()->getRowArray();
if (empty($record) || empty($record['upload_file'])) {
$data['message'] = 'File record not found';
return view('errors/404', $data);
}
$fileName = basename((string) $record['upload_file']);
$storage = \Config\Services::getFileStorageService();
$result = $storage->download(WRITEPATH . 'uploads/claims_dump', $fileName);
if (! ($result['success'] ?? false)) {
$data['message'] = 'The Physical File Not Found';
return view('errors/404', $data);
}
$downloadAs = storage_upload_display_name($fileName);
if (! empty($result['path']) && is_file($result['path'])) {
return $this->response->download($result['path'], null)->setFileName($downloadAs);
}
if (! empty($result['content'])) {
return $this->response->download($downloadAs, $result['content'])->setFileName($downloadAs);
}
$data['message'] = 'The Physical File Not Found';
return view('errors/404', $data);
}
/**
* Resolve claims_dump file to a local path for any processors (local first, else S3).
*/
public function resolveDumpLocalPath(string $fileName): ?string
{
return storage_ensure_local_file(WRITEPATH . 'uploads/claims_dump', $fileName);
}
} }

View File

@ -1311,7 +1311,7 @@ class ClientController extends AdminController
// print_r($data); die; // print_r($data); die;
unset($data['file_name']); unset($data['file_name']);
$uploadFilePath = WRITEPATH . 'uploads/client_kyc_documents'; $uploadFilePath = WRITEPATH . 'uploads/client_kyc_documents';
$File = file_Upload($this->request->getFile('file_name'), $uploadFilePath, UPLOAD_EXT_KYC_DOCS); $File = storage_file_Upload($this->request->getFile('file_name'), $uploadFilePath, UPLOAD_EXT_KYC_DOCS);
if (!empty($File)) { if (!empty($File)) {
$data['file_name'] = $File; $data['file_name'] = $File;
@ -1321,7 +1321,7 @@ class ClientController extends AdminController
} }
$data['created_by'] = get_session_userid(); $data['created_by'] = get_session_userid();
$insert = $this->clientKYCDocsModel->insert($data); $insert = $this->insertPrimaryKycDocument($data);
if ($insert) { if ($insert) {
// $kycDocs = $this->clientKYCDocsModel->where('client_id', $this->request->getPost('client_id'))->findAll(); // $kycDocs = $this->clientKYCDocsModel->where('client_id', $this->request->getPost('client_id'))->findAll();
if ($form_type == "others") { if ($form_type == "others") {
@ -1414,7 +1414,7 @@ class ClientController extends AdminController
} }
foreach ($uploadedFiles as $index => $singleFile) { foreach ($uploadedFiles as $index => $singleFile) {
$fileName = file_Upload_for_lead($singleFile, $uploadFilePath, UPLOAD_EXT_KYC_DOCS); $fileName = storage_file_Upload($singleFile, $uploadFilePath, UPLOAD_EXT_KYC_DOCS);
if (empty($fileName)) { if (empty($fileName)) {
return $this->respond(['status' => false, 'code' => 404, 'message' => 'Failed to upload KYC document'], 200); return $this->respond(['status' => false, 'code' => 404, 'message' => 'Failed to upload KYC document'], 200);
} }
@ -1459,14 +1459,14 @@ class ClientController extends AdminController
} }
$file = $this->request->getFile('file_name'); $file = $this->request->getFile('file_name');
$fileName = file_Upload_for_lead($file, $uploadFilePath, UPLOAD_EXT_KYC_DOCS); $fileName = storage_file_Upload($file, $uploadFilePath, UPLOAD_EXT_KYC_DOCS);
if (!empty($fileName)) { if (!empty($fileName)) {
$sanitized_data['file_name'] = $fileName; $sanitized_data['file_name'] = $fileName;
} }
$sanitized_data['created_by'] = get_session_userid(); $sanitized_data['created_by'] = get_session_userid();
$insertID = $this->clientKYCDocsModel->insert($sanitized_data); $insertID = $this->insertPrimaryKycDocument($sanitized_data);
if ($insertID) { if ($insertID) {
$kycDocs = $this->generateKycPrimaryTable($client_id); $kycDocs = $this->generateKycPrimaryTable($client_id);
@ -1510,7 +1510,7 @@ class ClientController extends AdminController
$file = $this->request->getFile('file_name'); $file = $this->request->getFile('file_name');
$fileName = file_Upload_for_lead($file, $uploadFilePath, UPLOAD_EXT_KYC_DOCS); $fileName = storage_file_Upload($file, $uploadFilePath, UPLOAD_EXT_KYC_DOCS);
if (!empty($fileName)) { if (!empty($fileName)) {
$sanitized_data['file_name'] = $fileName; $sanitized_data['file_name'] = $fileName;
@ -1518,9 +1518,10 @@ class ClientController extends AdminController
$id = $sanitized_data['PrimaryKey']; $id = $sanitized_data['PrimaryKey'];
$sanitized_data['client_id'] = $id; $sanitized_data['client_id'] = $id;
$sanitized_data['kyc_doc_type_id'] = $this->request->getPost('kyc_doc_id'); $sanitized_data['kyc_doc_type_id'] = $this->request->getPost('kyc_doc_id');
$sanitized_data['created_by'] = get_session_userid();
$sanitized_data['updated_by'] = get_session_userid(); $sanitized_data['updated_by'] = get_session_userid();
$insertID = $this->clientKYCDocsModel->insert($sanitized_data); $insertID = $this->insertPrimaryKycDocument($sanitized_data);
if ($insertID) { if ($insertID) {
if ($form_type === 'others') { if ($form_type === 'others') {
$kycDocs = $this->generateKycOthersTable($sanitized_data['client_id']); $kycDocs = $this->generateKycOthersTable($sanitized_data['client_id']);
@ -1536,12 +1537,7 @@ class ClientController extends AdminController
public function deleteClientKycDocs($id = null) public function deleteClientKycDocs($id = null)
{ {
$client_id = $this->request->getGet('client_id'); $client_id = $this->request->getGet('client_id');
$updateData = [ $delete = $this->softDeleteKycDocument((int) $id);
'is_active' => 0,
'updated_by' => get_session_userid()
];
$delete = $this->clientKYCDocsModel->update($id, $updateData);
if ($delete) { if ($delete) {
$response = ['status' => true, 'code' => 200, 'id' => $id]; $response = ['status' => true, 'code' => 200, 'id' => $id];
if (!empty($client_id)) { if (!empty($client_id)) {
@ -1555,12 +1551,7 @@ class ClientController extends AdminController
public function deleteClientKycOtherDocs($id = null) public function deleteClientKycOtherDocs($id = null)
{ {
$client_id = $this->request->getGet('client_id'); $client_id = $this->request->getGet('client_id');
$updateData = [ $delete = $this->softDeleteKycDocument((int) $id);
'is_active' => 0,
'updated_by' => get_session_userid()
];
$delete = $this->clientKYCDocsModel->update($id, $updateData);
if ($delete) { if ($delete) {
$response = ['status' => true, 'code' => 200, 'id' => $id]; $response = ['status' => true, 'code' => 200, 'id' => $id];
if (!empty($client_id)) { if (!empty($client_id)) {
@ -1613,7 +1604,7 @@ class ClientController extends AdminController
$file = $this->request->getFile('file_name'); $file = $this->request->getFile('file_name');
$uploadFilePath = WRITEPATH . 'uploads/client_kyc_documents'; $uploadFilePath = WRITEPATH . 'uploads/client_kyc_documents';
$fileName = file_Upload($file, $uploadFilePath, UPLOAD_EXT_KYC_DOCS); $fileName = storage_file_Upload($file, $uploadFilePath, UPLOAD_EXT_KYC_DOCS);
if (!empty($fileName)) { if (!empty($fileName)) {
$sanitized_data['file_name'] = $fileName; $sanitized_data['file_name'] = $fileName;
@ -1626,7 +1617,14 @@ class ClientController extends AdminController
$this->myLogger->logme('info', 'Result of file_Upload: ' . $fileName); $this->myLogger->logme('info', 'Result of file_Upload: ' . $fileName);
unset($data['file_name']); unset($data['file_name']);
// Primary typed docs: replace previous active upload for same type.
// Additional docs (kyc_doc_type_id empty/0) still allow multiple rows.
$kycDocTypeId = (int) ($sanitized_data['kyc_doc_type_id'] ?? 0);
if ($kycDocTypeId > 0) {
$insertID = $this->insertPrimaryKycDocument($sanitized_data);
} else {
$insertID = $this->clientKYCDocsModel->insert($sanitized_data); $insertID = $this->clientKYCDocsModel->insert($sanitized_data);
}
if ($insertID) { if ($insertID) {
$html = $this->generateKycSingleTable($sanitized_data['client_id']); $html = $this->generateKycSingleTable($sanitized_data['client_id']);
@ -1685,21 +1683,11 @@ class ClientController extends AdminController
if ($uploadedFile && $uploadedFile->isValid() && !$uploadedFile->hasMoved()) { if ($uploadedFile && $uploadedFile->isValid() && !$uploadedFile->hasMoved()) {
$new_file_name = file_Upload($uploadedFile, $uploadFilePath, UPLOAD_EXT_KYC_DOCS); $new_file_name = storage_file_Upload($uploadedFile, $uploadFilePath, UPLOAD_EXT_KYC_DOCS);
if (!$new_file_name) { if (!$new_file_name) {
return $this->respond(['status' => false, 'code' => 500, 'message' => 'New file upload failed on server.'], 200); return $this->respond(['status' => false, 'code' => 500, 'message' => 'New file upload failed on server.'], 200);
} }
$updateData['file_name'] = $new_file_name; $updateData['file_name'] = $new_file_name;
// Delete the old file from the storage if it exists
// if (!empty($old_file_name)) {
// $old_file_path = $uploadFilePath . '/' . $old_file_name;
// if (file_exists($old_file_path)) {
// unlink($old_file_path);
// // Optionally delete from G-Drive here if applicable
// }
// }
} }
if (empty($updateData)) { if (empty($updateData)) {
@ -1711,6 +1699,19 @@ class ClientController extends AdminController
$update = $this->clientKYCDocsModel->update($kyc_id, $updateData); $update = $this->clientKYCDocsModel->update($kyc_id, $updateData);
if ($update) { if ($update) {
// After successful replace, remove previous storage object when unused.
$oldStored = basename((string) $old_file_name);
if ($oldStored !== '' && !empty($new_file_name) && $oldStored !== $new_file_name) {
$stillUsed = $this->clientKYCDocsModel
->where('file_name', $oldStored)
->where('is_active', 1)
->countAllResults();
if ($stillUsed === 0) {
$storage = \Config\Services::getFileStorageService();
$storage->delete($uploadFilePath, $oldStored);
}
}
return $this->respond([ return $this->respond([
'status' => true, 'status' => true,
'message' => 'Document updated successfully', 'message' => 'Document updated successfully',
@ -1736,13 +1737,28 @@ class ClientController extends AdminController
return $this->respond(['status' => false, 'code' => 400, 'message' => 'Missing document ID.'], 200); return $this->respond(['status' => false, 'code' => 400, 'message' => 'Missing document ID.'], 200);
} }
// Soft-delete path (also removes unused storage object)
if ((int) $is_active === 0) {
$delete = $this->softDeleteKycDocument((int) $kyc_id);
if ($delete) {
return $this->respond([
'status' => true,
'code' => 200,
'id' => $kyc_id,
'message' => 'Document successfully deactivated.',
'html' => $this->generateKycSingleTable($client_id),
'dropdown' => $this->fetch_dropdown($client_id)
], 200);
}
return $this->respond(['status' => false, 'code' => 404, 'message' => 'Failed to update record (ID not found or DB error).'], 200);
}
$updateData = [ $updateData = [
'is_active' => (int) $is_active, 'is_active' => (int) $is_active,
'updated_by' => get_session_userid() 'updated_by' => get_session_userid()
]; ];
$delete = $this->clientKYCDocsModel->update($kyc_id, $updateData); $delete = $this->clientKYCDocsModel->update($kyc_id, $updateData);
if ($delete) { if ($delete) {
@ -3364,13 +3380,14 @@ class ClientController extends AdminController
} }
$uploadFilePath = WRITEPATH . 'uploads/non_eb_rack_rate'; $uploadFilePath = WRITEPATH . 'uploads/non_eb_rack_rate';
$fileName = file_Upload($this->request->getFile('file'), $uploadFilePath, UPLOAD_EXT_NON_EB_RACK_RATE); $uploadedFile = $this->request->getFile('file');
$originalName = $uploadedFile ? $uploadedFile->getClientName() : '';
$fileName = storage_file_Upload($uploadedFile, $uploadFilePath, UPLOAD_EXT_NON_EB_RACK_RATE);
if (empty($fileName)) { if (empty($fileName)) {
return $this->respond(['status' => false, 'message' => 'Invalid file. Only PDF and Excel files are allowed.'], 200); return $this->respond(['status' => false, 'message' => 'Invalid file. Only PDF and Excel files are allowed.'], 200);
} }
$originalName = $this->request->getFile('file')->getClientName();
$ext = pathinfo($fileName, PATHINFO_EXTENSION); $ext = pathinfo($fileName, PATHINFO_EXTENSION);
$jsonField = is_array($policy) ? ($policy['non_eb_rack_rate_files'] ?? null) : ($policy->non_eb_rack_rate_files ?? null); $jsonField = is_array($policy) ? ($policy['non_eb_rack_rate_files'] ?? null) : ($policy->non_eb_rack_rate_files ?? null);
@ -3378,7 +3395,7 @@ class ClientController extends AdminController
$fileEntry = [ $fileEntry = [
'name' => $fileName, 'name' => $fileName,
'original_name' => $originalName, 'original_name' => $originalName ?: storage_upload_display_name($fileName),
'type' => $ext, 'type' => $ext,
'uploaded_at' => date('Y-m-d H:i:s'), 'uploaded_at' => date('Y-m-d H:i:s'),
]; ];
@ -3409,10 +3426,11 @@ class ClientController extends AdminController
$this->clientPolicyModel->where('id', $clientPolicyId)->set(['non_eb_rack_rate_files' => json_encode($files)])->update(); $this->clientPolicyModel->where('id', $clientPolicyId)->set(['non_eb_rack_rate_files' => json_encode($files)])->update();
// Delete physical file // Delete from S3/local storage
$filePath = WRITEPATH . 'uploads/non_eb_rack_rate/' . $filename; $storedName = basename((string) $filename);
if (file_exists($filePath)) { if ($storedName !== '') {
unlink($filePath); $storage = \Config\Services::getFileStorageService();
$storage->delete(WRITEPATH . 'uploads/non_eb_rack_rate', $storedName);
} }
return $this->respond(['status' => true], 200); return $this->respond(['status' => true], 200);
@ -3795,8 +3813,8 @@ class ClientController extends AdminController
$file = $files['file_name'][$key]; $file = $files['file_name'][$key];
if (!empty($docName) && $file->isValid() && !$file->hasMoved()) { if (!empty($docName) && $file->isValid() && !$file->hasMoved()) {
// Upload the file // Upload the file (unique storage key; safe for S3 + duplicate names)
$uploadedFileName = file_Upload_for_lead($file, $uploadFilePath, UPLOAD_EXT_KYC_DOCS); $uploadedFileName = storage_file_Upload($file, $uploadFilePath, UPLOAD_EXT_KYC_DOCS);
if ($uploadedFileName) { if ($uploadedFileName) {
// Prepare data for each document upload // Prepare data for each document upload
@ -3856,30 +3874,52 @@ class ClientController extends AdminController
public function generateKycPrimaryTable($client_id) public function generateKycPrimaryTable($client_id)
{ {
$clientId = (int) $client_id;
$db = db_connect(); $db = db_connect();
$builder = $db->table('kyc_docs kd');
$builder->select('kd.*, ck.file_name AS upload_doc_name, ck.id AS client_kyc_id');
$builder->join('clients c', 'kd.kyc_type_id = c.entity_type_id');
$builder->join(
'client_kyc_documents ck',
'kd.id = ck.kyc_doc_type_id AND ck.client_id = c.id AND ck.is_active = 1',
'left'
);
$builder->where('c.id', $client_id);
$builder->where('kd.is_active',1);
$builder->groupBy(['kd.id', 'ck.file_name']); // Required document types for this client's entity.
$docs = $db->table('kyc_docs kd')
->select('kd.*')
->join('clients c', 'kd.kyc_type_id = c.entity_type_id')
->where('c.id', $clientId)
->where('kd.is_active', 1)
->groupBy('kd.id')
->orderBy('kd.id', 'ASC')
->get()
->getResultArray();
$query = $builder->get(); // Latest active upload per doc type (prevents duplicate Status rows).
$result['data'] = $query->getResultArray(); $uploads = $this->clientKYCDocsModel
$result['client_id'] = $client_id; ->select('id, kyc_doc_type_id, file_name')
->where('client_id', $clientId)
->where('is_active', 1)
->where('kyc_doc_type_id IS NOT NULL', null, false)
->where('kyc_doc_type_id !=', 0)
->orderBy('id', 'DESC')
->findAll();
$table = view('client_kyc_primary_table', $result); $latestByType = [];
foreach ($uploads as $upload) {
$typeId = (int) ($upload['kyc_doc_type_id'] ?? 0);
$storedName = trim((string) ($upload['file_name'] ?? ''));
if ($typeId <= 0 || $storedName === '' || isset($latestByType[$typeId])) {
continue;
}
$latestByType[$typeId] = $upload;
}
return $table; foreach ($docs as &$doc) {
// print_r($table); die; $typeId = (int) ($doc['id'] ?? 0);
$latest = $latestByType[$typeId] ?? null;
$doc['upload_doc_name'] = $latest['file_name'] ?? null;
$doc['client_kyc_id'] = $latest['id'] ?? null;
}
unset($doc);
$result['data'] = $docs;
$result['client_id'] = $clientId;
return view('client_kyc_primary_table', $result);
} }
public function generateKycOthersTable($client_id) public function generateKycOthersTable($client_id)
@ -4905,17 +4945,139 @@ class ClientController extends AdminController
return $this->respond(['Status' => true, 'code' => 200, 'data' => $data, 'client_policy_id' => $client_policy_id, 'policy' => $polices], 200); return $this->respond(['Status' => true, 'code' => 200, 'data' => $data, 'client_policy_id' => $client_policy_id, 'policy' => $polices], 200);
} }
public function downloadKYCDocument($file_name) public function downloadKYCDocument($fileOrId = null)
{ {
return $this->downloadKycDocumentFromStorage($fileOrId);
$file = WRITEPATH . 'uploads/client_kyc_documents/' . $file_name; // Example file path
if (file_exists($file)) {
return $this->response->download($file, null)->setFileName($file_name);
} else {
$data['message'] = 'The Physical File Not Found';
echo view('errors/404', $data);
} }
/**
* Download KYC file by client_kyc_documents.id (preferred) or legacy stored file_name.
*/
private function downloadKycDocumentFromStorage($fileOrId)
{
if ($fileOrId === null || $fileOrId === '') {
$data['message'] = 'No file specified.';
return view('errors/404', $data);
}
$uploadFilePath = WRITEPATH . 'uploads/client_kyc_documents';
$storedFileName = null;
$downloadAs = null;
// Prefer lookup by KYC document id so duplicate original names never collide.
if (ctype_digit((string) $fileOrId)) {
$record = $this->clientKYCDocsModel->find((int) $fileOrId);
if (empty($record) || empty($record['file_name'])) {
$data['message'] = 'File record not found';
return view('errors/404', $data);
}
$storedFileName = basename((string) $record['file_name']);
$downloadAs = storage_upload_display_name($storedFileName);
} else {
$storedFileName = basename((string) $fileOrId);
$downloadAs = storage_upload_display_name($storedFileName);
}
$storage = \Config\Services::getFileStorageService();
$result = $storage->download($uploadFilePath, $storedFileName);
if (!($result['success'] ?? false)) {
$data['message'] = 'The Physical File Not Found';
return view('errors/404', $data);
}
// Local disk: stream file path
if (!empty($result['path']) && is_file($result['path'])) {
return $this->response->download($result['path'], null)->setFileName($downloadAs);
}
// S3: force attachment download in the same flow (no new-tab redirect)
if (!empty($result['content'])) {
return $this->response
->download($downloadAs, $result['content'])
->setFileName($downloadAs);
}
$data['message'] = 'The Physical File Not Found';
return view('errors/404', $data);
}
/**
* Soft-delete helper: deactivate row and remove unused physical/S3 object.
*/
private function softDeleteKycDocument(int $id): bool
{
$record = $this->clientKYCDocsModel->find($id);
if (empty($record)) {
return false;
}
$updated = $this->clientKYCDocsModel->update($id, [
'is_active' => 0,
'updated_by' => get_session_userid(),
]);
if (! $updated) {
return false;
}
$storedFileName = basename((string) ($record['file_name'] ?? ''));
if ($storedFileName === '') {
return true;
}
// Only delete storage object when no other active row still points at it (legacy shared names).
$stillUsed = $this->clientKYCDocsModel
->where('file_name', $storedFileName)
->where('is_active', 1)
->where('id !=', $id)
->countAllResults();
if ($stillUsed === 0) {
$storage = \Config\Services::getFileStorageService();
$storage->delete(WRITEPATH . 'uploads/client_kyc_documents', $storedFileName);
}
return true;
}
/**
* Soft-delete every active primary KYC upload for a client + doc type.
* Prevents duplicate Status rows for the same required document.
*/
private function deactivateActivePrimaryKycDocs(int $clientId, int $kycDocTypeId): void
{
if ($clientId <= 0 || $kycDocTypeId <= 0) {
return;
}
$existing = $this->clientKYCDocsModel
->where('client_id', $clientId)
->where('kyc_doc_type_id', $kycDocTypeId)
->where('is_active', 1)
->findAll();
foreach ($existing as $row) {
$this->softDeleteKycDocument((int) $row['id']);
}
}
/**
* Insert a primary KYC file after deactivating any previous active upload
* for the same client + document type.
*
* @return int|false insert id
*/
private function insertPrimaryKycDocument(array $data)
{
$clientId = (int) ($data['client_id'] ?? 0);
$kycDocTypeId = (int) ($data['kyc_doc_type_id'] ?? 0);
if ($clientId > 0 && $kycDocTypeId > 0) {
$this->deactivateActivePrimaryKycDocs($clientId, $kycDocTypeId);
}
return $this->clientKYCDocsModel->insert($data);
} }
//for this function policy binding dropdown list use ( client policy ) //for this function policy binding dropdown list use ( client policy )
@ -9926,22 +10088,9 @@ class ClientController extends AdminController
return $default_templates_inserted ? true : false; return $default_templates_inserted ? true : false;
} }
public function downloadClientKycDocs_2($file_name = null) public function downloadClientKycDocs_2($fileOrId = null)
{ {
if (!$file_name) { return $this->downloadKycDocumentFromStorage($fileOrId);
return "No file specified.";
}
// Use absolute path to your upload folder
$file = WRITEPATH . 'uploads/client_kyc_documents/' . $file_name;
if (file_exists($file)) {
// download() takes the path as first param and null (or data) as second
return $this->response->download($file, null);
} else {
$data['message'] = 'The Physical File Not Found';
echo view('errors/404', $data);
}
} }
} }

View File

@ -1488,7 +1488,7 @@ class EmpDataServiceController extends BaseController
'event_type' => $file['event_type'], 'event_type' => $file['event_type'],
]; ];
$file_name_with_path = WRITEPATH . "/uploads/import_excel/" . $file['file_name']; $file_name_with_path = storage_ensure_local_file(WRITEPATH . 'uploads/import_excel', $file['file_name']);
$excel_data = $this->readExcelFileToArray($file_name_with_path); $excel_data = $this->readExcelFileToArray($file_name_with_path);
$excel_header = $excel_data[0]; $excel_header = $excel_data[0];
unset($excel_data[0]); unset($excel_data[0]);
@ -2016,7 +2016,7 @@ class EmpDataServiceController extends BaseController
$this->myLogger->logme('error', 'Inception Update TPA and UHID -- file name : {data}', ['data' => $file['file_name']]); $this->myLogger->logme('error', 'Inception Update TPA and UHID -- file name : {data}', ['data' => $file['file_name']]);
$file_name_with_path = WRITEPATH . "/uploads/import_excel/" . $file['file_name']; $file_name_with_path = storage_ensure_local_file(WRITEPATH . 'uploads/import_excel', $file['file_name']);
$excel_data = $this->readExcelFileToArray($file_name_with_path); $excel_data = $this->readExcelFileToArray($file_name_with_path);
unset($excel_data[0]); // Remove header row unset($excel_data[0]); // Remove header row
// array_pop($excel_data); // array_pop($excel_data);
@ -2286,9 +2286,9 @@ class EmpDataServiceController extends BaseController
'event_type' => $file['event_type'], 'event_type' => $file['event_type'],
]; ];
$file_name_with_path = WRITEPATH . "/uploads/import_excel/" . $file['file_name']; $file_name_with_path = storage_ensure_local_file(WRITEPATH . 'uploads/import_excel', $file['file_name']);
if (!file_exists($file_name_with_path)) { if (empty($file_name_with_path) || !file_exists($file_name_with_path)) {
$this->myLogger->logme('error', 'Correction File Validation -- The Physical file not found'); $this->myLogger->logme('error', 'Correction File Validation -- The Physical file not found');
$this->myLogger->logme('error', 'Correction File Validation -- File Name : {data}', ['data' => $file['file_name']]); $this->myLogger->logme('error', 'Correction File Validation -- File Name : {data}', ['data' => $file['file_name']]);
@ -2574,7 +2574,7 @@ class EmpDataServiceController extends BaseController
$this->myLogger->logme('error', 'importCorrectionUpdateEndorsementID file name : {data}', ['data'=> $file['file_name']]); $this->myLogger->logme('error', 'importCorrectionUpdateEndorsementID file name : {data}', ['data'=> $file['file_name']]);
$file_name_with_path = WRITEPATH . "/uploads/import_excel/" . $file['file_name']; $file_name_with_path = storage_ensure_local_file(WRITEPATH . 'uploads/import_excel', $file['file_name']);
$excel_data = $this->readExcelFileToArray($file_name_with_path); $excel_data = $this->readExcelFileToArray($file_name_with_path);
unset($excel_data[0]); unset($excel_data[0]);
@ -2711,9 +2711,9 @@ class EmpDataServiceController extends BaseController
$client_policy_data = $this->clientPolicyModel->where('id', $client_policy_id)->first(); $client_policy_data = $this->clientPolicyModel->where('id', $client_policy_id)->first();
$file_name_with_path = WRITEPATH . "/uploads/import_excel/" . $file['file_name']; $file_name_with_path = storage_ensure_local_file(WRITEPATH . 'uploads/import_excel', $file['file_name']);
if (!file_exists($file_name_with_path)) { if (empty($file_name_with_path) || !file_exists($file_name_with_path)) {
return 'The Physical file not found'; return 'The Physical file not found';
} }
@ -3213,7 +3213,7 @@ class EmpDataServiceController extends BaseController
$this->myLogger->logme('error', 'SI Enhancement Update Endorsement ID -- file name : {data}', ['data' => $file['file_name']]); $this->myLogger->logme('error', 'SI Enhancement Update Endorsement ID -- file name : {data}', ['data' => $file['file_name']]);
$file_name_with_path = WRITEPATH . "/uploads/import_excel/" . $file['file_name']; $file_name_with_path = storage_ensure_local_file(WRITEPATH . 'uploads/import_excel', $file['file_name']);
$excel_data = $this->readExcelFileToArray($file_name_with_path); $excel_data = $this->readExcelFileToArray($file_name_with_path);
unset($excel_data[0]); unset($excel_data[0]);
@ -3455,9 +3455,9 @@ class EmpDataServiceController extends BaseController
]; ];
$file_name_with_path = WRITEPATH . "/uploads/import_excel/" . $file['file_name']; $file_name_with_path = storage_ensure_local_file(WRITEPATH . 'uploads/import_excel', $file['file_name']);
if (!file_exists($file_name_with_path)) { if (empty($file_name_with_path) || !file_exists($file_name_with_path)) {
return 'The Physical file not found'; return 'The Physical file not found';
} }
@ -3788,7 +3788,7 @@ class EmpDataServiceController extends BaseController
$this->myLogger->logme('error', 'Deletion Update Endorsement ID -- file name : {data}', ['data' => $file['file_name']]); $this->myLogger->logme('error', 'Deletion Update Endorsement ID -- file name : {data}', ['data' => $file['file_name']]);
$file_name_with_path = WRITEPATH . "/uploads/import_excel/" . $file['file_name']; $file_name_with_path = storage_ensure_local_file(WRITEPATH . 'uploads/import_excel', $file['file_name']);
$excel_data = $this->readExcelFileToArray($file_name_with_path); $excel_data = $this->readExcelFileToArray($file_name_with_path);
unset($excel_data[0]); unset($excel_data[0]);
// array_pop($excel_data); // array_pop($excel_data);
@ -3968,9 +3968,9 @@ class EmpDataServiceController extends BaseController
$batch_code = $file['batch_code']; $batch_code = $file['batch_code'];
$user_id = $file['created_by']; $user_id = $file['created_by'];
$file_name_with_path = WRITEPATH . "/uploads/import_excel/" . $file['file_name']; $file_name_with_path = storage_ensure_local_file(WRITEPATH . 'uploads/import_excel', $file['file_name']);
if (!file_exists($file_name_with_path)) { if (empty($file_name_with_path) || !file_exists($file_name_with_path)) {
$this->myLogger->logme('error', 'Addition And Dependent Addition File Validation -- The Physical file not found'); $this->myLogger->logme('error', 'Addition And Dependent Addition File Validation -- The Physical file not found');
$this->myLogger->logme('error', 'Addition And Dependent Addition File Validation -- File Name : {data}', ['data' => $file['file_name']]); $this->myLogger->logme('error', 'Addition And Dependent Addition File Validation -- File Name : {data}', ['data' => $file['file_name']]);
@ -4273,7 +4273,7 @@ class EmpDataServiceController extends BaseController
$this->myLogger->logme('error', 'importCorrectionUpdateEndorsementID file name : {data}', ['data'=> $file['file_name']]); $this->myLogger->logme('error', 'importCorrectionUpdateEndorsementID file name : {data}', ['data'=> $file['file_name']]);
$file_name_with_path = WRITEPATH . "/uploads/import_excel/" . $file['file_name']; $file_name_with_path = storage_ensure_local_file(WRITEPATH . 'uploads/import_excel', $file['file_name']);
$excel_data = $this->readExcelFileToArray($file_name_with_path); $excel_data = $this->readExcelFileToArray($file_name_with_path);
unset($excel_data[0]); unset($excel_data[0]);

View File

@ -288,12 +288,10 @@ class EmployeeController extends AdminController
} }
} }
$is_moved = $avatar->move(WRITEPATH . 'uploads/excel/'); $fileSizeBytes = (is_object($avatar) && method_exists($avatar, 'getSize')) ? (int) $avatar->getSize() : 0;
if ($is_moved) { $filename = storage_file_Upload($avatar, WRITEPATH . 'uploads/excel/', UPLOAD_EXT_EXCEL);
$filename = $avatar->getName(); if ($filename !== '') {
$fileSize = $avatar->getSize(); // File size in bytes $fileSize = $fileSizeBytes / (1024 * 1024); // Convert to MB
$fileSize = $fileSize / (1024 * 1024); // Convert to MB
// Handle successful upload, e.g., log success or further processing
$this->myLogger->logme("error", 'File move successful'); $this->myLogger->logme("error", 'File move successful');
} else { } else {
$this->myLogger->logme("error", 'File move failed'); $this->myLogger->logme("error", 'File move failed');
@ -873,8 +871,11 @@ class EmployeeController extends AdminController
$batch_data['file'] = $this->request->getFile('import_file_data'); $batch_data['file'] = $this->request->getFile('import_file_data');
$file = $this->request->getFile('import_file_data'); $file = $this->request->getFile('import_file_data');
$is_moved = $file->move(WRITEPATH . 'uploads/import_excel'); $filename = storage_file_Upload($file, WRITEPATH . 'uploads/import_excel/', UPLOAD_EXT_EXCEL);
$filename = $file->getName(); if ($filename === '') {
session()->setFlashdata('error', 'File upload failed');
return redirect()->to(base_url('employee/upload'));
}
$this->myLogger->logme('error', 'Inception Import file name : {data}', ['data' => $filename]); $this->myLogger->logme('error', 'Inception Import file name : {data}', ['data' => $filename]);
$random_number_count = 4; $random_number_count = 4;
@ -1182,34 +1183,32 @@ class EmployeeController extends AdminController
public function downloadFileList($file_id = null) public function downloadFileList($file_id = null)
{ {
// $actionType = $this->request->getGet();
$file_data = $this->fileModel->where('id', $file_id)->first(); $file_data = $this->fileModel->where('id', $file_id)->first();
$fileName = $file_data['file_name']; if (empty($file_data) || empty($file_data['file_name'])) {
$data['message'] = 'File record not found';
return view('errors/404', $data);
}
$error_data = json_decode($file_data['reason']); $fileName = basename((string) $file_data['file_name']);
$storage = \Config\Services::getFileStorageService();
$filePath = WRITEPATH . '/uploads/excel/' . $fileName; $result = $storage->download(WRITEPATH . 'uploads/excel', $fileName);
try { try {
if ($result['success'] ?? false) {
// Check if the file exists $downloadAs = storage_upload_display_name($fileName);
if (file_exists($filePath)) { if (! empty($result['path']) && is_file($result['path'])) {
// Set the appropriate MIME type return $this->response->download($result['path'], null)->setFileName($downloadAs);
$mimeType = mime_content_type($filePath); }
if (! empty($result['content'])) {
// Send the file to the client for download return $this->response->download($downloadAs, $result['content'])->setFileName($downloadAs);
return $this->response->download($filePath, null, $mimeType); }
} else { }
$data['message'] = 'The Physical File Not Found'; $data['message'] = 'The Physical File Not Found';
echo view('errors/404', $data); return view('errors/404', $data);
}
} catch (\Exception $e) { } catch (\Exception $e) {
// Handle any exceptions $this->myLogger->logme('error', $e->getMessage());
$errorMessage = $e->getMessage(); echo $e->getMessage();
$this->myLogger->logme('error', $errorMessage);
// You can return an error response here
echo $errorMessage;
} }
} }
@ -1253,10 +1252,10 @@ class EmployeeController extends AdminController
], 200); ], 200);
} }
$filePath = WRITEPATH . 'uploads/excel/' . $file_name['file_name']; $filePath = storage_ensure_local_file(WRITEPATH . 'uploads/excel', $file_name['file_name']);
// ✅ File not exists on disk // ✅ File not exists on disk
if (!file_exists($filePath)) { if (empty($filePath) || !file_exists($filePath)) {
return $this->respond([ return $this->respond([
'dataStatus' => false, 'dataStatus' => false,
'code' => 200, 'code' => 200,
@ -1349,10 +1348,10 @@ class EmployeeController extends AdminController
} }
$fileName = $file_data['file_name']; $fileName = $file_data['file_name'];
$filePath = WRITEPATH . '/uploads/excel/' . $fileName; $filePath = storage_ensure_local_file(WRITEPATH . 'uploads/excel', $fileName);
// Check if the file exists // Check if the file exists
if (!file_exists($filePath)) { if (empty($filePath) || !file_exists($filePath)) {
$error_message = "File not found"; $error_message = "File not found";
$this->myLogger->logme('error', $error_message . ' for file id ' . $file_id); $this->myLogger->logme('error', $error_message . ' for file id ' . $file_id);
$data['message'] = 'Physical File Not Found'; $data['message'] = 'Physical File Not Found';
@ -2513,7 +2512,7 @@ class EmployeeController extends AdminController
// dd($error_data); // dd($error_data);
$file_name_with_path = WRITEPATH . "/uploads/import_excel/" . $file['file_name']; $file_name_with_path = storage_ensure_local_file(WRITEPATH . 'uploads/import_excel', $file['file_name']);
if (!file_exists($file_name_with_path)) { if (!file_exists($file_name_with_path)) {
$error_message = "File not found"; $error_message = "File not found";
@ -3036,32 +3035,32 @@ class EmployeeController extends AdminController
public function download_import_file($file_id) public function download_import_file($file_id)
{ {
// $actionType = $this->request->getGet();
$file_data = $this->batchFileModel->where('id', $file_id)->first(); $file_data = $this->batchFileModel->where('id', $file_id)->first();
$fileName = $file_data['file_name']; if (empty($file_data) || empty($file_data['file_name'])) {
$data['message'] = 'File record not found';
return view('errors/404', $data);
}
$filePath = WRITEPATH . '/uploads/import_excel/' . $fileName; $fileName = basename((string) $file_data['file_name']);
$storage = \Config\Services::getFileStorageService();
$result = $storage->download(WRITEPATH . 'uploads/import_excel', $fileName);
try { try {
if ($result['success'] ?? false) {
// Check if the file exists $downloadAs = storage_upload_display_name($fileName);
if (file_exists($filePath)) { if (! empty($result['path']) && is_file($result['path'])) {
// Set the appropriate MIME type return $this->response->download($result['path'], null)->setFileName($downloadAs);
$mimeType = mime_content_type($filePath); }
if (! empty($result['content'])) {
// Send the file to the client for download return $this->response->download($downloadAs, $result['content'])->setFileName($downloadAs);
return $this->response->download($filePath, null, $mimeType); }
} else { }
$data['message'] = 'The Physical File Not Found'; $data['message'] = 'The Physical File Not Found';
echo view('errors/404', $data); return view('errors/404', $data);
}
} catch (\Exception $e) { } catch (\Exception $e) {
// Handle any exceptions $this->myLogger->logme('error', $e->getMessage());
$errorMessage = $e->getMessage(); echo $e->getMessage();
$this->myLogger->logme('error', $errorMessage);
// You can return an error response here
echo $errorMessage;
} }
} }
@ -4835,9 +4834,13 @@ class EmployeeController extends AdminController
date('Ymd_His') date('Ymd_His')
); );
$filePath = WRITEPATH . 'uploads/excel/' . $fileName; $filePath = WRITEPATH . 'uploads/excel/' . $fileName;
if (! is_dir(WRITEPATH . 'uploads/excel')) {
mkdir(WRITEPATH . 'uploads/excel', 0755, true);
}
$writer = new Xlsx($spreadsheet); $writer = new Xlsx($spreadsheet);
$writer->save($filePath); $writer->save($filePath);
storage_mirror_generated_file($filePath, WRITEPATH . 'uploads/excel', $fileName);
// Create a new entry in the files table so that the // Create a new entry in the files table so that the
// existing Employee Upload with Events pipeline can process it. // existing Employee Upload with Events pipeline can process it.
@ -5118,9 +5121,13 @@ class EmployeeController extends AdminController
date('Ymd_His') date('Ymd_His')
); );
$filePath = WRITEPATH . 'uploads/excel/' . $fileName; $filePath = WRITEPATH . 'uploads/excel/' . $fileName;
if (! is_dir(WRITEPATH . 'uploads/excel')) {
mkdir(WRITEPATH . 'uploads/excel', 0755, true);
}
$writer = new Xlsx($spreadsheet); $writer = new Xlsx($spreadsheet);
$writer->save($filePath); $writer->save($filePath);
storage_mirror_generated_file($filePath, WRITEPATH . 'uploads/excel', $fileName);
// Insert into files table so the existing correction pipeline can process it. // Insert into files table so the existing correction pipeline can process it.
$loggedInUserId = $batchFile['created_by'] ?? get_session_userid(); $loggedInUserId = $batchFile['created_by'] ?? get_session_userid();
@ -7109,9 +7116,13 @@ class EmployeeController extends AdminController
date('Ymd_His') date('Ymd_His')
); );
$generatedExcelPath = WRITEPATH . 'uploads/excel/' . $generatedFileName; $generatedExcelPath = WRITEPATH . 'uploads/excel/' . $generatedFileName;
if (! is_dir(WRITEPATH . 'uploads/excel')) {
mkdir(WRITEPATH . 'uploads/excel', 0755, true);
}
$writer = new Xls($spreadsheet); $writer = new Xls($spreadsheet);
$writer->save($generatedExcelPath); $writer->save($generatedExcelPath);
storage_mirror_generated_file($generatedExcelPath, WRITEPATH . 'uploads/excel', $generatedFileName);
// return "HI"; // return "HI";
// 1) Create files-table entry for EmployeeServiceController::employeeDisembark. // 1) Create files-table entry for EmployeeServiceController::employeeDisembark.
$newFileId = $this->fileModel->insert([ $newFileId = $this->fileModel->insert([
@ -7198,7 +7209,13 @@ class EmployeeController extends AdminController
date('Ymd_His') date('Ymd_His')
); );
$generatedImportPath = WRITEPATH . 'uploads/import_excel/' . $generatedImportFileName; $generatedImportPath = WRITEPATH . 'uploads/import_excel/' . $generatedImportFileName;
if (! is_dir(WRITEPATH . 'uploads/import_excel')) {
mkdir(WRITEPATH . 'uploads/import_excel', 0755, true);
}
$success = generate_excel($excel_data_info['header'], $excel_data_info['data'], $generatedImportPath); $success = generate_excel($excel_data_info['header'], $excel_data_info['data'], $generatedImportPath);
if ($success && is_file($generatedImportPath)) {
storage_mirror_generated_file($generatedImportPath, WRITEPATH . 'uploads/import_excel', $generatedImportFileName);
}
// print_rr($success); // print_rr($success);
// die; // die;

View File

@ -1026,10 +1026,10 @@ class EmployeeMultiEventServiceController extends BaseController
//file not found in DB //file not found in DB
return array('status' => false, 'msg' => 'file not found in DB'); return array('status' => false, 'msg' => 'file not found in DB');
} }
$file_name_with_path = WRITEPATH . "/uploads/excel/" . $file['file_name']; $file_name_with_path = storage_ensure_local_file(WRITEPATH . 'uploads/excel', $file['file_name']);
//check physical file //check physical file
if (!file_exists($file_name_with_path)) { if (empty($file_name_with_path) || !file_exists($file_name_with_path)) {
//file not found update status and reason //file not found update status and reason
$message = "Physcial file not found - " . $file_name_with_path; $message = "Physcial file not found - " . $file_name_with_path;
// echo $message; // echo $message;
@ -1399,10 +1399,10 @@ class EmployeeMultiEventServiceController extends BaseController
return array('status' => false, 'msg' => 'file not found in DB'); return array('status' => false, 'msg' => 'file not found in DB');
} }
$file_name_with_path = WRITEPATH . "/uploads/excel/" . $file['file_name']; $file_name_with_path = storage_ensure_local_file(WRITEPATH . 'uploads/excel', $file['file_name']);
//check physical file //check physical file
if (!file_exists($file_name_with_path)) { if (empty($file_name_with_path) || !file_exists($file_name_with_path)) {
//file not found update status and reason //file not found update status and reason
$message = "Physcial file not found - " . $file_name_with_path; $message = "Physcial file not found - " . $file_name_with_path;
$this->myLogger->logme('error', ($message . ' for file id ' . $file_id)); $this->myLogger->logme('error', ($message . ' for file id ' . $file_id));
@ -1829,10 +1829,10 @@ class EmployeeMultiEventServiceController extends BaseController
return array('status' => false, 'msg' => 'file not found in DB'); return array('status' => false, 'msg' => 'file not found in DB');
} }
// $file_name_with_path = WRITEPATH . "/uploads/excel/" . $file['file_name']; // $file_name_with_path = storage_ensure_local_file(WRITEPATH . 'uploads/excel', $file['file_name']);
// //check physical file // //check physical file
// if (!file_exists($file_name_with_path)) { // if (empty($file_name_with_path) || !file_exists($file_name_with_path)) {
// //file not found update status and reason // //file not found update status and reason
// $message = "Physical file not found"; // $message = "Physical file not found";
// // echo $message; // // echo $message;
@ -1975,7 +1975,7 @@ class EmployeeMultiEventServiceController extends BaseController
$file['action'] = $params['action']; $file['action'] = $params['action'];
// dd($file); // dd($file);
// $file_name_with_path = WRITEPATH . "/uploads/excel/" . $file['file_name']; // $file_name_with_path = storage_ensure_local_file(WRITEPATH . 'uploads/excel', $file['file_name']);
// $spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load($file_name_with_path); // $spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load($file_name_with_path);
// $sheet = $spreadsheet->getActiveSheet(); // $sheet = $spreadsheet->getActiveSheet();
// $highestRowAndColumn = $sheet->getHighestRowAndColumn(); // $highestRowAndColumn = $sheet->getHighestRowAndColumn();
@ -2114,7 +2114,7 @@ class EmployeeMultiEventServiceController extends BaseController
$file['action'] = $params['action']; $file['action'] = $params['action'];
// $file_name_with_path = WRITEPATH . "/uploads/excel/" . $file['file_name']; // $file_name_with_path = storage_ensure_local_file(WRITEPATH . 'uploads/excel', $file['file_name']);
// $spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load($file_name_with_path); // $spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load($file_name_with_path);
// $sheet = $spreadsheet->getActiveSheet(); // $sheet = $spreadsheet->getActiveSheet();
// $highestRowAndColumn = $sheet->getHighestRowAndColumn(); // $highestRowAndColumn = $sheet->getHighestRowAndColumn();
@ -2191,7 +2191,7 @@ class EmployeeMultiEventServiceController extends BaseController
$file = $this->fileModel->find((int)$file_id); $file = $this->fileModel->find((int)$file_id);
$file['action'] = $params['action']; $file['action'] = $params['action'];
// $file_name_with_path = WRITEPATH . "/uploads/excel/" . $file['file_name']; // $file_name_with_path = storage_ensure_local_file(WRITEPATH . 'uploads/excel', $file['file_name']);
// $spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load($file_name_with_path); // $spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load($file_name_with_path);
// $sheet = $spreadsheet->getActiveSheet(); // $sheet = $spreadsheet->getActiveSheet();
// $highestRowAndColumn = $sheet->getHighestRowAndColumn(); // $highestRowAndColumn = $sheet->getHighestRowAndColumn();
@ -2492,10 +2492,10 @@ class EmployeeMultiEventServiceController extends BaseController
// dd($error_data); // dd($error_data);
// return $error_data; // return $error_data;
$file_name_with_path = WRITEPATH . "/uploads/excel/" . $file['file_name']; $file_name_with_path = storage_ensure_local_file(WRITEPATH . 'uploads/excel', $file['file_name']);
//check the file exist or not //check the file exist or not
if (!file_exists($file_name_with_path)) { if (empty($file_name_with_path) || !file_exists($file_name_with_path)) {
$error_message = "File not found"; $error_message = "File not found";
$this->myLogger->logme('error', ($error_message . ' for file id ' . $file_id)); $this->myLogger->logme('error', ($error_message . ' for file id ' . $file_id));
return 0; return 0;
@ -2656,10 +2656,10 @@ class EmployeeMultiEventServiceController extends BaseController
//file not found in DB //file not found in DB
return array('status' => false, 'msg' => 'file not found in DB'); return array('status' => false, 'msg' => 'file not found in DB');
} }
$file_name_with_path = WRITEPATH . "/uploads/excel/" . $file['file_name']; $file_name_with_path = storage_ensure_local_file(WRITEPATH . 'uploads/excel', $file['file_name']);
//check physical file //check physical file
if (!file_exists($file_name_with_path)) { if (empty($file_name_with_path) || !file_exists($file_name_with_path)) {
//file not found update status and reason //file not found update status and reason
$message = "Physical file not found"; $message = "Physical file not found";
// echo $message; // echo $message;
@ -2870,7 +2870,7 @@ class EmployeeMultiEventServiceController extends BaseController
$deletion_column_to_check = $this->deletion_excel_columns; $deletion_column_to_check = $this->deletion_excel_columns;
$si_column_to_check = $this->si_enhance_excel_columns; $si_column_to_check = $this->si_enhance_excel_columns;
$file_name_with_path = WRITEPATH . "uploads/excel/" . $file_name; $file_name_with_path = storage_ensure_local_file(WRITEPATH . 'uploads/excel', $file_name);
$spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load($file_name_with_path); $spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load($file_name_with_path);
$worksheet = $spreadsheet->getActiveSheet(); $worksheet = $spreadsheet->getActiveSheet();
@ -3103,8 +3103,8 @@ class EmployeeMultiEventServiceController extends BaseController
} }
// ✅ Define File Paths // ✅ Define File Paths
// $inception_file_path = !empty($file['file_name']) ? WRITEPATH . "uploads/excel/" . $file['file_name'] : ''; // $inception_file_path = !empty($file['file_name']) ? storage_ensure_local_file(WRITEPATH . 'uploads/excel', $file['file_name']) : '';
$member_file_path = !empty($lead_data['file_name']) ? WRITEPATH . "uploads/lead_files/" . $lead_data['file_name'] : ''; $member_file_path = !empty($lead_data['file_name']) ? (storage_ensure_local_file(WRITEPATH . 'uploads/lead_files', $lead_data['file_name']) ?? '') : '';
// ✅ Check Inception File // ✅ Check Inception File
// if (empty($file['file_name']) || !file_exists($inception_file_path)) { // if (empty($file['file_name']) || !file_exists($inception_file_path)) {
@ -3118,7 +3118,7 @@ class EmployeeMultiEventServiceController extends BaseController
// } // }
// ✅ Check Member File // ✅ Check Member File
if (empty($lead_data['file_name']) || !file_exists($member_file_path)) { if (empty($lead_data['file_name']) || empty($member_file_path) || !file_exists($member_file_path)) {
$message = empty($lead_data['file_name']) ? "Member file name is missing" : "Member data physical file not found"; $message = empty($lead_data['file_name']) ? "Member file name is missing" : "Member data physical file not found";
$this->myLogger->logme('error', "$message for lead id {$lead_data['id']}"); $this->myLogger->logme('error', "$message for lead id {$lead_data['id']}");
$this->fileModel->update($file_id, [ $this->fileModel->update($file_id, [

View File

@ -757,10 +757,11 @@ class EmployeeRestController extends AdminController
$sum_insured_amount_for_check_employee_1 = isset($policy_permium_1['si']) ? $policy_permium_1['si'] : null; $sum_insured_amount_for_check_employee_1 = isset($policy_permium_1['si']) ? $policy_permium_1['si'] : null;
$sum_insured_amount_for_check_employee_2 = isset($policy_permium_2['si']) ? $policy_permium_2['si'] : null; $sum_insured_amount_for_check_employee_2 = isset($policy_permium_2['si']) ? $policy_permium_2['si'] : null;
$fileName = sanitize_upload_filename($file->getName()); $filename = storage_file_Upload($file, WRITEPATH . 'uploads/excel/', UPLOAD_EXT_EXCEL);
$is_moved = $file->move(WRITEPATH . 'uploads/excel', $fileName); if ($filename === '') {
$filename = $file->getName(); return $this->respond(['status' => 'failed', 'code' => 500, 'message' => 'File upload failed.'], 200);
$file_name_with_path = WRITEPATH . "/uploads/excel/" . $filename; }
$file_name_with_path = storage_ensure_local_file(WRITEPATH . 'uploads/excel', $filename);
//make an entry in DB //make an entry in DB
$file_id = $this->fileModel->insert(['file_name' => $filename, 'client_id' => $client_id, 'policy_id' => $policy_id, 'created_by' => $employee_id, 'status' => 'inprogress', 'action' => 'enrollment', 'client_branch_id' => $client_branch_id]); //here field policy_id have client_policy_id and not policy id from policy master $file_id = $this->fileModel->insert(['file_name' => $filename, 'client_id' => $client_id, 'policy_id' => $policy_id, 'created_by' => $employee_id, 'status' => 'inprogress', 'action' => 'enrollment', 'client_branch_id' => $client_branch_id]); //here field policy_id have client_policy_id and not policy id from policy master
@ -775,7 +776,7 @@ class EmployeeRestController extends AdminController
} }
//check the file exist or not //check the file exist or not
if (! file_exists($file_name_with_path)) { if (empty($file_name_with_path) || ! file_exists($file_name_with_path)) {
session()->setFlashdata('error', 'File not found'); session()->setFlashdata('error', 'File not found');
return redirect()->to(base_url('employee/upload')); return redirect()->to(base_url('employee/upload'));
} }
@ -3850,7 +3851,7 @@ class EmployeeRestController extends AdminController
$file_data = []; $file_data = [];
if (isset($get_file_data) && ! empty($get_file_data)) { if (isset($get_file_data) && ! empty($get_file_data)) {
$file_path = WRITEPATH . 'uploads/claim_files/'; $file_path = WRITEPATH . 'uploads/claim_files/';
$file_data = multi_file_Upload($get_file_data, $file_path, $get_docs_name, UPLOAD_EXT_CLAIM_DOCS); $file_data = storage_multi_file_Upload($get_file_data, $file_path, $get_docs_name, UPLOAD_EXT_CLAIM_DOCS);
} }
if (empty($received_data['doa'])) { if (empty($received_data['doa'])) {
@ -4808,20 +4809,17 @@ class EmployeeRestController extends AdminController
]; ];
} }
// Upload folder path // Upload folder path (S3-only when FILE_STORAGE_DRIVER=s3)
$uploadPath = WRITEPATH . 'uploads/hr_files/'; $uploadPath = WRITEPATH . 'uploads/hr_files/';
$newFileName = storage_file_Upload($file, $uploadPath, UPLOAD_EXT_EXCEL);
// If directory not exists, create it if ($newFileName === '') {
if (! is_dir($uploadPath)) { return [
mkdir($uploadPath, 0755, true); 'status' => false,
'message' => 'File upload failed.',
'data' => [],
];
} }
// New file name with timestamp
$newFileName = time() . '_' . $file->getRandomName();
// Move file
$file->move($uploadPath, $newFileName);
// Prepare data // Prepare data
$data = [ $data = [
'client_id' => $post_data['client_id'], 'client_id' => $post_data['client_id'],
@ -4966,25 +4964,36 @@ class EmployeeRestController extends AdminController
// Find record // Find record
if ($client_data && $client_data['hr_file_processed_by'] == 1) { if ($client_data && $client_data['hr_file_processed_by'] == 1) {
$record = $this->fileModel->where('id', (int) $file_id)->find(); $record = $this->fileModel->where('id', (int) $file_id)->find();
$uploadPath = WRITEPATH . 'uploads/excel/'; $uploadPath = WRITEPATH . 'uploads/excel';
} else { } else {
$record = $this->hrFileUploadModel->where('id', (int) $file_id)->find(); $record = $this->hrFileUploadModel->where('id', (int) $file_id)->find();
$uploadPath = WRITEPATH . 'uploads/hr_files/'; $uploadPath = WRITEPATH . 'uploads/hr_files';
} }
if (! $record) { if (! $record) {
return $this->failNotFound("File record not found"); return $this->failNotFound("File record not found");
} }
$filePath = $uploadPath . $record[0]['file_name']; $storedName = basename((string) ($record[0]['file_name'] ?? ''));
if ($storedName === '') {
if (! file_exists($filePath)) {
return $this->failNotFound("File not found on server"); return $this->failNotFound("File not found on server");
} }
// Force file download $storage = \Config\Services::getFileStorageService();
return $this->response->download($filePath, null) $result = $storage->download($uploadPath, $storedName);
->setFileName($record[0]['file_name']); if (! ($result['success'] ?? false)) {
return $this->failNotFound("File not found on server");
}
$downloadAs = storage_upload_display_name($storedName);
if (! empty($result['path']) && is_file($result['path'])) {
return $this->response->download($result['path'], null)->setFileName($downloadAs);
}
if (! empty($result['content'])) {
return $this->response->download($downloadAs, $result['content'])->setFileName($downloadAs);
}
return $this->failNotFound("File not found on server");
} catch (\Exception $e) { } catch (\Exception $e) {
return $this->failServerError($e->getMessage()); return $this->failServerError($e->getMessage());
@ -5626,7 +5635,7 @@ class EmployeeRestController extends AdminController
$file_data = []; $file_data = [];
if (isset($get_file_data) && ! empty($get_file_data)) { if (isset($get_file_data) && ! empty($get_file_data)) {
$file_path = WRITEPATH . 'uploads/claim_files/'; $file_path = WRITEPATH . 'uploads/claim_files/';
$file_data = multi_file_Upload($get_file_data, $file_path, $get_docs_name, UPLOAD_EXT_CLAIM_DOCS); $file_data = storage_multi_file_Upload($get_file_data, $file_path, $get_docs_name, UPLOAD_EXT_CLAIM_DOCS);
} }
$result = $this->handleCliamFiles($file_data, $ticket_id, null, false, true); $result = $this->handleCliamFiles($file_data, $ticket_id, null, false, true);
@ -5671,17 +5680,26 @@ class EmployeeRestController extends AdminController
return view('errors/404', $data); return view('errors/404', $data);
} }
$uploadPath = WRITEPATH . 'uploads/import_excel/'; $uploadPath = WRITEPATH . 'uploads/import_excel';
$filePath = $uploadPath . $record['file_name']; $fileName = basename((string) ($record['file_name'] ?? ''));
$storage = \Config\Services::getFileStorageService();
$result = $storage->download($uploadPath, $fileName);
if (! file_exists($filePath)) { if (! ($result['success'] ?? false)) {
// return $this->failNotFound("File not found on server");
$data['message'] = 'The Physical File Not Found'; $data['message'] = 'The Physical File Not Found';
return view('errors/404', $data); return view('errors/404', $data);
} }
// Force file download $downloadAs = storage_upload_display_name($fileName);
return $this->response->download($filePath, null)->setFileName($record['file_name']); if (! empty($result['path']) && is_file($result['path'])) {
return $this->response->download($result['path'], null)->setFileName($downloadAs);
}
if (! empty($result['content'])) {
return $this->response->download($downloadAs, $result['content'])->setFileName($downloadAs);
}
$data['message'] = 'The Physical File Not Found';
return view('errors/404', $data);
} catch (\Exception $e) { } catch (\Exception $e) {
$data['message'] = 'File record not found'; $data['message'] = 'File record not found';
return view('errors/404', $data); return view('errors/404', $data);
@ -5880,14 +5898,31 @@ class EmployeeRestController extends AdminController
return $this->respond(['status' => false, 'code' => 404, 'message' => 'The Physical File Not Found in server'], 200); return $this->respond(['status' => false, 'code' => 404, 'message' => 'The Physical File Not Found in server'], 200);
} }
$filePath = $uploadFilePath . '/' . $pt_files_data['file_name']; $storedFileName = basename((string) ($pt_files_data['file_name'] ?? ''));
if ($storedFileName === '') {
if (! file_exists($filePath)) {
return $this->respond(['status' => false, 'code' => 404, 'message' => 'The Physical File Not Found in server'], 200); return $this->respond(['status' => false, 'code' => 404, 'message' => 'The Physical File Not Found in server'], 200);
} }
// Force file download $storage = \Config\Services::getFileStorageService();
return $this->response->download($filePath, null)->setFileName($pt_files_data['file_name']); $result = $storage->download($uploadFilePath, $storedFileName);
if (! ($result['success'] ?? false)) {
return $this->respond(['status' => false, 'code' => 404, 'message' => 'The Physical File Not Found in server'], 200);
}
$downloadAs = storage_upload_display_name($storedFileName);
if (! empty($result['path']) && is_file($result['path'])) {
return $this->response->download($result['path'], null)->setFileName($downloadAs);
}
if (! empty($result['content'])) {
return $this->response
->download($downloadAs, $result['content'])
->setFileName($downloadAs);
}
return $this->respond(['status' => false, 'code' => 404, 'message' => 'The Physical File Not Found in server'], 200);
} }
public function bulkEcardDownloadAsZip() public function bulkEcardDownloadAsZip()

View File

@ -803,10 +803,10 @@ class EmployeeServiceController extends AdminController
//file not found in DB //file not found in DB
return array('status' => false, 'msg' => 'file not found in DB'); return array('status' => false, 'msg' => 'file not found in DB');
} }
$file_name_with_path = WRITEPATH."/uploads/excel/".$file['file_name']; $file_name_with_path = storage_ensure_local_file(WRITEPATH . 'uploads/excel', $file['file_name']);
//check physical file //check physical file
if(!file_exists($file_name_with_path)) if(empty($file_name_with_path) || !file_exists($file_name_with_path))
{ {
//file not found update status and reason //file not found update status and reason
$message = "Physcial file not found"; $message = "Physcial file not found";
@ -1123,10 +1123,10 @@ class EmployeeServiceController extends AdminController
//file not found in DB //file not found in DB
return array('status' => false, 'msg' => 'file not found in DB'); return array('status' => false, 'msg' => 'file not found in DB');
} }
$file_name_with_path = WRITEPATH."/uploads/excel/".$file['file_name']; $file_name_with_path = storage_ensure_local_file(WRITEPATH . 'uploads/excel', $file['file_name']);
//check physical file //check physical file
if(!file_exists($file_name_with_path)) if(empty($file_name_with_path) || !file_exists($file_name_with_path))
{ {
//file not found update status and reason //file not found update status and reason
$message = "Physical file not found"; $message = "Physical file not found";
@ -1382,10 +1382,10 @@ class EmployeeServiceController extends AdminController
//file not found in DB //file not found in DB
return array('status' => false, 'msg' => 'file not found in DB'); return array('status' => false, 'msg' => 'file not found in DB');
} }
$file_name_with_path = WRITEPATH . "/uploads/excel/" . $file['file_name']; $file_name_with_path = storage_ensure_local_file(WRITEPATH . 'uploads/excel', $file['file_name']);
//check physical file //check physical file
if (!file_exists($file_name_with_path)) { if (empty($file_name_with_path) || !file_exists($file_name_with_path)) {
//file not found update status and reason //file not found update status and reason
$message = "Physical file not found"; $message = "Physical file not found";
// echo $message; // echo $message;
@ -1575,7 +1575,7 @@ class EmployeeServiceController extends AdminController
$file = $this->fileModel->find((int)$file_id); $file = $this->fileModel->find((int)$file_id);
// dd($file); // dd($file);
$file_name_with_path = WRITEPATH . "/uploads/excel/" . $file['file_name']; $file_name_with_path = storage_ensure_local_file(WRITEPATH . 'uploads/excel', $file['file_name']);
$spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load($file_name_with_path); $spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load($file_name_with_path);
$sheet = $spreadsheet->getActiveSheet(); $sheet = $spreadsheet->getActiveSheet();
@ -1715,7 +1715,7 @@ class EmployeeServiceController extends AdminController
$file = $this->fileModel->find((int)$file_id); $file = $this->fileModel->find((int)$file_id);
// dd($file); // dd($file);
$file_name_with_path = WRITEPATH."/uploads/excel/".$file['file_name']; $file_name_with_path = storage_ensure_local_file(WRITEPATH . 'uploads/excel', $file['file_name']);
$spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load($file_name_with_path); $spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load($file_name_with_path);
$sheet = $spreadsheet->getActiveSheet(); $sheet = $spreadsheet->getActiveSheet();
@ -1802,7 +1802,7 @@ class EmployeeServiceController extends AdminController
$file = $this->fileModel->find((int)$file_id); $file = $this->fileModel->find((int)$file_id);
// dd($file); // dd($file);
$file_name_with_path = WRITEPATH . "/uploads/excel/" . $file['file_name']; $file_name_with_path = storage_ensure_local_file(WRITEPATH . 'uploads/excel', $file['file_name']);
$spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load($file_name_with_path); $spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load($file_name_with_path);
$sheet = $spreadsheet->getActiveSheet(); $sheet = $spreadsheet->getActiveSheet();
@ -2137,10 +2137,10 @@ class EmployeeServiceController extends AdminController
// dd($error_data); // dd($error_data);
// return $error_data; // return $error_data;
$file_name_with_path = WRITEPATH."/uploads/excel/".$file['file_name']; $file_name_with_path = storage_ensure_local_file(WRITEPATH . 'uploads/excel', $file['file_name']);
//check the file exist or not //check the file exist or not
if(!file_exists($file_name_with_path)) if(empty($file_name_with_path) || !file_exists($file_name_with_path))
{ {
$error_message = "File not found"; $error_message = "File not found";
$this->myLogger->logme('error',($error_message . ' for file id ' . $file_id)); $this->myLogger->logme('error',($error_message . ' for file id ' . $file_id));
@ -2299,10 +2299,10 @@ class EmployeeServiceController extends AdminController
//file not found in DB //file not found in DB
return array('status' => false, 'msg' => 'file not found in DB'); return array('status' => false, 'msg' => 'file not found in DB');
} }
$file_name_with_path = WRITEPATH."/uploads/excel/".$file['file_name']; $file_name_with_path = storage_ensure_local_file(WRITEPATH . 'uploads/excel', $file['file_name']);
//check physical file //check physical file
if(!file_exists($file_name_with_path)) if(empty($file_name_with_path) || !file_exists($file_name_with_path))
{ {
//file not found update status and reason //file not found update status and reason
$message = "Physical file not found"; $message = "Physical file not found";
@ -2539,8 +2539,8 @@ class EmployeeServiceController extends AdminController
} }
// ✅ Define File Paths // ✅ Define File Paths
$inception_file_path = !empty($file['file_name']) ? WRITEPATH . "uploads/excel/" . $file['file_name'] : ''; $inception_file_path = !empty($file['file_name']) ? (storage_ensure_local_file(WRITEPATH . 'uploads/excel', $file['file_name']) ?? '') : '';
$member_file_path = !empty($lead_data['file_name']) ? WRITEPATH . "uploads/lead_files/" . $lead_data['file_name'] : ''; $member_file_path = !empty($lead_data['file_name']) ? (storage_ensure_local_file(WRITEPATH . 'uploads/lead_files', $lead_data['file_name']) ?? '') : '';
// ✅ Check Inception File // ✅ Check Inception File
if (empty($file['file_name']) || !file_exists($inception_file_path)) { if (empty($file['file_name']) || !file_exists($inception_file_path)) {
@ -2554,7 +2554,7 @@ class EmployeeServiceController extends AdminController
} }
// ✅ Check Member File // ✅ Check Member File
if (empty($lead_data['file_name']) || !file_exists($member_file_path)) { if (empty($lead_data['file_name']) || empty($member_file_path) || !file_exists($member_file_path)) {
$message = empty($lead_data['file_name']) ? "Member file name is missing" : "Member data physical file not found"; $message = empty($lead_data['file_name']) ? "Member file name is missing" : "Member data physical file not found";
$this->myLogger->logme('error', "$message for lead id {$lead_data['id']}"); $this->myLogger->logme('error', "$message for lead id {$lead_data['id']}");
$this->fileModel->update($file_id, [ $this->fileModel->update($file_id, [

View File

@ -70,7 +70,7 @@ class FhplApiController extends BaseController
public function SubmitClaim($claimId = null) // 515 public function SubmitClaim($claimId = null) // 515
{ {
helper(['api', 'tpa_claim_push_log']); helper(['api', 'tpa_claim_push_log', 'utility']);
$data = $this->db->table('ticket_master tm') $data = $this->db->table('ticket_master tm')
->select(' ->select('
@ -103,18 +103,21 @@ class FhplApiController extends BaseController
return ['status' => false, 'message' => 'Claim Push FAILED | Claim or File Missing']; return ['status' => false, 'message' => 'Claim Push FAILED | Claim or File Missing'];
} }
// Build absolute file path
$file_id = $data['fileId'] ?? null; $file_id = $data['fileId'] ?? null;
$filename = basename($data['filePath']); $filename = basename($data['filePath']);
$pdfPath = WRITEPATH . 'uploads/claim_files/' . $filename; $resolved = storage_resolve_claim_file_path(WRITEPATH . 'uploads/claim_files', $filename);
if (!($resolved['success'] ?? false) || empty($resolved['path'])) {
if (!file_exists($pdfPath)) { tpa_claim_push_log($claimId, "FHPL - Claim Push FAILED | claimId: {$claimId} - PDF not found in local/S3");
tpa_claim_push_log($claimId, "FHPL - Claim Push FAILED | claimId: {$claimId} - PDF not found on server");
return ['status' => false, 'message' => 'Claim Push FAILED | PDF not found on server']; return ['status' => false, 'message' => 'Claim Push FAILED | PDF not found on server'];
} }
// Convert PDF to Base64 $rawContent = @file_get_contents($resolved['path']);
$fileContent = base64_encode(file_get_contents($pdfPath)); storage_cleanup_temp_claim_file($resolved);
if ($rawContent === false) {
tpa_claim_push_log($claimId, "FHPL - Claim Push FAILED | claimId: {$claimId} - Unable to read file for base64");
return ['status' => false, 'message' => 'Claim Push FAILED | PDF not readable'];
}
$fileContent = base64_encode($rawContent);
// Generate FHPL Token // Generate FHPL Token
$tokenResponse = $this->generateAuthToken(); $tokenResponse = $this->generateAuthToken();

View File

@ -84,7 +84,7 @@ class HealthIndiaApiController extends BaseController
public function SubmitClaim($claimId = null) public function SubmitClaim($claimId = null)
{ {
helper(['api', 'tpa_claim_push_log']); helper(['api', 'tpa_claim_push_log', 'utility']);
tpa_claim_push_log($claimId, 'HEALTH_INDIA - Claim Push | Started for claimId: ' . $claimId); tpa_claim_push_log($claimId, 'HEALTH_INDIA - Claim Push | Started for claimId: ' . $claimId);
@ -130,18 +130,21 @@ class HealthIndiaApiController extends BaseController
return ['status' => false, 'message' => 'Claim Push FAILED | File Missing']; return ['status' => false, 'message' => 'Claim Push FAILED | File Missing'];
} }
// Build absolute file path
$file_id = $data['fileId'] ?? null; $file_id = $data['fileId'] ?? null;
$filename = basename($data['filePath']); $filename = basename($data['filePath']);
$pdfPath = WRITEPATH . 'uploads/claim_files/' . $filename; $resolved = storage_resolve_claim_file_path(WRITEPATH . 'uploads/claim_files', $filename);
if (!($resolved['success'] ?? false) || empty($resolved['path'])) {
if (!file_exists($pdfPath)) { tpa_claim_push_log($claimId, "HEALTH_INDIA - Claim Push FAILED | claimId: {$claimId} - PDF not found in local/S3 for file: {$filename}");
tpa_claim_push_log($claimId, "HEALTH_INDIA - Claim Push FAILED | claimId: {$claimId} - PDF not found on server at path: {$pdfPath}");
return ['status' => false, 'message' => 'Claim Push FAILED | PDF not found on server']; return ['status' => false, 'message' => 'Claim Push FAILED | PDF not found on server'];
} }
// Convert PDF to Base64 $rawContent = @file_get_contents($resolved['path']);
$fileContent = base64_encode(file_get_contents($pdfPath)); storage_cleanup_temp_claim_file($resolved);
if ($rawContent === false) {
tpa_claim_push_log($claimId, "HEALTH_INDIA - Claim Push FAILED | claimId: {$claimId} - Unable to read file for base64: {$filename}");
return ['status' => false, 'message' => 'Claim Push FAILED | PDF not readable'];
}
$fileContent = base64_encode($rawContent);
// Generate Health India Token // Generate Health India Token
$tokenResponse = $this->generateAuthToken(); $tokenResponse = $this->generateAuthToken();

View File

@ -1172,7 +1172,7 @@ class LeadsController extends BaseController
$multi_file_data = []; $multi_file_data = [];
foreach ($files as $index => $value) { foreach ($files as $index => $value) {
$file_name = file_Upload_for_lead($value, $uploadFilePath, UPLOAD_EXT_LEAD_FILES); $file_name = storage_file_Upload($value, $uploadFilePath, UPLOAD_EXT_LEAD_FILES);
$multi_file_data[] = [ $multi_file_data[] = [
'file_name' => $file_name, 'file_name' => $file_name,
'docs_name' => $docs_names[$index] ?? '', 'docs_name' => $docs_names[$index] ?? '',
@ -1280,7 +1280,7 @@ class LeadsController extends BaseController
} }
$uploadFilePath = WRITEPATH . 'uploads/lead_files/'; $uploadFilePath = WRITEPATH . 'uploads/lead_files/';
$fileName = file_Upload_for_lead($file, $uploadFilePath, UPLOAD_EXT_LEAD_FILES); $fileName = storage_file_Upload($file, $uploadFilePath, UPLOAD_EXT_LEAD_FILES);
if (empty($fileName)) { if (empty($fileName)) {
return $this->respond(['status' => 'error', 'code' => 400, 'message' => 'File upload failed. Check file type or size.'], 400); return $this->respond(['status' => 'error', 'code' => 400, 'message' => 'File upload failed. Check file type or size.'], 400);
@ -2170,13 +2170,15 @@ class LeadsController extends BaseController
continue; continue;
} }
$utrNo = isset($installment['utr_no']) ? trim((string) $installment['utr_no']) : '';
$data = [ $data = [
'lead_id' => $lead_id, 'lead_id' => $lead_id,
'installment_amount' => $installment['installment_amount'] ?? null, 'installment_amount' => $installment['installment_amount'] ?? null,
'payment_date' => ! empty($installment['payment_date']) 'payment_date' => ! empty($installment['payment_date'])
? change_date_format($installment['payment_date']) ? change_date_format($installment['payment_date'])
: null, : null,
'utr_no' => $installment['utr_no'] ?? null, 'utr_no' => $utrNo !== '' ? $utrNo : null,
]; ];
$installmentId = ! empty($installment['id']) ? (int) $installment['id'] : null; $installmentId = ! empty($installment['id']) ? (int) $installment['id'] : null;
@ -2247,11 +2249,11 @@ class LeadsController extends BaseController
$temp_file_path = $filepath['filePath']; $temp_file_path = $filepath['filePath'];
$temp_file_name = $filepath['fileName']; $temp_file_name = $filepath['fileName'];
$lead_file_path = WRITEPATH . 'uploads/lead_files/' . $lead_data['file_name']; $lead_file_path = storage_ensure_local_file(WRITEPATH . 'uploads/lead_files', $lead_data['file_name']);
// dd($lead_data, $temp_file_path, $temp_file_name, $lead_file_path); // dd($lead_data, $temp_file_path, $temp_file_name, $lead_file_path);
if ($lead_file_path) { if (! empty($lead_file_path) && is_file($lead_file_path)) {
$filePaths = [ $filePaths = [
['file_path' => $temp_file_path, 'sheets' => []], ['file_path' => $temp_file_path, 'sheets' => []],
['file_path' => $lead_file_path, 'sheets' => []], ['file_path' => $lead_file_path, 'sheets' => []],
@ -3058,22 +3060,23 @@ class LeadsController extends BaseController
{ {
$lead_id = $params['lead_id']; $lead_id = $params['lead_id'];
$lead_data = $this->leadsModel->find((int) $lead_id); $lead_data = $this->leadsModel->find((int) $lead_id);
$file_name_with_path = WRITEPATH . "/uploads/lead_files/" . $lead_data['file_name'];
if (! $lead_data) { if (! $lead_data) {
return ['status' => 'failed', 'message' => 'Opportunity data not found']; return ['status' => 'failed', 'message' => 'Opportunity data not found'];
} }
$file_name_with_path = ! empty($lead_data['file_name'])
? storage_ensure_local_file(WRITEPATH . 'uploads/lead_files', $lead_data['file_name'])
: null;
try { try {
if ($lead_data['file_name']) { if ($lead_data['file_name']) {
// $file_name_with_path = WRITEPATH . "/uploads/lead_files/NonPrintableCharacters.xlsx";
//check physical file //check physical file
if (! file_exists($file_name_with_path)) { if (empty($file_name_with_path) || ! file_exists($file_name_with_path)) {
//file not found update status and reason //file not found update status and reason
$message = "Lead Physcial file not found"; $message = "Lead Physcial file not found";
// echo $message; // echo $message;
$this->myLogger->logme('error', ($message . ' for file ' . $file_name_with_path)); $this->myLogger->logme('error', ($message . ' for file ' . ($lead_data['file_name'] ?? '')));
return ['status' => 'failed', 'message' => 'no physical file']; return ['status' => 'failed', 'message' => 'no physical file'];
} }
@ -3129,12 +3132,13 @@ class LeadsController extends BaseController
echo "Location: " . $result['fullpath'] . "\n"; echo "Location: " . $result['fullpath'] . "\n";
echo "Filename: " . $result['filename'] . "\n"; echo "Filename: " . $result['filename'] . "\n";
$filePaths = [ $filePaths = [
['file_path' => WRITEPATH . 'uploads/lead_files/' . $lead_data['file_name'], 'sheets' => [0, 1]], ['file_path' => $file_name_with_path, 'sheets' => [0, 1]],
['file_path' => WRITEPATH . '/uploads/lead_files/' . $result['filename'], 'sheets' => []], ['file_path' => $result['fullpath'], 'sheets' => []],
]; ];
$outputPath = WRITEPATH . 'uploads/lead_files/' . $lead_data['file_name']; $outputPath = $file_name_with_path;
$result_merge = ExcelMergeHelper::mergeExcelFiles($filePaths, $outputPath); $result_merge = ExcelMergeHelper::mergeExcelFiles($filePaths, $outputPath);
if ($result_merge) { if ($result_merge) {
storage_mirror_generated_file($outputPath, WRITEPATH . 'uploads/lead_files', $lead_data['file_name']);
// Call the delete function after the file is successfully created // Call the delete function after the file is successfully created
$deleteResponse = $this->deleteGeneratedFile($result['fullpath']); $deleteResponse = $this->deleteGeneratedFile($result['fullpath']);
@ -3697,8 +3701,8 @@ class LeadsController extends BaseController
if ($lead_data['file_name'] != null && $lead_data['file_name'] != '') { if ($lead_data['file_name'] != null && $lead_data['file_name'] != '') {
$temp_file_path = $file_info['filePath']; $temp_file_path = $file_info['filePath'];
$temp_file_name = $file_info['fileName']; $temp_file_name = $file_info['fileName'];
$lead_file_path = WRITEPATH . 'uploads/lead_files/' . $lead_data['file_name']; $lead_file_path = storage_ensure_local_file(WRITEPATH . 'uploads/lead_files', $lead_data['file_name']);
if ($lead_file_path) { if (! empty($lead_file_path) && is_file($lead_file_path)) {
$filePaths = [ $filePaths = [
['file_path' => $temp_file_path, 'sheets' => []], ['file_path' => $temp_file_path, 'sheets' => []],
['file_path' => $lead_file_path, 'sheets' => []], ['file_path' => $lead_file_path, 'sheets' => []],
@ -7406,7 +7410,7 @@ class LeadsController extends BaseController
$fileIds = json_decode($json_string, true); $fileIds = json_decode($json_string, true);
log_message('error', 'Decoded fileIds: ' . print_r($fileIds, true)); log_message('error', 'Decoded fileIds: ' . print_r($fileIds, true));
$lead_file_path = WRITEPATH . 'uploads/lead_files/'; $lead_file_path = WRITEPATH . 'uploads/lead_files';
log_message('error', 'Lead file path: ' . $lead_file_path); log_message('error', 'Lead file path: ' . $lead_file_path);
foreach ($fileIds as $id) { foreach ($fileIds as $id) {
@ -7422,13 +7426,16 @@ class LeadsController extends BaseController
if ($lead_file) { if ($lead_file) {
log_message('error', 'Found lead file: ' . print_r($lead_file, true)); log_message('error', 'Found lead file: ' . print_r($lead_file, true));
$fullPath = $lead_file_path . $lead_file['file_name']; if (empty($lead_file['file_name'])) {
log_message('error', 'Full file path: ' . $fullPath); log_message('error', 'File name is empty for ID: ' . $id);
continue;
}
if (file_exists($fullPath)) { $fullPath = storage_ensure_local_file($lead_file_path, $lead_file['file_name']);
log_message('error', 'Full file path: ' . ($fullPath ?? ''));
if (! empty($fullPath) && file_exists($fullPath)) {
log_message('error', 'File exists at path: ' . $fullPath); log_message('error', 'File exists at path: ' . $fullPath);
if (! empty($lead_file['file_name'])) {
log_message('error', 'File name is not empty: ' . $lead_file['file_name']); log_message('error', 'File name is not empty: ' . $lead_file['file_name']);
$attachments[] = [ $attachments[] = [
@ -7436,10 +7443,7 @@ class LeadsController extends BaseController
'filePath' => $fullPath, 'filePath' => $fullPath,
]; ];
} else { } else {
log_message('error', 'File name is empty for ID: ' . $id); log_message('error', 'File does not exist at path for: ' . $lead_file['file_name']);
}
} else {
log_message('error', 'File does not exist at path: ' . $fullPath);
} }
} else { } else {
log_message('warning', 'No active lead file found for ID: ' . $id . ' and lead_id: ' . $lead_id); log_message('warning', 'No active lead file found for ID: ' . $id . ' and lead_id: ' . $lead_id);
@ -7463,15 +7467,17 @@ class LeadsController extends BaseController
return ['status' => 'failed', 'message' => 'Opportunity data not found']; return ['status' => 'failed', 'message' => 'Opportunity data not found'];
} }
$file_name_with_path = WRITEPATH . "/uploads/lead_files/" . $lead_data['file_name']; $file_name_with_path = ! empty($lead_data['file_name'])
? storage_ensure_local_file(WRITEPATH . 'uploads/lead_files', $lead_data['file_name'])
: null;
if ($lead_data['file_name']) { if ($lead_data['file_name']) {
//check physical file //check physical file
if (! file_exists($file_name_with_path)) { if (empty($file_name_with_path) || ! file_exists($file_name_with_path)) {
$message = "Lead Physcial file not found"; $message = "Lead Physcial file not found";
$this->myLogger->logme('error', ($message . ' for file ' . $file_name_with_path)); $this->myLogger->logme('error', ($message . ' for file ' . ($lead_data['file_name'] ?? '')));
return ['status' => 'failed', 'message' => 'no physical file']; return ['status' => 'failed', 'message' => 'no physical file'];
} }
@ -7946,15 +7952,28 @@ class LeadsController extends BaseController
public function downloadMemberFile($fileName) public function downloadMemberFile($fileName)
{ {
$filePath = WRITEPATH . 'uploads/lead_files/' . $fileName; $fileName = basename((string) $fileName);
$uploadFilePath = WRITEPATH . 'uploads/lead_files';
$storage = \Config\Services::getFileStorageService();
$result = $storage->download($uploadFilePath, $fileName);
if (! file_exists($filePath)) { if (! ($result['success'] ?? false)) {
$data['message'] = 'The Physical File Not Found'; $data['message'] = 'The Physical File Not Found';
echo view('errors/404', $data); return view('errors/404', $data);
} }
// force download $downloadAs = storage_upload_display_name($fileName);
return $this->response->download($filePath, null);
if (! empty($result['path']) && is_file($result['path'])) {
return $this->response->download($result['path'], null)->setFileName($downloadAs);
}
if (! empty($result['content'])) {
return $this->response->download($downloadAs, $result['content'])->setFileName($downloadAs);
}
$data['message'] = 'The Physical File Not Found';
return view('errors/404', $data);
} }
// ----------- MEMBER DATA VALIDAATION ------------------------------------------------------------------------------------------------------ // ----------- MEMBER DATA VALIDAATION ------------------------------------------------------------------------------------------------------
@ -8005,11 +8024,13 @@ class LeadsController extends BaseController
// dd($family_composition); // dd($family_composition);
// get the file path // get the file path
$file_name_with_path = WRITEPATH . "/uploads/lead_files/" . $lead_data['file_name']; $file_name_with_path = ! empty($lead_data['file_name'])
$this->myLogger->logme('error', "File path: {$file_name_with_path}"); ? storage_ensure_local_file(WRITEPATH . 'uploads/lead_files', $lead_data['file_name'])
: null;
$this->myLogger->logme('error', "File path: " . ($file_name_with_path ?? ''));
//check physical file //check physical file
if (! file_exists($file_name_with_path)) { if (empty($file_name_with_path) || ! file_exists($file_name_with_path)) {
//file not found update status and reason //file not found update status and reason
$message = "Physcial file not found"; $message = "Physcial file not found";
$this->myLogger->logme('error', ($message . ' for lead id ' . $lead_id)); $this->myLogger->logme('error', ($message . ' for lead id ' . $lead_id));
@ -8257,10 +8278,10 @@ class LeadsController extends BaseController
// dd($error_data); // dd($error_data);
// return $error_data; // return $error_data;
$file_name_with_path = WRITEPATH . "/uploads/lead_files/" . $file['file_name']; $file_name_with_path = storage_ensure_local_file(WRITEPATH . 'uploads/lead_files', $file['file_name']);
//check the file exist or not //check the file exist or not
if (! file_exists($file_name_with_path)) { if (empty($file_name_with_path) || ! file_exists($file_name_with_path)) {
$error_message = "File not found"; $error_message = "File not found";
$this->myLogger->logme('error', ($error_message . ' for file id ' . $lead_id)); $this->myLogger->logme('error', ($error_message . ' for file id ' . $lead_id));
return 0; return 0;
@ -8363,10 +8384,10 @@ class LeadsController extends BaseController
} }
$fileName = $file_data['file_name']; $fileName = $file_data['file_name'];
$filePath = WRITEPATH . '/uploads/lead_files/' . $fileName; $filePath = storage_ensure_local_file(WRITEPATH . 'uploads/lead_files', $fileName);
// Check if the file exists // Check if the file exists
if (! file_exists($filePath)) { if (empty($filePath) || ! file_exists($filePath)) {
$error_message = "File not found"; $error_message = "File not found";
$this->myLogger->logme('error', $error_message . ' for file id ' . $lead_id); $this->myLogger->logme('error', $error_message . ' for file id ' . $lead_id);
$data['message'] = 'Physical File Not Found'; $data['message'] = 'Physical File Not Found';
@ -8423,11 +8444,13 @@ class LeadsController extends BaseController
} }
} }
// Create a new filename for the modified Excel file // Create a temporary error Excel for download only (not persisted to S3)
$newFileName = 'error_with_highlight_' . $fileName; $newFileName = 'error_with_highlight_' . $fileName;
$tmpDir = rtrim(WRITEPATH, '/\\') . DIRECTORY_SEPARATOR . 'cache' . DIRECTORY_SEPARATOR . 'claim_files_runtime';
// Save the modified Excel file to a new location if (! is_dir($tmpDir)) {
$newFilePath = WRITEPATH . '/uploads/lead_files/' . $newFileName; @mkdir($tmpDir, 0755, true);
}
$newFilePath = $tmpDir . DIRECTORY_SEPARATOR . $newFileName;
$writer = new \PhpOffice\PhpSpreadsheet\Writer\Xlsx($spreadsheet); $writer = new \PhpOffice\PhpSpreadsheet\Writer\Xlsx($spreadsheet);
$writer->save($newFilePath); $writer->save($newFilePath);

View File

@ -3144,6 +3144,8 @@ class MasterController extends AdminController
'template_bg' => ROOTPATH . 'public/uploads/template_bg/', 'template_bg' => ROOTPATH . 'public/uploads/template_bg/',
'attachments' => WRITEPATH . 'uploads/attachments/', 'attachments' => WRITEPATH . 'uploads/attachments/',
'cache' => WRITEPATH . 'cache', 'cache' => WRITEPATH . 'cache',
'storage_runtime' => WRITEPATH . 'cache/storage_runtime/',
'claim_files_runtime' => WRITEPATH . 'cache/claim_files_runtime/',
'sample_import_excel' => ROOTPATH . 'public/sample_import_excel', 'sample_import_excel' => ROOTPATH . 'public/sample_import_excel',
'lead_files' => WRITEPATH . 'uploads/lead_files/', 'lead_files' => WRITEPATH . 'uploads/lead_files/',
'claim_files' => WRITEPATH . 'uploads/claim_files/', 'claim_files' => WRITEPATH . 'uploads/claim_files/',

View File

@ -30,7 +30,7 @@ class MediAssistApiController extends BaseController
public function SubmitClaim ($claimId = null) public function SubmitClaim ($claimId = null)
{ {
helper(['api', 'tpa_claim_push_log']); helper(['api', 'tpa_claim_push_log', 'utility']);
// $url = ''. getenv('MEDI_ASSIST_API_BASE_URL').'/SubmitClaim'; // $url = ''. getenv('MEDI_ASSIST_API_BASE_URL').'/SubmitClaim';
$url = getenv('MEDI_ASSIST_API_BASE_URL_CLAIMSUBMIT'); $url = getenv('MEDI_ASSIST_API_BASE_URL_CLAIMSUBMIT');
@ -76,18 +76,11 @@ class MediAssistApiController extends BaseController
// Map DB result to request body // Map DB result to request body
if ($data) { if ($data) {
$filePath = $data['filePath'] ?? ''; $filename = basename((string) ($data['filePath'] ?? ''));
$filename = basename($filePath);
$fileDir = WRITEPATH . 'uploads/claim_files/'.$filename;
if ($fileDir) {
$downloadUrl = base_url('fileDownload?file_path=').$fileDir;
$file_id = $data['fileId'] ?? null; $file_id = $data['fileId'] ?? null;
} else {
$downloadUrl = ''; $downloadUrl = '';
if (!empty($file_id) && $filename !== '') {
$downloadUrl = storage_claim_file_download_url($filename, $file_id);
} }
$body = [ $body = [
@ -883,6 +876,7 @@ class MediAssistApiController extends BaseController
public function IRSubmission($claimId = null) // 585 this id for test public function IRSubmission($claimId = null) // 585 this id for test
{ {
helper('utility');
log_message('error',"MEDI_ASSIST - IR Submission | INIT for ticket_id={$claimId}"); log_message('error',"MEDI_ASSIST - IR Submission | INIT for ticket_id={$claimId}");
// 1. FETCH TICKET DETAILS // 1. FETCH TICKET DETAILS
@ -930,13 +924,9 @@ class MediAssistApiController extends BaseController
if (!empty($file['url']) && $file['file_type'] == 2) { if (!empty($file['url']) && $file['file_type'] == 2) {
$filename = basename($file['url']); $filename = basename($file['url']);
$fileDir = WRITEPATH . 'uploads/claim_files/' . $filename; $downloadUrl = storage_claim_file_download_url($filename, $file['id'] ?? null);
if ($downloadUrl === '') {
if (file_exists($fileDir)) { log_message('error',"MEDI_ASSIST - IR Submission File NOT FOUND in local/S3 → {$filename}");
$downloadUrl = base_url('fileDownload?file_path=') . $fileDir;
} else {
$downloadUrl = "";
log_message('error',"MEDI_ASSIST - IR Submission File NOT FOUND on server → {$fileDir}");
} }
log_message('error',"MEDI_ASSIST - IR Submission Attachment Ready: {$filename} | URL={$downloadUrl}"); log_message('error',"MEDI_ASSIST - IR Submission Attachment Ready: {$filename} | URL={$downloadUrl}");

View File

@ -1041,7 +1041,7 @@ class NonEbClaimController extends BaseController
} }
$uploadPath = WRITEPATH . 'uploads/non_eb_asset_files/'; $uploadPath = WRITEPATH . 'uploads/non_eb_asset_files/';
$fileName = file_Upload($file, $uploadPath, UPLOAD_EXT_ASSET_FILES); $fileName = storage_file_Upload($file, $uploadPath, UPLOAD_EXT_ASSET_FILES);
return !empty($fileName) ? $fileName : null; return !empty($fileName) ? $fileName : null;
} }
@ -1105,7 +1105,7 @@ class NonEbClaimController extends BaseController
return $this->respond(['status' => false, 'message' => 'Failed to upload file']); return $this->respond(['status' => false, 'message' => 'Failed to upload file']);
} else { } else {
$file_path = WRITEPATH . 'uploads/claim_files/'; $file_path = WRITEPATH . 'uploads/claim_files/';
$file_data = multi_file_Upload($get_file_data, $file_path, $data['docs_name'], UPLOAD_EXT_CLAIM_DOCS); $file_data = storage_multi_file_Upload($get_file_data, $file_path, $data['docs_name'], UPLOAD_EXT_CLAIM_DOCS);
if (!empty($file_data)) { if (!empty($file_data)) {
$insertArr = []; $insertArr = [];
foreach ($file_data as $f) { foreach ($file_data as $f) {
@ -1151,8 +1151,7 @@ class NonEbClaimController extends BaseController
if (empty(trim($id ?? ''))) { if (empty(trim($id ?? ''))) {
return $this->response->setJSON(['status' => false, 'message' => 'Invalid ID']); return $this->response->setJSON(['status' => false, 'message' => 'Invalid ID']);
} }
$updated = $this->claimFilesModel->where('id', $id)->set(['is_active' => 0])->update(); if (storage_soft_delete_claim_file((int) $id)) {
if ($updated) {
return $this->response->setJSON(['status' => true, 'message' => 'File removed successfully.']); return $this->response->setJSON(['status' => true, 'message' => 'File removed successfully.']);
} }
return $this->response->setJSON(['status' => false, 'message' => 'Failed to remove file.']); return $this->response->setJSON(['status' => false, 'message' => 'Failed to remove file.']);

View File

@ -364,7 +364,7 @@ class NotificationController extends AdminController
// Define upload path and attempt file upload // Define upload path and attempt file upload
$uploadFilePath = WRITEPATH . 'uploads/attachments'; $uploadFilePath = WRITEPATH . 'uploads/attachments';
$uploadedFile = $this->request->getFile('file'); $uploadedFile = $this->request->getFile('file');
$fileName = file_Upload_for_lead($uploadedFile, $uploadFilePath, UPLOAD_EXT_MAIL_ATTACHMENTS); $fileName = storage_file_Upload($uploadedFile, $uploadFilePath, UPLOAD_EXT_MAIL_ATTACHMENTS);
if ($fileName) { if ($fileName) {
// Prepare data for insertion // Prepare data for insertion
@ -396,11 +396,14 @@ class NotificationController extends AdminController
public function removeAttachmentsForMailTemplates($id, $client_id, $template_name) public function removeAttachmentsForMailTemplates($id, $client_id, $template_name)
{ {
$attachment_data_for_unlink_file = $this->MailAttachmentModel->where('id', $id)->first(); $attachment_data_for_unlink_file = $this->MailAttachmentModel->where('id', $id)->first();
$file_path = WRITEPATH . $attachment_data_for_unlink_file['file_path']; $storedName = basename((string) ($attachment_data_for_unlink_file['file_name'] ?? ''));
if ($this->MailAttachmentModel->where('id', $id)->delete()) { if ($this->MailAttachmentModel->where('id', $id)->delete()) {
unlink($file_path); if ($storedName !== '') {
$storage = \Config\Services::getFileStorageService();
$storage->delete(WRITEPATH . 'uploads/attachments', $storedName);
}
$find_notification = $this->notificationModel->where('client_id', $client_id)->where('template_name', $template_name)->first(); $find_notification = $this->notificationModel->where('client_id', $client_id)->where('template_name', $template_name)->first();
$attachmentDatas = $this->MailAttachmentModel->where('notification_id', $find_notification['id'])->where('is_active', 1)->findAll(); $attachmentDatas = $this->MailAttachmentModel->where('notification_id', $find_notification['id'])->where('is_active', 1)->findAll();

View File

@ -3694,8 +3694,8 @@ class PolicyTransactionController extends BaseController
if (!empty($docName) && $file->isValid() && !$file->hasMoved()) { if (!empty($docName) && $file->isValid() && !$file->hasMoved()) {
// Upload the file // Upload via FileStorageService (S3-only when enabled; unique storage key)
$uploadedFileName = file_Upload_for_lead($file, $uploadFilePath, UPLOAD_EXT_POLICY_DOCS); $uploadedFileName = storage_file_Upload($file, $uploadFilePath, UPLOAD_EXT_POLICY_DOCS);
if ($uploadedFileName) { if ($uploadedFileName) {
// Prepare data for each document upload // Prepare data for each document upload
@ -4489,10 +4489,8 @@ class PolicyTransactionController extends BaseController
return $this->respond(['dataStatus' => false, 'code' => 400, 'message' => 'File not found'], 400); return $this->respond(['dataStatus' => false, 'code' => 400, 'message' => 'File not found'], 400);
} }
$is_moved = $avatar->move(WRITEPATH . 'uploads/statements/'); $filename = storage_file_Upload($avatar, WRITEPATH . 'uploads/statements/', UPLOAD_EXT_EXCEL);
if ($is_moved) { if ($filename !== '') {
$filename = $avatar->getName();
// Handle successful upload, e.g., log success or further processing
$this->myLogger->logme("error", 'Statement File moved successful'); $this->myLogger->logme("error", 'Statement File moved successful');
} else { } else {
$this->myLogger->logme("error", 'Statement File move failed'); $this->myLogger->logme("error", 'Statement File move failed');
@ -4588,7 +4586,7 @@ class PolicyTransactionController extends BaseController
//file not found in DB //file not found in DB
return array('status' => false, 'msg' => 'statement file not found in DB'); return array('status' => false, 'msg' => 'statement file not found in DB');
} }
$file_name_with_path = WRITEPATH . "/uploads/statements/" . $file['file_name']; $file_name_with_path = storage_ensure_local_file(WRITEPATH . 'uploads/statements', $file['file_name']);
//check physical file //check physical file
if (!file_exists($file_name_with_path)) { if (!file_exists($file_name_with_path)) {
@ -4708,7 +4706,7 @@ class PolicyTransactionController extends BaseController
$this->insurerStatements->where('id', $file_id)->set(['file_status' => 'failed', 'reason' => json_encode(['error_code' => 0, 'error_data' => 'statement file not found in DB'])])->update(); $this->insurerStatements->where('id', $file_id)->set(['file_status' => 'failed', 'reason' => json_encode(['error_code' => 0, 'error_data' => 'statement file not found in DB'])])->update();
return array('status' => false, 'msg' => 'statement file not found in DB'); return array('status' => false, 'msg' => 'statement file not found in DB');
} }
$file_name_with_path = WRITEPATH . "/uploads/statements/" . $file['file_name']; $file_name_with_path = storage_ensure_local_file(WRITEPATH . 'uploads/statements', $file['file_name']);
//check physical file //check physical file
if (!file_exists($file_name_with_path)) { if (!file_exists($file_name_with_path)) {
@ -4858,7 +4856,7 @@ class PolicyTransactionController extends BaseController
//file not found in DB //file not found in DB
return array('status' => false, 'msg' => 'statement file not found in DB'); return array('status' => false, 'msg' => 'statement file not found in DB');
} }
$file_name_with_path = WRITEPATH . "/uploads/statements/" . $file['file_name']; $file_name_with_path = storage_ensure_local_file(WRITEPATH . 'uploads/statements', $file['file_name']);
//check physical file //check physical file
if (!file_exists($file_name_with_path)) { if (!file_exists($file_name_with_path)) {
@ -5034,7 +5032,7 @@ class PolicyTransactionController extends BaseController
$this->insurerStatements->where('id', $file_id)->set(['file_status' => 'failed', 'reason' => json_encode(['error_code' => 0, 'error_data' => 'statement file not found in DB'])])->update(); $this->insurerStatements->where('id', $file_id)->set(['file_status' => 'failed', 'reason' => json_encode(['error_code' => 0, 'error_data' => 'statement file not found in DB'])])->update();
return array('status' => false, 'error_code' => 0, 'error_data' => 'statement file not found in DB'); return array('status' => false, 'error_code' => 0, 'error_data' => 'statement file not found in DB');
} }
$file_name_with_path = WRITEPATH . "/uploads/statements/" . $file['file_name']; $file_name_with_path = storage_ensure_local_file(WRITEPATH . 'uploads/statements', $file['file_name']);
//check physical file //check physical file
if (!file_exists($file_name_with_path)) { if (!file_exists($file_name_with_path)) {
@ -5211,7 +5209,7 @@ class PolicyTransactionController extends BaseController
//file not found in DB //file not found in DB
return array('status' => false, 'error_code' => 0, 'error_data' => 'statement file not found in DB'); return array('status' => false, 'error_code' => 0, 'error_data' => 'statement file not found in DB');
} }
$file_name_with_path = WRITEPATH . "/uploads/statements/" . $file['file_name']; $file_name_with_path = storage_ensure_local_file(WRITEPATH . 'uploads/statements', $file['file_name']);
//check physical file //check physical file
if (!file_exists($file_name_with_path)) { if (!file_exists($file_name_with_path)) {
@ -5522,13 +5520,22 @@ class PolicyTransactionController extends BaseController
} }
$fileName = basename($statement['file_name']); $fileName = basename($statement['file_name']);
$filePath = WRITEPATH . 'uploads/statements/' . $fileName; $storage = \Config\Services::getFileStorageService();
$result = $storage->download(WRITEPATH . 'uploads/statements', $fileName);
if (!is_file($filePath)) { if (! ($result['success'] ?? false)) {
throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound('Statement file not found'); throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound('Statement file not found');
} }
return $this->response->download($filePath, null)->setFileName($fileName); $downloadAs = storage_upload_display_name($fileName);
if (! empty($result['path']) && is_file($result['path'])) {
return $this->response->download($result['path'], null)->setFileName($downloadAs);
}
if (! empty($result['content'])) {
return $this->response->download($downloadAs, $result['content'])->setFileName($downloadAs);
}
throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound('Statement file not found');
} }
public function getFileErr() public function getFileErr()
@ -6233,13 +6240,10 @@ class PolicyTransactionController extends BaseController
return $this->respond(['status' => false, 'code' => 400, 'message' => 'File not found'], 400); return $this->respond(['status' => false, 'code' => 400, 'message' => 'File not found'], 400);
} }
$is_moved = $avatar->move(WRITEPATH . 'uploads/bds_dump_excel/'); $filename = storage_file_Upload($avatar, WRITEPATH . 'uploads/bds_dump_excel/', UPLOAD_EXT_EXCEL);
if ($is_moved) {
$filename = $avatar->getName();
$fileSize = $avatar->getSize(); // File size in bytes
$fileSize = $fileSize / (1024 * 1024); // Convert to MB
if ($filename !== '') {
$fileSize = method_exists($avatar, 'getSize') ? ($avatar->getSize() / (1024 * 1024)) : 0;
$this->myLogger->logme("error", 'File move successful'); $this->myLogger->logme("error", 'File move successful');
} else { } else {
$this->myLogger->logme("error", 'File move failed'); $this->myLogger->logme("error", 'File move failed');
@ -6271,32 +6275,33 @@ class PolicyTransactionController extends BaseController
public function downloadBDSDumpFile($file_id) public function downloadBDSDumpFile($file_id)
{ {
// $actionType = $this->request->getGet();
$file_data = $this->bdsDumpModel->where('id', $file_id)->first(); $file_data = $this->bdsDumpModel->where('id', $file_id)->first();
$fileName = $file_data['file_name']; if (empty($file_data) || empty($file_data['file_name'])) {
$data['message'] = 'File record not found';
return view('errors/404', $data);
}
$filePath = WRITEPATH . '/uploads/bds_dump_excel/' . $fileName; $fileName = basename((string) $file_data['file_name']);
$storage = \Config\Services::getFileStorageService();
$result = $storage->download(WRITEPATH . 'uploads/bds_dump_excel', $fileName);
try { try {
if ($result['success'] ?? false) {
// Check if the file exists $downloadAs = storage_upload_display_name($fileName);
if (file_exists($filePath)) { if (! empty($result['path']) && is_file($result['path'])) {
// Set the appropriate MIME type return $this->response->download($result['path'], null)->setFileName($downloadAs);
$mimeType = mime_content_type($filePath); }
if (! empty($result['content'])) {
// Send the file to the client for download return $this->response->download($downloadAs, $result['content'])->setFileName($downloadAs);
return $this->response->download($filePath, null, $mimeType); }
} else { }
$data['message'] = 'The Physical File Not Found'; $data['message'] = 'The Physical File Not Found';
echo view('errors/404', $data); return view('errors/404', $data);
}
} catch (\Exception $e) { } catch (\Exception $e) {
// Handle any exceptions $this->myLogger->logme('error', $e->getMessage());
$errorMessage = $e->getMessage(); $data['message'] = 'The Physical File Not Found';
$this->myLogger->logme('error', $errorMessage); return view('errors/404', $data);
// You can return an error response here
echo $errorMessage;
} }
} }
@ -6311,7 +6316,7 @@ class PolicyTransactionController extends BaseController
return array('status' => false, 'message' => 'File not found in Database'); return array('status' => false, 'message' => 'File not found in Database');
} }
$file_name_with_path = WRITEPATH . "/uploads/bds_dump_excel/" . $file['file_name']; $file_name_with_path = storage_ensure_local_file(WRITEPATH . 'uploads/bds_dump_excel', $file['file_name']);
//check physical file exist //check physical file exist
if (!file_exists($file_name_with_path)) { if (!file_exists($file_name_with_path)) {
@ -6499,7 +6504,7 @@ class PolicyTransactionController extends BaseController
return array('status' => false, 'message' => 'File not found in Database'); return array('status' => false, 'message' => 'File not found in Database');
} }
$file_name_with_path = WRITEPATH . "/uploads/bds_dump_excel/" . $file['file_name']; $file_name_with_path = storage_ensure_local_file(WRITEPATH . 'uploads/bds_dump_excel', $file['file_name']);
//check physical file exist //check physical file exist
if (!file_exists($file_name_with_path)) { if (!file_exists($file_name_with_path)) {
@ -6792,7 +6797,7 @@ class PolicyTransactionController extends BaseController
{ {
// $file_name = "claims_dump_form_client.xlsx"; // $file_name = "claims_dump_form_client.xlsx";
// Load the Excel file // Load the Excel file
$file_name_with_path = WRITEPATH . "/uploads/bds_dump_excel/" . $file_name; $file_name_with_path = storage_ensure_local_file(WRITEPATH . 'uploads/bds_dump_excel', $file_name);
$spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load($file_name_with_path); $spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load($file_name_with_path);
$worksheet = $spreadsheet->getActiveSheet(); $worksheet = $spreadsheet->getActiveSheet();
@ -6822,7 +6827,7 @@ class PolicyTransactionController extends BaseController
$error_data = json_decode($file['reason']); $error_data = json_decode($file['reason']);
// dd($error_data); // dd($error_data);
$file_name_with_path = WRITEPATH . "/uploads/bds_dump_excel/" . $file['file_name']; $file_name_with_path = storage_ensure_local_file(WRITEPATH . 'uploads/bds_dump_excel', $file['file_name']);
// Kint::dump(file_exists($file_name_with_path)); die; // Kint::dump(file_exists($file_name_with_path)); die;
//check the file exist or not //check the file exist or not
@ -7230,4 +7235,53 @@ class PolicyTransactionController extends BaseController
} }
} }
/**
* Download policy transaction (pt_files) document from local/S3 storage.
*/
public function downloadPtDocument($fileOrId = null)
{
if ($fileOrId === null || $fileOrId === '') {
$data['message'] = 'No file specified.';
return view('errors/404', $data);
}
$uploadFilePath = WRITEPATH . 'uploads/client_kyc_documents';
$storedFileName = null;
$downloadAs = null;
if (ctype_digit((string) $fileOrId)) {
$record = $this->PTFileModel->find((int) $fileOrId);
if (empty($record) || empty($record['file_name'])) {
$data['message'] = 'File record not found';
return view('errors/404', $data);
}
$storedFileName = basename((string) $record['file_name']);
$downloadAs = storage_upload_display_name($storedFileName);
} else {
$storedFileName = basename((string) $fileOrId);
$downloadAs = storage_upload_display_name($storedFileName);
}
$storage = \Config\Services::getFileStorageService();
$result = $storage->download($uploadFilePath, $storedFileName);
if (! ($result['success'] ?? false)) {
$data['message'] = 'The Physical File Not Found';
return view('errors/404', $data);
}
if (! empty($result['path']) && is_file($result['path'])) {
return $this->response->download($result['path'], null)->setFileName($downloadAs);
}
if (! empty($result['content'])) {
return $this->response
->download($downloadAs, $result['content'])
->setFileName($downloadAs);
}
$data['message'] = 'The Physical File Not Found';
return view('errors/404', $data);
}
} }

View File

@ -825,6 +825,7 @@ class RestAuthenticationController extends AdminController
$HRAccessData['post_client_id'] = md5($HRAccessData['post_client_id']); $HRAccessData['post_client_id'] = md5($HRAccessData['post_client_id']);
$HRAccessData['claims_sub_menu'] = $claimsSubMenu; $HRAccessData['claims_sub_menu'] = $claimsSubMenu;
print_r($HRAccessData); die;
$token = JWTToken::encode($HRAccessData); $token = JWTToken::encode($HRAccessData);
$getAllhrData[$key]['token'] = $token; $getAllhrData[$key]['token'] = $token;

View File

@ -2419,34 +2419,27 @@ class TicketController extends BaseController
// $actionType = $this->request->getGet(); // $actionType = $this->request->getGet();
$claimFiles = new ClaimFilesModel(); $claimFiles = new ClaimFilesModel();
$file_data = $claimFiles->where('id', $claim_file_id)->first(); $file_data = $claimFiles->where('id', $claim_file_id)->first();
// $fileName = $file_data['doc_name']; if (empty($file_data)) {
$data['message'] = 'File record not found';
return view('errors/404', $data);
}
$url = $file_data['url']; $fileName = $this->resolveClaimFileDiskName($file_data);
$parts = explode('/', $url);
$fileName = end($parts);
$filePath = WRITEPATH . '/uploads/claim_files/' . $fileName;
try { try {
$download = $this->downloadFileFromStorage(WRITEPATH . 'uploads/claim_files', $fileName);
// Check if the file exists if ($download !== null) {
if (file_exists($filePath)) { return $download;
// Set the appropriate MIME type }
$mimeType = mime_content_type($filePath);
// Send the file to the client for download
return $this->response->download($filePath, null, $mimeType);
} else {
$data['message'] = 'The Physical File Not Found'; $data['message'] = 'The Physical File Not Found';
echo view('errors/404', $data); return view('errors/404', $data);
}
} catch (\Exception $e) { } catch (\Exception $e) {
// Handle any exceptions // Handle any exceptions
$errorMessage = $e->getMessage(); $errorMessage = $e->getMessage();
$this->myLogger->logme('error', $errorMessage); $this->myLogger->logme('error', $errorMessage);
// You can return an error response here $data['message'] = 'The Physical File Not Found';
echo $errorMessage; return view('errors/404', $data);
} }
} }
@ -2466,21 +2459,35 @@ class TicketController extends BaseController
throw PageNotFoundException::forPageNotFound(); throw PageNotFoundException::forPageNotFound();
} }
$url = $file_record['url']; $fileName = $this->resolveClaimFileDiskName($file_record);
$parts = explode('/', $url);
$fileName = end($parts);
$filePath = WRITEPATH . '/uploads/claim_files/' . $fileName;
if (! is_file($filePath)) {
throw PageNotFoundException::forPageNotFound();
}
$ext = strtolower(pathinfo($fileName, PATHINFO_EXTENSION) ?: ''); $ext = strtolower(pathinfo($fileName, PATHINFO_EXTENSION) ?: '');
if (! in_array($ext, ['pdf', 'png', 'jpg', 'jpeg'], true)) { if (! in_array($ext, ['pdf', 'png', 'jpg', 'jpeg'], true)) {
throw PageNotFoundException::forPageNotFound(); throw PageNotFoundException::forPageNotFound();
} }
return $this->response->download($filePath, null, true)->inline()->setFileName($fileName); $storage = \Config\Services::getFileStorageService();
$uploadPath = WRITEPATH . 'uploads/claim_files';
$result = $storage->download($uploadPath, $fileName);
if (! ($result['success'] ?? false)) {
throw PageNotFoundException::forPageNotFound();
}
if (! empty($result['path']) && is_file($result['path'])) {
return $this->response->download($result['path'], null, true)->inline()->setFileName($fileName);
}
if (! empty($result['content'])) {
$mimeType = getMimeTypeByFileName($fileName) ?: 'application/octet-stream';
return $this->response
->setHeader('Content-Type', $mimeType)
->setHeader('Content-Disposition', 'inline; filename="' . $fileName . '"')
->setBody($result['content']);
}
throw PageNotFoundException::forPageNotFound();
} }
public function convertHtmlToTextOld($html) public function convertHtmlToTextOld($html)
@ -3729,15 +3736,15 @@ class TicketController extends BaseController
mkdir($uploadPath, 0755, true); mkdir($uploadPath, 0755, true);
} }
$diskFileName = file_Upload_for_lead($file, $uploadPath, ['pdf']); $uploaded = storage_claim_file_Upload($file, $uploadPath, ['pdf']);
if (empty($diskFileName)) { if ($uploaded === '') {
return ['status' => false, 'message' => 'Failed to upload ' . $documentLabel . ' file.']; return ['status' => false, 'message' => 'Failed to upload ' . $documentLabel . ' file.'];
} }
return [ return [
'status' => true, 'status' => true,
'data' => [ 'data' => [
'file_name' => $diskFileName, 'file_name' => $uploaded['disk_name'],
'mime_type' => $mime ?: 'application/pdf', 'mime_type' => $mime ?: 'application/pdf',
], ],
]; ];
@ -3857,7 +3864,7 @@ class TicketController extends BaseController
$file_data = []; $file_data = [];
if(isset($get_file_data) && !empty($get_file_data)){ if(isset($get_file_data) && !empty($get_file_data)){
$file_path = WRITEPATH . 'uploads/claim_files/'; $file_path = WRITEPATH . 'uploads/claim_files/';
$file_data = multi_file_Upload($get_file_data, $file_path, $get_docs_name, UPLOAD_EXT_CLAIM_DOCS); $file_data = storage_multi_file_Upload($get_file_data, $file_path, $get_docs_name, UPLOAD_EXT_CLAIM_DOCS);
} }
if(!empty($file_data)){ if(!empty($file_data)){
@ -3980,30 +3987,25 @@ class TicketController extends BaseController
{ {
$id = $this->request->getGet('id'); $id = $this->request->getGet('id');
if (empty(trim($id))) { if (empty(trim($id ?? ''))) {
return $this->response->setJSON([ return $this->response->setJSON([
'status' => false, 'status' => false,
'message' => 'Invalid ID' 'message' => 'Invalid ID'
]); ]);
} }
$updated = $this->claimFilesModel if (storage_soft_delete_claim_file((int) $id)) {
->where('id', $id)
->set(['is_active' => 0])
->update();
if ($updated) {
return $this->response->setJSON([ return $this->response->setJSON([
'status' => true, 'status' => true,
'message' => 'URL successfully marked inactive.' 'message' => 'URL successfully marked inactive.'
]); ]);
} else { }
return $this->response->setJSON([ return $this->response->setJSON([
'status' => false, 'status' => false,
'message' => 'Failed to update record.' 'message' => 'Failed to update record.'
]); ]);
} }
}
public function recursive_json_decode($input) public function recursive_json_decode($input)
{ {
@ -4389,13 +4391,10 @@ class TicketController extends BaseController
return $this->respond(['status' => false, 'code' => 400, 'message' => 'File not found'], 400); return $this->respond(['status' => false, 'code' => 400, 'message' => 'File not found'], 400);
} }
$is_moved = $avatar->move(WRITEPATH . 'uploads/claim_dump_excel/'); $filename = storage_file_Upload($avatar, WRITEPATH . 'uploads/claim_dump_excel/', UPLOAD_EXT_EXCEL);
if ($is_moved) {
$filename = $avatar->getName();
$fileSize = $avatar->getSize(); // File size in bytes
$fileSize = $fileSize / (1024 * 1024); // Convert to MB
if ($filename !== '') {
$fileSize = method_exists($avatar, 'getSize') ? ($avatar->getSize() / (1024 * 1024)) : 0;
$this->myLogger->logme("error", 'File move successful'); $this->myLogger->logme("error", 'File move successful');
} else { } else {
@ -4487,34 +4486,30 @@ class TicketController extends BaseController
{ {
// $actionType = $this->request->getGet(); // $actionType = $this->request->getGet();
$file_data = $this->claimDumpFileModel->where('id', $file_id)->first(); $file_data = $this->claimDumpFileModel->where('id', $file_id)->first();
if (empty($file_data)) {
$data['message'] = 'File record not found';
return view('errors/404', $data);
}
$fileName = $file_data['file_name']; $fileName = $file_data['file_name'];
$filePath = WRITEPATH . '/uploads/claim_dump_excel/' . $fileName;
try { try {
$download = $this->downloadFileFromStorage(WRITEPATH . 'uploads/claim_dump_excel', $fileName);
// Check if the file exists if ($download !== null) {
if (file_exists($filePath)) { return $download;
// Set the appropriate MIME type }
$mimeType = mime_content_type($filePath);
// Send the file to the client for download
return $this->response->download($filePath, null, $mimeType);
} else {
$data['message'] = 'The Physical File Not Found'; $data['message'] = 'The Physical File Not Found';
echo view('errors/404', $data); return view('errors/404', $data);
}
} catch (\Exception $e) { } catch (\Exception $e) {
// Handle any exceptions // Handle any exceptions
$errorMessage = $e->getMessage(); $errorMessage = $e->getMessage();
$this->myLogger->logme('error', $errorMessage); $this->myLogger->logme('error', $errorMessage);
// You can return an error response here $data['message'] = 'The Physical File Not Found';
echo $errorMessage; return view('errors/404', $data);
} }
} }
/** /**
* Soft-delete a TPA claim dump upload: dump rows + tickets created by that file_id. * Soft-delete a TPA claim dump upload: dump rows + tickets created by that file_id.
*/ */
@ -4566,6 +4561,7 @@ class TicketController extends BaseController
], 200); ], 200);
} }
} }
/** /**
* List dump rows for a file where ticket_id is still NULL (not moved to ticket_master). * List dump rows for a file where ticket_id is still NULL (not moved to ticket_master).
*/ */
@ -5174,14 +5170,9 @@ class TicketController extends BaseController
return $this->respond(['status' => false, 'code' => 400, 'message' => 'File not found'], 400); return $this->respond(['status' => false, 'code' => 400, 'message' => 'File not found'], 400);
} }
$is_moved = $file->move(WRITEPATH . 'uploads/claims_mis/'); $filename = storage_file_Upload($file, WRITEPATH . 'uploads/claims_mis/', UPLOAD_EXT_EXCEL);
if ($is_moved) {
$file_path = WRITEPATH.'uploads/claims_mis';
$filename = file_Upload_for_lead($file, $file_path, UPLOAD_EXT_EXCEL);
$fileSize = $file->getSize(); // File size in bytes
$fileSize = $fileSize / (1024 * 1024); // Convert to MB
if ($filename !== '') {
$this->myLogger->logme("error", 'File move successful'); $this->myLogger->logme("error", 'File move successful');
$request_data = $this->request->getPost(); $request_data = $this->request->getPost();
@ -5194,9 +5185,7 @@ class TicketController extends BaseController
if(isset($data['to_date']) && !empty($data['to_date'])){ if(isset($data['to_date']) && !empty($data['to_date'])){
$data['to_date'] = change_date_format($data['to_date'], 'd/m/Y', 'Y-m-d'); $data['to_date'] = change_date_format($data['to_date'], 'd/m/Y', 'Y-m-d');
} }
if(!empty($file_name)){ $data['file_name'] = $filename;
$data['file_name'] = $file;
}
$response = $this->claimmisFileModel->insert($data); $response = $this->claimmisFileModel->insert($data);
@ -5260,17 +5249,13 @@ class TicketController extends BaseController
return view('errors/404', $data); return view('errors/404', $data);
} }
$uploadPath = WRITEPATH . 'uploads/claims_mis/'; $download = $this->downloadFileFromStorage(WRITEPATH . 'uploads/claims_mis', $record['file_name']);
$filePath = $uploadPath . $record['file_name']; if ($download === null) {
// dd($filePath);
if (!file_exists($filePath)) {
$data['message'] = 'The Physical File Not Found'; $data['message'] = 'The Physical File Not Found';
return view('errors/404', $data); return view('errors/404', $data);
} }
// Force file download return $download;
return $this->response->download($filePath, null)->setFileName($record['file_name']);
} catch (\Exception $e) { } catch (\Exception $e) {
// return $this->failServerError($e->getMessage()); // return $this->failServerError($e->getMessage());
@ -5280,4 +5265,38 @@ class TicketController extends BaseController
} }
} }
private function resolveClaimFileDiskName(array $fileRecord): string
{
$url = (string) ($fileRecord['url'] ?? '');
if ($url !== '') {
return basename($url);
}
return basename((string) ($fileRecord['file_name'] ?? ''));
}
/**
* Download helper for phased local->S3 migration.
* Returns null when file is unavailable in both local and S3.
*/
private function downloadFileFromStorage(string $uploadPath, string $fileName)
{
$storage = \Config\Services::getFileStorageService();
$result = $storage->download($uploadPath, $fileName);
if (!($result['success'] ?? false)) {
return null;
}
if (!empty($result['path']) && is_file($result['path'])) {
return $this->response->download($result['path'], null)->setFileName($fileName);
}
if (!empty($result['content'])) {
return $this->response->download($fileName, $result['content'])->setFileName($fileName);
}
return null;
}
} }

View File

@ -965,7 +965,7 @@ class TicketServiceController extends AdminController
return array('status' => false, 'message' => 'File not found in Database'); return array('status' => false, 'message' => 'File not found in Database');
} }
$file_name_with_path = WRITEPATH . "/uploads/claim_dump_excel/" . $file['file_name']; $file_name_with_path = storage_ensure_local_file(WRITEPATH . 'uploads/claim_dump_excel', $file['file_name']);
//check physical file exist //check physical file exist
if (!file_exists($file_name_with_path)) { if (!file_exists($file_name_with_path)) {
@ -1174,7 +1174,7 @@ class TicketServiceController extends AdminController
return array('status' => false, 'message' => 'File not found in Database'); return array('status' => false, 'message' => 'File not found in Database');
} }
$file_name_with_path = WRITEPATH . "/uploads/claim_dump_excel/" . $file['file_name']; $file_name_with_path = storage_ensure_local_file(WRITEPATH . 'uploads/claim_dump_excel', $file['file_name']);
//check physical file //check physical file
if (!file_exists($file_name_with_path)) { if (!file_exists($file_name_with_path)) {
@ -1360,7 +1360,7 @@ class TicketServiceController extends AdminController
return array('status' => false, 'message' => 'File not found in Database'); return array('status' => false, 'message' => 'File not found in Database');
} }
$file_name_with_path = WRITEPATH . "/uploads/claim_dump_excel/" . $file['file_name']; $file_name_with_path = storage_ensure_local_file(WRITEPATH . 'uploads/claim_dump_excel', $file['file_name']);
//check physical file //check physical file
if (!file_exists($file_name_with_path)) { if (!file_exists($file_name_with_path)) {
@ -1478,7 +1478,7 @@ class TicketServiceController extends AdminController
{ {
// $file_name = "claims_dump_form_client.xlsx"; // $file_name = "claims_dump_form_client.xlsx";
// Load the Excel file // Load the Excel file
$file_name_with_path = WRITEPATH . "/uploads/claim_dump_excel/" . $file_name; $file_name_with_path = storage_ensure_local_file(WRITEPATH . 'uploads/claim_dump_excel', $file_name);
$spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load($file_name_with_path); $spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load($file_name_with_path);
$worksheet = $spreadsheet->getActiveSheet(); $worksheet = $spreadsheet->getActiveSheet();
@ -1751,7 +1751,7 @@ class TicketServiceController extends AdminController
$error_data = json_decode($file['reason']); $error_data = json_decode($file['reason']);
// dd($error_data); // dd($error_data);
$file_name_with_path = WRITEPATH . "/uploads/claim_dump_excel/" . $file['file_name']; $file_name_with_path = storage_ensure_local_file(WRITEPATH . 'uploads/claim_dump_excel', $file['file_name']);
//check the file exist or not //check the file exist or not
if (!file_exists($file_name_with_path)) { if (!file_exists($file_name_with_path)) {
@ -1870,7 +1870,7 @@ class TicketServiceController extends AdminController
]; ];
} }
$filePath = WRITEPATH . 'uploads' . DIRECTORY_SEPARATOR . 'claim_dump_excel' . DIRECTORY_SEPARATOR . $fileData['file_name']; $filePath = storage_ensure_local_file(WRITEPATH . 'uploads/claim_dump_excel', $fileData['file_name']);
if ($requirePhysicalFile && !is_file($filePath)) { if ($requirePhysicalFile && !is_file($filePath)) {
return [ return [

View File

@ -134,7 +134,7 @@ class VidalApiController extends BaseController
public function SubmitClaim ($claimId = null) //515 public function SubmitClaim ($claimId = null) //515
{ {
helper(['api', 'tpa_claim_push_log']); helper(['api', 'tpa_claim_push_log', 'utility']);
// Fetch the data from DB // Fetch the data from DB
$data = $this->db->table('ticket_master tm') $data = $this->db->table('ticket_master tm')
@ -181,12 +181,21 @@ class VidalApiController extends BaseController
$filePath = $data['filePath'] ?? ''; $filePath = $data['filePath'] ?? '';
$filename = basename($filePath); $filename = basename($filePath);
$filePath = WRITEPATH . 'uploads/claim_files/'.$filename; $resolved = storage_resolve_claim_file_path(WRITEPATH . 'uploads/claim_files', $filename);
if (!($resolved['success'] ?? false) || empty($resolved['path'])) {
tpa_claim_push_log($claimId, "VIDAL - Claim Push | Submit claim failed - File not found in local/S3: {$filename}");
return $this->response->setJSON([
'status' => false,
'message' => 'File upload failed',
'data' => ['message' => 'Claim file not found in storage'],
]);
}
// dd($data); // dd($data);
// Upload file first // Upload file first
$upload = $this->uploadFileToVidal($filePath, $filename, $claimId); $upload = $this->uploadFileToVidal($resolved['path'], $filename, $claimId);
storage_cleanup_temp_claim_file($resolved);
if ($upload['status'] !== true) { if ($upload['status'] !== true) {
tpa_claim_push_log($claimId, "VIDAL - Claim Push | Submit claim failed - File upload failed"); tpa_claim_push_log($claimId, "VIDAL - Claim Push | Submit claim failed - File upload failed");
return $this->response->setJSON([ return $this->response->setJSON([
@ -1663,6 +1672,7 @@ class VidalApiController extends BaseController
public function IRSubmission($claimId = null) public function IRSubmission($claimId = null)
{ {
helper('utility');
log_message('error', "VIDAL - IR Submission | INIT for ticket_id={$claimId}"); log_message('error', "VIDAL - IR Submission | INIT for ticket_id={$claimId}");
// 1. FETCH TICKET DETAILS // 1. FETCH TICKET DETAILS
@ -1718,14 +1728,20 @@ class VidalApiController extends BaseController
foreach ($fileData as $file) { foreach ($fileData as $file) {
if (empty($file['filePath'])) { $storedPath = (string) ($file['filePath'] ?? $file['url'] ?? '');
if ($storedPath === '') {
continue; continue;
} }
$filename = basename($file['filePath']); $filename = basename($storedPath);
$fullPath = WRITEPATH . 'uploads/claim_files/' . $filename; $resolved = storage_resolve_claim_file_path(WRITEPATH . 'uploads/claim_files', $filename);
if (!($resolved['success'] ?? false) || empty($resolved['path'])) {
log_message('error', "VIDAL - IR Submission FAILED → File not found in local/S3 | {$filename}");
continue;
}
$upload = $this->uploadFileToVidal($fullPath, $filename); $upload = $this->uploadFileToVidal($resolved['path'], $filename);
storage_cleanup_temp_claim_file($resolved);
if (empty($upload['status']) || $upload['status'] !== true) { if (empty($upload['status']) || $upload['status'] !== true) {
log_message('error', "VIDAL - IR Submission FAILED → File upload failed"); log_message('error', "VIDAL - IR Submission FAILED → File upload failed");

View File

@ -682,7 +682,7 @@ class VoloApiController extends BaseController
*/ */
public function SubmitClaim($claimId = null) public function SubmitClaim($claimId = null)
{ {
helper(['api', 'tpa_claim_push_log']); helper(['api', 'tpa_claim_push_log', 'utility']);
$data = $this->db->table('ticket_master tm') $data = $this->db->table('ticket_master tm')
->select(' ->select('
@ -713,14 +713,12 @@ class VoloApiController extends BaseController
$file_id = $data['fileId'] ?? null; $file_id = $data['fileId'] ?? null;
$filename = basename($data['filePath']); $filename = basename($data['filePath']);
$pdfPath = WRITEPATH . 'uploads/claim_files/' . $filename; $publicUrl = storage_claim_file_download_url($filename, $file_id);
if (!is_readable($pdfPath)) { if ($publicUrl === '') {
tpa_claim_push_log($claimId, 'VOLO - Claim Push FAILED | claimId: ' . $claimId . ' | PDF not readable'); tpa_claim_push_log($claimId, 'VOLO - Claim Push FAILED | claimId: ' . $claimId . ' | PDF not available on S3/local');
return ['status' => false, 'message' => 'Claim Push FAILED | PDF not found on server']; return ['status' => false, 'message' => 'Claim Push FAILED | PDF not found on server'];
} }
$publicUrl = base_url('fileDownload?file_path=') . $pdfPath;
$entityId = $this->resolveEntityId($data['policyNo'] ?? ''); $entityId = $this->resolveEntityId($data['policyNo'] ?? '');
if ($entityId === null) { if ($entityId === null) {
tpa_claim_push_log($claimId, 'VOLO - Claim Push FAILED | claimId: ' . $claimId . ' | entity id not resolved'); tpa_claim_push_log($claimId, 'VOLO - Claim Push FAILED | claimId: ' . $claimId . ' | entity id not resolved');

View File

@ -86,11 +86,14 @@ if (! function_exists('merge_ticket_pdfs')) {
$sourceFiles = []; $sourceFiles = [];
foreach ($rows as $row) { foreach ($rows as $row) {
$full = merge_ticket_pdf_resolve_disk_path($row, $uploadDir); $full = merge_ticket_pdf_resolve_disk_path($row, $uploadDir, true);
if ($full !== null) { if ($full !== null) {
$mime = merge_ticket_pdf_resolve_mime($full, (string) ($row['mime_type'] ?? '')); $mime = merge_ticket_pdf_resolve_mime($full, (string) ($row['mime_type'] ?? ''));
if (! in_array($mime, $opts['include_mime_types'], true)) { if (! in_array($mime, $opts['include_mime_types'], true)) {
log_message('error', "merge_ticket_pdfs | unsupported source mime {$mime} | claim_file_id={$row['id']} | path={$full}"); log_message('error', "merge_ticket_pdfs | unsupported source mime {$mime} | claim_file_id={$row['id']} | path={$full}");
if (strpos($full, 'claim_files_runtime') !== false) {
@unlink($full);
}
continue; continue;
} }
@ -98,10 +101,11 @@ if (! function_exists('merge_ticket_pdfs')) {
'path' => $full, 'path' => $full,
'mime' => $mime, 'mime' => $mime,
'id' => $row['id'] ?? null, 'id' => $row['id'] ?? null,
'is_temp' => strpos($full, 'claim_files_runtime') !== false,
]; ];
} else { } else {
$name = ! empty($row['url']) ? $row['url'] : ($row['file_name'] ?? ''); $name = ! empty($row['url']) ? $row['url'] : ($row['file_name'] ?? '');
log_message('error', "merge_ticket_pdfs | missing file on disk | claim_file_id={$row['id']} | path=" . $uploadDir . basename((string) $name)); log_message('error', "merge_ticket_pdfs | missing file in local/S3 | claim_file_id={$row['id']} | path=" . $uploadDir . basename((string) $name));
} }
} }
@ -110,6 +114,14 @@ if (! function_exists('merge_ticket_pdfs')) {
return $result; return $result;
} }
$cleanupMergeTemps = static function (array $files): void {
foreach ($files as $sourceFile) {
if (! empty($sourceFile['is_temp']) && ! empty($sourceFile['path']) && is_file($sourceFile['path'])) {
@unlink($sourceFile['path']);
}
}
};
$result['source_count'] = count($sourceFiles); $result['source_count'] = count($sourceFiles);
log_message( log_message(
'error', 'error',
@ -162,22 +174,39 @@ if (! function_exists('merge_ticket_pdfs')) {
} }
if ($totalPages === 0) { if ($totalPages === 0) {
$cleanupMergeTemps($sourceFiles);
$result['message'] = 'All source PDF/image files failed to import'; $result['message'] = 'All source PDF/image files failed to import';
return $result; return $result;
} }
$mpdf->Output($mergedPath, Destination::FILE); $mpdf->Output($mergedPath, Destination::FILE);
} catch (\Throwable $e) { } catch (\Throwable $e) {
$cleanupMergeTemps($sourceFiles);
log_message('error', 'merge_ticket_pdfs | mpdf failure | ticket_id=' . $ticket_master_id . ' | ' . $e->getMessage()); log_message('error', 'merge_ticket_pdfs | mpdf failure | ticket_id=' . $ticket_master_id . ' | ' . $e->getMessage());
$result['message'] = 'Merge failed: ' . $e->getMessage(); $result['message'] = 'Merge failed: ' . $e->getMessage();
return $result; return $result;
} }
if (! is_file($mergedPath)) { if (! is_file($mergedPath)) {
$cleanupMergeTemps($sourceFiles);
$result['message'] = 'Merged file was not created'; $result['message'] = 'Merged file was not created';
return $result; return $result;
} }
$storage = \Config\Services::getFileStorageService();
if ($storage->usesS3()) {
$uploadResult = $storage->upload($mergedPath, rtrim($uploadDir, '/\\'), $mergedName);
if (! ($uploadResult['success'] ?? false)) {
log_message('error', 'merge_ticket_pdfs | failed to mirror merged file to S3 | ticket_id=' . $ticket_master_id . ' | ' . json_encode($uploadResult));
@unlink($mergedPath);
$cleanupMergeTemps($sourceFiles);
$result['message'] = 'Merged file upload to storage failed';
return $result;
}
// S3-only: drop permanent local merged copy after successful upload.
@unlink($mergedPath);
}
if ($opts['replace']) { if ($opts['replace']) {
$claimFiles $claimFiles
->where('ticket_id', $ticket_master_id) ->where('ticket_id', $ticket_master_id)
@ -203,6 +232,8 @@ if (! function_exists('merge_ticket_pdfs')) {
$insertedId = $claimFiles->insert($insertData); $insertedId = $claimFiles->insert($insertData);
$cleanupMergeTemps($sourceFiles);
if (! $insertedId) { if (! $insertedId) {
log_message('error', 'merge_ticket_pdfs | DB insert failed for merged file | ticket_id=' . $ticket_master_id); log_message('error', 'merge_ticket_pdfs | DB insert failed for merged file | ticket_id=' . $ticket_master_id);
@unlink($mergedPath); @unlink($mergedPath);
@ -356,7 +387,7 @@ if (! function_exists('merge_ticket_pdf_resolve_disk_path')) {
/** /**
* Resolve on-disk path for a claim_files row (url and/or file_name). * Resolve on-disk path for a claim_files row (url and/or file_name).
*/ */
function merge_ticket_pdf_resolve_disk_path(array $row, string $uploadDir): ?string function merge_ticket_pdf_resolve_disk_path(array $row, string $uploadDir, bool $allowTempDownload = true): ?string
{ {
$candidates = []; $candidates = [];
if (! empty($row['url'])) { if (! empty($row['url'])) {
@ -374,6 +405,14 @@ if (! function_exists('merge_ticket_pdf_resolve_disk_path')) {
if (is_file($full) && is_readable($full)) { if (is_file($full) && is_readable($full)) {
return $full; return $full;
} }
if ($allowTempDownload) {
helper('utility');
$resolved = storage_resolve_claim_file_path(rtrim($uploadDir, '/\\'), $name);
if (($resolved['success'] ?? false) && ! empty($resolved['path']) && is_file($resolved['path'])) {
return $resolved['path'];
}
}
} }
return null; return null;
@ -489,8 +528,22 @@ if (! function_exists('merge_ticket_manual_merge_status')) {
$sourceRowCount++; $sourceRowCount++;
$full = merge_ticket_pdf_resolve_disk_path($row, $uploadDir); $full = merge_ticket_pdf_resolve_disk_path($row, $uploadDir, false);
if ($full === null) { if ($full === null) {
helper('utility');
$name = basename((string) (! empty($row['url']) ? $row['url'] : ($row['file_name'] ?? '')));
if ($name === '') {
continue;
}
$storage = \Config\Services::getFileStorageService();
$available = $storage->exists(rtrim($uploadDir, '/\\'), $name);
if (! $available) {
continue;
}
$mime = merge_ticket_pdf_resolve_mime($name, (string) ($row['mime_type'] ?? ''));
if (in_array($mime, $opts['include_mime_types'], true)) {
$mergeableCount++;
}
continue; continue;
} }

View File

@ -34,11 +34,14 @@ class sendMailNotification
$attachments = []; $attachments = [];
foreach ($attachment_data as $data) { foreach ($attachment_data as $data) {
$resolved = storage_resolve_mail_attachment_path($data['file_path'] ?? null, $data['file_name'] ?? null);
if (($resolved['success'] ?? false) && ! empty($resolved['path'])) {
$attachments[] = [ $attachments[] = [
"filePath" => WRITEPATH . $data['file_path'], "filePath" => $resolved['path'],
"fileName" => $data['file_name'] "fileName" => $resolved['display_name'] ?? $data['file_name'],
]; ];
} }
}
$mail = $dataToInsert['email_corporate']; $mail = $dataToInsert['email_corporate'];
$subject = $notification['subject']; $subject = $notification['subject'];
@ -125,11 +128,14 @@ class sendMailNotification
$attachments = []; $attachments = [];
foreach ($attachment_data as $data) { foreach ($attachment_data as $data) {
$resolved = storage_resolve_mail_attachment_path($data['file_path'] ?? null, $data['file_name'] ?? null);
if (($resolved['success'] ?? false) && ! empty($resolved['path'])) {
$attachments[] = [ $attachments[] = [
"filePath" => WRITEPATH . $data['file_path'], "filePath" => $resolved['path'],
"fileName" => $data['file_name'] "fileName" => $resolved['display_name'] ?? $data['file_name'],
]; ];
} }
}
$mail_content = $notification['mail_content']; $mail_content = $notification['mail_content'];
@ -1268,11 +1274,14 @@ class sendMailNotification
$attachments = []; $attachments = [];
foreach ($attachment_data as $data) { foreach ($attachment_data as $data) {
$resolved = storage_resolve_mail_attachment_path($data['file_path'] ?? null, $data['file_name'] ?? null);
if (($resolved['success'] ?? false) && ! empty($resolved['path'])) {
$attachments[] = [ $attachments[] = [
"filePath" => WRITEPATH . $data['file_path'], "filePath" => $resolved['path'],
"fileName" => $data['file_name'] "fileName" => $resolved['display_name'] ?? $data['file_name'],
]; ];
} }
}
// print_r($attachments); die; // print_r($attachments); die;
@ -1361,11 +1370,14 @@ class sendMailNotification
$attachments = []; $attachments = [];
foreach ($attachment_data as $data) { foreach ($attachment_data as $data) {
$resolved = storage_resolve_mail_attachment_path($data['file_path'] ?? null, $data['file_name'] ?? null);
if (($resolved['success'] ?? false) && ! empty($resolved['path'])) {
$attachments[] = [ $attachments[] = [
"filePath" => WRITEPATH . $data['file_path'], "filePath" => $resolved['path'],
"fileName" => $data['file_name'] "fileName" => $resolved['display_name'] ?? $data['file_name'],
]; ];
} }
}
$mail_content = $notification['mail_content']; $mail_content = $notification['mail_content'];
$subject = $notification['subject']; $subject = $notification['subject'];
@ -1416,11 +1428,14 @@ class sendMailNotification
$attachments = []; $attachments = [];
foreach ($attachment_data as $data) { foreach ($attachment_data as $data) {
$resolved = storage_resolve_mail_attachment_path($data['file_path'] ?? null, $data['file_name'] ?? null);
if (($resolved['success'] ?? false) && ! empty($resolved['path'])) {
$attachments[] = [ $attachments[] = [
"filePath" => WRITEPATH . $data['file_path'], "filePath" => $resolved['path'],
"fileName" => $data['file_name'] "fileName" => $resolved['display_name'] ?? $data['file_name'],
]; ];
} }
}
$mail_content = $notification['mail_content']; $mail_content = $notification['mail_content'];
$subject = $notification['subject']; $subject = $notification['subject'];

View File

@ -99,6 +99,181 @@ if (! function_exists('file_Upload')) {
} }
} }
/**
* Extract original/display filename from a unique storage key.
* Unique keys are stored as: {timestamp}_{hex}_{sanitizedOriginalName}
* Legacy plain filenames are returned unchanged.
*/
if (! function_exists('storage_upload_display_name')) {
function storage_upload_display_name(?string $storedName): string
{
$storedName = (string) $storedName;
if ($storedName === '') {
return '';
}
if (preg_match('/^\d+_[a-f0-9]+_(.+)$/i', $storedName, $matches)) {
return $matches[1];
}
return $storedName;
}
}
/**
* Build a collision-safe storage filename while preserving the original name for display/download.
*/
if (! function_exists('storage_unique_upload_name')) {
function storage_unique_upload_name(string $originalName): string
{
$displayName = sanitize_upload_filename($originalName);
return time() . '_' . bin2hex(random_bytes(8)) . '_' . $displayName;
}
}
/**
* Upload via FileStorageService (S3 wrapper).
* Uses folder path last segment as the S3 folder/bucket prefix.
* Stores a unique disk/S3 key so same original names never overwrite each other.
*
* Env RETAIN_LOCAL (default false):
* - false / missing: S3-only temp stage upload delete local
* - true: dual-write keep permanent local copy under $filepath after S3 upload
*
* Processors should still use storage_ensure_local_file() when local may be missing.
*
* @param bool $retainLocal Unused; behaviour is controlled by env RETAIN_LOCAL only.
*/
if (! function_exists('storage_file_Upload')) {
function storage_file_Upload($fileToUpload, $filepath, array $allowedExtensions = UPLOAD_ALLOWED_EXTENSIONS, bool $retainLocal = false)
{
if ($fileToUpload === null || ! $fileToUpload->isValid() || $fileToUpload->hasMoved()) {
log_message('error', 'storage_file_Upload validation failed | ' . json_encode([
'filepath' => $filepath,
'reason' => $fileToUpload === null ? 'file_null' : (!$fileToUpload->isValid() ? 'invalid_file' : 'already_moved'),
'error' => (is_object($fileToUpload) && method_exists($fileToUpload, 'getErrorString')) ? $fileToUpload->getErrorString() : null,
], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE));
return "";
}
if (! validate_upload_extension($fileToUpload, $allowedExtensions)) {
log_message('error', 'storage_file_Upload extension rejected | ' . json_encode([
'filepath' => $filepath,
'client_name' => method_exists($fileToUpload, 'getClientName') ? $fileToUpload->getClientName() : null,
'extension' => method_exists($fileToUpload, 'getExtension') ? $fileToUpload->getExtension() : null,
'allowed_extensions' => $allowedExtensions,
], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE));
return "";
}
$originalName = method_exists($fileToUpload, 'getClientName') && $fileToUpload->getClientName()
? $fileToUpload->getClientName()
: $fileToUpload->getName();
$fileName = storage_unique_upload_name($originalName);
$storage = \Config\Services::getFileStorageService();
$filepath = rtrim($filepath, '/\\');
// Env controls retention; missing / empty / false => do not keep local when on S3.
$retainLocal = storage_env_retain_local();
if ($storage->usesS3()) {
if ($retainLocal) {
if (! is_dir($filepath)) {
mkdir($filepath, 0755, true);
}
$fileToUpload->move($filepath . DIRECTORY_SEPARATOR, $fileName);
$localPath = $filepath . DIRECTORY_SEPARATOR . $fileName;
$result = $storage->upload($localPath, $filepath, $fileName);
if (! ($result['success'] ?? false)) {
@unlink($localPath);
log_message('error', 'storage_file_Upload retain_local failed | ' . json_encode([
'filepath' => $filepath,
'file_name' => $fileName,
'message' => $result['message'] ?? null,
], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE));
return '';
}
log_message('info', 'storage_file_Upload retain_local completed | ' . json_encode([
'filepath' => $filepath,
'file_name' => $fileName,
'display_name' => storage_upload_display_name($fileName),
'retain_local' => true,
'bucket' => $storage->getBucket(),
], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE));
return $fileName;
}
// S3-only: stage briefly, upload, always delete local.
$tmpDir = storage_runtime_temp_dir();
if (! is_dir($tmpDir)) {
@mkdir($tmpDir, 0755, true);
}
$fileToUpload->move($tmpDir . DIRECTORY_SEPARATOR, $fileName);
$localPath = $tmpDir . DIRECTORY_SEPARATOR . $fileName;
$result = $storage->upload($localPath, $filepath, $fileName);
@unlink($localPath);
log_message(
($result['success'] ?? false) ? 'info' : 'error',
'storage_file_Upload s3_only completed | ' . json_encode([
'filepath' => $filepath,
'file_name' => $fileName,
'display_name' => storage_upload_display_name($fileName),
'success' => $result['success'] ?? false,
'key' => $result['key'] ?? null,
'message' => $result['message'] ?? null,
'bucket' => $storage->getBucket(),
'retain_local' => false,
], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE)
);
return ($result['success'] ?? false) ? $fileName : '';
}
// Local-driver mode: keep file under the upload folder.
$result = $storage->upload($fileToUpload, $filepath, $fileName);
log_message(
($result['success'] ?? false) ? 'info' : 'error',
'storage_file_Upload completed | ' . json_encode([
'filepath' => $filepath,
'file_name' => $fileName,
'display_name' => storage_upload_display_name($fileName),
'success' => $result['success'] ?? false,
'key' => $result['key'] ?? null,
'url' => $result['url'] ?? null,
'message' => $result['message'] ?? null,
'bucket' => $storage->getBucket(),
'uses_s3' => $storage->usesS3(),
'retain_local' => $retainLocal,
], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE)
);
return ($result['success'] ?? false) ? $fileName : "";
}
}
/**
* Read RETAIN_LOCAL from env. Default / missing / empty => false.
*/
if (! function_exists('storage_env_retain_local')) {
function storage_env_retain_local(): bool
{
$raw = env('RETAIN_LOCAL', null);
if ($raw === null || $raw === '') {
return false;
}
if (is_bool($raw)) {
return $raw;
}
return filter_var((string) $raw, FILTER_VALIDATE_BOOLEAN);
}
}
if (! function_exists('file_Upload_random_name')) { if (! function_exists('file_Upload_random_name')) {
function file_Upload_random_name($fileToUpload, $filepath, array $allowedExtensions = UPLOAD_ALLOWED_EXTENSIONS, string $namePrefix = ''): array function file_Upload_random_name($fileToUpload, $filepath, array $allowedExtensions = UPLOAD_ALLOWED_EXTENSIONS, string $namePrefix = ''): array
{ {
@ -285,6 +460,489 @@ if (! function_exists('multi_file_Upload')) {
} }
} }
/**
* Claim file upload via FileStorageService (S3) with local disk copy retained
* for merge/TPA integrations during phased migration.
*/
if (! function_exists('storage_multi_file_Upload')) {
function storage_multi_file_Upload($fileToUpload, $filepath, $docs_name = [], array $allowedExtensions = UPLOAD_EXT_CLAIM_DOCS)
{
$uploadedFiles = [];
$filepath = rtrim($filepath, '/\\') . DIRECTORY_SEPARATOR;
$storage = \Config\Services::getFileStorageService();
if (! is_dir(rtrim($filepath, '/\\'))) {
mkdir(rtrim($filepath, '/\\'), 0755, true);
}
$files = is_array($fileToUpload) ? $fileToUpload : [$fileToUpload];
foreach ($files as $file) {
if (is_array($file)) {
foreach ($file as $index => $f) {
$uploaded = storage_claim_file_Upload($f, $filepath, $allowedExtensions);
if ($uploaded === '') {
continue;
}
$uploadedFiles[] = [
'file_name' => $uploaded['display_name'],
'doc_name' => $docs_name[$index] ?? $uploaded['display_name'],
'file_path' => $uploaded['disk_name'],
];
}
} else {
$uploaded = storage_claim_file_Upload($file, $filepath, $allowedExtensions);
if ($uploaded === '') {
continue;
}
$uploadedFiles[] = [
'file_name' => $uploaded['display_name'],
'doc_name' => $docs_name[0] ?? $uploaded['display_name'],
'file_path' => $uploaded['disk_name'],
];
}
}
log_message('info', 'storage_multi_file_Upload completed | ' . json_encode([
'filepath' => $filepath,
'uploaded_count' => count($uploadedFiles),
'uses_s3' => $storage->usesS3(),
'bucket' => $storage->getBucket(),
], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE));
return $uploadedFiles;
}
}
/**
* Single claim file upload: save locally, then mirror to S3 when enabled.
*
* @return array{display_name:string,disk_name:string}|string
*/
if (! function_exists('storage_claim_file_Upload')) {
function storage_claim_file_Upload($fileToUpload, $filepath, array $allowedExtensions = UPLOAD_EXT_CLAIM_DOCS)
{
if ($fileToUpload === null || ! $fileToUpload->isValid() || $fileToUpload->hasMoved()) {
return '';
}
if (! validate_upload_extension($fileToUpload, $allowedExtensions)) {
return '';
}
$filepath = rtrim($filepath, '/\\') . DIRECTORY_SEPARATOR;
$displayName = sanitize_upload_filename($fileToUpload->getName());
$diskName = $fileToUpload->getRandomName();
$storage = \Config\Services::getFileStorageService();
if ($storage->usesS3()) {
$tmpDir = storage_runtime_temp_dir();
if (! is_dir($tmpDir)) {
@mkdir($tmpDir, 0755, true);
}
$fileToUpload->move($tmpDir . DIRECTORY_SEPARATOR, $diskName);
$localPath = $tmpDir . DIRECTORY_SEPARATOR . $diskName;
$result = $storage->upload($localPath, rtrim($filepath, '/\\'), $diskName);
@unlink($localPath);
log_message(
($result['success'] ?? false) ? 'info' : 'error',
'storage_claim_file_Upload s3_only | ' . json_encode([
'filepath' => $filepath,
'disk_name' => $diskName,
'display_name' => $displayName,
'success' => $result['success'] ?? false,
'key' => $result['key'] ?? null,
'message' => $result['message'] ?? null,
'bucket' => $storage->getBucket(),
], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE)
);
if (! ($result['success'] ?? false)) {
return '';
}
} else {
if (! is_dir($filepath)) {
@mkdir($filepath, 0755, true);
}
$fileToUpload->move($filepath, $diskName);
}
return [
'display_name' => $displayName,
'disk_name' => $diskName,
];
}
}
/**
* Build a TPA-facing download URL for a claim file.
* Prefers an S3 presigned URL; falls back to app downloadClaimFile/{id} for local mode.
*/
if (! function_exists('storage_claim_file_download_url')) {
function storage_claim_file_download_url(string $diskName, $fileId = null, int $expirationMinutes = 360): string
{
$diskName = basename(trim($diskName));
if ($diskName === '') {
return '';
}
$uploadPath = WRITEPATH . 'uploads/claim_files';
$storage = \Config\Services::getFileStorageService();
if ($storage->usesS3()) {
if (! $storage->exists($uploadPath, $diskName)) {
log_message('error', 'storage_claim_file_download_url | missing on S3 | ' . $diskName);
return '';
}
$result = $storage->getPresignedUrl($uploadPath, $diskName, max(1, $expirationMinutes));
if (($result['success'] ?? false) && ! empty($result['url'])) {
return (string) $result['url'];
}
log_message('error', 'storage_claim_file_download_url | presign failed | ' . json_encode([
'disk_name' => $diskName,
'message' => $result['message'] ?? null,
], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE));
return '';
}
$localPath = $storage->resolveLocalPath($uploadPath, $diskName);
if (! is_file($localPath)) {
return '';
}
if ($fileId !== null && $fileId !== '') {
return base_url('downloadClaimFile/' . $fileId);
}
return '';
}
}
/**
* Soft-delete claim_files row and remove unused local/S3 object.
*
* @return bool
*/
if (! function_exists('storage_soft_delete_claim_file')) {
function storage_soft_delete_claim_file(int $claimFileId): bool
{
if ($claimFileId <= 0) {
return false;
}
$claimFiles = new \App\Models\ClaimFilesModel();
$record = $claimFiles->find($claimFileId);
if (empty($record)) {
return false;
}
$updated = $claimFiles->update($claimFileId, ['is_active' => 0]);
if (! $updated) {
return false;
}
$diskName = basename((string) (! empty($record['url']) ? $record['url'] : ($record['file_name'] ?? '')));
if ($diskName === '') {
return true;
}
$stillUsed = $claimFiles
->where('is_active', 1)
->where('id !=', $claimFileId)
->groupStart()
->where('url', $diskName)
->orWhere('url', WRITEPATH . 'uploads/claim_files/' . $diskName)
->orWhere('file_name', $diskName)
->groupEnd()
->countAllResults();
if ($stillUsed === 0) {
$storage = \Config\Services::getFileStorageService();
$storage->delete(WRITEPATH . 'uploads/claim_files', $diskName);
}
return true;
}
}
/**
* Resolve a claim file from local/S3 into a readable local path.
*
* @return array{success:bool,path:?string,is_temp:bool,message:string}
*/
if (! function_exists('storage_resolve_claim_file_path')) {
function storage_resolve_claim_file_path(string $uploadPath, string $fileName): array
{
$empty = [
'success' => false,
'path' => null,
'is_temp' => false,
'message' => 'File not found',
];
$fileName = basename(trim($fileName));
if ($fileName === '') {
$empty['message'] = 'Invalid file name';
return $empty;
}
$storage = \Config\Services::getFileStorageService();
$uploadPath = rtrim($uploadPath, '/\\');
$localPath = $storage->resolveLocalPath($uploadPath, $fileName);
if (is_file($localPath) && is_readable($localPath)) {
return [
'success' => true,
'path' => $localPath,
'is_temp' => false,
'message' => 'Local file found',
];
}
if (! $storage->usesS3()) {
return $empty;
}
$download = $storage->download($uploadPath, $fileName);
if (! ($download['success'] ?? false)) {
$empty['message'] = (string) ($download['message'] ?? 'S3 download failed');
return $empty;
}
if (! empty($download['path']) && is_file((string) $download['path'])) {
return [
'success' => true,
'path' => (string) $download['path'],
'is_temp' => false,
'message' => 'Resolved from storage path',
];
}
$content = $download['content'] ?? null;
if (! is_string($content) || $content === '') {
$empty['message'] = 'S3 returned empty content';
return $empty;
}
$tmpDir = rtrim(WRITEPATH, '/\\') . DIRECTORY_SEPARATOR . 'cache' . DIRECTORY_SEPARATOR . 'claim_files_runtime';
if (! is_dir($tmpDir)) {
@mkdir($tmpDir, 0755, true);
}
$tmpPath = $tmpDir . DIRECTORY_SEPARATOR . uniqid('claim_', true) . '_' . $fileName;
$written = @file_put_contents($tmpPath, $content);
if ($written === false || ! is_file($tmpPath)) {
$empty['message'] = 'Failed to write temp file';
return $empty;
}
storage_register_temp_file($tmpPath);
return [
'success' => true,
'path' => $tmpPath,
'is_temp' => true,
'message' => 'Resolved from S3 content',
];
}
}
if (! function_exists('storage_cleanup_temp_claim_file')) {
function storage_cleanup_temp_claim_file(array $resolved): void
{
if (($resolved['success'] ?? false) && ($resolved['is_temp'] ?? false) && ! empty($resolved['path'])) {
storage_cleanup_temp_file((string) $resolved['path']);
}
}
}
/**
* Runtime temp directory for S3→local staging (never a permanent upload folder).
*/
if (! function_exists('storage_runtime_temp_dir')) {
function storage_runtime_temp_dir(): string
{
return rtrim(WRITEPATH, '/\\') . DIRECTORY_SEPARATOR . 'cache' . DIRECTORY_SEPARATOR . 'storage_runtime';
}
}
/**
* Register a temp path for automatic cleanup at request/CLI shutdown.
*
* @var list<string>|null
*/
if (! function_exists('storage_register_temp_file')) {
function storage_register_temp_file(string $path): void
{
static $registered = [];
static $shutdownRegistered = false;
$path = (string) $path;
if ($path === '' || in_array($path, $registered, true)) {
return;
}
$registered[] = $path;
if (! $shutdownRegistered) {
$shutdownRegistered = true;
register_shutdown_function(static function () use (&$registered): void {
foreach ($registered as $tmp) {
storage_cleanup_temp_file($tmp);
}
$registered = [];
});
}
}
}
/**
* Delete a temp runtime file (storage_runtime / claim_files_runtime only).
*/
if (! function_exists('storage_cleanup_temp_file')) {
function storage_cleanup_temp_file(?string $path): void
{
if ($path === null || $path === '' || ! is_file($path)) {
return;
}
$real = realpath($path);
if ($real === false) {
@unlink($path);
return;
}
$allowed = [];
foreach ([storage_runtime_temp_dir(), rtrim(WRITEPATH, '/\\') . DIRECTORY_SEPARATOR . 'cache' . DIRECTORY_SEPARATOR . 'claim_files_runtime'] as $dir) {
if (! is_dir($dir)) {
@mkdir($dir, 0755, true);
}
$resolvedDir = realpath($dir);
if ($resolvedDir !== false) {
$allowed[] = $resolvedDir;
}
}
foreach ($allowed as $root) {
if (strpos($real, rtrim($root, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR) === 0) {
@unlink($real);
return;
}
}
}
}
/**
* Resolve a mail-template attachment to a readable local path (local first, else S3→temp).
*/
if (! function_exists('storage_resolve_mail_attachment_path')) {
function storage_resolve_mail_attachment_path(?string $relativePath, ?string $fileName = null): array
{
$name = basename((string) ($fileName ?: $relativePath));
if ($name === '') {
return ['success' => false, 'path' => null, 'is_temp' => false, 'display_name' => ''];
}
$uploadDir = WRITEPATH . 'uploads/attachments';
$legacyPath = $relativePath ? (WRITEPATH . ltrim(str_replace('\\', '/', $relativePath), '/')) : null;
if ($legacyPath && is_file($legacyPath)) {
return [
'success' => true,
'path' => $legacyPath,
'is_temp' => false,
'display_name' => storage_upload_display_name($name),
];
}
$resolved = storage_resolve_claim_file_path($uploadDir, $name);
$resolved['display_name'] = storage_upload_display_name($name);
if (($resolved['success'] ?? false) && ($resolved['is_temp'] ?? false) && ! empty($resolved['path'])) {
storage_register_temp_file((string) $resolved['path']);
}
return $resolved;
}
}
/**
* Ensure a file exists on local disk for job processors.
* Local first (legacy leftovers); if missing and S3 has it, download into
* writable/cache/storage_runtime/ (temp) and auto-clean at request shutdown.
*/
if (! function_exists('storage_ensure_local_file')) {
function storage_ensure_local_file(string $uploadPath, string $fileName): ?string
{
$fileName = basename(trim($fileName));
if ($fileName === '') {
return null;
}
$storage = \Config\Services::getFileStorageService();
$localPath = $storage->resolveLocalPath($uploadPath, $fileName);
if (is_file($localPath) && is_readable($localPath)) {
return $localPath;
}
if (! $storage->usesS3()) {
return null;
}
$result = $storage->download($uploadPath, $fileName);
if (! ($result['success'] ?? false)) {
return null;
}
$content = $result['content'] ?? null;
if (! is_string($content) || $content === '') {
// download() may have returned a local path already
if (! empty($result['path']) && is_file((string) $result['path'])) {
$existing = (string) $result['path'];
// If path is already under runtime, register cleanup; else leave as-is.
storage_register_temp_file($existing);
return $existing;
}
return null;
}
$tmpDir = storage_runtime_temp_dir();
if (! is_dir($tmpDir)) {
@mkdir($tmpDir, 0755, true);
}
$tmpPath = $tmpDir . DIRECTORY_SEPARATOR . uniqid('stor_', true) . '_' . $fileName;
if (@file_put_contents($tmpPath, $content) === false || ! is_file($tmpPath)) {
return null;
}
storage_register_temp_file($tmpPath);
return $tmpPath;
}
}
/**
* After generating a local workbook, mirror to S3 (when enabled) and remove local permanent copy.
*/
if (! function_exists('storage_mirror_generated_file')) {
function storage_mirror_generated_file(string $localPath, string $uploadPath, string $fileName): bool
{
if (! is_file($localPath)) {
return false;
}
$storage = \Config\Services::getFileStorageService();
if (! $storage->usesS3()) {
return true;
}
$result = $storage->upload($localPath, rtrim($uploadPath, '/\\'), $fileName);
@unlink($localPath);
return (bool) ($result['success'] ?? false);
}
}
if (! function_exists('file_unlink')) { if (! function_exists('file_unlink')) {
function file_unlink($filepath) function file_unlink($filepath)
{ {
@ -580,8 +1238,11 @@ if (! function_exists('excelFileGDriveUpload')) {
->first(); ->first();
if ($data) { if ($data) {
$uploadFilePath .= '/' . $data['file_name']; $resolved = storage_ensure_local_file($uploadFilePath, $data['file_name']);
// dd($data, $uploadFilePath); if (empty($resolved) || ! is_file($resolved)) {
return;
}
$uploadFilePath = $resolved;
$GoogleDriveController = new GoogleDriveController(); $GoogleDriveController = new GoogleDriveController();
$result = $GoogleDriveController->uploadFiletoGdrive( $result = $GoogleDriveController->uploadFiletoGdrive(

View File

@ -0,0 +1,342 @@
<?php
namespace App\Libraries;
/**
* Thin wrapper over S3Service for general app uploads.
*
* Takes a local folder path + file name and maps the last path segment
* (e.g. client's uploads/client_kyc_documents) to the S3 folder/key prefix.
* Uses AWS_FILE_UPLOAD_BUCKET when set; falls back to AWS_BUCKET.
*/
class FileStorageService
{
protected $s3Service;
protected $bucket;
protected $driver;
public function __construct()
{
$this->s3Service = \Config\Services::getS3Service(false);
$this->bucket = getenv('AWS_FILE_UPLOAD_BUCKET') ?: getenv('AWS_BUCKET');
$this->driver = strtolower((string) (getenv('FILE_STORAGE_DRIVER') ?: 's3'));
}
public function usesS3(): bool
{
return $this->driver === 's3' && !empty($this->bucket);
}
public function getBucket(): ?string
{
return $this->bucket ?: null;
}
/**
* Convert a legacy local upload path to an S3 folder prefix.
* Last path segment becomes the bucket folder name.
* e.g. WRITEPATH/uploads/client_kyc_documents -> client_kyc_documents
*/
public function normalizeFolder(string $filepath): string
{
$path = str_replace('\\', '/', trim($filepath));
$path = rtrim($path, '/');
if ($path === '') {
return '';
}
$segments = array_values(array_filter(explode('/', $path), static function ($segment) {
return $segment !== '';
}));
return $segments ? (string) end($segments) : '';
}
public function buildKey(string $folder, string $fileName): string
{
$folder = trim($folder, '/');
$fileName = ltrim($fileName, '/');
return $folder !== '' ? $folder . '/' . $fileName : $fileName;
}
public function resolveLocalPath(string $filepath, string $fileName): string
{
return rtrim($filepath, '/\\') . DIRECTORY_SEPARATOR . $fileName;
}
/**
* Collect upload file metadata for logging.
*/
protected function getFileMeta($file, string $fallbackName): array
{
$isUploadedObject = is_object($file) && method_exists($file, 'isValid');
$resolvedName = $fallbackName;
$tmpPath = null;
$size = null;
$mimeType = null;
$extension = null;
$isValid = null;
$hasMoved = null;
$error = null;
if ($isUploadedObject) {
if (method_exists($file, 'getClientName')) {
$resolvedName = $file->getClientName() ?: $fallbackName;
}
$tmpPath = method_exists($file, 'getTempName') ? $file->getTempName() : null;
$size = method_exists($file, 'getSize') ? $file->getSize() : null;
$mimeType = method_exists($file, 'getMimeType') ? $file->getMimeType() : null;
$extension = method_exists($file, 'getExtension') ? $file->getExtension() : null;
$isValid = method_exists($file, 'isValid') ? $file->isValid() : null;
$hasMoved = method_exists($file, 'hasMoved') ? $file->hasMoved() : null;
$error = method_exists($file, 'getErrorString') ? $file->getErrorString() : null;
} elseif (is_string($file)) {
$tmpPath = $file;
$resolvedName = basename($file) ?: $fallbackName;
if (is_file($file)) {
$size = filesize($file);
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mimeType = $finfo ? finfo_file($finfo, $file) : null;
if ($finfo) {
finfo_close($finfo);
}
}
$extension = pathinfo($resolvedName, PATHINFO_EXTENSION);
}
return [
'resolved_name' => $resolvedName,
'tmp_path' => $tmpPath,
'size_bytes' => $size,
'mime_type' => $mimeType,
'extension' => $extension,
'is_valid' => $isValid,
'has_moved' => $hasMoved,
'upload_error' => $error,
];
}
protected function logUpload(string $event, array $details, string $level = 'info'): void
{
log_message($level, 'FileStorage Upload ' . $event . ' | ' . json_encode($details, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE));
}
/**
* Upload a file using folder path + file name.
*
* @return array{success:bool,key:?string,file_name:string,message:string,url:?string}
*/
public function upload($file, string $filepath, string $fileName): array
{
$folder = $this->normalizeFolder($filepath);
$key = $this->buildKey($folder, $fileName);
$fileMeta = $this->getFileMeta($file, $fileName);
$baseLog = [
'driver' => $this->driver,
'uses_s3' => $this->usesS3(),
'bucket' => $this->bucket,
'filepath' => $filepath,
'folder' => $folder,
'key' => $key,
'file_name' => $fileName,
'file' => $fileMeta,
];
$this->logUpload('started', $baseLog);
if ($this->usesS3()) {
try {
$result = $this->s3Service->upload($file, $folder, $fileName, $this->bucket);
$response = [
'success' => (bool) ($result['success'] ?? false),
'key' => $result['key'] ?? $key,
'file_name' => $fileName,
'url' => $result['url'] ?? null,
'message' => $result['message'] ?? '',
];
if ($response['success']) {
$this->logUpload('s3_success', array_merge($baseLog, [
'result' => $response,
's3_result' => $result,
]));
} else {
$this->logUpload('s3_failure', array_merge($baseLog, [
'result' => $response,
's3_result' => $result,
]), 'error');
}
return $response;
} catch (\Throwable $e) {
$response = [
'success' => false,
'key' => null,
'file_name' => $fileName,
'url' => null,
'message' => 'Upload exception: ' . $e->getMessage(),
];
$this->logUpload('s3_exception', array_merge($baseLog, [
'result' => $response,
'error_message' => $e->getMessage(),
'error_code' => $e->getCode(),
'exception_class' => get_class($e),
'error_file' => $e->getFile(),
'error_line' => $e->getLine(),
]), 'error');
return $response;
}
}
if (is_object($file) && method_exists($file, 'isValid') && $file->isValid() && !$file->hasMoved()) {
try {
$targetDir = rtrim($filepath, '/\\');
if (!is_dir($targetDir)) {
mkdir($targetDir, 0755, true);
}
$file->move($targetDir . DIRECTORY_SEPARATOR, $fileName);
$response = [
'success' => true,
'key' => $key,
'file_name' => $fileName,
'url' => null,
'message' => 'File uploaded successfully',
'local_path' => $this->resolveLocalPath($filepath, $fileName),
];
$this->logUpload('local_success', array_merge($baseLog, [
'result' => $response,
]));
return $response;
} catch (\Throwable $e) {
$response = [
'success' => false,
'key' => null,
'file_name' => $fileName,
'url' => null,
'message' => 'Local upload failed: ' . $e->getMessage(),
];
$this->logUpload('local_failure', array_merge($baseLog, [
'result' => $response,
'error_message' => $e->getMessage(),
'exception_class' => get_class($e),
'error_file' => $e->getFile(),
'error_line' => $e->getLine(),
]), 'error');
return $response;
}
}
$response = [
'success' => false,
'key' => null,
'file_name' => $fileName,
'url' => null,
'message' => 'Invalid file upload',
];
$this->logUpload('validation_failed', array_merge($baseLog, [
'result' => $response,
]), 'error');
return $response;
}
public function exists(string $filepath, string $fileName): bool
{
$folder = $this->normalizeFolder($filepath);
$key = $this->buildKey($folder, $fileName);
if ($this->usesS3()) {
return $this->s3Service->exists($key, $this->bucket);
}
return is_file($this->resolveLocalPath($filepath, $fileName));
}
public function getPresignedUrl(string $filepath, string $fileName, int $expiration = 60): array
{
$folder = $this->normalizeFolder($filepath);
$key = $this->buildKey($folder, $fileName);
if (!$this->usesS3()) {
return [
'success' => false,
'url' => null,
'message' => 'Presigned URLs are only available when S3 storage is enabled',
];
}
return $this->s3Service->getPresignedUrl($key, $expiration, $this->bucket);
}
/**
* Download file contents for forced browser download (attachment).
*
* @return array{success:bool,content:?string,path:?string,message:string}
*/
public function download(string $filepath, string $fileName): array
{
$localPath = $this->resolveLocalPath($filepath, $fileName);
if (is_file($localPath)) {
return [
'success' => true,
'content' => null,
'path' => $localPath,
'message' => 'Local file found',
];
}
if (!$this->usesS3()) {
return [
'success' => false,
'content' => null,
'path' => null,
'message' => 'File not found',
];
}
$folder = $this->normalizeFolder($filepath);
$key = $this->buildKey($folder, $fileName);
$result = $this->s3Service->download($key, null, $this->bucket);
return [
'success' => (bool) ($result['success'] ?? false),
'content' => $result['content'] ?? null,
'path' => null,
'message' => $result['message'] ?? 'Download failed',
'key' => $key,
];
}
public function delete(string $filepath, string $fileName): array
{
$folder = $this->normalizeFolder($filepath);
$key = $this->buildKey($folder, $fileName);
$localPath = $this->resolveLocalPath($filepath, $fileName);
// Always remove leftover local copy when present (S3-only cleanup).
if (is_file($localPath)) {
@unlink($localPath);
}
if ($this->usesS3()) {
return $this->s3Service->delete($key, $this->bucket);
}
return [
'success' => true,
'message' => 'File deleted successfully',
];
}
}

View File

@ -4,7 +4,6 @@ namespace App\Libraries;
use Aws\S3\S3Client; use Aws\S3\S3Client;
use Aws\Exception\AwsException; use Aws\Exception\AwsException;
use CodeIgniter\HTTP\ResponseInterface;
class S3Service class S3Service
{ {
@ -27,8 +26,17 @@ class S3Service
], ],
]); ]);
$this->baseUrl = "https://{$this->bucket}.s3.{$this->region}.amazonaws.com/"; $this->baseUrl = $this->buildBaseUrl($this->bucket);
// echo $this->baseUrl;die(); }
protected function resolveBucket(?string $bucket = null): string
{
return $bucket ?: $this->bucket;
}
protected function buildBaseUrl(string $bucket): string
{
return "https://{$bucket}.s3.{$this->region}.amazonaws.com/";
} }
/** /**
@ -37,27 +45,45 @@ class S3Service
* @param mixed $file File object or file path * @param mixed $file File object or file path
* @param string $folder Folder path in S3 bucket (optional) * @param string $folder Folder path in S3 bucket (optional)
* @param string $fileName Custom file name (optional) * @param string $fileName Custom file name (optional)
* @param string|null $bucket Override destination bucket (optional)
* @return array ['success' => bool, 'url' => string, 'key' => string, 'message' => string] * @return array ['success' => bool, 'url' => string, 'key' => string, 'message' => string]
*/ */
public function upload($file, string $folder = '', string $fileName = null): array public function upload($file, string $folder = '', string $fileName = null, ?string $bucket = null): array
{ {
$targetBucket = $this->resolveBucket($bucket);
$startLog = [
'bucket' => $targetBucket,
'region' => $this->region,
'folder' => $folder,
'file_name' => $fileName,
'file_type' => is_object($file) ? get_class($file) : gettype($file),
];
log_message('info', 'S3 Upload started | ' . json_encode($startLog, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE));
try { try {
// Handle CodeIgniter file upload object // Handle CodeIgniter file upload object
if (is_object($file) && method_exists($file, 'isValid')) { if (is_object($file) && method_exists($file, 'isValid')) {
if (!$file->isValid()) { if (!$file->isValid()) {
return [ $fail = [
'success' => false, 'success' => false,
'message' => 'Invalid file upload', 'message' => 'Invalid file upload',
'url' => null, 'url' => null,
'key' => null 'key' => null
]; ];
log_message('error', 'S3 Upload validation failed | ' . json_encode(array_merge($startLog, [
'result' => $fail,
'error' => method_exists($file, 'getErrorString') ? $file->getErrorString() : null,
]), JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE));
return $fail;
} }
$filePath = $file->getTempName(); $filePath = $file->getTempName();
$originalName = $fileName ?? $file->getClientName(); $originalName = $fileName ?? $file->getClientName();
$sizeBytes = method_exists($file, 'getSize') ? $file->getSize() : null;
} else { } else {
// Handle file path string // Handle file path string
$filePath = $file; $filePath = $file;
$originalName = $fileName ?? basename($file); $originalName = $fileName ?? basename($file);
$sizeBytes = is_string($filePath) && is_file($filePath) ? filesize($filePath) : null;
} }
// Generate unique file name // Generate unique file name
@ -75,22 +101,55 @@ class S3Service
finfo_close($finfo); finfo_close($finfo);
$result = $this->s3Client->putObject([ $result = $this->s3Client->putObject([
'Bucket' => $this->bucket, 'Bucket' => $targetBucket,
'Key' => $key, 'Key' => $key,
'Body' => fopen($filePath, 'rb'), // Stream instead of loading into memory 'Body' => fopen($filePath, 'rb'), // Stream instead of loading into memory
'ContentType' => $mimeType, 'ContentType' => $mimeType,
// 'ACL' => 'public-read', // 'ACL' => 'public-read',
]); ]);
return [ $success = [
'success' => true, 'success' => true,
'url' => $this->baseUrl . $key, 'url' => $this->buildBaseUrl($targetBucket) . $key,
'key' => $key, 'key' => $key,
'message' => 'File uploaded successfully' 'message' => 'File uploaded successfully'
]; ];
log_message('info', 'S3 Upload successful | ' . json_encode(array_merge($startLog, [
'tmp_path' => $filePath,
'original_name' => $originalName,
'unique_name' => $uniqueName,
'key' => $key,
'mime_type' => $mimeType,
'size_bytes' => $sizeBytes,
'etag' => $result['ETag'] ?? null,
'object_url' => $result['ObjectURL'] ?? null,
'result' => $success,
]), JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE));
return $success;
} catch (AwsException $e) { } catch (AwsException $e) {
log_message('error', 'S3 Upload Error: ' . $e->getMessage()); log_message('error', 'S3 Upload Error | ' . json_encode(array_merge($startLog, [
'error_message' => $e->getMessage(),
'aws_error_code' => $e->getAwsErrorCode(),
'aws_error_type' => $e->getAwsErrorType(),
'status_code' => $e->getStatusCode(),
'request_id' => $e->getAwsRequestId(),
]), JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE));
return [
'success' => false,
'message' => 'Upload failed: ' . $e->getMessage(),
'url' => null,
'key' => null
];
} catch (\Throwable $e) {
log_message('error', 'S3 Upload Exception | ' . json_encode(array_merge($startLog, [
'error_message' => $e->getMessage(),
'exception_class' => get_class($e),
'error_file' => $e->getFile(),
'error_line' => $e->getLine(),
]), JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE));
return [ return [
'success' => false, 'success' => false,
'message' => 'Upload failed: ' . $e->getMessage(), 'message' => 'Upload failed: ' . $e->getMessage(),
@ -105,13 +164,14 @@ class S3Service
* *
* @param string $key S3 object key (file path in bucket) * @param string $key S3 object key (file path in bucket)
* @param string $savePath Local path to save the file (optional) * @param string $savePath Local path to save the file (optional)
* @param string|null $bucket Override source bucket (optional)
* @return array ['success' => bool, 'path' => string, 'content' => string, 'message' => string] * @return array ['success' => bool, 'path' => string, 'content' => string, 'message' => string]
*/ */
public function download(string $key, string $savePath = null): array public function download(string $key, string $savePath = null, ?string $bucket = null): array
{ {
try { try {
$result = $this->s3Client->getObject([ $result = $this->s3Client->getObject([
'Bucket' => $this->bucket, 'Bucket' => $this->resolveBucket($bucket),
'Key' => $key, 'Key' => $key,
]); ]);
@ -156,13 +216,14 @@ class S3Service
* *
* @param string $key S3 object key * @param string $key S3 object key
* @param int $expiration Expiration time in minutes (default: 60) * @param int $expiration Expiration time in minutes (default: 60)
* @param string|null $bucket Override source bucket (optional)
* @return array ['success' => bool, 'url' => string, 'message' => string] * @return array ['success' => bool, 'url' => string, 'message' => string]
*/ */
public function getPresignedUrl(string $key, int $expiration = 60): array public function getPresignedUrl(string $key, int $expiration = 60, ?string $bucket = null): array
{ {
try { try {
$cmd = $this->s3Client->getCommand('GetObject', [ $cmd = $this->s3Client->getCommand('GetObject', [
'Bucket' => $this->bucket, 'Bucket' => $this->resolveBucket($bucket),
'Key' => $key 'Key' => $key
]); ]);
@ -189,13 +250,14 @@ class S3Service
* Delete file from S3 * Delete file from S3
* *
* @param string $key S3 object key * @param string $key S3 object key
* @param string|null $bucket Override source bucket (optional)
* @return array ['success' => bool, 'message' => string] * @return array ['success' => bool, 'message' => string]
*/ */
public function delete(string $key): array public function delete(string $key, ?string $bucket = null): array
{ {
try { try {
$this->s3Client->deleteObject([ $this->s3Client->deleteObject([
'Bucket' => $this->bucket, 'Bucket' => $this->resolveBucket($bucket),
'Key' => $key, 'Key' => $key,
]); ]);
@ -217,43 +279,59 @@ class S3Service
* Check if file exists in S3 * Check if file exists in S3
* *
* @param string $key S3 object key * @param string $key S3 object key
* @param string|null $bucket Override source bucket (optional)
* @return bool * @return bool
*/ */
public function exists(string $key): bool public function exists(string $key, ?string $bucket = null): bool
{ {
return $this->s3Client->doesObjectExist($this->bucket, $key); return $this->s3Client->doesObjectExist($this->resolveBucket($bucket), $key);
} }
/** /**
* List files in S3 bucket * List files in S3 bucket
* *
* @param string $prefix Folder prefix (optional) * @param string $prefix Folder prefix (optional)
* @param string|null $bucket Override source bucket (optional)
* @return array ['success' => bool, 'files' => array, 'message' => string] * @return array ['success' => bool, 'files' => array, 'message' => string]
*/ */
public function listFiles(string $prefix = ''): array public function listFiles(string $prefix = '', ?string $bucket = null): array
{ {
try { try {
$result = $this->s3Client->listObjectsV2([ $targetBucket = $this->resolveBucket($bucket);
'Bucket' => $this->bucket,
'Prefix' => $prefix,
]);
$files = []; $files = [];
$token = null;
do {
$params = [
'Bucket' => $targetBucket,
'Prefix' => $prefix,
];
if ($token !== null) {
$params['ContinuationToken'] = $token;
}
$result = $this->s3Client->listObjectsV2($params);
if (isset($result['Contents'])) { if (isset($result['Contents'])) {
foreach ($result['Contents'] as $object) { foreach ($result['Contents'] as $object) {
$files[] = [ $files[] = [
'key' => $object['Key'], 'key' => $object['Key'],
'size' => $object['Size'], 'size' => $object['Size'],
'last_modified' => $object['LastModified']->format('Y-m-d H:i:s'), 'last_modified' => $object['LastModified']->format('Y-m-d H:i:s'),
'url' => $this->baseUrl . $object['Key'] 'url' => $this->buildBaseUrl($targetBucket) . $object['Key'],
]; ];
} }
} }
$token = ! empty($result['IsTruncated'])
? ($result['NextContinuationToken'] ?? null)
: null;
} while ($token !== null);
return [ return [
'success' => true, 'success' => true,
'files' => $files, 'files' => $files,
'message' => 'Files retrieved successfully' 'message' => 'Files retrieved successfully',
]; ];
} catch (AwsException $e) { } catch (AwsException $e) {
@ -261,7 +339,7 @@ class S3Service
return [ return [
'success' => false, 'success' => false,
'files' => [], 'files' => [],
'message' => 'Failed to list files: ' . $e->getMessage() 'message' => 'Failed to list files: ' . $e->getMessage(),
]; ];
} }
} }

View File

@ -46,7 +46,7 @@ class ZipService
unlink($tempZipPath); unlink($tempZipPath);
} }
$get_presinged_url = $this->s3Service->getPresignedUrl($uploadResult['key'], 2,880); $get_presinged_url = $this->s3Service->getPresignedUrl($uploadResult['key'], 2880);
// To delete the original temprory folder after zipping and uploading // To delete the original temprory folder after zipping and uploading
// $this->deleteDirectory($localFolderPath); // $this->deleteDirectory($localFolderPath);

View File

@ -30,7 +30,7 @@ class ClientKYCDocsModel extends Model
public function getClientKYCDriveFilesIndex($client_id,$client_doc_name = '') public function getClientKYCDriveFilesIndex($client_id,$client_doc_name = '')
{ {
$query = $this->select('client_kyc_documents.client_id,client_kyc_documents.file_name, kyc_docs.file_name as doc_name,"url","client_policy_id","kyc" as file_type') $query = $this->select('client_kyc_documents.id,client_kyc_documents.client_id,client_kyc_documents.file_name, kyc_docs.file_name as doc_name,"url","client_policy_id","kyc" as file_type')
->join('kyc_docs', 'kyc_docs.id = client_kyc_documents.kyc_doc_type_id') ->join('kyc_docs', 'kyc_docs.id = client_kyc_documents.kyc_doc_type_id')
->where(['client_kyc_documents.client_id' => $client_id, 'client_kyc_documents.is_active' => 1]) ->where(['client_kyc_documents.client_id' => $client_id, 'client_kyc_documents.is_active' => 1])
->when($client_doc_name, function($query) use ($client_doc_name){ ->when($client_doc_name, function($query) use ($client_doc_name){

View File

@ -627,17 +627,17 @@
const viewHref = escapeClaimFileListAttr(claimFileViewOpenUrl(item, base_url)); const viewHref = escapeClaimFileListAttr(claimFileViewOpenUrl(item, base_url));
const downloadHref = escapeClaimFileListAttr(claimFileDownloadOpenUrl(item, base_url)); const downloadHref = escapeClaimFileListAttr(claimFileDownloadOpenUrl(item, base_url));
const fileNameLinkHref = viewOk ? viewHref : downloadHref; const fileNameLinkHref = viewOk ? viewHref : downloadHref;
const fileNameLinkTitle = viewOk ? 'View in new tab' : 'Download'; const fileNameLinkTitle = viewOk ? 'View file' : 'Download';
html += ` html += `
<tr> <tr>
<td class="text-center">${index + 1}</td> <td class="text-center">${index + 1}</td>
<td>${item.doc_name}</td> <td>${item.doc_name}</td>
<td><a href="${fileNameLinkHref}" target="_blank" rel="noopener noreferrer" title="${fileNameLinkTitle}">${item.file_type == 1 ? item.url : item.doc_name}</a></td> <td><a href="${fileNameLinkHref}" title="${fileNameLinkTitle}">${item.file_type == 1 ? item.url : item.doc_name}</a></td>
<td class="text-center"> <td class="text-center">
<span class="badge ${tpaBadgeClass}" style="font-size:13px; padding:8px 12px; font-weight:600;">${tpaLabel}</span> <span class="badge ${tpaBadgeClass}" style="font-size:13px; padding:8px 12px; font-weight:600;">${tpaLabel}</span>
</td> </td>
<td> <td>
<a href="${downloadHref}" target="_blank" rel="noopener noreferrer" class="text-primary mr-2" title="Download"> <a href="${downloadHref}" class="text-primary mr-2" title="Download" download>
<i class="mdi mdi-download"></i> <i class="mdi mdi-download"></i>
</a> </a>
<a href="javascript:void(0);" class="delete-url" <a href="javascript:void(0);" class="delete-url"

View File

@ -558,16 +558,16 @@
// "&file_name=" + item.file_name + // "&file_name=" + item.file_name +
// "&client_policy_id=client_policy_id"; // "&client_policy_id=client_policy_id";
var url = '<?= base_url('download-kyc-docs/') ?>' + item.file_name; var url = '<?= base_url('download-kyc-docs/') ?>' + item.id;
if(item.kyc_doc_type_id == '0'){ if(item.kyc_doc_type_id == '0'){
table += ` table += `
<tr id="kyc-${item.id}"> <tr id="kyc-${item.id}">
<td>${item.other_docs_name}</td> <td>${item.other_docs_name}</td>
<td>${item.file_name}</td> <td>${item.file_name ? item.file_name.replace(/^\d+_[a-f0-9]+_/i, '') : ''}</td>
<td> <td>
<a href = "${url}" data-id="${item.id}" class="mdi mdi-download" style="font-size:18px;" target="_blank"></a> <a href = "${url}" data-id="${item.id}" class="mdi mdi-download" style="font-size:18px;" download></a>
</td> </td>
</tr> </tr>
`; `;
@ -589,7 +589,7 @@
// console.log(document.getElementById('name_' + item.kyc_doc_type_id)); // console.log(document.getElementById('name_' + item.kyc_doc_type_id));
setTimeout(function() { setTimeout(function() {
$('#name_'+item.kyc_doc_type_id).show(); $('#name_'+item.kyc_doc_type_id).show();
$('#name_'+item.kyc_doc_type_id).html(item.file_name); $('#name_'+item.kyc_doc_type_id).html(item.file_name ? item.file_name.replace(/^\d+_[a-f0-9]+_/i, '') : '');
$('#form_'+item.kyc_doc_type_id).hide(); $('#form_'+item.kyc_doc_type_id).hide();
// console.log('step 1') // console.log('step 1')
@ -600,14 +600,14 @@
// "&file_name=" + item.file_name + // "&file_name=" + item.file_name +
// "&client_policy_id=client_policy_id"; // "&client_policy_id=client_policy_id";
var url = '<?= base_url('download-kyc-docs/') ?>' + item.file_name; var url = '<?= base_url('download-kyc-docs/') ?>' + item.id;
if(item.file_name != null && item.file_name != ""){ if(item.file_name != null && item.file_name != ""){
// console.log('step 2') // console.log('step 2')
$('#download_'+item.kyc_doc_type_id).show(); $('#download_'+item.kyc_doc_type_id).show();
$('#download_' + item.kyc_doc_type_id).attr('href', url).attr('target', '_blank');; $('#download_' + item.kyc_doc_type_id).attr('href', url).removeAttr('target').attr('download', '');
$('#delete_'+item.kyc_doc_type_id).show(); $('#delete_'+item.kyc_doc_type_id).show();
} }
else{ else{

View File

@ -282,11 +282,13 @@
$(document).on('click', '.btn-download-kyc', function (e) { $(document).on('click', '.btn-download-kyc', function (e) {
e.preventDefault(); // Prevent default link behavior e.preventDefault(); // Prevent default link behavior
// var kyc_id = $(this).attr('data-id'); var kycId = $(this).attr('data-id');
// var client_id = $(this).attr('data-client_id');
var file = $(this).attr('data-file'); var file = $(this).attr('data-file');
if (file) { if (kycId) {
window.location.href = "<?= base_url('client/kyc/download_2') ?>/" + file; window.location.href = "<?= base_url('client/kyc/download_2') ?>/" + kycId;
} else if (file) {
// Legacy fallback for older rows/markup
window.location.href = "<?= base_url('client/kyc/download_2') ?>/" + encodeURIComponent(file);
} else { } else {
toastr.warning('File is missing.'); toastr.warning('File is missing.');
} }

View File

@ -1,11 +1,12 @@
<?php if (isset($data) && !empty($data)): ?> <?php if (isset($data) && !empty($data)): ?>
<?php foreach ($data as $index => $item): ?> <?php foreach ($data as $index => $item): ?>
<?php $displayName = storage_upload_display_name($item['file_name'] ?? ''); ?>
<tr id="kyc-<?= $item['id'] ?>"> <tr id="kyc-<?= $item['id'] ?>">
<!-- <td><?= $index + 1; ?></td> --> <!-- <td><?= $index + 1; ?></td> -->
<td><?= esc($item['other_docs_name']); ?></td> <td><?= esc($item['other_docs_name']); ?></td>
<td><?= esc($item['file_name']); ?></td> <td><?= esc($displayName); ?></td>
<td> <td>
<a href="<?= base_url('download-kyc-docs/') . ($item['file_name'] ?? '') ?>" data-id="<?= esc($item['id']); ?>" class="mdi mdi-download mr-2" style="font-size:18px;" target="_blank"></a> <a href="<?= base_url('download-kyc-docs/') . ($item['id'] ?? '') ?>" data-id="<?= esc($item['id']); ?>" class="mdi mdi-download mr-2" style="font-size:18px;" download></a>
<i <i
data-id="<?= esc($item['id']); ?>" data-id="<?= esc($item['id']); ?>"
data-client-id="<?= esc($client_id); ?>" data-client-id="<?= esc($client_id); ?>"

View File

@ -1,10 +1,14 @@
<?php if (isset($data) && !empty($data)): ?> <?php if (isset($data) && !empty($data)): ?>
<?php foreach ($data as $index => $item): ?> <?php foreach ($data as $index => $item): ?>
<?php
$uploadDocName = $item['upload_doc_name'] ?? '';
$displayName = storage_upload_display_name($uploadDocName);
?>
<tr> <tr>
<td><?= $index + 1; ?></td> <td><?= $index + 1; ?></td>
<td><?= esc($item['file_name']); ?></td> <td><?= esc($item['file_name']); ?></td>
<?php if(empty($item['upload_doc_name'])) { ?> <?php if(empty($uploadDocName)) { ?>
<td id="form_<?= esc($item['id']); ?>"> <td id="form_<?= esc($item['id']); ?>">
<form class="ajax" enctype="multipart/form-data" method="post"> <form class="ajax" enctype="multipart/form-data" method="post">
<input class="file-input__input" type="file" name="file_name" accept=".pdf,.jpg,.jpeg,.png"> <input class="file-input__input" type="file" name="file_name" accept=".pdf,.jpg,.jpeg,.png">
@ -16,10 +20,10 @@
</td> </td>
<td></td> <td></td>
<?php } else { ?> <?php } else { ?>
<td><?= esc($item['upload_doc_name']); ?></td> <td><?= esc($displayName); ?></td>
<td> <td>
<a href="<?= base_url('download-kyc-docs/') . ($item['upload_doc_name'] ?? '') ?>" data-id="<?= esc($item['id']); ?>" class="mdi mdi-download mr-2" style="font-size:18px;" target="_blank"></a> <a href="<?= base_url('download-kyc-docs/') . ($item['client_kyc_id'] ?? '') ?>" data-id="<?= esc($item['client_kyc_id'] ?? ''); ?>" class="mdi mdi-download mr-2" style="font-size:18px;" download></a>
<?php if (!empty($item['upload_doc_name']) && !empty($item['client_kyc_id'])): ?> <?php if (!empty($uploadDocName) && !empty($item['client_kyc_id'])): ?>
<i <i
data-id="<?= esc($item['client_kyc_id']); ?>" data-id="<?= esc($item['client_kyc_id']); ?>"
data-client-id="<?= esc($client_id); ?>" data-client-id="<?= esc($client_id); ?>"

View File

@ -5,7 +5,8 @@
<?php else : ?> <?php else : ?>
<?php foreach ($ckdlist as $index => $value) : <?php foreach ($ckdlist as $index => $value) :
$sno = $index + 1; $sno = $index + 1;
$fileName = !empty($value['file_name']) ? $value['file_name'] : '-'; $storedName = !empty($value['file_name']) ? $value['file_name'] : '';
$fileName = $storedName !== '' ? storage_upload_display_name($storedName) : '-';
?> ?>
<tr id="data_row_<?= $value['id'] ?>"> <tr id="data_row_<?= $value['id'] ?>">
<td><?= $sno ?></td> <td><?= $sno ?></td>
@ -13,13 +14,14 @@
<td><?= esc($fileName) ?></td> <td><?= esc($fileName) ?></td>
<td> <td>
<a class="mdi mdi-download mr-1 btn-download-kyc" <a class="mdi mdi-download mr-1 btn-download-kyc"
data-file="<?= $fileName ?>" data-id="<?= $value['id'] ?>"
data-file="<?= esc($fileName) ?>"
style="font-size:18px;"></a> style="font-size:18px;"></a>
<a class="mdi mdi-pencil mr-1 btn-edit-kyc" <a class="mdi mdi-pencil mr-1 btn-edit-kyc"
data-id="<?= $value['id'] ?>" data-id="<?= $value['id'] ?>"
data-client_id="<?= $value['client_id'] ?>" data-client_id="<?= $value['client_id'] ?>"
data-old_file_name="<?= $fileName ?>" data-old_file_name="<?= esc($storedName) ?>"
data-kyc_doc_type_id="<?= $value['kyc_doc_type_id'] ?>" data-kyc_doc_type_id="<?= $value['kyc_doc_type_id'] ?>"
style="font-size:18px;"></a> style="font-size:18px;"></a>
@ -36,7 +38,7 @@
<form id="kyc_form_<?= $value['id'] ?>" class="kyc-edit-form"> <form id="kyc_form_<?= $value['id'] ?>" class="kyc-edit-form">
<input type="hidden" name="id" value="<?= $value['id'] ?>"> <input type="hidden" name="id" value="<?= $value['id'] ?>">
<input type="hidden" name="client_id" value="<?= $value['client_id'] ?>"> <input type="hidden" name="client_id" value="<?= $value['client_id'] ?>">
<input type="hidden" name="old_file_name" value="<?= $fileName ?>"> <input type="hidden" name="old_file_name" value="<?= esc($storedName) ?>">
<div class="row align-items-end"> <div class="row align-items-end">
<div class="col-md-8"> <div class="col-md-8">

View File

@ -1109,14 +1109,14 @@
row.append($('<td>').text(index+1)); row.append($('<td>').text(index+1));
row.append($('<td>').text(item.doc_name)); row.append($('<td>').text(item.doc_name));
row.append($('<td>').text(item.file_name)); row.append($('<td>').text(item.file_name ? String(item.file_name).replace(/^\d+_[a-f0-9]+_/i, '') : ''));
var url = '<?= base_url('download-kyc-docs/') ?>' + item.file_name; var url = '<?= base_url('download-pt-docs/') ?>' + item.id;
var link = $('<a>') var link = $('<a>')
.attr('href', url) .attr('href', url)
.attr('target', '_blank') // Open in a new tab .attr('download', true)
.attr('style', 'font-size:18px;') .attr('style', 'font-size:18px;')
.attr('data-id', item.id) .attr('data-id', item.id)
.addClass('mdi mdi-download') .addClass('mdi mdi-download')

View File

@ -1356,7 +1356,7 @@ function appendFileTableBody(data)
row.append($('<td>').text(index+1)); row.append($('<td>').text(index+1));
row.append($('<td>').text(item.doc_name)); row.append($('<td>').text(item.doc_name));
row.append($('<td>').text(item.file_name)); row.append($('<td>').text(item.file_name ? String(item.file_name).replace(/^\d+_[a-f0-9]+_/i, '') : ''));
// var url = "<?= base_url('/downloadGdriveFile'); ?>" + // var url = "<?= base_url('/downloadGdriveFile'); ?>" +
// "?client_id=" + item.client_id + // "?client_id=" + item.client_id +
@ -1364,12 +1364,12 @@ function appendFileTableBody(data)
// "&file_name=" + item.file_name + // "&file_name=" + item.file_name +
// "&client_policy_id=" + item.client_policy_id; // "&client_policy_id=" + item.client_policy_id;
var url = '<?= base_url('download-kyc-docs/') ?>' + item.file_name; var url = '<?= base_url('download-pt-docs/') ?>' + item.id;
var link = $('<a>') var link = $('<a>')
.attr('href', url) .attr('href', url)
.attr('target', '_blank') // Open in a new tab .attr('download', true)
.attr('style', 'font-size:18px;') .attr('style', 'font-size:18px;')
.attr('data-id', item.id) .attr('data-id', item.id)
.addClass('mdi mdi-download') .addClass('mdi mdi-download')
@ -1467,11 +1467,12 @@ function appendVehicleFileTableBody(data)
// Add row number, document name, and file name // Add row number, document name, and file name
row.append($('<td>').text(index + 1)); row.append($('<td>').text(index + 1));
row.append($('<td>').text(item.other_docs_name)); row.append($('<td>').text(item.other_docs_name));
row.append($('<td>').text(item.file_name)); row.append($('<td>').text(item.file_name ? String(item.file_name).replace(/^\d+_[a-f0-9]+_/i, '') : ''));
// Create the download link // Create the download link
var downloadLink = $('<a>') var downloadLink = $('<a>')
.attr('href', '<?= base_url('download-kyc-docs/') ?>' + item.file_name) .attr('href', '<?= base_url('download-kyc-docs/') ?>' + item.id)
.attr('download', true)
.attr('style', 'font-size:18px;') .attr('style', 'font-size:18px;')
.attr('data-id', item.id) .attr('data-id', item.id)
.addClass('mdi mdi-download') .addClass('mdi mdi-download')

View File

@ -1120,7 +1120,7 @@ function appendFileTableBody(data)
row.append($('<td>').text(index+1)); row.append($('<td>').text(index+1));
row.append($('<td>').text(item.doc_name)); row.append($('<td>').text(item.doc_name));
row.append($('<td>').text(item.file_name)); row.append($('<td>').text(item.file_name ? String(item.file_name).replace(/^\d+_[a-f0-9]+_/i, '') : ''));
// var url = "<?= base_url('/downloadGdriveFile'); ?>" + // var url = "<?= base_url('/downloadGdriveFile'); ?>" +
// "?client_id=" + item.client_id + // "?client_id=" + item.client_id +
@ -1128,12 +1128,12 @@ function appendFileTableBody(data)
// "&file_name=" + item.file_name + // "&file_name=" + item.file_name +
// "&client_policy_id=" + item.client_policy_id; // "&client_policy_id=" + item.client_policy_id;
var url = '<?= base_url('download-kyc-docs/') ?>' + item.file_name; var url = '<?= base_url('download-pt-docs/') ?>' + item.id;
var link = $('<a>') var link = $('<a>')
.attr('href', url) .attr('href', url)
.attr('target', '_blank') // Open in a new tab .attr('download', true)
.attr('style', 'font-size:18px;') .attr('style', 'font-size:18px;')
.attr('data-id', item.id) .attr('data-id', item.id)
.addClass('mdi mdi-download') .addClass('mdi mdi-download')
@ -1224,11 +1224,12 @@ function appendVehicleFileTableBody(data)
// Add row number, document name, and file name // Add row number, document name, and file name
row.append($('<td>').text(index + 1)); row.append($('<td>').text(index + 1));
row.append($('<td>').text(item.other_docs_name)); row.append($('<td>').text(item.other_docs_name));
row.append($('<td>').text(item.file_name)); row.append($('<td>').text(item.file_name ? String(item.file_name).replace(/^\d+_[a-f0-9]+_/i, '') : ''));
// Create the download link // Create the download link
var downloadLink = $('<a>') var downloadLink = $('<a>')
.attr('href', '<?= base_url('download-kyc-docs/') ?>' + item.file_name) .attr('href', '<?= base_url('download-kyc-docs/') ?>' + item.id)
.attr('download', true)
.attr('style', 'font-size:18px;') .attr('style', 'font-size:18px;')
.attr('data-id', item.id) .attr('data-id', item.id)
.addClass('mdi mdi-download') .addClass('mdi mdi-download')

View File

@ -35,7 +35,7 @@
foreach ($message['files_data'] as $index => $datas) { foreach ($message['files_data'] as $index => $datas) {
$index = $index + 1; $index = $index + 1;
?> ?>
<p>File <?= $index ?> : <a href="<?= base_url('downloadClaimFile/') . $datas['id'] ?>" target="_blank"><?= $datas['doc_name'] ?></a></p> <p>File <?= $index ?> : <a href="<?= base_url('downloadClaimFile/') . $datas['id'] ?>" download><?= $datas['doc_name'] ?></a></p>
<?php } } ?> <?php } } ?>
</div> </div>

View File

View File