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 += `

Item: ${escapeHtml(group.itemName)}

ItemCode: ${escapeHtml(group.itemNo)}

${group.previousPricePO ? `
Previous Price base on latest PO's ${escapeHtml(group.previousPricePO)}
` : ''}
`; // 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 += ` `; }); html += `
Supplier Prev.Price Qty UnitPrice Discount TotalPrice Terms LeadTime Vatable Remarks
${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 || '')}
`; }); $('#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('
Canvass Report
'); 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); }); }