@ -3063,8 +3063,9 @@
}
}
function onDashboardPrinterFilterChange() {
function onDashboardPrinterFilterChange() {
const pid = document.getElementById('dashboard-printer-filter').value;
const pid = document.getElementById('dashboard-printer-filter')? .value || '' ;
const tonerSelect = document.getElementById('dashboard-toner-filter');
const tonerSelect = document.getElementById('dashboard-toner-filter');
if (!tonerSelect) return;
tonerSelect.innerHTML = '< option value = "" > -- All Toners --< / option > ';
tonerSelect.innerHTML = '< option value = "" > -- All Toners --< / option > ';
tonerSelect.disabled = true;
tonerSelect.disabled = true;
@ -3121,9 +3122,10 @@
}
}
function onDashboardPeriodPresetChange() {
function onDashboardPeriodPresetChange() {
const val = document.getElementById('dashboard-period-preset').value;
const val = document.getElementById('dashboard-period-preset')? .value || '' ;
const startWrapper = document.getElementById('dashboard-start-date-wrapper');
const startWrapper = document.getElementById('dashboard-start-date-wrapper');
const endWrapper = document.getElementById('dashboard-end-date-wrapper');
const endWrapper = document.getElementById('dashboard-end-date-wrapper');
if (startWrapper & & endWrapper) {
if (val === 'custom') {
if (val === 'custom') {
startWrapper.style.display = 'block';
startWrapper.style.display = 'block';
endWrapper.style.display = 'block';
endWrapper.style.display = 'block';
@ -3132,10 +3134,11 @@
endWrapper.style.display = 'none';
endWrapper.style.display = 'none';
}
}
}
}
}
function matchesPeriod(dateString) {
function matchesPeriod(dateString) {
if (!dateString) return false;
if (!dateString) return false;
const preset = document.getElementById('dashboard-period-preset').value;
const preset = document.getElementById('dashboard-period-preset')? .value || 'all' ;
if (preset === 'all') return true;
if (preset === 'all') return true;
const itemDate = new Date(dateString);
const itemDate = new Date(dateString);
@ -3162,8 +3165,8 @@
const startOfYear = new Date(now.getFullYear(), 0, 1);
const startOfYear = new Date(now.getFullYear(), 0, 1);
return itemDate >= startOfYear;
return itemDate >= startOfYear;
} else if (preset === 'custom') {
} else if (preset === 'custom') {
const startInput = document.getElementById('dashboard-start-date').value;
const endInput = document.getElementById('dashboard-end-date').value;
const startInput = document.getElementById('dashboard-start-date')? .value || '' ;
const endInput = document.getElementById('dashboard-end-date')? .value || '' ;
const filterStart = startInput ? new Date(startInput) : null;
const filterStart = startInput ? new Date(startInput) : null;
const filterEnd = endInput ? new Date(endInput) : null;
const filterEnd = endInput ? new Date(endInput) : null;
@ -3231,9 +3234,9 @@
}
}
function updateDashboardData() {
function updateDashboardData() {
const selectedPrinter = document.getElementById('dashboard-printer-filter').value;
const selectedToner = document.getElementById('dashboard-toner-filter').value;
const selectedWorkorder = document.getElementById('dashboard-workorder-filter').value;
const selectedPrinter = document.getElementById('dashboard-printer-filter')? .value || '' ;
const selectedToner = document.getElementById('dashboard-toner-filter')? .value || '' ;
const selectedWorkorder = document.getElementById('dashboard-workorder-filter')? .value || '' ;
const groups = {};
const groups = {};
@ -3548,9 +3551,9 @@
}
}
function loadDashboardDetailsData() {
function loadDashboardDetailsData() {
const selectedPrinter = document.getElementById('dashboard-printer-filter').value;
const selectedToner = document.getElementById('dashboard-toner-filter').value;
const selectedWorkorder = document.getElementById('dashboard-workorder-filter').value;
const selectedPrinter = document.getElementById('dashboard-printer-filter')? .value || '' ;
const selectedToner = document.getElementById('dashboard-toner-filter')? .value || '' ;
const selectedWorkorder = document.getElementById('dashboard-workorder-filter')? .value || '' ;
let rawData = [];
let rawData = [];
if (activeDashboardDetailsType === 'workorder_registered') {
if (activeDashboardDetailsType === 'workorder_registered') {
@ -3767,6 +3770,82 @@
}
}
});
});
filtered = Object.values(groups);
} else if (activeDashboardDetailsType === 'outward_register') {
const groups = {};
filtered.forEach(item => {
const cleanRef = (item.itcell_ref_no & & String(item.itcell_ref_no).trim() !== '' & & String(item.itcell_ref_no).trim() !== 'null')
? String(item.itcell_ref_no).trim()
: (item.req_no & & String(item.req_no).trim() !== '' ? String(item.req_no).trim() : ('OUT-' + item.id));
const key = cleanRef;
if (!groups[key]) {
groups[key] = {
key: key,
itcell_ref_no: item.itcell_ref_no || '',
req_no: item.req_no || '',
dept_name: item.dept_name || item.dept_id || '-',
dept_id: item.dept_id,
zone_name: item.zone_name || item.zone_id || '-',
zone_id: item.zone_id,
qty_requested: 0,
qty_delivered: 0,
request_date: item.request_date || null,
outward_date: item.outward_date || null,
cdate: item.cdate || null,
updated_date: item.updated_date || null,
final_delivered_uploads: [],
receiver_photos: [],
req_nos: [],
printer_names: [],
model_names: [],
items: []
};
}
groups[key].qty_requested += parseInt(item.qty_requested || 0);
groups[key].qty_delivered += parseInt(item.qty_delivered || 0);
groups[key].items.push(item);
if (item.req_no & & !groups[key].req_nos.includes(item.req_no)) {
groups[key].req_nos.push(item.req_no);
}
if (item.printer_name & & !groups[key].printer_names.includes(item.printer_name)) {
groups[key].printer_names.push(item.printer_name);
}
if (item.model_name & & !groups[key].model_names.includes(item.model_name)) {
groups[key].model_names.push(item.model_name);
}
if (item.request_date & & !groups[key].request_date) {
groups[key].request_date = item.request_date;
}
if (item.outward_date & & !groups[key].outward_date) {
groups[key].outward_date = item.outward_date;
}
if (item.cdate & & (!groups[key].cdate || new Date(item.cdate) > new Date(groups[key].cdate))) {
groups[key].cdate = item.cdate;
}
if (item.updated_date & & (!groups[key].updated_date || new Date(item.updated_date) > new Date(groups[key].updated_date))) {
groups[key].updated_date = item.updated_date;
}
if (item.final_delivered_upload) {
const files = item.final_delivered_upload.split(',').map(f => (f || '').trim()).filter(Boolean);
files.forEach(f => {
if (!groups[key].final_delivered_uploads.includes(f)) {
groups[key].final_delivered_uploads.push(f);
}
});
}
if (item.receiver_photo) {
const files = item.receiver_photo.split(',').map(f => (f || '').trim()).filter(Boolean);
files.forEach(f => {
if (!groups[key].receiver_photos.includes(f)) {
groups[key].receiver_photos.push(f);
}
});
}
});
filtered = Object.values(groups);
filtered = Object.values(groups);
} else if (activeDashboardDetailsType === 'available_stock') {
} else if (activeDashboardDetailsType === 'available_stock') {
const groups = {};
const groups = {};
@ -3894,9 +3973,9 @@
dashboardDetailsCurrentPage = targetPage;
dashboardDetailsCurrentPage = targetPage;
}
}
const selectedCategory = document.getElementById('dashboard-details-category-filter').value;
const selectedDept = document.getElementById('dashboard-details-dept-filter').value;
const selectedStockStatus = document.getElementById('dashboard-details-stock-filter').value;
const selectedCategory = document.getElementById('dashboard-details-category-filter')? .value || '' ;
const selectedDept = document.getElementById('dashboard-details-dept-filter')? .value || '' ;
const selectedStockStatus = document.getElementById('dashboard-details-stock-filter')? .value || '' ;
const searchQuery = (document.getElementById('dashboard-details-search')?.value || '').toLowerCase().trim();
const searchQuery = (document.getElementById('dashboard-details-search')?.value || '').toLowerCase().trim();
// Apply categorywise (Printer Make), department, stock status, and text search filters
// Apply categorywise (Printer Make), department, stock status, and text search filters
@ -3993,7 +4072,7 @@
< th class = "text-center" > Registered Qty< / th >
< th class = "text-center" > Registered Qty< / th >
< th > Start Date< / th >
< th > Start Date< / th >
< th > End Date< / th >
< th > End Date< / th >
< th class = "text-center" > DC Copy< / th >
< th class = "text-center" > Workorder Copy< / th >
< / tr > `;
< / tr > `;
pagedData.forEach((item, idx) => {
pagedData.forEach((item, idx) => {
@ -4194,11 +4273,10 @@
} else if (activeDashboardDetailsType === 'outward_register') {
} else if (activeDashboardDetailsType === 'outward_register') {
thead.innerHTML = `
thead.innerHTML = `
< tr >
< tr >
< th > S.No< / th >
< th > Req. No< / th >
< th style = "width: 60px;" > S.No< / th >
< th > Req. No / IT Cell Ref < / th >
< th > Department< / th >
< th > Department< / th >
< th > Printer Model< / th >
< th > Toner Model< / th >
< th > Zone< / th >
< th class = "text-center" > Qty Req< / th >
< th class = "text-center" > Qty Req< / th >
< th class = "text-center" > Qty Issued< / th >
< th class = "text-center" > Qty Issued< / th >
< th > Requested Date< / th >
< th > Requested Date< / th >
@ -4209,41 +4287,37 @@
pagedData.forEach((item, idx) => {
pagedData.forEach((item, idx) => {
const tr = document.createElement('tr');
const tr = document.createElement('tr');
const globalIdx = (dashboardDetailsCurrentPage - 1) * dashboardDetailsPageSize + idx + 1;
const globalIdx = (dashboardDetailsCurrentPage - 1) * dashboardDetailsPageSize + idx + 1;
const reqDateFormatted = formatTimestamp(item.cdate);
const dateFormatted = formatTimestamp(item.updated_date);
let docBtn = '';
if (item.final_delivered_upload) {
const paths = item.final_delivered_upload.split(',');
docBtn = paths.map((p, index) => {
const trimmed = p.trim();
const url = trimmed.startsWith('.') ? trimmed.substring(1) : trimmed;
const label = paths.length > 1 ? `View Doc ${index + 1}` : `View Doc`;
return `< a href = "${contextPath + url}" target = "_blank" class = "btn-action btn-view-doc me-1 mb-1" style = "display: inline-flex; align-items: center; gap: 4px;" > < i class = "fa-solid fa-file-pdf" > < / i > ${label}< / a > `;
}).join(' ');
}
let photoBtn = '';
if (item.receiver_photo) {
const photos = item.receiver_photo.split(',');
photoBtn = photos.map((p, pIdx) => {
const trimmed = p.trim();
const url = trimmed.startsWith('.') ? trimmed.substring(1) : trimmed;
const label = photos.length > 1 ? `View Photo ${pIdx + 1}` : `View Photo`;
return `< a href = "${contextPath + url}" target = "_blank" class = "btn-action btn-view-photo me-1 mb-1" style = "display: inline-flex; align-items: center; gap: 4px;" > < i class = "fa-solid fa-image" > < / i > ${label}< / a > `;
}).join(' ');
}
const pdfBtn = `< button type = "button" class = "btn-action btn-pdf" onclick = "downloadOutwardItemPdfAck(${item.id})" > < i class = "fa-solid fa-file-arrow-down" > < / i > PDF Ack< / button > `;
const reqDateFormatted = (item.request_date & & String(item.request_date).trim() !== '' & & String(item.request_date).trim() !== 'null')
? formatDateOnly(item.request_date)
: (formatTimestamp(item.cdate) || '-');
const dateFormatted = (item.outward_date & & String(item.outward_date).trim() !== '' & & String(item.outward_date).trim() !== 'null')
? formatDateOnly(item.outward_date)
: (formatTimestamp(item.updated_date) || '-');
const groupRefParam = item.itcell_ref_no || item.req_no || (item.items & & item.items[0] ? item.items[0].req_no : (item.key || ''));
const viewBtn = `< button type = "button" class = "btn btn-sm btn-primary fw-bold px-3 py-1 me-1 mb-1"
style="border-radius: 20px; font-size: 11px; background-color: #0f5c78; border-color: #0f5c78; box-shadow: 0 2px 4px rgba(15, 92, 120, 0.15);"
onclick="showOutwardBreakdownModal('${encodeURIComponent(groupRefParam)}')"
title="Click to view distributed toner breakdown">
< i class = "fa-solid fa-eye me-1" > < / i > View (${item.items ? item.items.length : 1})
< / button > `;
const modelsCountBadge = item.items & & item.items.length > 1
? `< br > < span class = "badge bg-light text-secondary border mt-1" style = "cursor: pointer;" onclick = "showOutwardBreakdownModal('${encodeURIComponent(groupRefParam)}');" title = "Click to view ${item.items.length} toners" > < i class = "fa-solid fa-layer-group me-1" > < / i > ${item.items.length} Toners< / span > `
: (item.items & & item.items.length === 1 ? `< br > < small class = "text-muted font-monospace" > ${escapeHtml(item.items[0].model_name || '')}< / small > ` : '');
const refLink = `< a href = "#" class = "fw-bold text-decoration-none d-inline-block text-primary font-monospace" style = "border-bottom: 1px dashed #0f5c78; cursor: pointer; font-size: 0.95rem;" onclick = "showOutwardBreakdownModal('${encodeURIComponent(groupRefParam)}'); return false;" title = "Click to view distributed toner breakdown" > ${escapeHtml(item.itcell_ref_no || item.req_no || '-')}< / a > `;
tr.innerHTML = `
tr.innerHTML = `
< td class = "fw-semibold text-secondary" > ${globalIdx}< / td >
< td class = "fw-semibold text-secondary" > ${globalIdx}< / td >
< td class = "fw-bold text-dark" > ${escapeHtml(item.req_no)}< / td >
< td > ${escapeHtml(item.dept_name)}< / td >
< td > ${escapeHtml(item.printer_name)}< / td >
< td > < span class = "badge-toner-model" > ${escapeHtml(item.model_name)}< / span > < / td >
< td class = "text-center font-monospace fw-bold" > ${item.qty_requested}< / td >
< td class = "text-center text-success fw-bold font-monospace" > ${item.qty_delivered}< / td >
< td > ${refLink}${modelsCountBadge}< / td >
< td > ${escapeHtml(item.dept_name || '-')}< / td >
< td > ${escapeHtml(item.zone_name || '-')}< / td >
< td class = "text-center font-monospace fw-bold text-dark" > ${item.qty_requested}< / td >
< td class = "text-center text-success fw-bold font-monospace" > ${item.qty_delivered || 0}< / td >
< td > < small class = "text-dark fw-semibold" > ${reqDateFormatted}< / small > < / td >
< td > < small class = "text-dark fw-semibold" > ${reqDateFormatted}< / small > < / td >
< td > < small class = "text-muted" > ${dateFormatted}< / small > < / td >
< td class = "text-center" > ${docBtn}${photoBtn}${pdf Btn}< / td >
< td > < small class = "text-muted fw-semibold " > ${dateFormatted}< / small > < / td >
< td class = "text-center" style = "white-space: nowrap;" > ${view Btn}< / td >
`;
`;
tbody.appendChild(tr);
tbody.appendChild(tr);
});
});
@ -5823,7 +5897,7 @@
${getSortHeader('Registered Qty', 'total_qty_registered', 'text-center')}
${getSortHeader('Registered Qty', 'total_qty_registered', 'text-center')}
${getSortHeader('Start Date', 'workorder_start_date')}
${getSortHeader('Start Date', 'workorder_start_date')}
${getSortHeader('End Date', 'workorder_end_date')}
${getSortHeader('End Date', 'workorder_end_date')}
< th class = "text-center" > DC Copy< / th >
< th class = "text-center" > Workorder Copy< / th >
< / tr > `;
< / tr > `;
// Group records by File No (or Ref No)
// Group records by File No (or Ref No)
@ -6424,7 +6498,12 @@
}
}
const groupRefParam = item.itcell_ref_no || item.req_no || (item.items & & item.items[0] ? item.items[0].req_no : '');
const groupRefParam = item.itcell_ref_no || item.req_no || (item.items & & item.items[0] ? item.items[0].req_no : '');
const pdfBtn = `< button type = "button" class = "btn-action btn-pdf mb-1" style = "font-size: 11px; padding: 4px 8px;" onclick = "downloadOutwardGroupPdfAck('${encodeURIComponent(groupRefParam)}')" > < i class = "fa-solid fa-file-arrow-down" > < / i > PDF Ack< / button > `;
const viewBtn = `< button type = "button" class = "btn btn-sm btn-primary fw-bold px-3 py-1 me-1 mb-1"
style="border-radius: 20px; font-size: 11px; background-color: #0f5c78; border-color: #0f5c78; box-shadow: 0 2px 4px rgba(15, 92, 120, 0.15);"
onclick="showOutwardBreakdownModal('${encodeURIComponent(groupRefParam)}')"
title="Click to view distributed toner breakdown">
< i class = "fa-solid fa-eye me-1" > < / i > View (${item.items ? item.items.length : 1})
< / button > `;
const modelsCountBadge = item.items & & item.items.length > 1
const modelsCountBadge = item.items & & item.items.length > 1
? `< br > < span class = "badge bg-light text-secondary border mt-1" style = "cursor: pointer;" onclick = "showOutwardBreakdownModal('${encodeURIComponent(groupRefParam)}');" title = "Click to view ${item.items.length} toners" > < i class = "fa-solid fa-layer-group me-1" > < / i > ${item.items.length} Toners< / span > `
? `< br > < span class = "badge bg-light text-secondary border mt-1" style = "cursor: pointer;" onclick = "showOutwardBreakdownModal('${encodeURIComponent(groupRefParam)}');" title = "Click to view ${item.items.length} toners" > < i class = "fa-solid fa-layer-group me-1" > < / i > ${item.items.length} Toners< / span > `
@ -6441,7 +6520,7 @@
< td class = "text-center text-success fw-bold font-monospace" > ${item.qty_delivered || 0}< / td >
< td class = "text-center text-success fw-bold font-monospace" > ${item.qty_delivered || 0}< / td >
< td > < small class = "text-dark fw-semibold" > ${reqDateFormatted}< / small > < / td >
< td > < small class = "text-dark fw-semibold" > ${reqDateFormatted}< / small > < / td >
< td > < small class = "text-muted fw-semibold" > ${dateFormatted}< / small > < / td >
< td > < small class = "text-muted fw-semibold" > ${dateFormatted}< / small > < / td >
< td class = "text-center" > ${docBtn}${photoBtn}${pdf Btn}< / td >
< td class = "text-center" style = "white-space: nowrap;" > ${view Btn}< / td >
`;
`;
tbody.appendChild(tr);
tbody.appendChild(tr);
});
});
@ -7564,9 +7643,6 @@
< td > < small class = "text-dark fw-semibold" > ${dateFormatted}< / small > < / td >
< td > < small class = "text-dark fw-semibold" > ${dateFormatted}< / small > < / td >
< td class = "text-center" style = "white-space: nowrap;" >
< td class = "text-center" style = "white-space: nowrap;" >
${viewBtn}
${viewBtn}
${docBtn}
${photoBtn}
${pdfBtn}
< / td >
< / td >
`;
`;
tbody.appendChild(tr);
tbody.appendChild(tr);
@ -7625,6 +7701,7 @@
itcell_ref_no: first.itcell_ref_no || refIdentifier,
itcell_ref_no: first.itcell_ref_no || refIdentifier,
req_no: first.req_no || refIdentifier,
req_no: first.req_no || refIdentifier,
dept_name: first.dept_name || first.dept_id || '-',
dept_name: first.dept_name || first.dept_id || '-',
request_date: first.request_date || '-',
outward_date: first.outward_date || (first.updated_date ? formatDateOnly(first.updated_date) : '-'),
outward_date: first.outward_date || (first.updated_date ? formatDateOnly(first.updated_date) : '-'),
items: filtered
items: filtered
};
};
@ -7745,6 +7822,7 @@
`;
`;
tbody.appendChild(tr);
tbody.appendChild(tr);
//< td class = "text-center" > ${docBtn || photoBtn ? (docBtn + ' ' + photoBtn) : '< span class = "text-muted" > -< / span > '}< / td >
// < td class = "text-center" > ${singlePdfBtn}< / td >
// < td class = "text-center" > ${singlePdfBtn}< / td >
});
});
@ -7797,15 +7875,18 @@
if (callback) callback();
if (callback) callback();
return;
return;
}
}
fetch(contextPath + 'gccservicepaymenttracker /api/vendors')
fetch(contextPath + 'gcctonermanagement /api/vendors')
.then(res => res.json())
.then(res => res.json())
.then(data => {
.then(data => {
data.forEach(v => {
( data || []) .forEach(v => {
vendorsMap[v.id] = v.vendor_name;
vendorsMap[v.id] = v.vendor_name;
});
});
if (callback) callback();
if (callback) callback();
})
})
.catch(err => console.error("Error loading vendors map:", err));
.catch(err => {
console.error("Error loading vendors map:", err);
if (callback) callback();
});
}
}
function fetchActiveWorkordersForInward() {
function fetchActiveWorkordersForInward() {
@ -8265,13 +8346,33 @@
return;
return;
}
}
document.getElementById('edit-request-is-group').value = 'false';
document.getElementById('edit-request-id').value = item.id || '';
document.getElementById('edit-request-id').value = item.id || '';
document.getElementById('edit-request-orig-itcell').value = item.itcell_ref_no || '';
document.getElementById('edit-request-req-no').value = item.req_no || '-';
document.getElementById('edit-request-req-no').value = item.req_no || '-';
document.getElementById('edit-request-itcell').value = item.itcell_ref_no || '';
document.getElementById('edit-request-itcell').value = item.itcell_ref_no || '';
document.getElementById('edit-request-qty').value = item.qty_requested || 1;
document.getElementById('edit-request-qty').value = item.qty_requested || 1;
const editDateInput = document.getElementById('edit-request-date');
const editDateInput = document.getElementById('edit-request-date');
if (editDateInput) editDateInput.value = item.request_date || '';
if (editDateInput) editDateInput.value = item.request_date || '';
// Update modal title
const titleEl = document.getElementById('editUserRequestModalLabel');
if (titleEl) titleEl.innerHTML = '< i class = "fa-solid fa-pen-to-square me-2" > < / i > Edit User Request Details';
// Show single item container, hide multi item container
const singleContainer = document.getElementById('edit-request-single-container');
const multiContainer = document.getElementById('edit-request-multi-container');
if (singleContainer) singleContainer.style.display = 'flex';
if (multiContainer) multiContainer.style.display = 'none';
// Restore required attributes for single mode
const printerSelect = document.getElementById('edit-request-printer');
const tonerSelect = document.getElementById('edit-request-toner');
const qtyInput = document.getElementById('edit-request-qty');
if (printerSelect) printerSelect.required = true;
if (tonerSelect) tonerSelect.required = true;
if (qtyInput) qtyInput.required = true;
// Reset file input
// Reset file input
const fileInput = document.getElementById('edit-request-file');
const fileInput = document.getElementById('edit-request-file');
if (fileInput) fileInput.value = '';
if (fileInput) fileInput.value = '';
@ -8327,7 +8428,6 @@
}
}
// Populate printers dropdown
// Populate printers dropdown
const printerSelect = document.getElementById('edit-request-printer');
if (printerSelect) {
if (printerSelect) {
printerSelect.innerHTML = '< option value = "" > -- Select Printer --< / option > ';
printerSelect.innerHTML = '< option value = "" > -- Select Printer --< / option > ';
(printersCached || []).forEach(p => {
(printersCached || []).forEach(p => {
@ -8358,15 +8458,144 @@
}
}
}
}
function openEditUserRequestGroupModal(itcellRefNo, items) {
if (!items || items.length === 0) return;
const firstItem = items[0];
document.getElementById('edit-request-is-group').value = 'true';
document.getElementById('edit-request-id').value = firstItem.id || '';
document.getElementById('edit-request-orig-itcell').value = itcellRefNo || '';
document.getElementById('edit-request-req-no').value = `Multi-Toner Request (${items.length} Toners)`;
document.getElementById('edit-request-itcell').value = itcellRefNo || '';
// Populate Requested Date from existing items
const editDateInput = document.getElementById('edit-request-date');
const foundDate = items.find(i => i.request_date & & String(i.request_date).trim() !== '' & & String(i.request_date).trim() !== 'null')?.request_date || '';
if (editDateInput) editDateInput.value = foundDate;
// Update modal title
const titleEl = document.getElementById('editUserRequestModalLabel');
if (titleEl) titleEl.innerHTML = `< i class = "fa-solid fa-pen-to-square me-2" > < / i > Edit Request Details & Date (${escapeHtml(itcellRefNo || 'Request')})`;
// Hide single item container, show multi item container
const singleContainer = document.getElementById('edit-request-single-container');
const multiContainer = document.getElementById('edit-request-multi-container');
if (singleContainer) singleContainer.style.display = 'none';
if (multiContainer) multiContainer.style.display = 'flex';
// Remove required from single container inputs so form can submit
const printerSelect = document.getElementById('edit-request-printer');
const tonerSelect = document.getElementById('edit-request-toner');
const qtyInput = document.getElementById('edit-request-qty');
if (printerSelect) printerSelect.required = false;
if (tonerSelect) tonerSelect.required = false;
if (qtyInput) qtyInput.required = false;
// Set multi count badge
const multiCountEl = document.getElementById('edit-request-multi-count');
if (multiCountEl) multiCountEl.textContent = items.length;
// Populate multi-toner items table
const multiTbody = document.getElementById('edit-request-multi-tbody');
if (multiTbody) {
multiTbody.innerHTML = '';
items.forEach((it, idx) => {
const tr = document.createElement('tr');
tr.innerHTML = `
< td class = "fw-semibold text-secondary text-center" > ${idx + 1}< / td >
< td class = "fw-bold text-dark font-monospace" > ${escapeHtml(it.req_no || '-')}< / td >
< td > ${escapeHtml(it.printer_name || '-')}< / td >
< td > < span class = "badge-toner-model" > ${escapeHtml(it.model_name || '-')}< / span > < / td >
< td class = "text-center" >
< input type = "number" min = "1" step = "1" required
class="form-control form-control-sm text-center edit-multi-qty-input fw-bold mx-auto"
style="width: 100px; border-radius: 6px; border: 1px solid #cbd5e1;"
data-id="${it.id}" value="${it.qty_requested || 1}">
< / td >
`;
multiTbody.appendChild(tr);
});
}
// Reset file input
const fileInput = document.getElementById('edit-request-file');
if (fileInput) fileInput.value = '';
const fileLabel = document.getElementById('edit-request-file-label');
if (fileLabel) fileLabel.textContent = 'Upload new PDF to replace (Optional)';
// Show current document link from any item with a file
const currentDocContainer = document.getElementById('edit-request-current-doc');
if (currentDocContainer) {
const foundUpload = items.find(i => i.user_request_upload & & String(i.user_request_upload).trim() !== '')?.user_request_upload || '';
if (foundUpload) {
currentDocContainer.innerHTML = `
< div class = "d-flex align-items-center gap-2 p-2 bg-light rounded border" >
< i class = "fa-solid fa-file-pdf text-danger" > < / i >
< span class = "small text-muted text-truncate" style = "max-width: 180px;" > Current File< / span >
< a href = "${resolveUploadUrl(foundUpload)}" target = "_blank" class = "btn btn-sm btn-outline-danger py-0 px-2 ms-auto" style = "font-size: 11px;" >
< i class = "fa-solid fa-eye" > < / i > View
< / a >
< / div >
`;
} else {
currentDocContainer.innerHTML = `< span class = "small text-muted" > < i class = "fa-solid fa-ban me-1" > < / i > No letter uploaded< / span > `;
}
}
// Populate departments dropdown
const deptSelect = document.getElementById('edit-request-dept');
if (deptSelect) {
deptSelect.innerHTML = '< option value = "" > -- Select Department --< / option > ';
(departmentsCached || []).forEach(d => {
const opt = document.createElement('option');
opt.value = d.dept_name || d.id;
opt.textContent = d.dept_name || `Dept #${d.id}`;
if (String(firstItem.dept_id) === String(d.id) || String(firstItem.dept_name) === String(d.dept_name) || String(firstItem.dept_id) === String(d.dept_name)) {
opt.selected = true;
}
deptSelect.appendChild(opt);
});
}
// Populate zones dropdown
const zoneSelect = document.getElementById('edit-request-zone');
if (zoneSelect) {
zoneSelect.innerHTML = '< option value = "" > -- Select Zone (Optional) --< / option > ';
(zonesCached || []).forEach(z => {
const opt = document.createElement('option');
opt.value = z.zone_name || z.id;
opt.textContent = z.zone_name || `Zone #${z.id}`;
if (String(firstItem.zone_id) === String(z.id) || String(firstItem.zone_name) === String(z.zone_name) || String(firstItem.zone_id) === String(z.zone_name)) {
opt.selected = true;
}
zoneSelect.appendChild(opt);
});
}
// Hide breakdown modal if open
const breakdownModalEl = document.getElementById('userRequestBreakdownModal');
if (breakdownModalEl) {
const breakdownModal = bootstrap.Modal.getInstance(breakdownModalEl);
if (breakdownModal) breakdownModal.hide();
}
const editModalEl = document.getElementById('editUserRequestModal');
if (editModalEl) {
const editModal = bootstrap.Modal.getOrCreateInstance(editModalEl);
editModal.show();
}
}
function openEditUserRequestByGroup(itcellRefNo, pid) {
function openEditUserRequestByGroup(itcellRefNo, pid) {
const cleanRef = String(itcellRefNo || '').trim();
const items = (userRequestsCached || []).filter(r =>
const items = (userRequestsCached || []).filter(r =>
String(r.itcell_ref_no).trim() === String(itcellRefNo).trim() & &
(pid === undefined || pid === null || String(r.pid) === String(pid))
(String(r.itcell_ref_no || '').trim() === cleanRef || String(r.req_no || '').trim() === cleanRef ) & &
(pid === undefined || pid === null || String(pid) === '' || String( r.pid) === String(pid))
);
);
if (items.length === 1) {
if (items.length === 1) {
openEditUserRequestModal(items[0].id);
openEditUserRequestModal(items[0].id);
} else if (items.length > 1) {
} else if (items.length > 1) {
showUserRequestBreakdownModal(itcellRefNo, pid);
openEditUserRequestGroupModal(cleanRef, items );
} else {
} else {
showNotification('warning', 'Not Found', 'No records found to edit.');
showNotification('warning', 'Not Found', 'No records found to edit.');
}
}
@ -8414,35 +8643,65 @@
function submitEditRequest(event) {
function submitEditRequest(event) {
if (event) event.preventDefault();
if (event) event.preventDefault();
const id = document.getElementById('edit-request-id').value ;
const isGroup = document.getElementById('edit-request-is-group')?.value === 'true' ;
const itcellRefNo = document.getElementById('edit-request-itcell').value.trim();
const itcellRefNo = document.getElementById('edit-request-itcell').value.trim();
const origItcell = document.getElementById('edit-request-orig-itcell').value.trim();
const deptId = document.getElementById('edit-request-dept').value.trim();
const deptId = document.getElementById('edit-request-dept').value.trim();
const zoneId = document.getElementById('edit-request-zone').value.trim();
const zoneId = document.getElementById('edit-request-zone').value.trim();
const editDateInput = document.getElementById('edit-request-date');
const requestDate = editDateInput ? editDateInput.value.trim() : '';
const fileInput = document.getElementById('edit-request-file');
if (!itcellRefNo || !deptId) {
showNotification('warning', 'Missing Fields', 'Please fill in all required fields.');
return;
}
const formData = new FormData();
formData.append('deptId', deptId);
formData.append('zoneId', zoneId);
formData.append('requestDate', requestDate);
if (fileInput & & fileInput.files.length > 0) {
formData.append('userRequestFile', fileInput.files[0]);
}
let endpoint = contextPath + 'gcctonermanagement/api/request/update';
if (isGroup) {
formData.append('itcellRefNo', origItcell || itcellRefNo);
formData.append('newItcellRefNo', itcellRefNo);
// Collect quantities for each item in the multi-table
const qtyInputs = document.querySelectorAll('.edit-multi-qty-input');
const items = [];
for (let i = 0; i < qtyInputs.length ; i + + ) {
const inp = qtyInputs[i];
const itemId = inp.getAttribute('data-id');
const qtyVal = parseInt(inp.value.trim());
if (isNaN(qtyVal) || qtyVal < = 0) {
showNotification('warning', 'Invalid Quantity', 'Please enter a valid positive quantity for all items.');
return;
}
items.push({ id: itemId, qty: qtyVal });
}
formData.append('itemsJson', JSON.stringify(items));
endpoint = contextPath + 'gcctonermanagement/api/request/update-group';
} else {
const id = document.getElementById('edit-request-id').value;
const pid = document.getElementById('edit-request-printer').value;
const pid = document.getElementById('edit-request-printer').value;
const tid = document.getElementById('edit-request-toner').value;
const tid = document.getElementById('edit-request-toner').value;
const qtyRequested = document.getElementById('edit-request-qty').value;
const qtyRequested = document.getElementById('edit-request-qty').value;
const fileInput = document.getElementById('edit-request-file');
if (!id || !itcellRefNo || !deptId || !pid || !tid || !qtyRequested) {
if (!i d || !pid || !tid || !qtyRequested) {
showNotification('warning', 'Missing Fields', 'Please fill in all required fields.');
showNotification('warning', 'Missing Fields', 'Please fill in all required fields.');
return;
return;
}
}
const formData = new FormData();
formData.append('id', id);
formData.append('id', id);
formData.append('itcellRefNo', itcellRefNo);
formData.append('itcellRefNo', itcellRefNo);
formData.append('deptId', deptId);
formData.append('zoneId', zoneId);
formData.append('pid', pid);
formData.append('pid', pid);
formData.append('tid', tid);
formData.append('tid', tid);
formData.append('qtyRequested', qtyRequested);
formData.append('qtyRequested', qtyRequested);
const editDateInput = document.getElementById('edit-request-date');
if (editDateInput) {
formData.append('requestDate', editDateInput.value.trim());
}
if (fileInput & & fileInput.files.length > 0) {
formData.append('userRequestFile', fileInput.files[0]);
}
}
const progressContainer = document.getElementById('edit-request-progress-container');
const progressContainer = document.getElementById('edit-request-progress-container');
@ -8454,7 +8713,7 @@
if (submitBtn) submitBtn.disabled = true;
if (submitBtn) submitBtn.disabled = true;
const xhr = new XMLHttpRequest();
const xhr = new XMLHttpRequest();
xhr.open('POST', contextPath + 'gcctonermanagement/api/request/update' , true);
xhr.open('POST', endpoint , true);
const csrf = getCsrfMeta();
const csrf = getCsrfMeta();
if (csrf.token & & csrf.header) {
if (csrf.token & & csrf.header) {
@ -8734,11 +8993,11 @@
if (!select) return;
if (!select) return;
select.innerHTML = '< option value = "" > -- Loading Vendors... --< / option > ';
select.innerHTML = '< option value = "" > -- Loading Vendors... --< / option > ';
fetch(contextPath + 'gccservicepaymenttracker /api/vendors')
fetch(contextPath + 'gcctonermanagement /api/vendors')
.then(res => res.json())
.then(res => res.json())
.then(data => {
.then(data => {
select.innerHTML = '< option value = "" > -- Select Vendor --< / option > ';
select.innerHTML = '< option value = "" > -- Select Vendor --< / option > ';
data.forEach(v => {
( data || []) .forEach(v => {
const opt = document.createElement('option');
const opt = document.createElement('option');
opt.value = v.id;
opt.value = v.id;
opt.textContent = v.vendor_name;
opt.textContent = v.vendor_name;
@ -8810,11 +9069,11 @@
if (!select) return;
if (!select) return;
select.innerHTML = '< option value = "" > -- Loading Vendors... --< / option > ';
select.innerHTML = '< option value = "" > -- Loading Vendors... --< / option > ';
fetch(contextPath + 'gccservicepaymenttracker /api/vendors')
fetch(contextPath + 'gcctonermanagement /api/vendors')
.then(res => res.json())
.then(res => res.json())
.then(data => {
.then(data => {
select.innerHTML = '< option value = "" > -- Select Vendor --< / option > ';
select.innerHTML = '< option value = "" > -- Select Vendor --< / option > ';
data.forEach(v => {
( data || []) .forEach(v => {
const opt = document.createElement('option');
const opt = document.createElement('option');
opt.value = v.id;
opt.value = v.id;
opt.textContent = v.vendor_name;
opt.textContent = v.vendor_name;
@ -9620,6 +9879,7 @@
itcell_ref_no: selectedKey,
itcell_ref_no: selectedKey,
req_no: groupItems[0]?.req_no || selectedKey,
req_no: groupItems[0]?.req_no || selectedKey,
dept_name: groupItems[0]?.dept_name || groupItems[0]?.dept_id || '',
dept_name: groupItems[0]?.dept_name || groupItems[0]?.dept_id || '',
request_date: groupItems[0]?.request_date || groupItems[0]?.created_date || groupItems[0]?.cdate || '',
outward_date: outwardDate,
outward_date: outwardDate,
itemIds: itemsToIssue.map(i => i.id),
itemIds: itemsToIssue.map(i => i.id),
items: issuedDetails
items: issuedDetails
@ -9801,57 +10061,120 @@
doc.setTextColor(15, 92, 120);
doc.setTextColor(15, 92, 120);
doc.text("TONER DELIVERY ACKNOWLEDGEMENT", 105, 45, null, null, "center");
doc.text("TONER DELIVERY ACKNOWLEDGEMENT", 105, 45, null, null, "center");
// Helper to format date strings cleanly
function formatPdfDate(val, fallbackToday = false) {
if (!val) {
if (fallbackToday) {
const now = new Date();
const dd = String(now.getDate()).padStart(2, '0');
const mm = String(now.getMonth() + 1).padStart(2, '0');
const yyyy = now.getFullYear();
return `${dd}/${mm}/${yyyy}`;
}
return '-';
}
if (typeof val === 'string' & & /^\d{2}\/\d{2}\/\d{4}/.test(val.trim())) {
return val.trim();
}
try {
const d = new Date(val);
if (!isNaN(d.getTime())) {
const dd = String(d.getDate()).padStart(2, '0');
const mm = String(d.getMonth() + 1).padStart(2, '0');
const yyyy = d.getFullYear();
const hh = d.getHours();
const min = d.getMinutes();
if (typeof val === 'string' & & (val.includes(':') || val.includes('T'))) {
const hhStr = String(hh).padStart(2, '0');
const minStr = String(min).padStart(2, '0');
return `${dd}/${mm}/${yyyy} ${hhStr}:${minStr}`;
}
return `${dd}/${mm}/${yyyy}`;
}
} catch (e) { }
return String(val);
}
// Header info details (Ref No, Department, Date)
// Header info details (Ref No, Department, Date)
doc.setFontSize(9.5);
doc.setFont('Helvetica', 'normal');
doc.setFontSize(9);
doc.setTextColor(51, 65, 85);
doc.setTextColor(51, 65, 85);
const refNoText = item.itcell_ref_no || item.req_no || '-';
const deptText = item.dept_name || item.dept_id || '-';
const outwardDateText = item.outward_date || (new Date().toLocaleDateString('en-GB') + ' ' + new Date().toLocaleTimeString('en-GB', { hour: '2-digit', minute: '2-digit' }));
const refNoText = String(item.itcell_ref_no || item.req_no || '-');
const deptText = String(item.dept_name || item.dept_id || '-');
// Determine User Requested Date
let reqDateRaw = item.request_date || item.cdate || item.created_date;
if (!reqDateRaw & & item.items & & item.items.length > 0) {
reqDateRaw = item.items[0].request_date || item.items[0].cdate || item.items[0].created_date;
}
const userRequestedDate = formatPdfDate(reqDateRaw);
// Determine Issued Date
let outwardDateRaw = item.outward_date || item.updated_date;
if (!outwardDateRaw & & item.items & & item.items.length > 0) {
outwardDateRaw = item.items[0].outward_date || item.items[0].updated_date;
}
const outwardDateText = formatPdfDate(outwardDateRaw, true);
// Left Column Info
doc.setFont('Helvetica', 'bold');
doc.setFont('Helvetica', 'bold');
doc.text("IT Cell Ref No:", 15, 54);
doc.text("IT Cell Ref No:", 15, 54);
doc.setFont('Helvetica', 'normal');
doc.setFont('Helvetica', 'normal');
doc.text(refNoText, 45, 54);
doc.text(refNoText, 43 , 54);
doc.setFont('Helvetica', 'bold');
doc.setFont('Helvetica', 'bold');
doc.text("Department:", 15, 60);
doc.text("Department:", 15, 60);
doc.setFont('Helvetica', 'normal');
doc.setFont('Helvetica', 'normal');
doc.text(deptText, 45, 60);
const wrappedDept = doc.splitTextToSize(deptText, 70);
doc.text(wrappedDept, 43, 60);
// Right Column Info (Properly aligned with adequate spacing to prevent overlap)
doc.setFont('Helvetica', 'bold');
doc.setFont('Helvetica', 'bold');
doc.text("Delivery Date:", 135, 54);
doc.text("User Requested Date:", 116 , 54);
doc.setFont('Helvetica', 'normal');
doc.setFont('Helvetica', 'normal');
doc.text(outwardDateText, 162, 54);
doc.text(userRequestedDate, 156 , 54);
let tableColumns = [];
doc.setFont('Helvetica', 'bold');
doc.text("Issued Date:", 116, 60);
doc.setFont('Helvetica', 'normal');
doc.text(outwardDateText, 156, 60);
let tableColumns = ["S.No", "Printer Model", "Toner Model", "Qty Issued"];
let tableRows = [];
let tableRows = [];
const getQtyVal = (obj) => {
const q = obj.qty_delivered ?? obj.qtyIssued ?? obj.qty_requested ?? '-';
return String(q);
};
const getTonerModelText = (obj) => {
let name = obj.model_name || obj.toner_model || '-';
if (obj.part_code & & !name.includes(obj.part_code)) {
name += ` (${obj.part_code})`;
}
return name;
};
if (item.items & & Array.isArray(item.items) & & item.items.length > 0) {
if (item.items & & Array.isArray(item.items) & & item.items.length > 0) {
tableColumns = ["S.No", "Printer Model", "Toner Model", "Qty Req", "Qty Issued"];
tableRows = item.items.map((it, idx) => [
tableRows = item.items.map((it, idx) => [
idx + 1,
idx + 1,
it.printer_name || '-',
(it.model_name || '-') + (it.part_code ? ` (${it.part_code})` : ''),
it.qty_requested || '-',
it.qty_delivered || '-'
it.printer_name || it.printer_model || '-',
getTonerModelText(it),
getQtyVal(it)
]);
]);
} else {
} else {
tableColumns = ["S.No", "Printer Model", "Toner Model", "Qty Req", "Qty Issued"];
tableRows = [
tableRows = [
[
[
1,
1,
item.printer_name || '-',
(item.model_name || '-') + (item.part_code ? ` (${item.part_code})` : ''),
item.qty_requested || '-',
item.qty_delivered || '-'
item.printer_name || item.printer_model || '-',
getTonerModelText(item),
getQtyVal(item)
]
]
];
];
}
}
doc.autoTable({
doc.autoTable({
startY: 66 ,
startY: 67 ,
margin: { left: 15, right: 15 },
margin: { left: 15, right: 15 },
head: [tableColumns],
head: [tableColumns],
body: tableRows,
body: tableRows,
@ -9870,18 +10193,38 @@
lineWidth: 0.1
lineWidth: 0.1
},
},
columnStyles: {
columnStyles: {
0: { width: 15, halign: 'center' },
3: { width: 25, halign: 'center', fontStyle: 'bold' },
4: { width: 25, halign: 'center', fontStyle: 'bold', textColor: [22, 101, 52] }
0: { cellWidth: 15, halign: 'center' },
1: { cellWidth: 50, halign: 'left' },
2: { cellWidth: 85, halign: 'left' },
3: { cellWidth: 30, halign: 'center', fontStyle: 'bold', textColor: [22, 101, 52] }
},
didParseCell: function (data) {
if (data.column.index === 0 || data.column.index === 3) {
data.cell.styles.halign = 'center';
}
}
}
});
});
const finalY = doc.lastAutoTable ? doc.lastAutoTable.finalY + 15 : 150;
const finalY = doc.lastAutoTable ? doc.lastAutoTable.finalY + 15 : 150;
// Signatures row
// Signatures row
const sigY = Math.max(finalY + 20, 230);
doc.setDrawColor(203, 213, 225);
doc.setLineWidth(0.25);
const sigY = Math.max(finalY + 20, 225);
// Left Side: Issued By (IT Cell)
// doc.setDrawColor(203, 213, 225);
// doc.setLineWidth(0.25);
// doc.line(15, sigY, 75, sigY);
// doc.setFont('Helvetica', 'bold');
// doc.setFontSize(9);
// doc.setTextColor(71, 85, 105);
// doc.text("Issued By (IT Cell)", 45, sigY + 5, null, null, "center");
// doc.setFont('Helvetica', 'normal');
// doc.setFontSize(8);
// doc.text("Greater Chennai Corporation", 45, sigY + 9, null, null, "center");
// Right Side: Receiver's Signature
doc.line(135, sigY, 195, sigY);
doc.line(135, sigY, 195, sigY);
doc.setFont('Helvetica', 'bold');
doc.setFont('Helvetica', 'bold');
@ -9893,13 +10236,13 @@
doc.setFontSize(8);
doc.setFontSize(8);
doc.text("Greater Chennai Corporation", 165, sigY + 9, null, null, "center");
doc.text("Greater Chennai Corporation", 165, sigY + 9, null, null, "center");
doc.setFontSize(8);
doc.text("Name: ______________________", 135 , sigY + 18);
doc.text("Mobile Number: _____________", 135 , sigY + 25);
doc.text("Designation: ________________", 135 , sigY + 32);
doc.setFontSize(8.5 );
doc.text("Name: ______________________", 130 , sigY + 18);
doc.text("Mobile Number: _____________", 130 , sigY + 25);
doc.text("Designation: ________________", 130 , sigY + 32);
if (signatureDataUrl) {
if (signatureDataUrl) {
doc.addImage(signatureDataUrl, 'PNG', 20 , sigY - 20, 40, 18);
doc.addImage(signatureDataUrl, 'PNG', 15 , sigY - 20, 40, 18);
}
}
callback(doc);
callback(doc);
@ -9931,12 +10274,16 @@
fetch(contextPath + 'gcctonermanagement/api/workorder/history')
fetch(contextPath + 'gcctonermanagement/api/workorder/history')
.then(res => res.json())
.then(res => res.json())
.then(data => {
.then(data => {
workorderHistoryCached = data;
renderWorkorderHistoryTable('workorder-history-table-body', data , true, 1);
workorderHistoryCached = data || [] ;
renderWorkorderHistoryTable('workorder-history-table-body', workorderHistoryCached , true, 1);
populateReportFileNoFilters();
populateReportFileNoFilters();
applyReportFilters();
applyReportFilters();
try {
if (typeof populateDashboardWorkOrders === 'function') populateDashboardWorkOrders();
if (typeof populateDashboardWorkOrders === 'function') populateDashboardWorkOrders();
if (typeof updateDashboardData === 'function') updateDashboardData();
if (typeof updateDashboardData === 'function') updateDashboardData();
} catch (e) {
console.warn("Dashboard sync skipped:", e);
}
})
})
.catch(err => {
.catch(err => {
console.error("Error fetching workorder history: ", err);
console.error("Error fetching workorder history: ", err);
@ -9964,7 +10311,7 @@
< th class = "text-center" > Total Qty< / th >
< th class = "text-center" > Total Qty< / th >
< th > Start Date< / th >
< th > Start Date< / th >
< th > End Date< / th >
< th > End Date< / th >
< th class = "text-center" > DC Copy< / th >
< th class = "text-center" > Workorder Copy< / th >
< th class = "text-center" > Action< / th >
< th class = "text-center" > Action< / th >
< / tr >
< / tr >
`;
`;
@ -12003,6 +12350,11 @@
< h5 class = "modal-title fw-bold" id = "userRequestBreakdownModalLabel" >
< h5 class = "modal-title fw-bold" id = "userRequestBreakdownModalLabel" >
< i class = "fa-solid fa-file-invoice me-2" > < / i > User Request Details Breakdown
< i class = "fa-solid fa-file-invoice me-2" > < / i > User Request Details Breakdown
< / h5 >
< / h5 >
< button type = "button" class = "btn btn-sm btn-outline-light fw-bold ms-auto me-2"
style="border-radius: 8px; font-size: 0.82rem;" id="user-breakdown-edit-btn"
onclick="openEditUserRequestByGroup(document.getElementById('user-breakdown-ref').textContent)">
< i class = "fa-solid fa-pen-to-square me-1" > < / i > Edit Request / Date
< / button >
< button type = "button" class = "btn-close btn-close-white" data-bs-dismiss = "modal"
< button type = "button" class = "btn-close btn-close-white" data-bs-dismiss = "modal"
aria-label="Close">< / button >
aria-label="Close">< / button >
< / div >
< / div >
@ -12142,6 +12494,8 @@
< form id = "edit-request-form" onsubmit = "submitEditRequest(event)" >
< form id = "edit-request-form" onsubmit = "submitEditRequest(event)" >
< div class = "modal-body p-4" >
< div class = "modal-body p-4" >
< input type = "hidden" id = "edit-request-id" name = "id" >
< input type = "hidden" id = "edit-request-id" name = "id" >
< input type = "hidden" id = "edit-request-is-group" name = "isGroup" value = "false" >
< input type = "hidden" id = "edit-request-orig-itcell" name = "origItcell" >
< div class = "row g-3" >
< div class = "row g-3" >
<!-- Request No (Readonly display) -->
<!-- Request No (Readonly display) -->
@ -12158,8 +12512,9 @@
< label class = "form-label fw-semibold text-secondary" for = "edit-request-itcell" >
< label class = "form-label fw-semibold text-secondary" for = "edit-request-itcell" >
< i class = "fa-solid fa-stamp text-primary me-1" > < / i > IT Cell Reference No. *
< i class = "fa-solid fa-stamp text-primary me-1" > < / i > IT Cell Reference No. *
< / label >
< / label >
< input type = "text" id = "edit-request-itcell" required class = "form-control-custom"
placeholder="e.g. IT/2026/001" maxlength="45">
< input type = "text" id = "edit-request-itcell" readonly class = "form-control-custom"
style="background-color: #f1f5f9; font-weight: bold;" placeholder="e.g. IT/2026/001"
maxlength="45">
< / div >
< / div >
<!-- User Requested Date -->
<!-- User Requested Date -->
@ -12173,8 +12528,7 @@
<!-- Department -->
<!-- Department -->
< div class = "col-12 col-md-6" >
< div class = "col-12 col-md-6" >
< label class = "form-label fw-semibold text-secondary" for = "edit-request-dept" >
< label class = "form-label fw-semibold text-secondary" for = "edit-request-dept" >
< i class = "fa-solid fa-landmark text-primary me-1" > < / i > Department / Office Name
*
< i class = "fa-solid fa-landmark text-primary me-1" > < / i > Department / Office Name *
< / label >
< / label >
< select id = "edit-request-dept" required class = "form-control-custom" >
< select id = "edit-request-dept" required class = "form-control-custom" >
< option value = "" > -- Select Department --< / option >
< option value = "" > -- Select Department --< / option >
@ -12192,6 +12546,30 @@
< / select >
< / select >
< / div >
< / div >
<!-- Current Uploaded File & New File Upload -->
< div class = "col-12 col-md-6" >
< label class = "form-label fw-semibold text-secondary" >
< i class = "fa-solid fa-file-pdf text-danger me-1" > < / i > Request Letter PDF
< / label >
< div id = "edit-request-current-doc" class = "mb-2" >
<!-- Populated dynamically with current file link -->
< / div >
< div class = "file-upload-card py-2"
onclick="document.getElementById('edit-request-file').click()"
style="border-radius: 8px; cursor: pointer;">
< i class = "fa-solid fa-cloud-arrow-up text-primary me-2" > < / i >
< span class = "upload-card-text" id = "edit-request-file-label"
style="font-size: 0.85rem;">
Upload new PDF to replace (Optional)
< / span >
< input type = "file" id = "edit-request-file" accept = ".pdf" class = "d-none"
onchange="handleFileSelection(this, 'edit-request-file-label')">
< / div >
< / div >
< / div >
<!-- Single Item Container (Visible for Single Toner Request) -->
< div class = "row g-3 mt-1" id = "edit-request-single-container" >
<!-- Printer Model -->
<!-- Printer Model -->
< div class = "col-12 col-md-6" >
< div class = "col-12 col-md-6" >
< label class = "form-label fw-semibold text-secondary" for = "edit-request-printer" >
< label class = "form-label fw-semibold text-secondary" for = "edit-request-printer" >
@ -12214,7 +12592,7 @@
< / div >
< / div >
<!-- Given Count (Quantity Requested) -->
<!-- Given Count (Quantity Requested) -->
< div class = "col-12 col-md-6 " >
< div class = "col-12" >
< label class = "form-label fw-semibold text-secondary" for = "edit-request-qty" >
< label class = "form-label fw-semibold text-secondary" for = "edit-request-qty" >
< i class = "fa-solid fa-boxes-stacked text-primary me-1" > < / i > Given Count / Qty
< i class = "fa-solid fa-boxes-stacked text-primary me-1" > < / i > Given Count / Qty
Requested *
Requested *
@ -12222,25 +12600,36 @@
< input type = "number" id = "edit-request-qty" required min = "1" step = "1"
< input type = "number" id = "edit-request-qty" required min = "1" step = "1"
class="form-control-custom" placeholder="e.g. 5">
class="form-control-custom" placeholder="e.g. 5">
< / div >
< / div >
< / div >
<!-- Current Uploaded File & New File Upload -->
< div class = "col-12 col-md-6" >
< label class = "form-label fw-semibold text-secondary" >
< i class = "fa-solid fa-file-pdf text-danger me-1" > < / i > Request Letter PDF
< / label >
< div id = "edit-request-current-doc" class = "mb-2" >
<!-- Populated dynamically with current file link -->
<!-- Multi Items Container (Visible for Multi - Toner Request) -->
< div class = "row g-3 mt-2" id = "edit-request-multi-container" style = "display: none;" >
< div class = "col-12" >
< div class = "alert alert-info py-2 px-3 mb-2 d-flex align-items-center gap-2"
style="font-size: 0.85rem; border-radius: 8px;">
< i class = "fa-solid fa-circle-info fs-5 text-primary" > < / i >
< div > < strong > Multi-Toner Request:< / strong > Updating the < strong > User Requested
Date< / strong > , Department, Zone, and Letter above applies to all < strong
id="edit-request-multi-count">0< / strong > toners in this request. You can
also adjust individual quantities below.< / div >
< / div >
< / div >
< div class = "file-upload-card py-2"
onclick="document.getElementById('edit-request-file').click()"
style="border-radius: 8px; cursor: pointer;">
< i class = "fa-solid fa-cloud-arrow-up text-primary me-2" > < / i >
< span class = "upload-card-text" id = "edit-request-file-label"
style="font-size: 0.85rem;">
Upload new PDF to replace (Optional)
< / span >
< input type = "file" id = "edit-request-file" accept = ".pdf" class = "d-none"
onchange="handleFileSelection(this, 'edit-request-file-label')">
< div class = "table-responsive border rounded"
style="max-height: 240px; overflow-y: auto;">
< table class = "table table-hover table-striped align-middle mb-0"
style="font-size: 0.88rem;">
< thead class = "table-light sticky-top" >
< tr >
< th style = "width: 50px;" > S.No< / th >
< th > Req. No< / th >
< th > Printer Model< / th >
< th > Toner Model< / th >
< th class = "text-center" style = "width: 140px;" > Qty Requested *< / th >
< / tr >
< / thead >
< tbody id = "edit-request-multi-tbody" >
<!-- Populated dynamically -->
< / tbody >
< / table >
< / div >
< / div >
< / div >
< / div >
< / div >
< / div >