From 0fd039d3bd6e5a98ea7ac0caa76822a76310200d Mon Sep 17 00:00:00 2001 From: Venkatesh Date: Wed, 22 Apr 2026 11:31:38 +0530 Subject: [PATCH] FIX_POS_SAVING_ISSUE --- app/Controllers/MasterController.php | 429 ++++++++++++++++----------- app/Views/pos_list.php | 65 +++- 2 files changed, 306 insertions(+), 188 deletions(-) diff --git a/app/Controllers/MasterController.php b/app/Controllers/MasterController.php index 75fd9800..863b1bb1 100755 --- a/app/Controllers/MasterController.php +++ b/app/Controllers/MasterController.php @@ -277,61 +277,61 @@ class MasterController extends AdminController echo view('insurer_onboarding', $data); echo view('layout/footer'); - } + } public function createInsurerGeneralInfo() { - $this->myLogger->logme('error','Insurer general info function called'); + $this->myLogger->logme('error', 'Insurer general info function called'); $rules = [ - 'name' => [ - 'label' => 'Insurer Name', - 'rules' => ['required', 'regex_match[/^[a-zA-Z0-9\s\-_]+$/]'], - 'errors' => [ - 'required' => 'Insurer Name is required.', - 'regex_match' => 'Insurer Name can only contain letters, numbers, spaces, hyphens, and underscores.', - ] - ], - 'short_name' => [ - 'label' => 'Insurer Short Name', - 'rules' => ['required', 'regex_match[/^[a-zA-Z0-9\-_]+$/]'], - 'errors' => [ - 'required' => 'Short Name is required.', - 'regex_match' => 'Short Name can only contain letters, numbers, hyphens, and underscores.', - ] - ], - 'type' => [ - 'label' => 'Insurer Type', - 'rules' => 'permit_empty|in_list[pvt,psu]', - 'errors' => [ - 'in_list' => 'Please select a valid Insurer Type (PVT or PSU).' - ] - ], - 'category' => [ - 'label' => 'Insurer Category', - 'rules' => 'permit_empty|in_list[life,general]', - 'errors' => [ - 'in_list' => 'Please select a valid Category (Life or General).' - ] - ], - 'addition_add_day' => [ - 'rules' => 'permit_empty' // Checkboxes return null if unchecked - ], - 'deletion_add_day' => [ - 'rules' => 'permit_empty' - ], - 'is_multi_event' => [ - 'rules' => 'permit_empty' - ], - 'insurer_logo' => [ + 'name' => [ + 'label' => 'Insurer Name', + 'rules' => ['required', 'regex_match[/^[a-zA-Z0-9\s\-_]+$/]'], + 'errors' => [ + 'required' => 'Insurer Name is required.', + 'regex_match' => 'Insurer Name can only contain letters, numbers, spaces, hyphens, and underscores.', + ] + ], + 'short_name' => [ + 'label' => 'Insurer Short Name', + 'rules' => ['required', 'regex_match[/^[a-zA-Z0-9\-_]+$/]'], + 'errors' => [ + 'required' => 'Short Name is required.', + 'regex_match' => 'Short Name can only contain letters, numbers, hyphens, and underscores.', + ] + ], + 'type' => [ + 'label' => 'Insurer Type', + 'rules' => 'permit_empty|in_list[pvt,psu]', + 'errors' => [ + 'in_list' => 'Please select a valid Insurer Type (PVT or PSU).' + ] + ], + 'category' => [ + 'label' => 'Insurer Category', + 'rules' => 'permit_empty|in_list[life,general]', + 'errors' => [ + 'in_list' => 'Please select a valid Category (Life or General).' + ] + ], + 'addition_add_day' => [ + 'rules' => 'permit_empty' // Checkboxes return null if unchecked + ], + 'deletion_add_day' => [ + 'rules' => 'permit_empty' + ], + 'is_multi_event' => [ + 'rules' => 'permit_empty' + ], + 'insurer_logo' => [ 'rules' => 'if_exist|is_image[insurer_logo]|max_size[insurer_logo,200]|ext_in[insurer_logo,jpg,jpeg,png]', 'errors' => [ 'is_image' => 'The uploaded file must be an image', 'max_size' => 'File size should not exceed 200 KB', 'ext_in' => 'Allowed file types: jpg, jpeg, png', ] - ], -]; + ], + ]; // $rules = [ // 'name' => [ // 'rules' => 'required', @@ -3538,8 +3538,9 @@ class MasterController extends AdminController { $posModel = new PartnerPosModel(); $method = $this->request->getMethod(); - + if ($this->request->getMethod() === 'post') { + try { $rules = [ 'manager_id' => [ @@ -3555,7 +3556,7 @@ class MasterController extends AdminController 'required' => 'Name is required', 'min_length' => 'Name must be at least 3 characters', 'max_length' => 'Name cannot exceed 100 characters', - 'alpha_space'=> 'Name can contain only letters and spaces' + 'alpha_space' => 'Name can contain only letters and spaces' ] ], 'pos_code' => [ @@ -3589,27 +3590,27 @@ class MasterController extends AdminController ] ], 'state' => [ - 'label' => 'State', - 'rules' => 'required|regex_match[/^[a-zA-Z0-9\/\-\_\.\s]+$/]', - 'errors' => [ - 'required' => 'State is required.', - 'regex_match' => 'State name can only contain letters, spaces, and hyphens.' - ] - ], - 'city' => [ - 'rules' => 'required|regex_match[/^[a-zA-Z0-9\s\-]+$/]', - 'errors' => [ - 'regex_match' => 'City can contain letters, numbers, spaces, and hyphens.' - ] - ], - 'pincode' => [ - 'rules' => 'required|numeric|exact_length[6]', - 'errors' => [ - 'required' => 'Pincode is required.', - 'numeric' => 'Pincode must be digits only.', - 'exact_length' => 'Pincode must be exactly 6 digits.' - ] - ], + 'label' => 'State', + 'rules' => 'required|regex_match[/^[a-zA-Z0-9\/\-\_\.\s]+$/]', + 'errors' => [ + 'required' => 'State is required.', + 'regex_match' => 'State name can only contain letters, spaces, and hyphens.' + ] + ], + 'city' => [ + 'rules' => 'required|regex_match[/^[a-zA-Z0-9\s\-]+$/]', + 'errors' => [ + 'regex_match' => 'City can contain letters, numbers, spaces, and hyphens.' + ] + ], + 'pincode' => [ + 'rules' => 'required|numeric|exact_length[6]', + 'errors' => [ + 'required' => 'Pincode is required.', + 'numeric' => 'Pincode must be digits only.', + 'exact_length' => 'Pincode must be exactly 6 digits.' + ] + ], 'aadhar' => [ 'rules' => 'required|numeric|exact_length[12]', 'errors' => [ @@ -3632,25 +3633,22 @@ class MasterController extends AdminController ] ], 'aadhar_file_name' => [ - 'rules' => 'permit_empty|uploaded[aadhar_file_name]|max_size[aadhar_file_name,5120]|ext_in[aadhar_file_name,pdf,jpg,jpeg,png]', + 'rules' => 'if_exist|max_size[aadhar_file_name,5120]|ext_in[aadhar_file_name,pdf,jpg,jpeg,png]', 'errors' => [ - 'uploaded' => 'Invalid Aadhaar file', 'max_size' => 'Aadhaar file size should not exceed 5MB', 'ext_in' => 'Aadhaar must be PDF or image (jpg, jpeg, png)' ] ], 'pan_file_name' => [ - 'rules' => 'permit_empty|uploaded[pan_file_name]|max_size[pan_file_name,5120]|ext_in[pan_file_name,pdf,jpg,jpeg,png]', + 'rules' => 'if_exist|max_size[pan_file_name,5120]|ext_in[pan_file_name,pdf,jpg,jpeg,png]', 'errors' => [ - 'uploaded' => 'Invalid PAN file', 'max_size' => 'PAN file size should not exceed 5MB', 'ext_in' => 'PAN must be PDF or image (jpg, jpeg, png)' ] ], 'certificate_file_name' => [ - 'rules' => 'permit_empty|uploaded[certificate_file_name]|max_size[certificate_file_name,5120]|ext_in[certificate_file_name,pdf,jpg,jpeg,png]', + 'rules' => 'if_exist|max_size[certificate_file_name,5120]|ext_in[certificate_file_name,pdf,jpg,jpeg,png]', 'errors' => [ - 'uploaded' => 'Invalid Certificate file', 'max_size' => 'Certificate file size should not exceed 5MB', 'ext_in' => 'Certificate must be PDF or image (jpg, jpeg, png)' ] @@ -3669,138 +3667,217 @@ class MasterController extends AdminController $data = $this->request->getPost(); $sanitized_post_data = sanitizeInputArrayAdvanced($data); $id = $sanitized_post_data['pk'] ?? null; - unset($sanitized_post_data['pk']); + unset($sanitized_post_data['pk']); try { // Certificate $certificate = $this->uploadPOSFile('certificate_file_name', 'pos_certificate_files'); - if ($certificate !== null) { $sanitized_post_data['certificate_file_name'] = $certificate; } else { unset($sanitized_post_data['certificate_file_name']); } + if ($certificate !== null) { + $sanitized_post_data['certificate_file_name'] = $certificate; + } else { + unset($sanitized_post_data['certificate_file_name']); + } // PAN file $panFile = $this->uploadPOSFile('pan_file_name', 'pos_certificate_files'); - if ($panFile !== null) { $sanitized_post_data['pan_file_name'] = $panFile; } else { unset($sanitized_post_data['pan_file_name']);} + if ($panFile !== null) { + $sanitized_post_data['pan_file_name'] = $panFile; + } else { + unset($sanitized_post_data['pan_file_name']); + } // Aadhaar file $aadharFile = $this->uploadPOSFile('aadhar_file_name', 'pos_certificate_files'); - if ($aadharFile !== null) { $sanitized_post_data['aadhar_file_name'] = $aadharFile; } else { unset($sanitized_post_data['aadhar_file_name']);} - - } catch (\RuntimeException $e) { - return $this->respond([ 'status' => false, 'code' => 400, 'message' => $e->getMessage(), 'data' => $sanitized_post_data ], 400); + if ($aadharFile !== null) { + $sanitized_post_data['aadhar_file_name'] = $aadharFile; + } else { + unset($sanitized_post_data['aadhar_file_name']); + } + } catch (\Exception $e) { + log_message('error', 'File upload error: ' . $e->getMessage() . ' | POST data: ' . json_encode($sanitized_post_data) . $e->getTraceAsString()); + return $this->respond(['status' => false, 'code' => 400, 'message' => $e->getMessage(), 'data' => $sanitized_post_data], 400); } - foreach ($sanitized_post_data as $k => $v) { - if ($v === '' || $v === null) { - unset($sanitized_post_data[$k]); - } + foreach ($sanitized_post_data as $k => $v) { + if ($v === '' || $v === null) { + unset($sanitized_post_data[$k]); } - + } + // INSERT / UPDATE - if (empty($id)) { - $status = $posModel->insert($sanitized_post_data); - } else { - $status = $posModel->update($id, $sanitized_post_data); - } + try { + if (empty($id)) { + $status = $posModel->insert($sanitized_post_data); + } else { + $status = $posModel->update($id, $sanitized_post_data); + } - if ($status) { - return $this->respond([ 'status' => true, 'code' => 200, 'message' => 'POS updated successfully', 'data' => $sanitized_post_data ], 200); - } + if ($status) { + return $this->respond(['status' => true, 'code' => 200, 'message' => 'POS updated successfully', 'data' => $sanitized_post_data], 200); + } - return $this->respond([ 'status' => false, 'code' => 400, 'message' => 'Failed to update', 'data' => $sanitized_post_data ], 400); - } - elseif ($method === 'get') { + $modelErrors = method_exists($posModel, 'errors') ? $posModel->errors() : []; + return $this->respond([ + 'status' => false, + 'code' => 400, + 'message' => 'Failed to update', + 'errors' => $modelErrors, + 'data' => $sanitized_post_data + ], 400); + } catch (\Throwable $e) { + log_message('error', 'partnerPOS DB error: ' . $e->getMessage() . ' | payload: ' . json_encode($sanitized_post_data) . ' | trace: ' . $e->getTraceAsString()); - $id = $this->request->getGet('pk') ?? null; + $message = 'Something went wrong while saving POS details.'; + $statusCode = 500; - $db = db_connect(); - - $builder = $db->table('partner_staff'); - - $data['manager_list'] = $builder->select('partner_staff.id, partner_staff.name') - ->where('partner_staff.is_active', 1) - ->where('partner_staff.role_id', 1) - ->get() - ->getResultArray(); - - - if (!empty($id)) { - - $data['pos_list'] = $posModel - ->select('partner_pos.*, partner_staff.name AS manager_name') - ->join('partner_staff', 'partner_staff.id = partner_pos.manager_id', 'left') - ->where('partner_pos.id', $id) - ->orderBy('partner_pos.id', 'DESC') - ->findAll(); - - if (!empty($data)) { - return $this->respond(['status' => true, 'code' => 200, 'data' => $data], 200); - } else { - return $this->respond(['status' => false, 'code' => 400, 'message' => 'No data found'], 200); - } - } - - $data['pos_list'] = $posModel - ->select('partner_pos.*, ps.name AS manager_name') - ->join('partner_staff ps', 'ps.id = partner_pos.manager_id', 'left') - ->orderBy('partner_pos.id', 'DESC') - ->findAll(); - - - return $this->loadLayout('pos_list', ['data' => $data,'tab_name' => 'POS details','page_name' => 'POS details']); - - } elseif ($method === 'delete') { - - // $input = $this->request->getRawInput(); - $id = $this->request->getGet('pk'); // ✅ THIS - $id = $id ?? null; - - if (empty($id)) { - return $this->respond([ - 'status' => false, - 'code' => 404, - 'message' => 'No ID provided for deletion' - ], 200); - } - - $update_status = $posModel->where('id', $id)->set(['is_active' => 0])->update(); - - if ($update_status) { - return $this->respond([ - 'status' => true, - 'code' => 200, - 'message' => 'Data removed successfully', - 'pk' => $id - ], 200); - } else { - return $this->respond([ - 'status' => false, - 'code' => 400, - 'message' => 'Failed to remove data', - 'pk' => $id - ], 200); - } + if (stripos($e->getMessage(), 'Duplicate entry') !== false) { + $statusCode = 400; + if (stripos($e->getMessage(), 'email') !== false) { + $message = 'Email already exists.'; + } elseif (stripos($e->getMessage(), 'mobile') !== false) { + $message = 'Mobile number already exists.'; + } else { + $message = 'Duplicate data found. Please check email/mobile.'; } } - private function uploadPOSFile(string $fieldName, string $uploadDir) - { - $file = $this->request->getFile($fieldName); + return $this->respond([ + 'status' => false, + 'code' => $statusCode, + 'message' => $message + ], $statusCode); + } + } catch (\Throwable $e) { + log_message( + 'error', + 'partnerPOS fatal error: ' . $e->getMessage() . + ' | file: ' . $e->getFile() . + ' | line: ' . $e->getLine() . + ' | trace: ' . $e->getTraceAsString() + ); + return $this->respond([ + 'status' => false, + 'code' => 500, + 'message' => 'Internal server error while processing POS request.' + ], 500); + } + } elseif ($method === 'get') { - if (!$file || !$file->isValid()) { return null; } + $id = $this->request->getGet('pk') ?? null; - $allowedMime = [ 'image/jpg', 'image/jpeg', 'image/png', 'image/webp', 'application/pdf']; + $db = db_connect(); - if (!in_array($file->getMimeType(), $allowedMime)) { throw new \RuntimeException('Invalid file format'); } + $builder = $db->table('partner_staff'); - $path = ROOTPATH . 'public/uploads/' . $uploadDir . '/'; + $data['manager_list'] = $builder->select('partner_staff.id, partner_staff.name') + ->where('partner_staff.is_active', 1) + ->where('partner_staff.role_id', 1) + ->get() + ->getResultArray(); - if (!is_dir($path)) { mkdir($path, 0755, true); } - $newName = $file->getRandomName(); - $file->move($path, $newName); + if (!empty($id)) { - return $newName; + $data['pos_list'] = $posModel + ->select('partner_pos.*, partner_staff.name AS manager_name') + ->join('partner_staff', 'partner_staff.id = partner_pos.manager_id', 'left') + ->where('partner_pos.id', $id) + ->orderBy('partner_pos.id', 'DESC') + ->findAll(); + + if (!empty($data)) { + return $this->respond(['status' => true, 'code' => 200, 'data' => $data], 200); + } else { + return $this->respond(['status' => false, 'code' => 400, 'message' => 'No data found'], 200); } + } + + $data['pos_list'] = $posModel + ->select('partner_pos.*, ps.name AS manager_name') + ->join('partner_staff ps', 'ps.id = partner_pos.manager_id', 'left') + ->orderBy('partner_pos.id', 'DESC') + ->findAll(); - } \ No newline at end of file + return $this->loadLayout('pos_list', ['data' => $data, 'tab_name' => 'POS details', 'page_name' => 'POS details']); + } elseif ($method === 'delete') { + + // $input = $this->request->getRawInput(); + $id = $this->request->getGet('pk'); // ✅ THIS + $id = $id ?? null; + + if (empty($id)) { + return $this->respond([ + 'status' => false, + 'code' => 404, + 'message' => 'No ID provided for deletion' + ], 200); + } + + $update_status = $posModel->where('id', $id)->set(['is_active' => 0])->update(); + + if ($update_status) { + return $this->respond([ + 'status' => true, + 'code' => 200, + 'message' => 'Data removed successfully', + 'pk' => $id + ], 200); + } else { + return $this->respond([ + 'status' => false, + 'code' => 400, + 'message' => 'Failed to remove data', + 'pk' => $id + ], 200); + } + } + } + + private function uploadPOSFile(string $fieldName, string $uploadDir) + { + $file = $this->request->getFile($fieldName); + + if (!$file) { + return null; + } + + // No file selected for this optional input. + if ($file->getError() === UPLOAD_ERR_NO_FILE) { + return null; + } + + if (!$file->isValid()) { + throw new \RuntimeException('File upload failed for ' . $fieldName); + } + + $allowedMime = [ + 'image/jpg', + 'image/jpeg', + 'image/pjpeg', + 'image/png', + 'image/x-png', + 'image/webp', + 'application/pdf' + ]; + + $mimeType = (string) $file->getMimeType(); + if (!in_array($mimeType, $allowedMime, true)) { + throw new \RuntimeException('Invalid file format for ' . $fieldName); + } + + $path = ROOTPATH . 'public/uploads/' . $uploadDir . '/'; + + if (!is_dir($path)) { + mkdir($path, 0755, true); + } + + $newName = $file->getRandomName(); + $file->move($path, $newName); + + return $newName; + } + + +} \ No newline at end of file diff --git a/app/Views/pos_list.php b/app/Views/pos_list.php index d989318f..56af9add 100644 --- a/app/Views/pos_list.php +++ b/app/Views/pos_list.php @@ -233,6 +233,7 @@ $pos_col_width_px = nhance_dt_column_widths_px($pos_header_labels, $pos_col_max_ + Allowed: PDF, PNG, JPG, JPEG.
@@ -241,6 +242,7 @@ $pos_col_width_px = nhance_dt_column_widths_px($pos_header_labels, $pos_col_max_
+ Allowed: PDF, PNG, JPG, JPEG.
@@ -249,6 +251,7 @@ $pos_col_width_px = nhance_dt_column_widths_px($pos_header_labels, $pos_col_max_
+ Allowed: PDF, PNG, JPG, JPEG. @@ -433,11 +436,17 @@ $pos_col_width_px = nhance_dt_column_widths_px($pos_header_labels, $pos_col_max_ }, error: function (xhr) { $('.loader, .loader-mask').fadeOut(); + let response = null; + try { + response = xhr.responseText ? JSON.parse(xhr.responseText) : null; + } catch (e) { + response = null; + } + if (xhr.status === 400) { - let response = JSON.parse(xhr.responseText); let errorMessages = ""; let seenMessages = []; // Array to store unique messages - if (response.errors) { + if (response && response.errors) { $.each(response.errors, function (field, message) { if (!seenMessages.includes(message)) { errorMessages += `• ${message}
`; @@ -446,16 +455,15 @@ $pos_col_width_px = nhance_dt_column_widths_px($pos_header_labels, $pos_col_max_ }); toastr.error(errorMessages, 'Validation Error', { "allowHtml": true }); } else { - toastr.warning(response.message || 'Validation failed', 'Warning'); + toastr.warning((response && response.message) ? response.message : 'Validation failed', 'Warning'); } } else if (xhr.status === 403) { - let response = JSON.parse(xhr.responseText); - toastr.error(response.message, 'Security Policy'); + toastr.error((response && response.message) ? response.message : 'Security policy error', 'Security Policy'); } else if (xhr.status === 500) { - toastr.error('Something went wrong . Please try again later.', 'Server Error'); + toastr.error((response && response.message) ? response.message : 'Something went wrong . Please try again later.', 'Server Error'); } else { - toastr.error('An unexpected error occurred. Please try again later.', 'Error'); + toastr.error((response && response.message) ? response.message : 'An unexpected error occurred. Please try again later.', 'Error'); } console.error('Unexpected error:', xhr.responseText); @@ -470,9 +478,32 @@ $pos_col_width_px = nhance_dt_column_widths_px($pos_header_labels, $pos_col_max_ $('#partnerPOSForm').parsley().reset(); } $('#manager_id').val(null).trigger('change'); + updateFileNameDisplay('#aadhar_file_name', '#aadhar_file_name_display', ''); + updateFileNameDisplay('#pan_file_name', '#pan_file_name_display', ''); + updateFileNameDisplay('#certificate_file_name', '#certificate_file_name_display', ''); } + function updateFileNameDisplay(inputSelector, displaySelector, existingName = '') { + const $display = $(displaySelector); + let fileName = ''; + + if (existingName && String(existingName).trim() !== '') { + fileName = String(existingName).trim(); + } else { + const inputEl = $(inputSelector)[0]; + if (inputEl && inputEl.files && inputEl.files.length > 0) { + fileName = inputEl.files[0].name || ''; + } + } + + if (fileName) { + $display.text('Uploaded: ' + fileName).show(); + } else { + $display.text('').hide(); + } + } + function appendEditData(data){ $('#pos_id').val(data.id); @@ -481,14 +512,12 @@ $pos_col_width_px = nhance_dt_column_widths_px($pos_header_labels, $pos_col_max_ $('#mobile').val(data.mobile); $('#pos_code').val(data.pos_code); - // Instead of setting the file input - $('#current_file_name').text(data['certificate_file_name'] || 'No file uploaded'); - $('#aadhar').val(data.aadhar); - $('#aadhar_file_name').text(data['aadhar_file_name'] || 'No file uploaded'); + updateFileNameDisplay('#aadhar_file_name', '#aadhar_file_name_display', data['aadhar_file_name'] || ''); $('#pan').val(data.pan); - $('#pan_file_name').text(data['pan_file_name'] || 'No file uploaded'); + updateFileNameDisplay('#pan_file_name', '#pan_file_name_display', data['pan_file_name'] || ''); + updateFileNameDisplay('#certificate_file_name', '#certificate_file_name_display', data['certificate_file_name'] || ''); $('#bank_name').val(data.bank_name); $('#account_holder_name').val(data.account_holder_name); @@ -508,6 +537,18 @@ $pos_col_width_px = nhance_dt_column_widths_px($pos_header_labels, $pos_col_max_ }); } + $('#aadhar_file_name').on('change', function () { + updateFileNameDisplay('#aadhar_file_name', '#aadhar_file_name_display'); + }); + + $('#pan_file_name').on('change', function () { + updateFileNameDisplay('#pan_file_name', '#pan_file_name_display'); + }); + + $('#certificate_file_name').on('change', function () { + updateFileNameDisplay('#certificate_file_name', '#certificate_file_name_display'); + }); + $('#aadhar').on('input', function () { this.value = this.value.replace(/[^0-9]/g, '');