function deliveryPostJson(endpoint, payload) { return fetch(ROOT_URL + endpoint, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }).then(function(response) { if (!response.ok) { throw new Error(endpoint + ' failed'); } return response.json(); }).then(function(data) { if (!data || data.ok !== true) { throw new Error((data && data.error) ? data.error : endpoint + ' returned an error'); } return data; }); } function deliveryManifestChainTitle(chainId) { if (!chainId) { return ''; } const chainCheck = Array.from(document.querySelectorAll('.delivery-chain-check')).find(function(check) { return check.value === chainId; }); return chainCheck?.getAttribute('data-label') || chainId; } function deliveryInputIsSelected(input) { if (!input) { return false; } const holder = input.closest('.holder'); const selectedTokens = window.deliverySelectedTokens instanceof Set ? window.deliverySelectedTokens : new Set(); return !!input.checked || input.dataset.selected === '1' || holder?.dataset?.selected === '1' || selectedTokens.has(input.name); } function deliveryBuildCoverReports(reports) { const coverReports = []; const coverReportTokens = new Set(); (reports || []).forEach(function(report) { const token = deliveryReportTokenForLegacyUpdate(report); const expandedReports = window.deliveryPuwerCoverReportMap?.[token] || [report]; expandedReports.forEach(function(coverReport) { const coverToken = deliveryReportTokenForLegacyUpdate(coverReport); if (!coverReportTokens.has(coverToken)) { coverReports.push(coverReport); coverReportTokens.add(coverToken); } }); }); return coverReports; } function deliveryBuildManifest(profile, orderedTokens) { const reports = []; const reportsByToken = new Map(); const allReportsByToken = new Map(); const selectedTokens = window.deliverySelectedTokens instanceof Set ? window.deliverySelectedTokens : new Set(); document.querySelectorAll('.repitem').forEach(function(input) { if (!input.name) { return; } const parts = input.name.split('-'); const holder = input.closest('.holder'); const chainId = holder?.dataset?.chainId || ''; const report = { repnumber: parseInt(parts[0] || '0', 10), itemnumber: parseInt(parts[1] || '0', 10), form: parseInt(parts[2] || '0', 10), surveyor: parseInt(parts[3] || '0', 10), status: input.getAttribute('data-status') || holder?.dataset?.status || '', chainId: chainId, chainTitle: deliveryManifestChainTitle(chainId), locationName: holder?.dataset?.locationName || '' }; allReportsByToken.set(input.name, report); if (deliveryInputIsSelected(input)) { reports.push(report); reportsByToken.set(input.name, report); } }); const sortedTokens = deliveryListFromAny(orderedTokens); const sortedReports = sortedTokens.length ? sortedTokens.map(function(token) { return reportsByToken.get(token) || (reports.length === 0 ? allReportsByToken.get(token) : null); }).filter(Boolean) : reports; if (!sortedReports.length && selectedTokens.size) { selectedTokens.forEach(function(token) { const report = allReportsByToken.get(token); if (report) { sortedReports.push(report); } }); } return { clientnumber: 0, site: parseInt(deliverySelectedSite || '0', 10), profile: profile || 'single', output: { mode: document.querySelector("input[name='outputMode']:checked")?.value || 'pdf', type: document.querySelector("input[name='outputType']:checked")?.value || 'rep', chainMode: document.querySelector("input[name='chainMode']:checked")?.value || 'merge' }, options: { attachSchedule: !!document.getElementById('schAttach')?.checked, attachWrittenScheme: !!document.getElementById('wsAttach')?.checked, chainCovers: !!document.getElementById('splitCoverByChain')?.checked, coverTemplate: document.getElementById('coverTemplate')?.value || 'default', dateStart: document.getElementById('date_start2')?.value || document.getElementById('date_start')?.value || '', dateEnd: document.getElementById('date_end2')?.value || document.getElementById('date_end')?.value || '', forceGenerate: !!document.getElementById('forceGen')?.checked, bypassDeliveryUpdate: !!document.getElementById('bypass')?.checked }, reports: sortedReports, coverReports: deliveryBuildCoverReports(sortedReports), files: [] }; } function deliveryReportTokenForLegacyUpdate(report) { return [ report.repnumber || 0, report.itemnumber || 0, report.form || 0, report.surveyor || 0 ].join('-'); } function deliveryAddFiles(manifest, files) { const seen = new Set((manifest.files || []).map(function(file) { return (file.source || '') + '/' + (file.file || ''); })); (files || []).forEach(function(file) { const key = (file.source || '') + '/' + (file.file || ''); if (!seen.has(key)) { manifest.files.push(file); seen.add(key); } }); } function deliverySetStatus(text, icon) { $('#statusCount').html(text + (icon ? '
' : '')); } function deliveryGenerateScheduleManifest(manifest) { if (!manifest.options.attachSchedule) { return Promise.resolve(manifest); } deliverySetStatus('Generating Schedule', 'fad clipboard-list'); return deliveryPostJson('/functions/delivery/generate_schedule.php', { manifest: manifest, tenant: TENANT_URL }).then(function(data) { deliveryAddFiles(manifest, data.files); return manifest; }); } function deliveryGenerateCoverManifest(manifest) { deliverySetStatus('Generating Report Cover', 'fad fa-blanket'); return deliveryPostJson('/functions/delivery/generate_covers.php', { manifest: manifest, tenant: TENANT_URL }).then(function(data) { deliveryAddFiles(manifest, data.files); return manifest; }); } function deliveryGenerateSingleReport(manifest, report) { deliverySetStatus('Generating Report ' + report.repnumber, 'fad fa-file-pdf'); return deliveryPostJson('/functions/delivery/generate_single.php', { manifest: manifest, report: report, tenant: TENANT_URL }).then(function(data) { deliveryAddFiles(manifest, data.files); return manifest; }); } function deliveryGenerateSingles(manifest, reports) { return (reports || []).reduce(function(chain, report) { return chain.then(function() { return deliveryGenerateSingleReport(manifest, report); }); }, Promise.resolve(manifest)); } function deliveryMultiCapableFormsManifest() { return ['500', '502', '503', '504', '506', '900']; } function deliveryReportsByFormSurveyor(reports) { const grouped = {}; reports.forEach(function(report) { const form = String(report.form || ''); const surveyor = String(report.surveyor || '0'); const key = form + '|' + surveyor; if (!grouped[key]) { grouped[key] = { form: form, surveyor: surveyor, reports: [] }; } grouped[key].reports.push(report); }); return grouped; } function deliveryGenerateMultiGroup(manifest, group) { const form = group.form; const reports = group.reports || []; if (deliveryMultiCapableFormsManifest().indexOf(String(form)) === -1 || reports.length <= 1) { return deliveryGenerateSingles(manifest, reports); } deliverySetStatus('Generating Multi ' + form + ' Report', 'fad fa-file-spreadsheet'); return deliveryPostJson('/functions/delivery/generate_multi.php', { manifest: manifest, reports: reports, form: parseInt(form, 10), tenant: TENANT_URL }).then(function(result) { deliveryAddFiles(manifest, result.files); return manifest; }); } function deliveryGenerateReportsManifest(manifest) { if (manifest.output.type === 'cover') { return Promise.resolve(manifest); } if (manifest.profile !== 'multi') { return deliveryGenerateSingles(manifest, manifest.reports); } const grouped = deliveryReportsByFormSurveyor(manifest.reports); return Object.keys(grouped).reduce(function(chain, key) { return chain.then(function() { return deliveryGenerateMultiGroup(manifest, grouped[key]); }); }, Promise.resolve(manifest)); } function deliveryResolveAttachmentManifest(manifest) { return deliveryPostJson('/functions/delivery/resolve_attachments.php', { manifest: manifest, files: manifest.files, tenant: TENANT_URL }).then(function(data) { manifest.files = data.files || manifest.files; return manifest; }); } function deliveryPackageZipManifest(manifest) { deliverySetStatus('Generating Zip', 'fad fa-file-archive'); return deliveryPostJson('/functions/delivery/package_zip.php', { manifest: manifest, files: manifest.files, tenant: TENANT_URL }).then(function(data) { return data.files && data.files[0] ? data.files[0] : null; }); } function deliveryMailerContext(manifest) { const siteSelect = document.getElementById('siteList2') || document.getElementById('siteList'); const selectedSiteOption = siteSelect?.options?.[siteSelect.selectedIndex] || null; let locationName = selectedSiteOption && selectedSiteOption.value !== '' ? selectedSiteOption.textContent.replace(/^\s*\S+\s+-\s+/, '').trim() : ''; if (locationName === '') { const selectedLocations = Array.from(new Set((manifest.reports || []) .map(function(report) { return String(report.locationName || '').trim(); }) .filter(Boolean))); if (selectedLocations.length === 1) { locationName = selectedLocations[0]; } else if (selectedLocations.length > 1) { locationName = 'multiple locations'; } } return { clientnumber: manifest.clientnumber, site: manifest.site || 0, locationName: locationName, dateStart: manifest.options?.dateStart || '', dateEnd: manifest.options?.dateEnd || '' }; } function deliveryCompleteManifest(manifest) { if (manifest.output.mode === 'zip') { return deliveryPackageZipManifest(manifest).then(function(zipFile) { if (zipFile) { document.getElementById('delivery').style.display = 'block'; document.getElementById('mailerContainer').innerHTML = ''; deliveryLoadMailer(Object.assign(deliveryMailerContext(manifest), { zips: zipFile, clientnumber: manifest.clientnumber })); } return manifest; }); } return deliveryResolveAttachmentManifest(manifest).then(function(finalManifest) { document.getElementById('delivery').style.display = 'block'; document.getElementById('mailerContainer').innerHTML = ''; deliveryLoadMailer(Object.assign(deliveryMailerContext(finalManifest), { attachments: finalManifest.files, clientnumber: finalManifest.clientnumber })); return finalManifest; }); } function deliverySelectedReportPayload(profile) { const manifest = deliveryBuildManifest(profile); const selectedTokens = manifest.reports.map(deliveryReportTokenForLegacyUpdate); const errorTokens = []; const hseFiles = []; manifest.reports.forEach(function(report) { if (String(report.status || '').toUpperCase() === 'URGENT') { const token = deliveryReportTokenForLegacyUpdate(report); errorTokens.push(token); hseFiles.push('../output/reports/' + manifest.clientnumber + '/' + report.repnumber + '_' + report.itemnumber + '.pdf'); } }); return { manifest: manifest, selected: selectedTokens, errordel: errorTokens, hse: hseFiles.join(',') }; } function deliveryPromptSort(profile) { const payload = deliverySelectedReportPayload(profile); if (!payload.manifest.reports.length) { showResponse('warning', 'No Items Selected'); return; } selected = deliveryListToJson(payload.selected); errordel = deliveryListToJson(payload.errordel); hse = payload.hse; deliveryStoreList('itemList', payload.selected); deliveryStoreList('multiList', profile === 'multi' ? payload.selected : []); const forceGen = payload.manifest.options.forceGenerate ? 'yes' : ''; const chainMode = payload.manifest.output.chainMode || 'merge'; if (profile === 'single' && payload.selected.length <= 1) { deliveryRunManifest('single', payload.selected); return; } if (profile === 'multi') { loadModalContent( '

Do you wish to manually sort the reports before producing the multiform output?

', "multiBox", "modal-xl", 1060, "true", 'Manual Sort', 'sortReports', 'genPack(' + deliveryJsArg(selected) + ',' + deliveryJsArg(errordel) + ',' + deliveryJsArg(hse) + ')', 'manualSort(' + deliveryJsArg(selected) + ',' + deliveryJsArg(errordel) + ',' + deliveryJsArg(hse) + ')' ); return; } loadModalContent( '

Do you wish to manually sort the reports?

', "multiBox", "modal-xl", 1060, "true", 'Manual Sort', 'sortReports', 'singleContinue(' + deliveryJsArg(selected) + ',' + deliveryJsArg(errordel) + ',' + deliveryJsArg(forceGen) + ',' + deliveryJsArg(hse) + ',' + deliveryJsArg(chainMode) + ')', 'manualSortSingle(' + deliveryJsArg(selected) + ',' + deliveryJsArg(errordel) + ',' + deliveryJsArg(forceGen) + ',' + deliveryJsArg(hse) + ',' + deliveryJsArg(chainMode) + ')' ); } function deliveryRunManifest(profile, orderedTokens) { const requestedTokens = deliveryListFromAny(orderedTokens); if (!requestedTokens.length) { const storedList = document.getElementById(profile === 'multi' ? 'multiList' : 'itemList'); const storedTokens = deliveryListFromAny(storedList?.textContent || storedList?.value || ''); if (storedTokens.length) { orderedTokens = storedTokens; } } const manifest = deliveryBuildManifest(profile, orderedTokens); if (!manifest.reports.length) { showResponse('warning', 'No Items Selected'); return; } $('#deliveryScreen').css('display', 'none'); $('#loading').css('display', 'block'); deliveryStoreList('itemList', manifest.reports.map(deliveryReportTokenForLegacyUpdate)); deliveryStoreList('multiList', manifest.profile === 'multi' ? manifest.reports.map(deliveryReportTokenForLegacyUpdate) : []); deliveryGenerateScheduleManifest(manifest) .then(deliveryGenerateCoverManifest) .then(deliveryGenerateReportsManifest) .then(deliveryCompleteManifest) .then(function() { $('#loading').css('display', 'none'); }) .catch(function(error) { console.error(error); $('#loading').css('display', 'none'); showResponse('danger', 'Unable to complete delivery output'); }); } function getChecks() { deliveryPromptSort('single'); } function getChecksMulti() { deliveryPromptSort('multi'); } function triggerZip() { deliveryPromptSort('multi'); } function singleContinue(selected, errordel, forceGen, hse, chainMode) { killModal('multiBox'); killModal('sortBox'); deliveryRunManifest('single', selected); } function genPack(selected, errordel, hse) { killModal('multiBox'); killModal('sortBox'); deliveryRunManifest('multi', selected); }