diff --git a/index.php b/index.php
index b14e2b2..04cb306 100644
--- a/index.php
+++ b/index.php
@@ -8827,11 +8827,15 @@ runtime_debug_mark('page:rendering', ['page' => (string)$page]);
-
+
-
+
@@ -8950,9 +8954,13 @@ runtime_debug_mark('page:rendering', ['page' => (string)$page]);
-
+
-
+
@@ -12000,7 +12008,13 @@ document.addEventListener('DOMContentLoaded', function() {
});
});
+
+ 'script', 'page' => (string)$page]); ?>
+
+
+
'script', 'page' => (string)$page]); ?>
+
'script', 'page' => (string)$page]); ?>
diff --git a/pages/lpo_quotation_script.php b/pages/lpo_quotation_script.php
index 1ce41eb..b46f8c2 100644
--- a/pages/lpo_quotation_script.php
+++ b/pages/lpo_quotation_script.php
@@ -2,36 +2,77 @@
initInvoiceForm('lpoProductSearchInput', 'lpoSearchSuggestions', 'lpoItemsTableBody', 'lpo_grand_display', 'lpo_subtotal_display', 'lpo_vat_display');
initInvoiceForm('editLpoProductSearchInput', 'editLpoSearchSuggestions', 'editLpoItemsTableBody', 'edit_lpo_grand_display', 'edit_lpo_subtotal_display', 'edit_lpo_vat_display');
+
+ const parseLpoQuotationButtonPayload = (btn) => {
+ if (!btn || !btn.dataset || !btn.dataset.json) return {};
+ try {
+ return JSON.parse(btn.dataset.json);
+ } catch (error) {
+ console.warn('Failed to parse LPO/Quotation payload from button data.', error);
+ return {};
+ }
+ };
+
+ const renderExistingDocumentItems = (items, tableBodyId, grandTotalId, subtotalId, totalVatId) => {
+ const tableBody = document.getElementById(tableBodyId);
+ const grandTotalEl = document.getElementById(grandTotalId);
+ const subtotalEl = document.getElementById(subtotalId);
+ const totalVatEl = document.getElementById(totalVatId);
+
+ if (!tableBody) return;
+ tableBody.innerHTML = '';
+
+ if (!Array.isArray(items) || items.length === 0) {
+ if (typeof recalculate === 'function') {
+ recalculate(tableBody, grandTotalEl, subtotalEl, totalVatEl);
+ }
+ return;
+ }
+
+ items.forEach(item => {
+ addItemToTable({
+ id: item.item_id || item.id,
+ name_en: item.name_en || item.item_name_en || 'Item',
+ name_ar: item.name_ar || item.item_name_ar || '',
+ sku: item.sku || '',
+ vat_rate: item.vat_rate || 0,
+ stock_quantity: item.stock_quantity || 0
+ }, tableBody, null, null, grandTotalEl, subtotalEl, totalVatEl, {
+ quantity: item.quantity,
+ unit_price: item.unit_price
+ });
+ });
+ };
+
document.querySelectorAll('.edit-lpo-btn').forEach(btn => {
btn.addEventListener('click', function() {
- const data = JSON.parse(this.dataset.json);
- document.getElementById('edit_lpo_id').value = data.id;
+ const data = parseLpoQuotationButtonPayload(this);
+ if (Object.keys(data).length === 0) return;
+
const supplierSelect = document.getElementById('edit_lpo_supplier_id');
- supplierSelect.value = data.supplier_id;
- if (window.jQuery && $(supplierSelect).data('select2')) {
- $(supplierSelect).trigger('change');
+ const supplierId = data.supplier_id ?? '';
+ const supplierLabel = data.supplier_name || '';
+
+ invoiceEnsureSelectOption('edit_lpo_supplier_id', supplierId, supplierLabel);
+
+ const lpoIdInput = document.getElementById('edit_lpo_id');
+ const lpoDateInput = document.getElementById('edit_lpo_date');
+ const deliveryDateInput = document.getElementById('edit_lpo_delivery_date');
+ const statusSelect = document.getElementById('edit_lpo_status');
+ const termsInput = document.getElementById('edit_lpo_terms');
+
+ if (lpoIdInput) lpoIdInput.value = data.id || '';
+ if (supplierSelect) {
+ invoiceSetBlankSelectOptionLabel(supplierSelect, (supplierId === '' && supplierLabel) ? supplierLabel : '---');
+ supplierSelect.value = supplierId;
+ invoiceSyncSelect2Value(supplierSelect);
}
- document.getElementById('edit_lpo_date').value = data.lpo_date;
- document.getElementById('edit_lpo_delivery_date').value = data.delivery_date || '';
- document.getElementById('edit_lpo_status').value = data.status || 'pending';
- document.getElementById('edit_lpo_terms').value = data.terms_conditions || '';
-
- const tableBody = document.getElementById('editLpoItemsTableBody');
- tableBody.innerHTML = '';
-
- data.items.forEach(item => {
- addItemToTable({
- id: item.item_id,
- name_en: item.name_en,
- name_ar: item.name_ar,
- sku: '',
- vat_rate: item.vat_rate || 0
- }, tableBody, null, null,
- document.getElementById('edit_lpo_grand_display'),
- document.getElementById('edit_lpo_subtotal_display'),
- document.getElementById('edit_lpo_vat_display'),
- { quantity: item.quantity, unit_price: item.unit_price });
- });
+ if (lpoDateInput) lpoDateInput.value = data.lpo_date || '';
+ if (deliveryDateInput) deliveryDateInput.value = data.delivery_date || '';
+ if (statusSelect) statusSelect.value = data.status || 'pending';
+ if (termsInput) termsInput.value = data.terms_conditions || '';
+
+ renderExistingDocumentItems(data.items || [], 'editLpoItemsTableBody', 'edit_lpo_grand_display', 'edit_lpo_subtotal_display', 'edit_lpo_vat_display');
});
});
@@ -182,29 +223,31 @@
document.querySelectorAll('.edit-quotation-btn').forEach(btn => {
btn.addEventListener('click', function() {
- const data = JSON.parse(this.dataset.json);
- document.getElementById('edit_quotation_id').value = data.id;
- document.getElementById('edit_quot_customer_id').value = data.customer_id;
- document.getElementById('edit_quot_date').value = data.quotation_date;
- document.getElementById('edit_quot_valid').value = data.valid_until || '';
- document.getElementById('edit_quot_status').value = data.status || 'pending';
-
- const tableBody = document.getElementById('editQuotItemsTableBody');
- tableBody.innerHTML = '';
-
- data.items.forEach(item => {
- addItemToTable({
- id: item.item_id,
- name_en: item.name_en,
- name_ar: item.name_ar,
- sku: '',
- vat_rate: item.vat_rate || 0
- }, tableBody, null, null,
- document.getElementById('edit_quot_grand_display'),
- document.getElementById('edit_quot_subtotal_display'),
- document.getElementById('edit_quot_vat_display'),
- { quantity: item.quantity, unit_price: item.unit_price });
- });
+ const data = parseLpoQuotationButtonPayload(this);
+ if (Object.keys(data).length === 0) return;
+
+ const customerSelect = document.getElementById('edit_quot_customer_id');
+ const customerId = data.customer_id ?? '';
+ const customerLabel = data.customer_name || data.party_name || '';
+
+ invoiceEnsureSelectOption('edit_quot_customer_id', customerId, customerLabel);
+
+ const quotationIdInput = document.getElementById('edit_quotation_id');
+ const quotationDateInput = document.getElementById('edit_quot_date');
+ const validUntilInput = document.getElementById('edit_quot_valid');
+ const statusSelect = document.getElementById('edit_quot_status');
+
+ if (quotationIdInput) quotationIdInput.value = data.id || '';
+ if (customerSelect) {
+ invoiceSetBlankSelectOptionLabel(customerSelect, (customerId === '' && customerLabel) ? customerLabel : '---');
+ customerSelect.value = customerId;
+ invoiceSyncSelect2Value(customerSelect);
+ }
+ if (quotationDateInput) quotationDateInput.value = data.quotation_date || '';
+ if (validUntilInput) validUntilInput.value = data.valid_until || '';
+ if (statusSelect) statusSelect.value = data.status || 'pending';
+
+ renderExistingDocumentItems(data.items || [], 'editQuotItemsTableBody', 'edit_quot_grand_display', 'edit_quot_subtotal_display', 'edit_quot_vat_display');
});
});
@@ -355,10 +398,8 @@
editBtn.className = 'btn btn-primary';
editBtn.innerHTML = ' Edit';
editBtn.onclick = function() {
- const editModal = new bootstrap.Modal(document.getElementById('editQuotationModal'));
modal.hide();
- const originalEditBtn = document.querySelector(`.edit-quotation-btn[data-json*='"id":${data.id},']`) ||
- document.querySelector(`.edit-quotation-btn[data-json*='"id":${data.id}']`);
+ const originalEditBtn = document.querySelector(`.edit-quotation-btn[data-id="${data.id}"]`);
if (originalEditBtn) originalEditBtn.click();
};
actionButtons.appendChild(editBtn);
diff --git a/pages/sales_purchases_invoice_actions_script.php b/pages/sales_purchases_invoice_actions_script.php
index fb6e408..8d3cf38 100644
--- a/pages/sales_purchases_invoice_actions_script.php
+++ b/pages/sales_purchases_invoice_actions_script.php
@@ -9,34 +9,6 @@
}
};
- const syncSelect2Value = (select) => {
- if (!select) return;
- if (select.classList.contains('select2') && window.jQuery && jQuery.fn && jQuery.fn.select2) {
- jQuery(select).trigger('change');
- }
- };
-
- const ensureSelectOption = (selectId, value, label = '') => {
- const select = document.getElementById(selectId);
- if (!select || value === null || value === undefined || String(value) === '') return;
-
- const alreadyExists = Array.from(select.options || []).some(option => option.value == String(value));
- if (!alreadyExists) {
- const option = document.createElement('option');
- option.value = String(value);
- option.textContent = label || String(value);
- select.appendChild(option);
- }
- };
-
- const setBlankSelectOptionLabel = (select, label = '---') => {
- if (!select) return;
- const emptyOption = Array.from(select.options || []).find(option => option.value === '');
- if (emptyOption) {
- emptyOption.textContent = label;
- }
- };
-
const normalizeEditPaymentType = (paymentType) => {
let normalized = String(paymentType || 'cash').toLowerCase().replace(/[\s-]+/g, '_');
if (normalized === 'pos') normalized = 'cash';
@@ -92,13 +64,13 @@
const partyId = data.customer_id ?? data.supplier_id ?? '';
const partyLabel = data.party_name || data.customer_name || data.supplier_name || '';
- ensureSelectOption('edit_customer_id', partyId, partyLabel);
+ invoiceEnsureSelectOption('edit_customer_id', partyId, partyLabel);
if (invoiceIdInput) invoiceIdInput.value = data.id || '';
if (partySelect) {
- setBlankSelectOptionLabel(partySelect, (partyId === '' && partyLabel) ? partyLabel : '---');
+ invoiceSetBlankSelectOptionLabel(partySelect, (partyId === '' && partyLabel) ? partyLabel : '---');
partySelect.value = partyId;
- syncSelect2Value(partySelect);
+ invoiceSyncSelect2Value(partySelect);
}
if (invoiceDateInput) invoiceDateInput.value = data.invoice_date || '';
if (dueDateInput) dueDateInput.value = data.due_date || '';
diff --git a/pages/sales_purchases_invoice_form_helpers.php b/pages/sales_purchases_invoice_form_helpers.php
index 45b3cf4..f2bd2f1 100644
--- a/pages/sales_purchases_invoice_form_helpers.php
+++ b/pages/sales_purchases_invoice_form_helpers.php
@@ -53,6 +53,100 @@
});
};
+
+ const invoiceSyncSelect2Value = (select) => {
+ if (!select) return;
+ if (select.classList.contains('select2') && window.jQuery && window.jQuery.fn && window.jQuery.fn.select2) {
+ window.jQuery(select).trigger('change');
+ }
+ };
+
+ const invoiceEnsureSelectOption = (selectId, value, label = '') => {
+ const select = document.getElementById(selectId);
+ if (!select || value === null || value === undefined || String(value) === '') return;
+
+ const alreadyExists = Array.from(select.options || []).some(option => option.value == String(value));
+ if (!alreadyExists) {
+ const option = document.createElement('option');
+ option.value = String(value);
+ option.textContent = label || String(value);
+ select.appendChild(option);
+ }
+ };
+
+ const invoiceSetBlankSelectOptionLabel = (select, label = '---') => {
+ if (!select) return;
+ const emptyOption = Array.from(select.options || []).find(option => option.value === '');
+ if (emptyOption) {
+ emptyOption.textContent = label;
+ }
+ };
+
+ const invoiceShowConfirmDialog = async ({
+ title = 'Are you sure?',
+ text = '',
+ confirmButtonText = 'Yes, continue',
+ cancelButtonText = 'Cancel',
+ icon = 'warning'
+ } = {}) => {
+ if (window.Swal) {
+ const result = await Swal.fire({
+ title,
+ text,
+ icon,
+ showCancelButton: true,
+ confirmButtonText,
+ cancelButtonText,
+ reverseButtons: true,
+ focusCancel: true,
+ confirmButtonColor: '#dc3545',
+ cancelButtonColor: '#6c757d'
+ });
+ return !!result.isConfirmed;
+ }
+
+ return window.confirm(text ? `${title}
+
+${text}` : title);
+ };
+
+ const bindInvoiceSweetConfirmForms = () => {
+ document.querySelectorAll('.js-swal-confirm-form').forEach(form => {
+ if (form.dataset.confirmBound === '1') return;
+ form.dataset.confirmBound = '1';
+
+ form.addEventListener('submit', async function(event) {
+ if (form.dataset.skipConfirm === '1') {
+ delete form.dataset.skipConfirm;
+ return;
+ }
+
+ event.preventDefault();
+
+ const confirmed = await invoiceShowConfirmDialog({
+ title: form.dataset.confirmTitle || 'Are you sure?',
+ text: form.dataset.confirmText || '',
+ confirmButtonText: form.dataset.confirmButton || 'Yes, continue',
+ cancelButtonText: form.dataset.cancelButton || 'Cancel',
+ icon: form.dataset.confirmIcon || 'warning'
+ });
+
+ if (!confirmed) return;
+
+ const submitter = event.submitter || null;
+ if (submitter && typeof form.requestSubmit === 'function') {
+ form.dataset.skipConfirm = '1';
+ form.requestSubmit(submitter);
+ return;
+ }
+
+ HTMLFormElement.prototype.submit.call(form);
+ });
+ });
+ };
+
+ bindInvoiceSweetConfirmForms();
+
function addItemToTable(item, tableBody, searchInput, suggestions, grandTotalEl, subtotalEl, totalVatEl, customData = null) {
if (suggestions) suggestions.style.display = 'none';
if (searchInput) searchInput.value = '';
diff --git a/pages/sales_purchases_page_script.php b/pages/sales_purchases_page_script.php
index 83f6f17..c242ecd 100644
--- a/pages/sales_purchases_page_script.php
+++ b/pages/sales_purchases_page_script.php
@@ -1,6 +1,5 @@
" data-total="= $inv['total_with_vat'] ?>" data-paid="= $inv['paid_amount'] ?>" data-bs-toggle="modal" data-bs-target="#payInvoiceModal" title="Payment">
-