ruleImportService = \Config\Services::ruleImportService(); } /** * 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'=>'error','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) { log_message('critical', 'RuleImportController::upload ' . $e->getMessage()); return $this->response->setJSON(['status'=>'exception','message'=>$e->getMessage()]); } } public function upload() { // Make sure filesystem helpers available if you need them helper(['filesystem']); // CommissionFilesModel – adjust namespace if different $commissionFilesModel = new \App\Models\CommissionFilesModel(); try { // --------------------------------------------------------- // 1. Get uploaded file // --------------------------------------------------------- $file = $this->request->getFile('rules_file'); if (!$file || !$file->isValid()) { log_message('warning', 'RuleImportController::upload - No file or invalid upload.'); return $this->respond([ 'status' => 'error', 'message' => 'No file uploaded or upload error.' ], 400); } // --------------------------------------------------------- // 2. Read POST fields // --------------------------------------------------------- $insurerId = $this->request->getPost('insurer_id'); $department = $this->request->getPost('department'); $commissionMonth = $this->request->getPost('commission_month'); $createdBy = $this->request->getPost('created_by'); if (empty($insurerId) || empty($department) || empty($commissionMonth) || empty($createdBy)) { log_message('warning', 'RuleImportController::upload - Missing required POST data.', [ 'insurer_id' => $insurerId, 'department' => $department, 'commission_month' => $commissionMonth, 'created_by' => $createdBy, ]); return $this->respond([ 'status' => 'error', 'message' => 'Missing required fields: insurer_id, department, commission_month, created_by.' ], 400); } // 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)) { log_message('error', "RuleImportController::upload - Failed to move uploaded file to {$movedFullPath}"); return $this->respond([ 'status' => 'error', 'message' => 'Failed to store uploaded file.' ], 500); } log_message('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'), ]; $commissionFilesModel->insert($insertData); $insertId = $commissionFilesModel->getInsertID(); if (empty($insertId)) { log_message('error', 'RuleImportController::upload - Failed to insert commission_files record', ['data' => $insertData]); return $this->respond([ 'status' => 'error', 'message' => 'Failed to record upload in database.' ], 500); } log_message('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, ]; log_message('info', 'RuleImportController::upload - Calling ruleImportService->processUpload', ['payload' => $payload]); $result = $this->ruleImportService->processUpload($payload); if (!is_array($result) || !isset($result['status'])) { log_message('error', 'RuleImportController::upload - Invalid service response', ['response' => $result]); // update file status as failed $commissionFilesModel->update($insertId, [ 'file_status' => 'failed', 'updated_by' => (int)$createdBy, 'updated_at' => date('Y-m-d H:i:s'), ]); return $this->respond([ 'status' => 'error', 'message' => 'Invalid response from import service.' ], 500); } // --------------------------------------------------------- // 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) { log_message('error', 'RuleImportController::upload - json_encode failed for rules', [ 'last_error' => json_last_error_msg() ]); // mark as failed since we cannot save rules $commissionFilesModel->update($insertId, [ 'file_status' => 'failed', 'updated_by' => (int)$createdBy, 'updated_at' => date('Y-m-d H:i:s'), ]); return $this->respond([ 'status' => 'error', 'message' => 'Failed to encode rules as JSON.' ], 500); } if (file_put_contents($jsonPath, $jsonData) === false) { log_message('error', 'RuleImportController::upload - Failed to write rules JSON file', ['json_path' => $jsonPath]); $commissionFilesModel->update($insertId, [ 'file_status' => 'failed', 'updated_by' => (int)$createdBy, 'updated_at' => date('Y-m-d H:i:s'), ]); return $this->respond([ 'status' => 'error', 'message' => 'Failed to store rules JSON file.' ], 500); } log_message('info', 'RuleImportController::upload - Rules JSON written', [ 'file_id' => $insertId, 'json_path' => $jsonPath, 'rules_cnt' => $rulesCount, ]); // Update DB: status, rules_count, updated_by $commissionFilesModel->update($insertId, [ 'file_status' => 'processed', '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' => 'success', '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; } $commissionFilesModel->update($insertId, $updateData); log_message('warning', "RuleImportController::upload - Validation failed for file_id={$insertId}", [ 'errors' => $errors, 'annotated_file' => $annotatedPath ]); return $this->respond([ 'status' => 'error', 'message' => 'Validation failed. No rules saved.', 'file_id' => $insertId, 'errors' => $errors, 'annotated_file' => $annotatedPath, ], 422); } // --------------------------------------------------------- // 8. Unexpected status // --------------------------------------------------------- log_message('error', 'RuleImportController::upload - Unexpected result status from service', ['result' => $result]); $commissionFilesModel->update($insertId, [ 'file_status' => 'failed', 'updated_by' => (int)$createdBy, 'updated_at' => date('Y-m-d H:i:s'), ]); return $this->respond([ 'status' => 'error', 'message' => 'Unexpected import service result.' ], 500); } catch (\Throwable $ex) { log_message('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 { $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) { log_message('error', 'RuleImportController::upload - failed to update commission_files after exception: ' . $e2->getMessage()); } } return $this->respond([ 'status' => 'exception', 'message' => $ex->getMessage(), ], 500); } } }