Commit 70860307 by Yvon Kerdoncuff

entirely rework inventaire par produits app

parent abe34fb6
Pipeline #4183 failed with stage
......@@ -397,12 +397,11 @@ class CagetteProducts(models.Model):
return api.search_read('product.product', cond, fields)
@staticmethod
def get_active_products_from_name(name):
def get_all_active_products():
api = OdooAPI()
cond = [['active', '=', True],
['name', 'ilike', name]]
fields = ['id', 'uom_id', 'name', 'qty_available', 'barcode', 'active', 'shelf_id', 'product_tmpl_id']
return api.search_read('product.product', cond, fields)
cond = [['active', '=', True]]
fields = ['id', 'uom_id', 'name', 'qty_available', 'barcode']
return api.search_read('product.product', cond, fields, limit=False)
@staticmethod
def get_vrac_products_from_cats(cats, withCandidate=False, fields=[]):
......
.main, .barcode_or_name_search_area {
margin-top: 20px;
}
#barcode_or_name_selector {
border: 1px solid #555;
border-radius:15px;
}
.stock_edit_input {
max-width: 100px;
}
.dataTables_filter {
display: block !important; /* S'assure qu'elle est bien affichée */
}
\ No newline at end of file
/*
* Récupération d'un produit par scan et affichage des informations du produits.
* Les informations actuellements récupérées sont :
* - Numéro de Rayon (not anymore : too slow)
* - Stock théorique
*
* Les informations actuellement modifiables sont :
......@@ -9,29 +8,17 @@
*/
var products = [],
products_table = null,
search_chars = [];
search_history = [];
products_table = null;
function reset_focus() {
$('#barcode_or_name_selector').val('');
$('#barcode_or_name_selector').focus();
}
function add_product(product) {
try {
// Add to list
products.push(product);
if (products_table == null) {
function init(products) {
// create table, show panel
products_table = $('#products_table').DataTable({
data: products,
columns:[
{data:"id", title: "id", visible: false},
columns: [
{data: "id", title: "id", visible: false},
{
data:"name",
title:"Produit",
data: "name",
title: "Produit",
width: "50%",
render: function (data, type, full, meta) {
// Add tooltip with barcode over product name
......@@ -47,15 +34,15 @@ function add_product(product) {
}
},
{
data:"uom_id.1",
data: "uom_id.1",
title: "Unité de vente",
className:"dt-body-center",
className: "dt-body-center",
orderable: false
},
{
data:"qty_available",
data: "qty_available",
title: "Stock théorique",
className:"dt-body-center",
className: "dt-body-center",
render: function (data, type, full, meta) {
return '<input type="number" class="stock_edit_input" value="' + data + '">'
+ ' <button type="button" class="stock_edit_button btn--primary"><i class="fas fa-lg fa-check"></i></button>';
......@@ -68,9 +55,11 @@ function add_product(product) {
"asc"
]
],
paging: false,
dom: 'lrtip', // Remove the search input from that table
language: {url : '/static/js/datatables/french.json'}
pageLength: 10,
deferRender: true,
processing: true,
searching: true,
language: {url: '/static/js/datatables/french.json'}
});
// Listener on 'Update product stock' button
......@@ -83,11 +72,11 @@ function add_product(product) {
.find('input')
.val();
if (row_data.uom_id[0] == 1) {
if (qty != 0 && qty/parseInt(qty) != 1) {
if (qty != 0 && qty / parseInt(qty) != 1) {
$.notify(
"Ce produit est vendu à l'unité : la valeur doit être un nombre entier !",
{
globalPosition:"top left",
globalPosition: "top left",
className: "error"
}
);
......@@ -112,40 +101,23 @@ function add_product(product) {
$.notify(
"Valeur inchangée.",
{
globalPosition:"top left",
globalPosition: "top left",
className: "info"
}
);
$("#products_table_filter input").focus()
}
} else {
$.notify(
"Valeur invalide.",
{
globalPosition:"top left",
globalPosition: "top left",
className: "error"
}
);
$("#products_table_filter input").focus()
}
});
} else {
// Add row to table
var rowNode = products_table.row.add(product).draw(false)
.node();
let onAnimationEnd = function() {
rowNode.classList.remove('blink_me');
};
// Handle blinking effect for newly added row
$(rowNode).addClass('blink_me');
rowNode.addEventListener('animationend', onAnimationEnd);
rowNode.addEventListener('webkitAnimationEnd', onAnimationEnd);
}
} catch (e) {
err = {msg: e.name + ' : ' + e.message, ctx: 'add_product'};
console.error(err);
report_JS_error(err, 'produits');
}
}
function update_product_stock(p_data) {
......@@ -162,6 +134,7 @@ function update_product_stock(p_data) {
delete p_data.qty;
closeModal();
$("#products_table_filter input").focus()
$.notify(
"Stock mis à jour !",
{
......@@ -169,8 +142,6 @@ function update_product_stock(p_data) {
className: "success"
}
);
reset_focus();
},
error: function(data) {
// server error
......@@ -189,39 +160,24 @@ function update_product_stock(p_data) {
}
// Fetch a product when barcode is read
function fetch_products_from_bc_or_name(input) {
if (input == '') {
reset_focus();
return 0;
}
if (search_history.includes(input)) {
$.notify(
"Recherche déjà effectuée !",
{
globalPosition: "top left",
className: "info"
}
);
reset_focus();
return 0;
} else {
search_history.push(input)
}
function fetch_products() {
openModal();
$.ajax({
url: "/products/get_products_data_by_barcode_or_name?input=" + input,
url: "/products/get_all_active_products",
success: function(data) {
reset_focus();
for (const product of data.products) {
add_product(product);
init(data.products)
closeModal();
// Attendre que le DOM soit complètement prêt avant de donner le focus
setTimeout(function() {
// Vérifier si l'input de la recherche est disponible
var searchInput = $("#products_table_filter input");
if (searchInput.length) {
searchInput.focus(); // Mettre le focus sur le champ de recherche
}
}, 100); // Attendre un court instant pour s'assurer que DataTables est complètement initialisé
},
error: function(data) {
closeModal();
if (data.status == 404) {
// Product not found (shouldn't rise)
$.notify(
......@@ -234,7 +190,7 @@ function fetch_products_from_bc_or_name(input) {
reset_focus();
} else {
// server error
err = {msg: "erreur serveur lors de la récupération du produit", ctx: 'fetch_products_from_bc_or_name'};
err = {msg: "erreur serveur lors de la récupération du produit", ctx: 'fetch_products'};
if (typeof data.responseJSON != 'undefined' && typeof data.responseJSON.error != 'undefined') {
err.msg += ' : ' + data.responseJSON.error;
}
......@@ -248,37 +204,5 @@ function fetch_products_from_bc_or_name(input) {
$(document).ready(function() {
$.ajaxSetup({ headers: { "X-CSRFToken": getCookie('csrftoken') } });
reset_focus();
$('#button_barcode_or_name_selector').on('click', function () {
input = $('#barcode_or_name_selector').val();
fetch_products_from_bc_or_name(input);
});
// Interception de la touche "Enter" dans le champ de texte
$('#barcode_or_name_selector').on('keypress', function(e) {
if (e.which === 13) { // Si la touche pressée est "Enter" (key code 13)
e.preventDefault(); // Empêche le comportement par défaut (rechargement ou soumission de formulaire)
input = $('#barcode_or_name_selector').val();
fetch_products_from_bc_or_name(input); // Appelle la fonction de recherche
}
});
// Barcode reader: listen for 13 digits read in a very short time
$('#search_input').keypress(function(e) {
if (e.which >= 48 && e.which <= 57) {
search_chars.push(String.fromCharCode(e.which));
}
if (search_chars.length >= 13) {
var barcode = search_chars.join("");
if (!isNaN(barcode)) {
search_chars = [];
setTimeout(function() {
fetch_products_from_bc_or_name(barcode);
}, 300);
}
}
});
fetch_products('');
});
......@@ -7,7 +7,7 @@ urlpatterns = [
url(r'^simple_list$', views.get_simple_list),
url(r'^get_product_for_order_helper$', views.get_product_for_order_helper),
url(r'^get_product_data$', views.get_product_data),
url(r'^get_products_data_by_barcode_or_name$', views.get_products_data_by_barcode_or_name),
url(r'^get_all_active_products$', views.get_all_active_products),
url(r'^get_products_stdprices$', views.get_products_stdprices),
url(r'^update_product_stock$', views.update_product_stock),
url(r'^update_product_purchase_ok$', views.update_product_purchase_ok),
......
......@@ -55,19 +55,8 @@ def get_product_for_order_helper(request):
else:
return JsonResponse(res, safe=False)
def get_products_data_by_barcode_or_name(request):
input = request.GET['input']
# check if it is probably a barcode input
if input.isdigit() and len(input) > 6:
products = CagetteProduct.get_product_from_barcode(input)
# or a text input
else:
products = CagetteProducts.get_active_products_from_name(input)
#commented because too slow
#for product in products:
# add_shelf_sortorder(product)
def get_all_active_products(request):
products = CagetteProducts.get_all_active_products()
if not products:
return JsonResponse({"product": products}, status=404)
else:
......
......@@ -18,11 +18,6 @@
<h1>Inventaire par produits</h1>
</div>
<div class="barcode_or_name_search_area txtcenter">
<input type="text" id="barcode_or_name_selector" name="barcode_or_name_selector" placeholder="Nom ou codebarre">
<button type="button" class="btn--primary" id="button_barcode_or_name_selector" name="button">Recherche</button>
</div>
<div class="main">
<table id="products_table" class="display" cellspacing="0" ></table>
</div>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment