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): ...@@ -397,12 +397,11 @@ class CagetteProducts(models.Model):
return api.search_read('product.product', cond, fields) return api.search_read('product.product', cond, fields)
@staticmethod @staticmethod
def get_active_products_from_name(name): def get_all_active_products():
api = OdooAPI() api = OdooAPI()
cond = [['active', '=', True], cond = [['active', '=', True]]
['name', 'ilike', name]] fields = ['id', 'uom_id', 'name', 'qty_available', 'barcode']
fields = ['id', 'uom_id', 'name', 'qty_available', 'barcode', 'active', 'shelf_id', 'product_tmpl_id'] return api.search_read('product.product', cond, fields, limit=False)
return api.search_read('product.product', cond, fields)
@staticmethod @staticmethod
def get_vrac_products_from_cats(cats, withCandidate=False, fields=[]): 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 { .stock_edit_input {
max-width: 100px; 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. * Récupération d'un produit par scan et affichage des informations du produits.
* Les informations actuellements récupérées sont : * Les informations actuellements récupérées sont :
* - Numéro de Rayon (not anymore : too slow)
* - Stock théorique * - Stock théorique
* *
* Les informations actuellement modifiables sont : * Les informations actuellement modifiables sont :
...@@ -9,29 +8,17 @@ ...@@ -9,29 +8,17 @@
*/ */
var products = [], var products = [],
products_table = null, products_table = null;
search_chars = [];
search_history = [];
function reset_focus() { function init(products) {
$('#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) {
// create table, show panel // create table, show panel
products_table = $('#products_table').DataTable({ products_table = $('#products_table').DataTable({
data: products, data: products,
columns:[ columns: [
{data:"id", title: "id", visible: false}, {data: "id", title: "id", visible: false},
{ {
data:"name", data: "name",
title:"Produit", title: "Produit",
width: "50%", width: "50%",
render: function (data, type, full, meta) { render: function (data, type, full, meta) {
// Add tooltip with barcode over product name // Add tooltip with barcode over product name
...@@ -47,15 +34,15 @@ function add_product(product) { ...@@ -47,15 +34,15 @@ function add_product(product) {
} }
}, },
{ {
data:"uom_id.1", data: "uom_id.1",
title: "Unité de vente", title: "Unité de vente",
className:"dt-body-center", className: "dt-body-center",
orderable: false orderable: false
}, },
{ {
data:"qty_available", data: "qty_available",
title: "Stock théorique", title: "Stock théorique",
className:"dt-body-center", className: "dt-body-center",
render: function (data, type, full, meta) { render: function (data, type, full, meta) {
return '<input type="number" class="stock_edit_input" value="' + data + '">' 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>'; + ' <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) { ...@@ -68,9 +55,11 @@ function add_product(product) {
"asc" "asc"
] ]
], ],
paging: false, pageLength: 10,
dom: 'lrtip', // Remove the search input from that table deferRender: true,
language: {url : '/static/js/datatables/french.json'} processing: true,
searching: true,
language: {url: '/static/js/datatables/french.json'}
}); });
// Listener on 'Update product stock' button // Listener on 'Update product stock' button
...@@ -83,11 +72,11 @@ function add_product(product) { ...@@ -83,11 +72,11 @@ function add_product(product) {
.find('input') .find('input')
.val(); .val();
if (row_data.uom_id[0] == 1) { if (row_data.uom_id[0] == 1) {
if (qty != 0 && qty/parseInt(qty) != 1) { if (qty != 0 && qty / parseInt(qty) != 1) {
$.notify( $.notify(
"Ce produit est vendu à l'unité : la valeur doit être un nombre entier !", "Ce produit est vendu à l'unité : la valeur doit être un nombre entier !",
{ {
globalPosition:"top left", globalPosition: "top left",
className: "error" className: "error"
} }
); );
...@@ -112,40 +101,23 @@ function add_product(product) { ...@@ -112,40 +101,23 @@ function add_product(product) {
$.notify( $.notify(
"Valeur inchangée.", "Valeur inchangée.",
{ {
globalPosition:"top left", globalPosition: "top left",
className: "info" className: "info"
} }
); );
$("#products_table_filter input").focus()
} }
} else { } else {
$.notify( $.notify(
"Valeur invalide.", "Valeur invalide.",
{ {
globalPosition:"top left", globalPosition: "top left",
className: "error" 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) { function update_product_stock(p_data) {
...@@ -162,6 +134,7 @@ function update_product_stock(p_data) { ...@@ -162,6 +134,7 @@ function update_product_stock(p_data) {
delete p_data.qty; delete p_data.qty;
closeModal(); closeModal();
$("#products_table_filter input").focus()
$.notify( $.notify(
"Stock mis à jour !", "Stock mis à jour !",
{ {
...@@ -169,8 +142,6 @@ function update_product_stock(p_data) { ...@@ -169,8 +142,6 @@ function update_product_stock(p_data) {
className: "success" className: "success"
} }
); );
reset_focus();
}, },
error: function(data) { error: function(data) {
// server error // server error
...@@ -189,39 +160,24 @@ function update_product_stock(p_data) { ...@@ -189,39 +160,24 @@ function update_product_stock(p_data) {
} }
// Fetch a product when barcode is read // Fetch a product when barcode is read
function fetch_products_from_bc_or_name(input) { function fetch_products() {
if (input == '') { openModal();
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)
}
$.ajax({ $.ajax({
url: "/products/get_products_data_by_barcode_or_name?input=" + input, url: "/products/get_all_active_products",
success: function(data) { success: function(data) {
reset_focus(); init(data.products)
closeModal();
for (const product of data.products) { // Attendre que le DOM soit complètement prêt avant de donner le focus
add_product(product); 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) { error: function(data) {
closeModal();
if (data.status == 404) { if (data.status == 404) {
// Product not found (shouldn't rise) // Product not found (shouldn't rise)
$.notify( $.notify(
...@@ -234,7 +190,7 @@ function fetch_products_from_bc_or_name(input) { ...@@ -234,7 +190,7 @@ function fetch_products_from_bc_or_name(input) {
reset_focus(); reset_focus();
} else { } else {
// server error // 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') { if (typeof data.responseJSON != 'undefined' && typeof data.responseJSON.error != 'undefined') {
err.msg += ' : ' + data.responseJSON.error; err.msg += ' : ' + data.responseJSON.error;
} }
...@@ -248,37 +204,5 @@ function fetch_products_from_bc_or_name(input) { ...@@ -248,37 +204,5 @@ function fetch_products_from_bc_or_name(input) {
$(document).ready(function() { $(document).ready(function() {
$.ajaxSetup({ headers: { "X-CSRFToken": getCookie('csrftoken') } }); $.ajaxSetup({ headers: { "X-CSRFToken": getCookie('csrftoken') } });
fetch_products('');
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);
}
}
});
}); });
...@@ -7,7 +7,7 @@ urlpatterns = [ ...@@ -7,7 +7,7 @@ urlpatterns = [
url(r'^simple_list$', views.get_simple_list), 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_for_order_helper$', views.get_product_for_order_helper),
url(r'^get_product_data$', views.get_product_data), 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'^get_products_stdprices$', views.get_products_stdprices),
url(r'^update_product_stock$', views.update_product_stock), url(r'^update_product_stock$', views.update_product_stock),
url(r'^update_product_purchase_ok$', views.update_product_purchase_ok), url(r'^update_product_purchase_ok$', views.update_product_purchase_ok),
......
...@@ -55,19 +55,8 @@ def get_product_for_order_helper(request): ...@@ -55,19 +55,8 @@ def get_product_for_order_helper(request):
else: else:
return JsonResponse(res, safe=False) return JsonResponse(res, safe=False)
def get_products_data_by_barcode_or_name(request): def get_all_active_products(request):
input = request.GET['input'] products = CagetteProducts.get_all_active_products()
# 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)
if not products: if not products:
return JsonResponse({"product": products}, status=404) return JsonResponse({"product": products}, status=404)
else: else:
......
...@@ -18,11 +18,6 @@ ...@@ -18,11 +18,6 @@
<h1>Inventaire par produits</h1> <h1>Inventaire par produits</h1>
</div> </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"> <div class="main">
<table id="products_table" class="display" cellspacing="0" ></table> <table id="products_table" class="display" cellspacing="0" ></table>
</div> </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