function debugDataStructure(data) {
console.group('Data Structure Analysis');
console.log('Raw data:', data);
console.log('Type:', typeof data);
console.log('Is Array:', Array.isArray(data));
console.log('Constructor:', data?.constructor?.name);
if (data && typeof data === 'object') {
console.log('Object keys:', Object.keys(data));
// Check if it's a wrapped response
if (data.data) console.log('data.data:', data.data);
if (data.result) console.log('data.result:', data.result);
if (data.items) console.log('data.items:', data.items);
// Sample first element if it's array-like
if (Array.isArray(data) && data.length > 0) {
console.log('First element:', data[0]);
console.log('First element keys:', Object.keys(data[0]));
}
}
console.groupEnd();
}
function viewItemToPrint() {
loader = $('#overlay, #loader').css('z-index', 1090);
$('#viewIteToPrint').modal('show');
$('#viewIteToPrint').css('z-index', 1050);
let PRNo = document.getElementById('label-prNo').innerHTML;
document.getElementById('label-print-prNo').innerHTML = PRNo;
tableName = '#selectPrintTable';
totalSelectedLabel = $('#totalSelectPrint');
clearTableSelection(tableName, selectedProductsMap, () => {
totalSelectedLabel.text(0);
}, 'selected-row', '.select-all-PrintItem-checkbox');
tableElement = $(tableName);
tableDestroy(tableElement);
let IsTagging = true;
var canvassPrinting = tableElement.DataTable({
ajax: $.extend({
url: endpoint.GetCanvassGroupByPRNo,
type: 'POST',
data: { PRNo, IsTagging }
}, beforeComplete(loader)),
language: {
emptyTable: "No record available"
},
initComplete: function () {
initializeTableSelection({
tableName: tableName,
dataTable: canvassPrinting,
selectedItemsMap: selectedProductsMap,
idKey: 'itemNo',
idKey2: 'prDetailsId',
checkboxClass: '.select-PrintItem-checkbox',
selectAllClass: '.select-all-PrintItem-checkbox',
selectedRowClass: 'selected-row',
updateCountCallback: function () {
totalSelectedLabel.text(getSelectedCount(selectedProductsMap));
}
});
},
columns: colCanvassItemToPrint,
error: errorHandler
});
}
function printPRNo(PRNo, IsTagging, AggreItemNo) {
return new Promise((resolve, reject) => {
$('#canvasContent').html('
Loading canvas data...
');
$.ajax({
url: endpoint.GetCanvassGroupByPRNo,
type: 'GET',
data: { PRNo, IsTagging, AggreItemNo },
success: function (data) {
try {
generateGroupedTable(data);
resolve();
loader.hide();
} catch (error) {
console.error('Error generating table:', error);
loader.hide();
$('#canvasContent').html(`
Error generating table:
Error: ${error.message}
Data received: ${JSON.stringify(data, null, 2)}
Full Error Details
${error.stack}
`);
reject(error);
}
},
error: function (xhr, status, error) {
console.error('AJAX Error:', error);
$('#canvasContent').html('Error loading data: ' + error + '
');
reject(error);
}
});
});
}
function generateGroupedTable(data) {
// Debug: Log the received data to console
/*
console.log('Is Array:', Array.isArray(data));
*/
// Handle different response formats
let processedData = data;
//console.log('Data type:', typeof data);
//console.log('Received data:', data);
// If data is wrapped in an object (common with ASP.NET Core)
if (data && typeof data === 'object' && !Array.isArray(data)) {
if (data.data && Array.isArray(data.data)) {
processedData = data.data;
} else if (data.result && Array.isArray(data.result)) {
processedData = data.result;
} else if (data.items && Array.isArray(data.items)) {
processedData = data.items;
} else {
// Try to find the first array property
for (let key in data) {
if (Array.isArray(data[key])) {
processedData = data[key];
break;
}
}
}
}
// Final validation
if (!Array.isArray(processedData)) {
console.error('Data is not an array:', processedData);
$('#canvasContent').html('Invalid data format received from server. Expected array but got: ' + typeof processedData + '
');
return;
}
if (processedData.length === 0) {
$('#canvasContent').html('No data found for the specified PR Number.
');
return;
}
// Group data by item (itemName + itemNo)
const groupedData = {};
// Debug: Log each row to see the actual data structure
// console.log('Processing', processedData.length, 'rows');
processedData.forEach((row, index) => {
// console.log(`Row ${index}:`, row);
// Handle different property name formats (camelCase vs PascalCase)
const itemName = row.itemName || row.ItemName || '';
const itemNo = row.itemNo || row.ItemNo || '';
const supplierId = row.supplierId || row.supplierId || 0;
const supplierName = row.supplierName || row.SupplierName || '';
const previousPrice = row.previousPrice || row.PreviousPrice || 0;
const qty = row.qty || row.Qty || 0;
const unit = row.uomName || row.UOMName || 'pcs';
const unitPrice = row.unitPrice || row.UnitPrice || 0;
const discount = row.discount || row.Discount || 0;
const totalAmount = row.totalAmount || row.TotalAmount || 0;
const terms = row.terms || row.Terms || '';
const remarks = row.remarks || row.Remarks || '';
const leadTime = row.leadTime || row.LeadTime || '';
const isVatable = row.isVatable || row.IsVatable || false;
const previousPricePO = row.previousPricePO || row.PreviousPricePO || 0;
// Debug: Log extracted values
/* console.log(`Extracted values for row ${index}:`, {
itemName, itemNo, supplierName, terms, remarks, leadTime, isVatable
});*/
const groupKey = `${itemNo}|${itemName}`;
if (!groupedData[groupKey]) {
groupedData[groupKey] = {
itemName: itemName,
itemNo: itemNo,
previousPricePO: previousPricePO,
suppliers: new Map() // Use Map to avoid duplicates
};
}
// Use supplier name as key to avoid duplicates, but handle empty supplier names
const supplierKey = supplierId ? supplierId : `supplier_${index}`;
if (!groupedData[groupKey].suppliers.has(supplierKey)) {
groupedData[groupKey].suppliers.set(supplierKey, {
supplierName: supplierName,
previousPrice: previousPrice,
qty: qty,
unit: unit,
unitPrice: unitPrice,
discount: discount,
totalAmount: totalAmount,
terms: terms,
remarks: remarks,
leadTime: leadTime,
isVatable: isVatable
});
/* console.log(`Added supplier ${supplierKey} to group ${groupKey}:`, {
terms, remarks, leadTime, isVatable
});*/
} else {
// Handle duplicate supplier case
const existing = groupedData[groupKey].suppliers.get(supplierKey);
if (unitPrice < existing.unitPrice && unitPrice > 0) {
groupedData[groupKey].suppliers.set(supplierKey, {
supplierName: supplierName,
previousPrice: previousPrice,
qty: qty,
unit: unit,
unitPrice: unitPrice,
discount: discount,
totalAmount: totalAmount,
terms: terms,
remarks: remarks,
leadTime: leadTime,
isVatable: isVatable
});
/* console.log(`Updated supplier ${supplierKey} in group ${groupKey}:`, {
terms, remarks, leadTime, isVatable
});*/
}
}
});
// Debug: Log final grouped data
// console.log('Final grouped data:', groupedData);
// Generate HTML
let html = '';
Object.keys(groupedData).sort().forEach(groupKey => {
const group = groupedData[groupKey];
html += `
| Supplier |
Prev.Price |
Qty |
UnitPrice |
Discount |
TotalPrice |
Terms |
LeadTime |
Vatable |
Remarks |
`;
// Convert Map to Array and sort suppliers by unit price (ascending)
const suppliersArray = Array.from(group.suppliers.values());
suppliersArray.sort((a, b) => {
// Sort by unit price (ascending), then by supplier name
if (a.unitPrice !== b.unitPrice) {
return (a.unitPrice || 0) - (b.unitPrice || 0);
}
return (a.supplierName || '').localeCompare(b.supplierName || '');
});
suppliersArray.forEach((supplier, supplierIndex) => {
// Auto-compute total amount: qty * unitPrice, or 0 if no offer (unitPrice is 0 or null)
let computedTotal = 0;
if (supplier.unitPrice && supplier.unitPrice > 0 && supplier.qty && supplier.qty > 0) {
computedTotal = parseFloat(supplier.qty) * parseFloat(supplier.unitPrice);
}
// Debug: Log each supplier's data being rendered
/* console.log(`Rendering supplier ${supplierIndex} for group ${groupKey}:`, {
supplierName: supplier.supplierName,
terms: supplier.terms,
remarks: supplier.remarks,
leadTime: supplier.leadTime,
isVatable: supplier.isVatable
});*/
html += `
| ${escapeHtml(supplier.supplierName || '')} |
${formatPrice(supplier.previousPrice)} |
${formatQuantity(supplier.qty, supplier.unit)} |
${formatPrice(supplier.unitPrice)} |
${escapeHtml(supplier.discount || '')} |
${formatPrice(computedTotal)} |
${escapeHtml(supplier.terms || '')} |
${escapeHtml(supplier.leadTime || '')} |
${supplier.isVatable ? 'YES' : 'NO'} |
${escapeHtml(supplier.remarks || '')} |
`;
});
html += `
`;
});
$('#canvasContent').html(html);
}
function formatPrice(value) {
if (!value || value === 0) return '0.00';
return parseFloat(value).toFixed(2).replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}
function formatQuantity(qty, unit) {
if (!qty) return '';
return parseFloat(qty).toFixed(0) + ' ' + (unit || 'pcs');
}
function escapeHtml(text) {
if (!text) return '';
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
function printRelatedItem() {
loader = $('#overlay, #loader').css('z-index', 1080);
let PRNo = document.getElementById('label-prNo').innerHTML;
const selectedItems = Object.values(selectedProductsMap);
if (selectedItems.length === 0) {
showToast('warning', 'Please select items for canvass first!', 'warning', 4000);
return;
}
const AggreItemNo = selectedItems.map(item => item.itemNo).join(',');
printPRNo(PRNo, false, AggreItemNo).then(() => {
document.getElementById('print-prNo').innerHTML = PRNo;
const iframe = document.createElement('iframe');
iframe.style.position = 'fixed';
iframe.style.right = '0';
iframe.style.bottom = '0';
iframe.style.width = '0';
iframe.style.height = '0';
iframe.style.border = 'none';
document.body.appendChild(iframe);
const doc = iframe.contentWindow.document;
doc.open();
doc.write('Print');
document.querySelectorAll('link[rel="stylesheet"]').forEach(sheet => doc.write(sheet.outerHTML));
document.querySelectorAll('style').forEach(style => doc.write(style.outerHTML));
doc.write(`
`);
doc.write('');
doc.write('');
const printContent = document.getElementById('printableRelatedItem').cloneNode(true);
doc.write(printContent.outerHTML);
doc.write('');
doc.close();
iframe.onload = function () {
iframe.contentWindow.print();
setTimeout(() => document.body.removeChild(iframe), 1000);
};
}).catch(err => {
console.error('Error loading data:', err);
});
}