nhance/app/Controllers/RuleImportController.php

425 lines
19 KiB
PHP

<?php
namespace App\Controllers;
use CodeIgniter\API\ResponseTrait;
use App\Models\CommissionFilesModel;
use App\Models\InsurerModel;
class RuleImportController extends AdminController
{
use ResponseTrait;
protected $myLogger;
protected $ruleImportService;
protected $commissionFilesModel;
protected $departments;
protected $insurerModel;
public function __construct()
{
set_session_context('RuleImportController');
$this->myLogger = \Config\Services::mylogger();
$this->ruleImportService = \Config\Services::ruleImportService();
$this->commissionFilesModel = new CommissionFilesModel();
$this->insurerModel = new InsurerModel();
$this->departments = [
'motor' => 'Motor',
'health' => 'Health',
];
}
public function commissionFileUploadList()
{
$data['page_name'] = "Commision File Upload";
$data['departments'] = $this->departments;
$data['insurers'] = $this->insurerModel->where('is_active', 1)->findAll();
$data['commission_file_list'] = $this->commissionFilesModel
->select('commission_files.*, insurers.name as insurer_name, user_profiles.first_name as created_user_name')
->join('insurers', 'commission_files.insurer_id = insurers.id')
->join('user_profiles', 'commission_files.created_by = user_profiles.id')
->where('commission_files.is_active', 1)
->orderBy('commission_files.id', 'desc')
->findAll();
// dd( $data);
return $this->loadLayout('commission_file_upload', $data);
}
/**
* Upload endpoint for form (POST)
* Input form field: 'rules_file'
*/
public function uploadORI()
{
// echo 'hi';
!dd($result = $this->ruleImportService->processUpload(['id' => 1,'file_name' => 'sample_commission.csv','insurer_id' => 5, 'department' => 'motor' ,'commission_month' => '2025-11-10']));die;
try {
$file = $this->request->getFile('rules_file');
if (!$file || !$file->isValid()) {
return $this->response->setJSON(['status'=>false,'message'=>'No file uploaded or upload error']);
}
// Move uploaded file to writable temp location
$tmpPath = WRITEPATH . 'uploads/' . $file->getRandomName();
$file->move(WRITEPATH . 'uploads', $file->getName()); // keep original name inside uploads
$uploadedFullPath = $file->getTempName(); // Note: CI may store in tmp; we will use moved file path instead
$movedPath = WRITEPATH . 'uploads/' . $file->getName();
// Process file
$result = $this->ruleImportService->processUpload($movedPath, $file->getName());
// Return JSON with annotated file link if present
if (isset($result['annotated_file']) && $result['annotated_file']) {
$annotUrl = base_url('writable/uploads/annotated/' . basename($result['annotated_file']));
$result['annotated_url'] = $annotUrl;
}
return $this->response->setJSON($result);
} catch (\Throwable $e) {
$this->myLogger->logme('critical', 'RuleImportController::upload ' . $e->getMessage());
return $this->response->setJSON(['status'=>false,'message'=>$e->getMessage()]);
}
}
public function upload()
{
try {
// ---------------------------------------------------------
// 1. Get uploaded file
// ---------------------------------------------------------
$file = $this->request->getFile('rules_file');
if (!$file || !$file->isValid()) {
$this->myLogger->logme('error', 'RuleImportController::upload - No file or invalid upload.');
return $this->respond(['status' => false, 'code' => 404, 'message' => 'No file uploaded or upload error.'], 200);
}
// ---------------------------------------------------------
// 2. Read POST fields
// ---------------------------------------------------------
$insurerId = $this->request->getPost('insurer_id');
$department = $this->request->getPost('department');
$commissionMonth = $this->request->getPost('commission_month');
$createdBy = get_session_userid();
if (empty($insurerId) || empty($department) || empty($commissionMonth)) {
$this->myLogger->logme('error', 'RuleImportController::upload - Missing required POST data.' . json_encode($this->request->getPost() ?? []));
return $this->respond(['status' => false, 'code' => 404, 'message' => 'Missing required fields: insurer_id, department, commission_month'], 200);
}
// Optional / default fields
$postedFileName = $this->request->getPost('file_name') ?: $file->getClientName();
$fileStatus = $this->request->getPost('file_status') ?: 'pending';
$isActive = $this->request->getPost('is_active') !== null ? (int)$this->request->getPost('is_active') : 1;
// rules_count is given by user but we will override it after processing on success
$postedRulesCount = $this->request->getPost('rules_count') !== null
? (int)$this->request->getPost('rules_count')
: 0;
// ---------------------------------------------------------
// 3. Move file to WRITEPATH/uploads/commission/files using user filename
// (no random name as per your requirement)
// ---------------------------------------------------------
$uploadDir = WRITEPATH . 'uploads/commission/files/';
if (!is_dir($uploadDir)) {
if (!mkdir($uploadDir, 0755, true) && !is_dir($uploadDir)) {
throw new \RuntimeException("Failed to create upload directory: {$uploadDir}");
}
}
// sanitize user file name but keep it deterministic (no random, no timestamp)
$safeName = preg_replace('/[^a-zA-Z0-9_\-\.]/', '_', $postedFileName);
$targetFileName = $safeName;
$movedFullPath = $uploadDir . $targetFileName;
$file->move($uploadDir, $targetFileName);
if (!file_exists($movedFullPath)) {
$this->myLogger->logme('error', "RuleImportController::upload - Failed to move uploaded file to {$movedFullPath}");
return $this->respond(['status' => false, 'code' => 404, 'message' => 'Failed to store uploaded file.'], 500);
}
$this->myLogger->logme('info', "RuleImportController::upload - File moved to {$movedFullPath}");
// ---------------------------------------------------------
// 4. Insert commission_files row with status pending
// ---------------------------------------------------------
$insertData = [
'file_name' => $targetFileName,
'insurer_id' => (int)$insurerId,
'department' => $department,
'commission_month' => $commissionMonth,
'rules_count' => 0, // will update on success
'file_status' => $fileStatus, // 'pending' by default
'is_active' => $isActive,
'created_by' => (int)$createdBy,
'created_at' => date('Y-m-d H:i:s'),
];
$this->commissionFilesModel->insert($insertData);
$insertId = $this->commissionFilesModel->getInsertID();
if (empty($insertId)) {
$this->myLogger->logme('error', 'RuleImportController::upload - Failed to insert commission_files record', ['data' => $insertData]);
return $this->respond([
'status' => false,
'code' => 404,
'message' => 'Failed to record upload in database.'
], 200);
}
$this->myLogger->logme('info', "RuleImportController::upload - commission_files inserted id={$insertId}", $insertData);
// ---------------------------------------------------------
// 5. Call ruleImportService->processUpload with inserted file info
// As per your spec:
// $this->ruleImportService->processUpload([
// 'id' => 1,
// 'file_name' => 'sample_commission.csv',
// 'insurer_id' => 5,
// 'department' => 'motor',
// 'commission_month' => '2025-11-10'
// ])
// ---------------------------------------------------------
$payload = [
'id' => (int)$insertId,
'file_name' => $targetFileName,
'insurer_id' => (int)$insurerId,
'department' => $department,
'commission_month' => $commissionMonth,
];
$this->myLogger->logme('info', 'RuleImportController::upload - Calling ruleImportService->processUpload', ['payload' => $payload]);
$result = $this->ruleImportService->processUpload($payload);
if (!is_array($result) || !isset($result['status'])) {
$this->myLogger->logme('error', 'RuleImportController::upload - Invalid service response', ['response' => $result]);
// update file status as failed
$this->commissionFilesModel->update($insertId, [
'file_status' => 'failed',
'updated_by' => (int)$createdBy,
'updated_at' => date('Y-m-d H:i:s'),
]);
return $this->respond([
'status' => false,
'code' => 404,
'message' => 'Invalid response from import service.'
], 200);
}
// ---------------------------------------------------------
// 6. Handle SUCCESS
// - result['rules'] exists
// - result['errors'] empty
// - NO annotated_file
// - Save rules as JSON in WRITEPATH/uploads/commission/json/{insurer_id}_{department}.json
// ---------------------------------------------------------
if ($result['status'] === 'success') {
$rulesArray = isset($result['rules']) && is_array($result['rules']) ? $result['rules'] : [];
$rulesCount = count($rulesArray);
// Save JSON to WRITEPATH . 'uploads/commission/json/{insurer_id}_{department}.json'
$jsonDir = WRITEPATH . 'uploads/commission/json/';
if (!is_dir($jsonDir)) {
if (!mkdir($jsonDir, 0755, true) && !is_dir($jsonDir)) {
throw new \RuntimeException("Failed to create JSON output directory: {$jsonDir}");
}
}
$deptSlug = preg_replace('/[^a-zA-Z0-9_\-]/', '_', strtolower($department));
$jsonName = (int)$insurerId . '_' . $deptSlug . '.json';
$jsonPath = $jsonDir . $jsonName;
$jsonData = json_encode($rulesArray, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
if ($jsonData === false) {
$this->myLogger->logme('error', 'RuleImportController::upload - json_encode failed for rules', [
'last_error' => json_last_error_msg()
]);
// mark as failed since we cannot save rules
$this->commissionFilesModel->update($insertId, [
'file_status' => 'failed',
'updated_by' => (int)$createdBy,
'updated_at' => date('Y-m-d H:i:s'),
]);
return $this->respond([
'status' => false,
'code' => 404,
'message' => 'Failed to encode rules as JSON.'
], 200);
}
if (file_put_contents($jsonPath, $jsonData) === false) {
$this->myLogger->logme('error', 'RuleImportController::upload - Failed to write rules JSON file', ['json_path' => $jsonPath]);
$this->commissionFilesModel->update($insertId, [
'file_status' => 'failed',
'updated_by' => (int)$createdBy,
'updated_at' => date('Y-m-d H:i:s'),
]);
return $this->respond([
'status' => false,
'code' => 404,
'message' => 'Failed to store rules JSON file.'
], 500);
}
$this->myLogger->logme('info', 'RuleImportController::upload - Rules JSON written', [
'file_id' => $insertId,
'json_path' => $jsonPath,
'rules_cnt' => $rulesCount,
]);
// Update DB: status, rules_count, updated_by
$this->commissionFilesModel->update($insertId, [
'file_status' => 'pending',
'rules_count' => $rulesCount,
'updated_by' => (int)$createdBy,
'updated_at' => date('Y-m-d H:i:s'),
// If you have a column for JSON path, uncomment:
// 'json_file_path' => $jsonPath,
]);
return $this->respond([
'status' => true,
'code' => 200,
'message' => 'File processed successfully.',
'file_id' => $insertId,
'rules_count' => $rulesCount,
'json_file' => $jsonPath,
'service' => $result, // optional: return full service response if you want
], 200);
}
// ---------------------------------------------------------
// 7. Handle ERROR (validation failed etc.)
// - Do NOT save any rules JSON
// - Update file_status to validation_failed
// - Store annotated_file path if you have such a column
// ---------------------------------------------------------
if ($result['status'] === 'error') {
$annotatedPath = $result['annotated_file'] ?? null;
$errors = $result['errors'] ?? [];
$updateData = [
'file_status' => 'validation_failed',
'rules_count' => 0, // do not save rules
'updated_by' => (int)$createdBy,
'updated_at' => date('Y-m-d H:i:s'),
];
// If you have a column for annotated file path, e.g. annotated_file_path
if ($annotatedPath) {
$updateData['annotated_file_path'] = $annotatedPath;
}
$this->commissionFilesModel->update($insertId, $updateData);
$this->myLogger->logme('error', "RuleImportController::upload - Validation failed for file_id={$insertId}", [
'errors' => $errors,
'annotated_file' => $annotatedPath
]);
return $this->respond([
'status' => false,
'code' => 404,
'message' => 'Validation failed. No rules saved.',
'file_id' => $insertId,
'errors' => $errors,
'annotated_file' => $annotatedPath,
], 422);
}
// ---------------------------------------------------------
// 8. Unexpected status
// ---------------------------------------------------------
$this->myLogger->logme('error', 'RuleImportController::upload - Unexpected result status from service', ['result' => $result]);
$this->commissionFilesModel->update($insertId, [
'file_status' => 'failed',
'updated_by' => (int)$createdBy,
'updated_at' => date('Y-m-d H:i:s'),
]);
return $this->respond([
'status' => false,
'code' => 404,
'message' => 'Unexpected import service result.'
], 500);
} catch (\Throwable $ex) {
$this->myLogger->logme('critical', 'RuleImportController::upload exception: ' . $ex->getMessage(), [
'trace' => $ex->getTraceAsString()
]);
// Try to update the commission_files record if insertId exists
if (isset($insertId) && !empty($insertId)) {
try {
$this->commissionFilesModel->update($insertId, [
'file_status' => 'failed',
'updated_by' => isset($createdBy) ? (int)$createdBy : null,
'updated_at' => date('Y-m-d H:i:s'),
'notes' => 'Upload exception: ' . $ex->getMessage(),
]);
} catch (\Throwable $e2) {
$this->myLogger->logme('error', 'RuleImportController::upload - failed to update commission_files after exception: ' . $e2->getMessage());
}
}
return $this->respond([
'status' => false,
'code' => 500,
'message' => $ex->getMessage(),
], 500);
}
}
public function downloadSampleCommissionFileUploadExcel()
{
$filePath = ROOTPATH . 'public/sample_excel/sample_commission.csv';
// Check if the file exists
if (file_exists($filePath)) {
// 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 {
// File not found, show an error message or redirect
echo view('errors/html/production');
}
}
public function downloadErrorFile()
{
$file_id = $this->request->getGet('file_id');
$file_data = $this->commissionFilesModel->where('id', $file_id)->where('is_active', 1)->first();
$filePath = WRITEPATH . 'uploads/commission/files/annotated_' . $file_data['file_name'];
// Check if the file exists
if (file_exists($filePath)) {
// 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 {
// File not found, show an error message or redirect
$data['message'] = 'The Physical File Not Found';
echo view('errors/404', $data);
}
}
public function deleteCommissionData($id)
{
$this->commissionFilesModel->where('id', $id)
->set(['is_active' => 0])
->update();
return $this->respond(['status' => true, 'code' => 200, 'message' => "File removed successfully"], 200);
}
}