/** @odoo-module **/ import publicWidget from "@web/legacy/js/public/public_widget"; publicWidget.registry.LoanerPortal = publicWidget.Widget.extend({ selector: '#loanerSection, #btn_checkout_loaner, .btn-loaner-return', start: function () { this._super.apply(this, arguments); this._allProducts = []; this._initLoanerSection(); this._initCheckoutButton(); this._initReturnButtons(); this._initModal(); }, _initModal: function () { var self = this; var modal = document.getElementById('loanerCheckoutModal'); if (!modal) return; var categorySelect = document.getElementById('modal_category_id'); var productSelect = document.getElementById('modal_product_id'); var lotSelect = document.getElementById('modal_lot_id'); var loanDays = document.getElementById('modal_loan_days'); var btnCheckout = document.getElementById('modal_btn_checkout'); var btnCreateProduct = document.getElementById('modal_btn_create_product'); var newCategorySelect = document.getElementById('modal_new_category_id'); var createResult = document.getElementById('modal_create_result'); modal.addEventListener('show.bs.modal', function () { self._loadCategories(categorySelect, newCategorySelect); self._loadProducts(null, productSelect, lotSelect); }); if (categorySelect) { categorySelect.addEventListener('change', function () { var catId = this.value ? parseInt(this.value) : null; self._filterProducts(catId, productSelect, lotSelect); }); } if (productSelect) { productSelect.addEventListener('change', function () { var prodId = this.value ? parseInt(this.value) : null; self._filterLots(prodId, lotSelect, loanDays); }); } if (btnCreateProduct) { btnCreateProduct.addEventListener('click', function () { var name = document.getElementById('modal_new_product_name').value.trim(); var serial = document.getElementById('modal_new_serial').value.trim(); var catId = newCategorySelect ? newCategorySelect.value : ''; if (!name || !serial) { alert('Please enter both product name and serial number.'); return; } btnCreateProduct.disabled = true; btnCreateProduct.innerHTML = ' Creating...'; self._rpc('/my/loaner/create-product', { product_name: name, serial_number: serial, category_id: catId || null, }).then(function (result) { if (result.success) { var opt = document.createElement('option'); opt.value = result.product_id; opt.text = result.product_name; opt.selected = true; productSelect.appendChild(opt); lotSelect.innerHTML = ''; var lotOpt = document.createElement('option'); lotOpt.value = result.lot_id; lotOpt.text = result.lot_name; lotOpt.selected = true; lotSelect.appendChild(lotOpt); self._allProducts.push({ id: result.product_id, name: result.product_name, category_id: catId ? parseInt(catId) : null, period_days: 7, lots: [{ id: result.lot_id, name: result.lot_name }], }); if (createResult) { createResult.style.display = ''; createResult.innerHTML = '
"' + result.product_name + '" (S/N: ' + result.lot_name + ') created!
'; } document.getElementById('modal_new_product_name').value = ''; document.getElementById('modal_new_serial').value = ''; } else { if (createResult) { createResult.style.display = ''; createResult.innerHTML = '
' + (result.error || 'Error') + '
'; } } btnCreateProduct.disabled = false; btnCreateProduct.innerHTML = ' Create Product'; }); }); } if (btnCheckout) { btnCheckout.addEventListener('click', function () { var productId = productSelect.value ? parseInt(productSelect.value) : null; var lotId = lotSelect.value ? parseInt(lotSelect.value) : null; var days = parseInt(loanDays.value) || 7; var orderId = document.getElementById('modal_order_id').value; var clientId = document.getElementById('modal_client_id').value; if (!productId) { alert('Please select a product.'); return; } btnCheckout.disabled = true; btnCheckout.innerHTML = ' Processing...'; self._rpc('/my/loaner/checkout', { product_id: productId, lot_id: lotId, sale_order_id: orderId ? parseInt(orderId) : null, client_id: clientId ? parseInt(clientId) : null, loaner_period_days: days, checkout_condition: 'good', checkout_notes: '', }).then(function (result) { if (result.success) { self._hideModal(modal); alert(result.message); location.reload(); } else { alert('Error: ' + (result.error || 'Unknown')); btnCheckout.disabled = false; btnCheckout.innerHTML = ' Checkout Loaner'; } }); }); } }, _loadCategories: function (categorySelect, newCategorySelect) { this._rpc('/my/loaner/categories', {}).then(function (categories) { categories = categories || []; if (categorySelect) { categorySelect.innerHTML = ''; categories.forEach(function (c) { var opt = document.createElement('option'); opt.value = c.id; opt.text = c.name; categorySelect.appendChild(opt); }); } if (newCategorySelect) { newCategorySelect.innerHTML = ''; categories.forEach(function (c) { var opt = document.createElement('option'); opt.value = c.id; opt.text = c.name; newCategorySelect.appendChild(opt); }); } }); }, _loadProducts: function (categoryId, productSelect, lotSelect) { var self = this; var params = {}; if (categoryId) params.category_id = categoryId; this._rpc('/my/loaner/products', params).then(function (products) { self._allProducts = products || []; self._renderProducts(self._allProducts, productSelect); if (lotSelect) lotSelect.innerHTML = ''; }); }, _filterProducts: function (categoryId, productSelect, lotSelect) { var filtered = this._allProducts; if (categoryId) { filtered = this._allProducts.filter(function (p) { return p.category_id === categoryId; }); } this._renderProducts(filtered, productSelect); if (lotSelect) lotSelect.innerHTML = ''; }, _renderProducts: function (products, productSelect) { if (!productSelect) return; productSelect.innerHTML = ''; products.forEach(function (p) { var opt = document.createElement('option'); opt.value = p.id; opt.text = p.name + ' (' + p.lots.length + ' avail)'; productSelect.appendChild(opt); }); }, _filterLots: function (productId, lotSelect, loanDays) { if (!lotSelect) return; lotSelect.innerHTML = ''; if (!productId) return; var product = this._allProducts.find(function (p) { return p.id === productId; }); if (product) { product.lots.forEach(function (lot) { var opt = document.createElement('option'); opt.value = lot.id; opt.text = lot.name; lotSelect.appendChild(opt); }); if (loanDays && product.period_days) { loanDays.value = product.period_days; } } }, _initCheckoutButton: function () { var self = this; var btns = document.querySelectorAll('#btn_checkout_loaner'); btns.forEach(function (btn) { btn.addEventListener('click', function () { var orderId = btn.dataset.orderId || ''; var clientId = btn.dataset.clientId || ''; var modalOrderId = document.getElementById('modal_order_id'); var modalClientId = document.getElementById('modal_client_id'); if (modalOrderId) modalOrderId.value = orderId; if (modalClientId) modalClientId.value = clientId; var modal = document.getElementById('loanerCheckoutModal'); self._showModal(modal); }); }); }, _initReturnButtons: function () { var self = this; var returnModal = document.getElementById('loanerReturnModal'); if (!returnModal) return; var btnSubmitReturn = document.getElementById('return_modal_btn_submit'); document.querySelectorAll('.btn-loaner-return').forEach(function (btn) { btn.addEventListener('click', function () { var checkoutId = parseInt(btn.dataset.checkoutId); var productName = btn.dataset.productName || 'Loaner'; document.getElementById('return_modal_checkout_id').value = checkoutId; document.getElementById('return_modal_product_name').textContent = productName; document.getElementById('return_modal_condition').value = 'good'; document.getElementById('return_modal_notes').value = ''; var locSelect = document.getElementById('return_modal_location_id'); locSelect.innerHTML = ''; self._rpc('/my/loaner/locations', {}).then(function (locations) { locations = locations || []; locSelect.innerHTML = ''; locations.forEach(function (l) { var opt = document.createElement('option'); opt.value = l.id; opt.text = l.name; locSelect.appendChild(opt); }); }); self._showModal(returnModal); }); }); if (btnSubmitReturn) { btnSubmitReturn.addEventListener('click', function () { var checkoutId = parseInt(document.getElementById('return_modal_checkout_id').value); var condition = document.getElementById('return_modal_condition').value; var notes = document.getElementById('return_modal_notes').value; var locationId = document.getElementById('return_modal_location_id').value; btnSubmitReturn.disabled = true; btnSubmitReturn.innerHTML = ' Processing...'; self._rpc('/my/loaner/return', { checkout_id: checkoutId, return_condition: condition, return_notes: notes, return_location_id: locationId ? parseInt(locationId) : null, }).then(function (result) { if (result.success) { self._hideModal(returnModal); alert(result.message); location.reload(); } else { alert('Error: ' + (result.error || 'Unknown')); btnSubmitReturn.disabled = false; btnSubmitReturn.innerHTML = ' Confirm Return'; } }); }); } }, _initLoanerSection: function () { var self = this; var loanerSection = document.getElementById('loanerSection'); if (!loanerSection) return; var productSelect = document.getElementById('loaner_product_id'); var lotSelect = document.getElementById('loaner_lot_id'); var periodInput = document.getElementById('loaner_period_days'); var checkoutFlag = document.getElementById('loaner_checkout'); var existingFields = document.getElementById('loaner_existing_fields'); var newFields = document.getElementById('loaner_new_fields'); var modeRadios = document.querySelectorAll('input[name="loaner_mode"]'); var btnCreate = document.getElementById('btn_create_loaner_product'); var createResult = document.getElementById('loaner_create_result'); var productsData = []; loanerSection.addEventListener('show.bs.collapse', function () { if (productSelect && productSelect.options.length <= 1) { self._rpc('/my/loaner/products', {}).then(function (data) { productsData = data || []; productSelect.innerHTML = ''; productsData.forEach(function (p) { var opt = document.createElement('option'); opt.value = p.id; opt.text = p.name + ' (' + p.lots.length + ' avail)'; productSelect.appendChild(opt); }); }); } }); loanerSection.addEventListener('shown.bs.collapse', function () { if (checkoutFlag) checkoutFlag.value = '1'; }); loanerSection.addEventListener('hidden.bs.collapse', function () { if (checkoutFlag) checkoutFlag.value = '0'; }); modeRadios.forEach(function (radio) { radio.addEventListener('change', function () { if (this.value === 'existing') { if (existingFields) existingFields.style.display = ''; if (newFields) newFields.style.display = 'none'; } else { if (existingFields) existingFields.style.display = 'none'; if (newFields) newFields.style.display = ''; } }); }); if (productSelect) { productSelect.addEventListener('change', function () { lotSelect.innerHTML = ''; var product = productsData.find(function (p) { return p.id === parseInt(productSelect.value); }); if (product) { product.lots.forEach(function (lot) { var opt = document.createElement('option'); opt.value = lot.id; opt.text = lot.name; lotSelect.appendChild(opt); }); if (periodInput && product.period_days) periodInput.value = product.period_days; } }); } if (btnCreate) { btnCreate.addEventListener('click', function () { var name = document.getElementById('loaner_new_product_name').value.trim(); var serial = document.getElementById('loaner_new_serial').value.trim(); if (!name || !serial) { alert('Enter both name and serial.'); return; } btnCreate.disabled = true; btnCreate.innerHTML = ' Creating...'; self._rpc('/my/loaner/create-product', { product_name: name, serial_number: serial, }).then(function (result) { if (result.success) { var opt = document.createElement('option'); opt.value = result.product_id; opt.text = result.product_name; opt.selected = true; productSelect.appendChild(opt); lotSelect.innerHTML = ''; var lotOpt = document.createElement('option'); lotOpt.value = result.lot_id; lotOpt.text = result.lot_name; lotOpt.selected = true; lotSelect.appendChild(lotOpt); document.getElementById('loaner_existing').checked = true; if (existingFields) existingFields.style.display = ''; if (newFields) newFields.style.display = 'none'; if (createResult) { createResult.style.display = ''; createResult.innerHTML = '
Created "' + result.product_name + '" (S/N: ' + result.lot_name + ')
'; } } else { if (createResult) { createResult.style.display = ''; createResult.innerHTML = '
' + (result.error || 'Error') + '
'; } } btnCreate.disabled = false; btnCreate.innerHTML = ' Create Product'; }); }); } }, _rpc: function (url, params) { return fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ jsonrpc: '2.0', method: 'call', id: 1, params: params }), }).then(function (r) { return r.json(); }).then(function (d) { return d.result; }); }, _showModal: function (modalEl) { if (!modalEl) return; var Modal = window.bootstrap ? window.bootstrap.Modal : null; if (Modal) { var inst = Modal.getOrCreateInstance ? Modal.getOrCreateInstance(modalEl) : new Modal(modalEl); inst.show(); } else if (window.$ || window.jQuery) { (window.$ || window.jQuery)(modalEl).modal('show'); } }, _hideModal: function (modalEl) { if (!modalEl) return; try { var Modal = window.bootstrap ? window.bootstrap.Modal : null; if (Modal && Modal.getInstance) { var inst = Modal.getInstance(modalEl); if (inst) inst.hide(); } else if (window.$ || window.jQuery) { (window.$ || window.jQuery)(modalEl).modal('hide'); } } catch (e) { /* non-blocking */ } }, });