diff --git a/api/beacons/delete.cfm b/api/beacons/delete.cfm index 52fe7dc..95523dd 100644 --- a/api/beacons/delete.cfm +++ b/api/beacons/delete.cfm @@ -40,46 +40,32 @@ if (bizId LTE 0) { apiAbort({ OK=false, ERROR="no_business_selected" }); } -if (!structKeyExists(data, "BeaconID") || !isNumeric(data.BeaconID) || int(data.BeaconID) LTE 0) { - apiAbort({ OK=false, ERROR="missing_beacon_id", MESSAGE="BeaconID is required" }); -} +// Get ServicePointID (sharding beacons are service points with BeaconMinor) +servicePointId = structKeyExists(data, "ServicePointID") && isNumeric(data.ServicePointID) ? int(data.ServicePointID) : 0; -beaconId = int(data.BeaconID); +if (servicePointId LTE 0) { + apiAbort({ OK=false, ERROR="missing_service_point_id", MESSAGE="ServicePointID is required" }); +} + - UPDATE Beacons - SET IsActive = 0 - WHERE ID = - AND ( - BusinessID = - OR ID IN ( - SELECT lt.BeaconID FROM lt_BeaconsID_BusinessesID lt - WHERE lt.BeaconID = - AND lt.BusinessID = - ) - ) + UPDATE ServicePoints + SET BeaconMinor = NULL + WHERE ID = + AND BusinessID = - - SELECT ID, IsActive - FROM Beacons - WHERE ID = - AND ( - BusinessID = - OR EXISTS ( - SELECT 1 FROM lt_BeaconsID_BusinessesID lt - WHERE lt.BeaconID = - AND lt.BusinessID = - ) - ) + SELECT ID FROM ServicePoints + WHERE ID = + AND BusinessID = LIMIT 1 - #serializeJSON({ OK=false, ERROR="not_found" })# + #serializeJSON({ OK=false, ERROR="not_found", DEBUG_ServicePointID=servicePointId, DEBUG_BusinessID=bizId })# -#serializeJSON({ OK=true, ERROR="", BeaconID=beaconId })# +#serializeJSON({ OK=true, ERROR="", ServicePointID=servicePointId })# diff --git a/api/setup/analyzeMenuUrl.cfm b/api/setup/analyzeMenuUrl.cfm index dcb75bb..6fe4ff1 100644 --- a/api/setup/analyzeMenuUrl.cfm +++ b/api/setup/analyzeMenuUrl.cfm @@ -121,13 +121,15 @@ - - ]*class="price"[^>]*>\$?([0-9.]+)', block)> + + + - \\$?([0-9.]+).*', '\1')> - - - + + + + + @@ -334,17 +336,43 @@ + + + + + + + + + + + - + + + + + + + + + diff --git a/api/setup/lookupTaxRate.cfm b/api/setup/lookupTaxRate.cfm index d148454..61aae79 100644 --- a/api/setup/lookupTaxRate.cfm +++ b/api/setup/lookupTaxRate.cfm @@ -3,32 +3,19 @@ - - - - - - - + + + + + + + + + + + @@ -47,43 +34,87 @@ - + - - + + + #serializeJSON(response)# + + - - - - + + + + #serializeJSON(response)# + + - - - + + + + + - - - - - + + + + + + + + + + #serializeJSON(response)# + + - - - + + + + + + + + + + + + + + + + + + - - - + - + - - - + diff --git a/portal/portal.js b/portal/portal.js index fa3c796..cb2edb1 100644 --- a/portal/portal.js +++ b/portal/portal.js @@ -1696,18 +1696,21 @@ const Portal = { return; } - container.innerHTML = this.beacons.map(b => ` -
-
-
${this.escapeHtml(b.Name)}
-
${b.UUID || b.NamespaceId || 'No UUID'}
+ container.innerHTML = this.beacons.map(b => { + const minorInfo = b.Minor ? ` (Minor: ${b.Minor})` : ''; + return ` +
+
+
${this.escapeHtml(b.Name)}${minorInfo}
+
${b.UUID || 'No UUID'}
+
+
+ + +
-
- - -
-
- `).join(''); + `; + }).join(''); }, // Load service points list @@ -1879,9 +1882,9 @@ const Portal = { this.showBeaconModal(beaconId); }, - // Delete beacon - async deleteBeacon(beaconId) { - if (!confirm('Are you sure you want to deactivate this beacon?')) return; + // Delete beacon (removes BeaconMinor from service point) + async deleteBeacon(servicePointId) { + if (!confirm('Are you sure you want to remove this beacon?')) return; try { const response = await fetch(`${this.config.apiBaseUrl}/beacons/delete.cfm`, { @@ -1891,19 +1894,19 @@ const Portal = { 'X-User-Token': this.config.token, 'X-Business-ID': this.config.businessId }, - body: JSON.stringify({ BeaconID: beaconId }) + body: JSON.stringify({ ServicePointID: servicePointId }) }); const data = await response.json(); if (data.OK) { - this.toast('Beacon deactivated', 'success'); + this.toast('Beacon removed', 'success'); await this.loadBeacons(); } else { - this.toast(data.ERROR || 'Failed to delete beacon', 'error'); + this.toast(data.ERROR || 'Failed to remove beacon', 'error'); } } catch (err) { - console.error('[Portal] Error deleting beacon:', err); - this.toast('Error deleting beacon', 'error'); + console.error('[Portal] Error removing beacon:', err); + this.toast('Error removing beacon', 'error'); } }, diff --git a/portal/setup-wizard.html b/portal/setup-wizard.html index 4c60bb6..80567ea 100644 --- a/portal/setup-wizard.html +++ b/portal/setup-wizard.html @@ -2509,6 +2509,110 @@ } } + function showAddModifierForm() { + // Initialize modifiers array if needed + if (!config.extractedData.modifiers) { + config.extractedData.modifiers = []; + } + + addMessage('ai', ` +
+

Add Modifier Template

+
+ + +
+
+ +
+
+ +
+
+ + + +
+
+ +
+
+ + + +
+
+ `); + } + + function addModifierOption() { + const container = document.getElementById('newModOptions'); + const row = document.createElement('div'); + row.className = 'modifier-option-row'; + row.innerHTML = \` + + + + \`; + container.appendChild(row); + } + + function removeModifierOption(btn) { + const row = btn.closest('.modifier-option-row'); + const container = document.getElementById('newModOptions'); + if (container.children.length > 1) { + row.remove(); + } + } + + function saveCurrentModifier() { + const name = document.getElementById('newModName').value.trim(); + if (!name) { + alert('Please enter a modifier name'); + return false; + } + + const required = document.getElementById('newModRequired').checked; + const optionRows = document.querySelectorAll('#newModOptions .modifier-option-row'); + const options = []; + + optionRows.forEach(row => { + const optName = row.querySelector('.option-name').value.trim(); + const optPrice = parseFloat(row.querySelector('.option-price').value) || 0; + if (optName) { + options.push({ name: optName, price: optPrice }); + } + }); + + if (options.length === 0) { + alert('Please add at least one option'); + return false; + } + + config.extractedData.modifiers.push({ + name: name, + required: required, + options: options, + appliesTo: 'uncertain' + }); + + return true; + } + + function saveModifierAndAddAnother() { + if (saveCurrentModifier()) { + showAddModifierForm(); + } + } + + function saveModifierAndContinue() { + if (saveCurrentModifier()) { + showItemsStep(); + } + } + function confirmModifiers() { const list = document.getElementById('modifiersList'); const templates = list.querySelectorAll('.modifier-template');