444 lines
20 KiB
JavaScript
444 lines
20 KiB
JavaScript
/** @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 = '<i class="fa fa-spinner fa-spin me-1"></i> 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 = '<div class="alert alert-success py-2"><i class="fa fa-check me-1"></i> "' + result.product_name + '" (S/N: ' + result.lot_name + ') created!</div>';
|
|
}
|
|
|
|
document.getElementById('modal_new_product_name').value = '';
|
|
document.getElementById('modal_new_serial').value = '';
|
|
} else {
|
|
if (createResult) {
|
|
createResult.style.display = '';
|
|
createResult.innerHTML = '<div class="alert alert-danger py-2">' + (result.error || 'Error') + '</div>';
|
|
}
|
|
}
|
|
btnCreateProduct.disabled = false;
|
|
btnCreateProduct.innerHTML = '<i class="fa fa-plus me-1"></i> 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 = '<i class="fa fa-spinner fa-spin me-1"></i> 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 = '<i class="fa fa-check me-1"></i> Checkout Loaner';
|
|
}
|
|
});
|
|
});
|
|
}
|
|
},
|
|
|
|
_loadCategories: function (categorySelect, newCategorySelect) {
|
|
this._rpc('/my/loaner/categories', {}).then(function (categories) {
|
|
categories = categories || [];
|
|
if (categorySelect) {
|
|
categorySelect.innerHTML = '<option value="">All Categories</option>';
|
|
categories.forEach(function (c) {
|
|
var opt = document.createElement('option');
|
|
opt.value = c.id;
|
|
opt.text = c.name;
|
|
categorySelect.appendChild(opt);
|
|
});
|
|
}
|
|
if (newCategorySelect) {
|
|
newCategorySelect.innerHTML = '<option value="">-- Select --</option>';
|
|
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 = '<option value="">-- Select Serial --</option>';
|
|
});
|
|
},
|
|
|
|
_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 = '<option value="">-- Select Serial --</option>';
|
|
},
|
|
|
|
_renderProducts: function (products, productSelect) {
|
|
if (!productSelect) return;
|
|
productSelect.innerHTML = '<option value="">-- Select Product --</option>';
|
|
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 = '<option value="">-- Select Serial --</option>';
|
|
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 = '<option value="">-- Loading... --</option>';
|
|
self._rpc('/my/loaner/locations', {}).then(function (locations) {
|
|
locations = locations || [];
|
|
locSelect.innerHTML = '<option value="">-- Select Location --</option>';
|
|
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 = '<i class="fa fa-spinner fa-spin me-1"></i> 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 = '<i class="fa fa-check me-1"></i> 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 = '<option value="">-- Select Product --</option>';
|
|
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 = '<option value="">-- Select Serial --</option>';
|
|
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 = '<i class="fa fa-spinner fa-spin me-1"></i> 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 = '<div class="alert alert-success py-2">Created "' + result.product_name + '" (S/N: ' + result.lot_name + ')</div>';
|
|
}
|
|
} else {
|
|
if (createResult) {
|
|
createResult.style.display = '';
|
|
createResult.innerHTML = '<div class="alert alert-danger py-2">' + (result.error || 'Error') + '</div>';
|
|
}
|
|
}
|
|
btnCreate.disabled = false;
|
|
btnCreate.innerHTML = '<i class="fa fa-plus me-1"></i> 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 */ }
|
|
},
|
|
});
|