GWM : Manual merge option

This commit is contained in:
Gowtham M 2026-05-18 16:40:05 +05:30
parent 413180a565
commit a2865f1096
4 changed files with 301 additions and 12 deletions

View File

@ -818,6 +818,7 @@ $routes->group("/ticket", ["filter" => "authMVC"], function ($routes) {
$routes->get("getMoreInfo","TicketController::getMoreInfo");
$routes->post('upload_url',"TicketController::upload_url");
$routes->post('getUrlDataByTicketId',"TicketController::getUrlDataByTicketId");
$routes->post('manualMergeClaimFiles', 'TicketController::manualMergeClaimFiles');
$routes->post('uploadClaimFilesToTPA', 'TicketController::uploadClaimFilesToTPA');
$routes->get('remove_url',"TicketController::remove_url");
$routes->get('fetchVehiclePolicy/(:any)','TicketController::fetchVehiclePolicy/$1');

View File

@ -3721,9 +3721,78 @@ class TicketController extends BaseController
->where('is_active', 1)
->findAll();
helper('merge_pdf');
$mergeUi = merge_ticket_manual_merge_status((int) $ticket_id);
return $this->response->setJSON([
'status' => true,
'data' => $urlData
'status' => true,
'data' => $urlData,
'merge_ui' => $mergeUi,
]);
}
/**
* Manually merge claim PDF/image files for a ticket (Claim Files tab).
*/
public function manualMergeClaimFiles()
{
$ticket_id = (int) $this->request->getPost('ticket_id');
if ($ticket_id <= 0) {
return $this->response->setStatusCode(400)->setJSON([
'status' => false,
'message' => 'Ticket ID is required',
]);
}
helper('merge_pdf');
$mergeUi = merge_ticket_manual_merge_status($ticket_id);
if (! $mergeUi['show_manual_merge'] && $mergeUi['mergeable_count'] < 1) {
return $this->response->setStatusCode(400)->setJSON([
'status' => false,
'message' => 'No PDF or image files available on disk to merge.',
]);
}
$ticket = $this->ticketMasterModel
->select('id, ticket_type_id')
->where('id', $ticket_id)
->where('is_active', 1)
->first();
if (! $ticket) {
return $this->response->setStatusCode(404)->setJSON([
'status' => false,
'message' => 'Claim not found.',
]);
}
try {
$result = merge_ticket_pdfs($ticket_id, [
'ticket_type' => (int) ($ticket['ticket_type_id'] ?? 1),
'created_by' => function_exists('get_session_userid') ? get_session_userid() : null,
]);
} catch (\Throwable $e) {
log_message('error', 'TicketController::manualMergeClaimFiles | ticket_id=' . $ticket_id . ' | ' . $e->getMessage());
return $this->response->setStatusCode(500)->setJSON([
'status' => false,
'message' => 'Merge failed: ' . $e->getMessage(),
]);
}
if (! ($result['status'] ?? false)) {
return $this->response->setJSON([
'status' => false,
'message' => $result['message'] ?? 'Merge failed. Check logs for details.',
'data' => $result,
]);
}
return $this->response->setJSON([
'status' => true,
'message' => $result['message'] ?? 'Documents merged successfully.',
'data' => $result,
]);
}

View File

@ -86,13 +86,8 @@ if (! function_exists('merge_ticket_pdfs')) {
$sourceFiles = [];
foreach ($rows as $row) {
$name = ! empty($row['url']) ? $row['url'] : ($row['file_name'] ?? '');
if (empty($name)) {
continue;
}
// url column may sometimes hold a full URL; we only care about the file basename on disk.
$full = $uploadDir . basename($name);
if (is_file($full) && is_readable($full)) {
$full = merge_ticket_pdf_resolve_disk_path($row, $uploadDir);
if ($full !== null) {
$mime = merge_ticket_pdf_resolve_mime($full, (string) ($row['mime_type'] ?? ''));
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}");
@ -105,7 +100,8 @@ if (! function_exists('merge_ticket_pdfs')) {
'id' => $row['id'] ?? null,
];
} else {
log_message('error', "merge_ticket_pdfs | missing file on disk | claim_file_id={$row['id']} | path={$full}");
$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));
}
}
@ -340,10 +336,50 @@ if (! function_exists('merge_ticket_pdf_resolve_mime')) {
return 'image/png';
}
if (in_array($detectedMime, ['application/octet-stream', 'binary/octet-stream'], true)) {
if ($ext === 'pdf') {
return 'application/pdf';
}
if (in_array($ext, ['jpg', 'jpeg'], true)) {
return 'image/jpeg';
}
if ($ext === 'png') {
return 'image/png';
}
}
return $detectedMime ?: ($storedMime ?: 'application/octet-stream');
}
}
if (! function_exists('merge_ticket_pdf_resolve_disk_path')) {
/**
* 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
{
$candidates = [];
if (! empty($row['url'])) {
$candidates[] = basename((string) $row['url']);
}
if (! empty($row['file_name'])) {
$candidates[] = basename((string) $row['file_name']);
}
foreach (array_unique($candidates) as $name) {
if ($name === '' || preg_match('#^https?://#i', $name)) {
continue;
}
$full = $uploadDir . $name;
if (is_file($full) && is_readable($full)) {
return $full;
}
}
return null;
}
}
if (! function_exists('merge_ticket_pdf_add_image_page')) {
/**
* Add an uploaded image as a single PDF page, preserving portrait/landscape
@ -397,3 +433,86 @@ if (! function_exists('merge_ticket_pdf_add_image_page')) {
return true;
}
}
if (! function_exists('merge_ticket_manual_merge_status')) {
/**
* UI/status helper: whether manual merge should be offered on Claim Files tab.
*
* @return array{
* has_merged_file: bool,
* mergeable_count: int,
* show_manual_merge: bool,
* button_label: string
* }
*/
function merge_ticket_manual_merge_status(int $ticket_master_id, array $opts = []): array
{
$opts += [
'include_file_types' => [1, 2],
'include_mime_types' => ['application/pdf', 'image/jpeg', 'image/png'],
];
$status = [
'has_merged_file' => false,
'mergeable_count' => 0,
'show_manual_merge' => false,
'button_label' => 'Merge documents',
];
if ($ticket_master_id <= 0) {
return $status;
}
$claimFiles = new ClaimFilesModel();
$rows = $claimFiles
->where('ticket_id', $ticket_master_id)
->where('is_active', 1)
->whereIn('file_type', array_merge($opts['include_file_types'], [MERGED_CLAIM_FILE_TYPE]))
->orderBy('id', 'ASC')
->findAll();
$uploadDir = rtrim(WRITEPATH, '/\\') . DIRECTORY_SEPARATOR
. 'uploads' . DIRECTORY_SEPARATOR
. 'claim_files' . DIRECTORY_SEPARATOR;
$mergeableCount = 0;
$sourceRowCount = 0;
foreach ($rows as $row) {
if ((int) ($row['file_type'] ?? 0) === MERGED_CLAIM_FILE_TYPE) {
$status['has_merged_file'] = true;
continue;
}
if (! in_array((int) ($row['file_type'] ?? 0), $opts['include_file_types'], true)) {
continue;
}
$sourceRowCount++;
$full = merge_ticket_pdf_resolve_disk_path($row, $uploadDir);
if ($full === null) {
continue;
}
$mime = merge_ticket_pdf_resolve_mime($full, (string) ($row['mime_type'] ?? ''));
if (in_array($mime, $opts['include_mime_types'], true)) {
$mergeableCount++;
}
}
$status['mergeable_count'] = $mergeableCount;
// Show manual merge when there is no merged file but user has uploaded docs in the list.
if (! $status['has_merged_file']) {
if ($mergeableCount >= 1 || $sourceRowCount >= 2) {
$status['show_manual_merge'] = true;
$status['button_label'] = 'Merge documents';
}
} elseif ($mergeableCount >= 2) {
$status['show_manual_merge'] = true;
$status['button_label'] = 'Re-merge documents';
}
return $status;
}
}

View File

@ -103,6 +103,11 @@
<h4 class="mb-0" style="position: relative;">File List</h4>
</div>
<div class="col-md-6 text-md-right mt-2 mt-md-0">
<button type="button" class="btn btn-warning waves-effect waves-light mr-2 d-none"
id="btn_manual_merge_claim_files"
title="Combine uploaded PDFs and images into one file">
Merge documents
</button>
<button type="button" class="btn btn-primary waves-effect waves-light"
id="btn_upload_claim_files_to_tpa">
Upload files to TPA
@ -170,9 +175,18 @@
<script>
$(document).ready(function(){
let ticket_id = $('#ticket_master_id').val();
let ticket_id = getClaimFileListTicketId();
$('#ticket_id_url').val(ticket_id);
let urlData = getUrlDataByTicketId(ticket_id);
if (ticket_id) {
getUrlDataByTicketId(ticket_id);
}
});
$(document).on('shown.bs.tab', 'a[href="#uploads-tab"], #uploads_tab', function () {
var ticket_id = getClaimFileListTicketId();
if (ticket_id) {
getUrlDataByTicketId(ticket_id);
}
});
function getClaimFileListTicketId() {
@ -183,6 +197,88 @@
return id;
}
function resolveManualMergeUi(serverMergeUi, fileListData) {
if (serverMergeUi && serverMergeUi.show_manual_merge) {
return serverMergeUi;
}
if (!fileListData || !fileListData.length) {
return serverMergeUi || { show_manual_merge: false };
}
var hasMerged = fileListData.some(function (item) {
return item.file_type == 4 || item.file_type === '4';
});
var sourceCount = fileListData.filter(function (item) {
return item.file_type == 1 || item.file_type === '1'
|| item.file_type == 2 || item.file_type === '2';
}).length;
if (!hasMerged && sourceCount >= 1) {
return {
show_manual_merge: true,
button_label: 'Merge documents',
mergeable_count: sourceCount
};
}
return serverMergeUi || { show_manual_merge: false };
}
function updateManualMergeButton(mergeUi, fileListData) {
var $btn = $('#btn_manual_merge_claim_files');
if (!$btn.length) {
return;
}
var resolved = resolveManualMergeUi(mergeUi, fileListData);
if (resolved && resolved.show_manual_merge) {
$btn.removeClass('d-none').css('display', 'inline-block');
$btn.text(resolved.button_label || 'Merge documents');
$btn.prop('disabled', false);
} else {
$btn.addClass('d-none').css('display', '');
}
}
$(document).on('click', '#btn_manual_merge_claim_files', function () {
var ticket_id = getClaimFileListTicketId();
if (!ticket_id) {
toastr.warning('Ticket ID is missing. Please reload the page.', 'Validation');
return;
}
var $btn = $(this);
$.ajax({
url: "<?= base_url('ticket/manualMergeClaimFiles') ?>",
type: "POST",
data: { ticket_id: ticket_id },
dataType: "json",
beforeSend: function () {
$btn.prop('disabled', true);
$('.loader').fadeIn();
$('.loader-mask').fadeIn();
},
success: function (res) {
if (res && res.status === true) {
toastr.success(res.message || 'Documents merged successfully', 'Success');
getUrlDataByTicketId(ticket_id);
} else {
toastr.error((res && res.message) ? res.message : 'Failed to merge documents', 'Error');
}
},
error: function (xhr) {
var msg = 'Failed to merge documents';
try {
var r = JSON.parse(xhr.responseText);
if (r.message) {
msg = r.message;
}
} catch (e) {}
toastr.error(msg, 'Error');
},
complete: function () {
$btn.prop('disabled', false);
$('.loader').fadeOut();
$('.loader-mask').delay(350).fadeOut('slow');
}
});
});
$(document).on('click', '#btn_upload_claim_files_to_tpa', function () {
var ticket_id = getClaimFileListTicketId();
if (!ticket_id) {
@ -395,10 +491,13 @@
console.log('Form submitted response:', response);
if (response.status === true) {
window._claimFilesMergeUi = response.merge_ui || null;
create_url_list(response.data);
updateManualMergeButton(response.merge_ui, response.data);
addHTMLInput();
return ;
} else {
updateManualMergeButton(null, []);
addHTMLInput();
console.warn("No Data");
}
@ -555,6 +654,7 @@
} else {
$('#table_bd').html('<tr><td colspan="5">No Data Found</td></tr>');
}
updateManualMergeButton(window._claimFilesMergeUi || null, data || []);
}
$(document).on('click', '.delete-url', function (e) {