/* Logique : Cette page peut avoir à traiter un groupe de commandes ou une unique commande. Pour garder une unique logique, une commande unique sera considérée comme un groupe de une commande. Sémantiquement, ici : list_to_process représente la liste des produits à réceptionner list_processed la liste des produit déjà réceptionnés */ /** * Associative array of current order(s) * If more than 1 element: group of orders * If 1 element: single order */ var orders = {}, is_group = false, group_ids = [] var reception_status, list_to_process = [], list_processed = [], table_to_process, table_processed, editing_product = null, // Store the product currently being edited editing_origin, // Keep track of where editing_product comes from processed_row_counter = 0, // Order in which products were added in processed list search_chars = [], user_comments = "", updatedProducts = [], // Keep record of updated products validProducts = [], // Keep record of directly validated products updateType = "" // step 1: qty_valid; step2: br_valid /* UTILS */ function back() { document.location.href = "/reception"; } /** Search if the product being edited is already in the updated products. * Returns its index or -1. */ function searchUpdatedProduct() { try { if (editing_product != null) { for (var i=0; i < updatedProducts.length; i++) { if (updatedProducts[i].product_id[0] == editing_product.product_id[0]) { return i; } } } } catch (e) { err = {msg: e.name + ' : ' + e.message, ctx: 'searchUpdatedProduct'} console.error(err) report_JS_error(err, 'reception') } return -1; } // Directly send a line to edition when barcode is read function select_product_from_bc(barcode) { try { if (editing_product == null) { var found = {data: null, place: null}; $.each(list_to_process, function(i,e) { if (e.barcode == barcode) { found.data = e; found.place = 'to_process'; } }); $.each(list_processed, function(i,e) { if (e.barcode == barcode) { found.data = e; found.place = 'processed'; } }); if (found.data !== null) { setLineEdition(found.data); if (found.place === 'to_process') { var row = table_to_process.row($('#'+found.data.product_id[0])) remove_from_toProcess(row, found.data); } else { var row = table_processed.row($('#'+found.data.product_id[0])) remove_from_processed(row, found.data); } } } } catch (e) { err = {msg: e.name + ' : ' + e.message, ctx: 'select_product_from_bc'} console.error(err) report_JS_error(err, 'reception') } } /* INIT */ // Get order(s) data from server function fetch_data() { try { $.ajaxSetup({ headers: { "X-CSRFToken": getCookie('csrftoken') } }); $.ajax({ type: 'POST', url: '../get_orders_lines', dataType:"json", traditional: true, contentType: "application/json; charset=utf-8", data: JSON.stringify({'po_ids' : group_ids}), success: function(data) { // for each order for (order_data of data.orders) { // for each product in order for (i in order_data.po) { // Does product already exists in list_to_process? var existing_index = null; for (var j = 0; j < list_to_process.length; j++) { if (order_data.po[i].product_id[0] == list_to_process[j].product_id[0]) { existing_index = j; break; } } // Products already exists: it is present in different orders if (existing_index != null) { // Add order id and product id to product list for other orders data if (!('other_orders_data' in list_to_process[existing_index])) { list_to_process[existing_index]['other_orders_data'] = [] } list_to_process[existing_index].other_orders_data.push({ id_po : order_data.id_po, id_product : order_data.po[i].id, initial_qty : order_data.po[i].product_qty, }); // If in step 1, concatenate qty in list_to_process if (reception_status == 'False') { list_to_process[existing_index].product_qty += order_data.po[i].product_qty; list_to_process[existing_index].package_qty += order_data.po[i].package_qty; list_to_process[existing_index].product_qty_package += order_data.po[i].product_qty_package; } } else { // Add product to list_to_process list_to_process.push(order_data.po[i]); // Save order id to keep track of where product comes from list_to_process[list_to_process.length-1]['id_po'] = order_data.id_po; } } } initLists(); }, error: function() { alert('Les données n\'ont pas pu être récupérées, réessayez plus tard.'); } }); } catch (e) { err = {msg: e.name + ' : ' + e.message, ctx: 'fetch_data'} console.error(err) report_JS_error(err, 'reception') } } /* LISTS HANDLING */ // Init Data & listeners function initLists(){ try { // Un-disable validation buttons now the data's here if (reception_status == "False") { document.getElementById("valid_qty").disabled = false; document.getElementById("valid_all_qties").disabled = false; } else if (reception_status == "qty_valid") { document.getElementById("valid_uprice").disabled = false; document.getElementById("valid_all_uprices").disabled = false; } // Set lists with local storage content for (var i = 0; i < updatedProducts.length; i++) { var product = updatedProducts[i]; product['row_counter'] = -1; list_processed.push(product); var toProcess_index = list_to_process.findIndex(x => x.id == updatedProducts[i]['id']); if (toProcess_index > -1) { list_to_process.splice(toProcess_index, 1); } } for (var i = 0; i < validProducts.length; i++) { var toProcess_index = list_to_process.findIndex(x => x.id == validProducts[i]); if (toProcess_index > -1) { var product = list_to_process[toProcess_index]; product['row_counter'] = -1; list_processed.push(product); list_to_process.splice(toProcess_index, 1); } } // Init table for to_process content table_to_process = $('#table_to_process').DataTable( { data: list_to_process, columns:[ {data:"product_id.0", title: "id", visible: false}, {data:"shelf_sortorder", title: "Rayon", className: "dt-body-center"}, { data:"product_id.1", title:"Produit", width: "50%", render: function (data, type, full, meta) { // Add tooltip with barcode over product name if ('barcode' in full) { var display_barcode = full.barcode; } else { var display_barcode = "Aucun"; } return '<div class="tooltip">' + data + ' <span class="tooltiptext tt_twolines">Code barre : ' + display_barcode + '</span> </div>'; } }, {data:"product_uom.1", title: "Unité vente", className:"dt-body-center", orderable: false}, { data:"product_qty", title: "Qté", className:"dt-body-center", visible: (reception_status == "False") }, { data:"price_unit", title:"Prix unit.", className:"dt-body-center", visible: (reception_status == "qty_valid") }, { title:"Editer", defaultContent: "<a class='btn' id='toProcess_line_edit' href='#'><i class='far fa-edit'></i></a>", className:"dt-body-center", orderable: false }, { title:"Valider", defaultContent: "<a class='btn' id='toProcess_line_valid' href='#'><i class='far fa-check-square'></i></a>", className:"dt-body-center", orderable: false } ], rowId : "product_id.0", order: [[ 0, "asc" ]], scrollY: "33vh", scrollCollapse: true, paging: false, dom: 'lrtip', // Remove the search input from that table language: {url : '/static/js/datatables/french.json'} }) // Init table for processed content table_processed = $('#table_processed').DataTable( { data: list_processed, columns:[ {data:"row_counter", title:"row_counter", visible: false}, // Hidden counter to display last row first {data:"shelf_sortorder", title: "Rayon", className:"dt-body-center"}, { data:"product_id.1", title:"Produit", width: "60%", render: function (data, type, full, meta) { // Add tooltip with barcode over product name if ('barcode' in full) { var display_barcode = full.barcode; } else { var display_barcode = "Aucun"; } return '<div class="tooltip">' + data + ' <span class="tooltiptext tt_twolines">Code barre : ' + display_barcode + '</span> </div>'; } }, {data:"product_uom.1", title: "Unité vente", className:"dt-body-center", orderable: false}, { data:"product_qty", title:"Qté", className:"dt-body-center", visible: (reception_status == "False") }, { data:"price_unit", title:"Prix unit", className:"dt-body-center", visible: (reception_status == "qty_valid") }, { title:"Editer", defaultContent: "<a class='btn' id='processed_line_edit' href='#'><i class='far fa-edit'></i></a>", className:"dt-body-center", orderable: false } ], rowId : "product_id.0", order: [[ 0, "desc" ]], scrollY: "28vh", scrollCollapse: true, paging: false, dom: 'lrtip', // Remove the search input from that table language: {url : '/static/js/datatables/french.json'} }); } catch (e) { err = {msg: e.name + ' : ' + e.message, ctx: 'initLists: init tables'} console.error(err) report_JS_error(err, 'reception') } /* Listeners */ // Direct valid from to_process $('#table_to_process tbody').on('click', 'a#toProcess_line_valid', function () { if (is_time_to('reception_direct_valid_order_line', 500)) { try { var row = table_to_process.row($(this).parents('tr')); var data = row.data(); add_to_processed(data); remove_from_toProcess(row, data); // Update local storage of product's order if (!orders[data.id_po]['valid_products']) orders[data.id_po]['valid_products'] = []; orders[data.id_po]['valid_products'].push(data['id']) localStorage.setItem("order_" + data.id_po, JSON.stringify(orders[data.id_po])); // Reset search document.getElementById('search_input').value = ''; $('table.dataTable').DataTable().search('').draw(); // Re set focus on input document.getElementById('search_input').focus(); } catch (e) { err = {msg: e.name + ' : ' + e.message, ctx: 'initLists: listener validate line'} console.error(err) report_JS_error(err, 'reception') } } } ); // Edit to_process line $('#table_to_process tbody').on('click', 'a#toProcess_line_edit', function () { try { // Prevent editing mutiple lines at a time if (editing_product == null) { var row = table_to_process.row($(this).parents('tr')); var data = row.data(); // Product goes to editing editing_origin = "to_process"; setLineEdition(data); remove_from_toProcess(row, data); document.getElementById('search_input').value = ''; $('table.dataTable').DataTable().search('').draw(); search_chars = []; } } catch (e) { err = {msg: e.name + ' : ' + e.message, ctx: 'initLists : listener edit line from list to process'} console.error(err) report_JS_error(err, 'reception') } } ); // Edit processed line $('#table_processed tbody').on('click', 'a#processed_line_edit', function () { try { // Prevent editing mutiple lines at a time if (editing_product == null) { var row = table_processed.row($(this).parents('tr')); var data = row.data(); //Go to editing editing_origin = "processed"; setLineEdition(row.data()); remove_from_processed(row, data); document.getElementById('search_input').value = ''; $('table.dataTable').DataTable().search('').draw(); search_chars = []; } } catch (e) { err = { msg: e.name + ' : ' + e.message, ctx: 'initLists: listener edit line from processed list' } console.error(err) report_JS_error(err, 'reception') } }); // Search input for both tables $('#search_input').on('keyup', function () { try { $('table.dataTable') .DataTable() .search(jQuery.fn.DataTable.ext.type.search.string(this.value)) // search without accents (see DataTable plugin) .draw(); } catch (e) { err = { msg: e.name + ' : ' + e.message, ctx: 'initLists: listener search_input ' } console.error(err) report_JS_error(err, 'reception') } } ); // Cancel line editing $('#edition_cancel').on('click', function () { if (editing_product != null) { if (editing_origin == "to_process") { add_to_toProcess(editing_product); } else if (editing_origin == "processed") { add_to_processed(editing_product, false); } clearLineEdition(); } }); } // Add a line to to_process function add_to_toProcess(product){ try { // Add to list list_to_process.push(product); // Add to table (no data binding...) var rowNode = table_to_process.row.add(product).draw(false).node(); // Handle blinking effect for newly added row $(rowNode).addClass('blink_me'); rowNode.addEventListener('animationend', onAnimationEnd); rowNode.addEventListener('webkitAnimationEnd', onAnimationEnd); function onAnimationEnd(e) { rowNode.classList.remove('blink_me'); } } catch (e) { err = {msg: e.name + ' : ' + e.message, ctx: 'add_to_toProcess'} console.error(err) report_JS_error(err, 'reception') } } // Add a line to processed function add_to_processed(product, withCounter = true){ try { // Add to list list_processed.push(product); // Add a counter to display first the last row added if (withCounter) { product.row_counter = processed_row_counter; processed_row_counter++; } // Add to table (no data binding...) var rowNode = table_processed.row.add(product).draw(false).node(); // Handle blinking efect for newly added row $(rowNode).addClass('blink_me'); rowNode.addEventListener('animationend', onAnimationEnd); rowNode.addEventListener('webkitAnimationEnd', onAnimationEnd); function onAnimationEnd(e) { rowNode.classList.remove('blink_me'); } } catch (e) { err = {msg: e.name + ' : ' + e.message, ctx: 'add_to_processed'} console.error(err) report_JS_error(err, 'reception') } } // Remove a line from to_process function remove_from_toProcess(row, product){ try { // Remove from list var index = list_to_process.indexOf(product); if (index > -1) { list_to_process.splice(index, 1); } //Remove from table row.remove().draw(); } catch (e) { err = {msg: e.name + ' : ' + e.message, ctx: 'remove_from_processed'} console.error(err) report_JS_error(err, 'reception') } } // Remove a line from processed function remove_from_processed(row, product){ try { // Remove from list var index = list_processed.indexOf(product); if (index > -1) { list_processed.splice(index, 1); } //Remove from table row.remove().draw(); } catch (e) { err = {msg: e.name + ' : ' + e.message, ctx: 'remove_from_processed'} console.error(err) report_JS_error(err, 'reception') } } /* EDITION */ // Set edition function setLineEdition(product) { editing_product = product; // name document.getElementById('product_name').innerHTML = editing_product.product_id[1]; // intput if (reception_status == "qty_valid") document.getElementById('edition_input').value = editing_product.price_unit; else document.getElementById('edition_input').value = editing_product.product_qty; document.getElementById("edition_input").focus(); // uom if (editing_product.product_uom[0] == 1) { // Unit if (reception_status == 'False') { document.getElementById('product_uom').innerHTML = ' unité(s)'; } else { document.getElementById('product_uom').innerHTML = ' / unité'; } } else if (editing_product.product_uom[0] == 21) { // kg if (reception_status == 'False') { document.getElementById('product_uom').innerHTML = ' kg'; } else { document.getElementById('product_uom').innerHTML = ' / kg'; } } // Make edition area blink when edition button clicked container_edition.classList.add('blink_me'); } // Clear edition function clearLineEdition() { editing_product = null; // Reset DOM values document.getElementById('product_name').innerHTML = ''; document.getElementById('edition_input').value = null; document.getElementById('search_input').focus(); document.getElementById('product_uom').innerHTML = ''; } /** * Update a product info : qty or unit price * If 'value' is set, use it as new value */ function editProductInfo (productToEdit, value = null) { try { // Check if the product is already in the 'updated' list var index = searchUpdatedProduct(); var firstUpdate = false; // If 'value' parameter not set, get value from edition input if (value == null) { var newValue = parseFloat(document.getElementById('edition_input').value.replace(',', '.')) } else { var newValue = value } // If qty edition & Check if qty changed if (reception_status == "False" && productToEdit.product_qty != newValue) { if (index == -1) { // First update productToEdit.old_qty = productToEdit.product_qty firstUpdate = true; } // Edit product info productToEdit.product_qty = newValue; /* If qty has changed, we choose to set detailed values as follow: 1 package (product_qty_package) of X products (package_qty) */ productToEdit.product_qty_package = 1; productToEdit.package_qty = productToEdit.product_qty; } // Check if price changed if (reception_status == "qty_valid" && productToEdit.price_unit != newValue) { if (index == -1) { // First update productToEdit.old_price_unit = productToEdit.price_unit productToEdit.new_shelf_price = null if (! isNaN(productToEdit.p_coeff)) { try { new_shelf_price = parseFloat(newValue * productToEdit.p_coeff) old_shelf_price = parseFloat(productToEdit.p_price * productToEdit.p_coeff) if (Math.abs(new_shelf_price - old_shelf_price) > 0.001) productToEdit.new_shelf_price = new_shelf_price.toFixed(2) } catch (e) { err = {msg: e.name + ' : ' + e.message, ctx: 'computing new_shelf_price'} console.error(err) report_JS_error(err, 'reception') } } firstUpdate = true; } productToEdit.price_unit = newValue; } // If the product info has been updated and for the first time if (firstUpdate) { updatedProducts.push(productToEdit); /* Update local storage of product order */ // Create 'updated_products' list in order if not exists if (!orders[productToEdit.id_po]['updated_products']) orders[productToEdit.id_po]['updated_products'] = []; // Add product to order's updated products if first update orders[productToEdit.id_po]['updated_products'].push(productToEdit) // May have been directly validated then updated from processed list // -> then: remove from 'valid_products' list for (i in orders[productToEdit.id_po]['valid_products']) { if (orders[productToEdit.id_po]['valid_products'][i] == productToEdit['id']) { orders[productToEdit.id_po]['valid_products'].splice(i, 1); } } } else { // Look for product in order's updated products list for (i in orders[productToEdit.id_po]['updated_products']) { if (orders[productToEdit.id_po]['updated_products'][i]['product_id'][0] == productToEdit['product_id'][0]) { orders[productToEdit.id_po]['updated_products'][i] = productToEdit } } } // Update local storage of product order localStorage.setItem("order_" + productToEdit.id_po, JSON.stringify(orders[productToEdit.id_po])); add_to_processed(productToEdit); } catch (e) { err = {msg: e.name + ' : ' + e.message, ctx: 'edit product info'} console.error(err) report_JS_error(err, 'reception') } return true; } // Validate product edition function validateEdition(form) { if (editing_product != null) { if (editProductInfo(editing_product)) { clearLineEdition(); } } } // Set the quantity to 0 for all the products in to_process function setAllQties() { // Iterate over all rows in to_process table_to_process.rows().every( function (rowIdx, tableLoop, rowLoop) { var data = this.data(); editProductInfo(data, 0); } ); list_to_process = []; table_to_process.rows().remove().draw(); } /* ACTIONS */ // Get labels to print for current orders from server function get_pdf_labels() { try { if (is_time_to('print_pdf_labels', 10000)) { // Concatenate orders id into a string, separated with comas, to retrieve oids = group_ids.join(',') // Send request & diret download pdf var filename = "codebarres_" + group_ids[0] + ".pdf"; $.ajax({ url: "../../orders/get_pdf_labels?oids=" + oids, success: download.bind(true, "pdf", filename) }); } else { alert("Vous avez cliqué il y a moins de 10s... Patience, la demande est en cours de traitement.") } } catch (e) { err = {msg: e.name + ' : ' + e.message, ctx: 'get_pdf_labels'} console.error(err) report_JS_error(err, 'reception') } } function print_product_labels() { try { if (is_time_to('print_pdt_labels', 10000)) { $.ajax("../../orders/print_product_labels?oids=" + group_ids.join(',')) .done(function(){ alert('Impression des étiquettes à coller sur les articles lancée.') }) } else { alert("Vous avez cliqué il y a moins de 10s... Patience, la demande est en cours de traitement.") } } catch (e) { err = {msg: e.name + ' : ' + e.message, ctx: 'print_product_labels'} console.error(err) report_JS_error(err, 'reception') } } /** DEPRECATED, printing is fired automaticaly now from server side. **/ // Send request to print a new shelf labels file for products with new price // function print_etiquettes() { // try { // // Additionnal security to be sure request isn't sent during step 1 // if (reception_status == 'qty_valid') { // // For all products with updated price // for (i in updatedProducts) { // // Send request // if (updatedProducts[i].new_shelf_price) { // $.ajax({ // url: tools_server + "/products/label_print/" // + updatedProducts[i].product_tmpl_id + "/" // + updatedProducts[i].new_shelf_price // }); // } // // } // // document.getElementById("etiquettesToPrint").innerHTML = "<br/><h5><b>Impression lancée !</b></h5>"; // } // } catch (e) { // err = {msg: e.name + ' : ' + e.message, ctx: 'print_etiquettes'} // console.error(err) // report_JS_error(err, 'reception') // } // } // Verifications before sending BC update function pre_send(type) { if (list_to_process.length > 0) { alert("Il reste des produits à traiter dans la commande."); } else { updateType = type; if (type == 'qty_valid') { var modal_next_step = '#templates #modal_qties_validation' } else { var modal_next_step = '#templates #modal_prices_validation' } openModal($(modal_next_step).html(), data_validation, 'Confirmer', false); } } function data_validation() { openModal() $.ajaxSetup({ headers: { "X-CSRFToken": getCookie('csrftoken') } }); $.ajax({ type: "POST", url: "../data_validation", dataType: "json", traditional: true, contentType: "application/json; charset=utf-8", data: JSON.stringify(group_ids), success: function(data) { if (data.unprocessable.length == 0) { // No product unprocessable, do process send() } else { $("#modal_unprocessable_porducts #list_unprocessable_porducts").html('') for (p of data.unprocessable) { $("#modal_unprocessable_porducts #list_unprocessable_porducts").append("<li>" + p[1] + "</li>") } openModal($("#modal_unprocessable_porducts").html(), function() {return 0}, 'Confirmer', true, false); } }, error: function(data) { // if error during validation, report error & go on so we don't block the process err = {msg: "erreur serveur lors de la validation des données", ctx: 'data_validation'} if (typeof data.responseJSON != 'undefined' && typeof data.responseJSON.error != 'undefined' ) { err.msg += ' : ' + data.responseJSON.error } console.error(err) report_JS_error(err, 'reception') send() } }) } // Send the request to the server function send() { try { // Loading on openModal(); // Only send to server the updated lines var update_data = { update_type: updateType, orders: {} }; // Set orders in update data with empty list of updated products for (order_id in orders) { update_data.orders[order_id] = {'po' : []} } // for each updated product, add it to its order list for (i in updatedProducts) { // if product was in different orders if ('other_orders_data' in updatedProducts[i]) { // for each other order of product for (other_order_data of updatedProducts[i].other_orders_data) { // Make a clone (deep copy) of the product object let product_copy = $.extend(true, {}, updatedProducts[i]); // Set correct order line id for this product product_copy.id = other_order_data.id_product; // If in step 1, dispatch quantity in other orders if (reception_status == 'False') { // Reset initial qties in respective orders product_copy.old_qty = other_order_data.initial_qty; for (j in orders[updatedProducts[i].id_po]['updated_products']) { if (orders[updatedProducts[i].id_po]['updated_products'][j].product_id[0] == product_copy.product_id[0]) { orders[updatedProducts[i].id_po]['updated_products'][j].old_qty -= other_order_data.initial_qty; break; } } if (product_copy.product_uom[0] == 21 && updatedProducts[i].product_qty > 0.1) { // kg // Add minimum qty in other orders product_copy.product_qty_package = 1; product_copy.package_qty = 0.1; product_copy.product_qty = 0.1; // Remove this qty from first order updatedProducts[i].package_qty -= 0.1; updatedProducts[i].product_qty -= 0.1; } else if (product_copy.product_uom[0] == 1 && updatedProducts[i].product_qty > 1) { // Unit product_copy.product_qty_package = 1; product_copy.package_qty = 1; product_copy.product_qty = 1; updatedProducts[i].package_qty -= 1; updatedProducts[i].product_qty -= 1; } else { // Not handled, all qty in one order product_copy.product_qty_package = 0; product_copy.package_qty = 0; product_copy.product_qty = 0; } } /* Add product to the other orders it belongs to */ // In update data update_data.orders[other_order_data.id_po]['po'].push(product_copy); // Add it to the 'updated products' of other orders (for error report) if (!('updated_products' in orders[other_order_data.id_po])) { orders[other_order_data.id_po]['updated_products'] = [] } orders[other_order_data.id_po]['updated_products'].push(product_copy) } } // Add product to order's prod list prod_order_id = updatedProducts[i].id_po update_data.orders[prod_order_id]['po'].push(updatedProducts[i]) } // console.log(update_data) // return -1 $.ajaxSetup({ headers: { "X-CSRFToken": getCookie('csrftoken') } }); $.ajax({ type: "PUT", url: "../update_orders", dataType: "json", traditional: true, contentType: "application/json; charset=utf-8", data: JSON.stringify(update_data), success: function(data) { try { // If step 1 (counting), open pop-up with procedure explanation if (reception_status == "False") { var barcodes_to_print = false; // Select products with local barcode and without barcode, when qty > 0 for (var i = 0; i < list_processed.length; i++) { if (list_processed[i].product_qty != 0) { // set DOM data if (typeof(list_processed[i].barcode) == "string" && list_processed[i].barcode.startsWith(fixed_barcode_prefix) && !barcodes_to_print) { // Products with barcode to print (local barcode) document.getElementById("barcodesToPrint").hidden = false; document.getElementById("nothingToDo").hidden = true; barcodes_to_print = true } else if (list_processed[i].barcode == false || list_processed[i].barcode == null || list_processed[i].barcode == "") { // Products with no barcode var node = document.createElement('li'); var textNode = document.createTextNode(list_processed[i]["product_id"][1]); node.appendChild(textNode); document.getElementById('barcodesEmpty_list').appendChild(node); if (document.getElementById("barcodesEmpty").hidden) { document.getElementById("barcodesEmpty").hidden = false; document.getElementById("nothingToDo").hidden = true; } } } } // Set order(s) name in popup DOM if (Object.keys(orders).length == 1) { // Single order document.getElementById("order_ref").innerHTML = orders[Object.keys(orders)[0]].name; } else { document.getElementById("success_order_name_container").hidden = true; document.getElementById("success_orders_name_container").hidden = false; for (order_id in orders) { var p_node = document.createElement('p'); var span_node = document.createElement('span'); span_node.className = 'order_ref_reminder'; var textNode = document.createTextNode(orders[order_id].name) span_node.appendChild(textNode); textNode = document.createTextNode( orders[order_id].partner + ' du ' + orders[order_id].date_order + ' : ' ); p_node.appendChild(textNode); p_node.appendChild(span_node); document.getElementById("orders_ref").appendChild(p_node); } } openModal( $('#modal_qtiesValidated').html(), function() {document.location.href = "/reception";}, 'Retour à la liste des commandes', true, false ); } else { // Print etiquettes with new prices if (updatedProducts.length > 0) { document.getElementById("etiquettesToPrint").hidden = false; } openModal( $('#templates #modal_pricesValidated').html(), function() {document.location.href = "/reception";}, 'Retour à la liste des commandes', true, false ); } // Go back to to_process list if modal closed $('#modal_closebtn_top').on('click', function (e) { document.location.href = "/reception"; }); $('#modal_closebtn_bottom').on('click', function (e) { document.location.href = "/reception"; }); // Clear local storage before leaving for (order_id in orders) { localStorage.removeItem("order_" + order_id); } // Delete group(s) if (is_group) { var grouped_orders = JSON.parse(localStorage.getItem('grouped_orders')); // Remove all groups containing these orders for (order_id in orders) { search: for (var i = 0; i < grouped_orders.length; i++) { for (var j = 0; j < grouped_orders[i].length; j++) { if (grouped_orders[i][j] == order_id) { grouped_orders.splice(i); break search; } } } } localStorage.setItem('grouped_orders' , JSON.stringify(grouped_orders)); } } catch (ee) { err = {msg: ee.name + ' : ' + ee.message, ctx: 'callback update_orders'} console.error(err) report_JS_error(err, 'reception') } }, error: function() { closeModal() alert('Erreur lors de la sauvegarde des données.'); } }); // Send changes between items to process and processed items var updates = { 'group_amount_total' : 0, 'update_type' : updateType, 'updated_products' : updatedProducts, 'user_comments': user_comments, 'orders' : [] }; for (i in orders) { updates.group_amount_total += orders[i].amount_total; updates.orders.push(orders[i]) } $.ajax({ type: "POST", url: "../save_error_report", dataType: "json", traditional: true, contentType: "application/json; charset=utf-8", data: JSON.stringify(updates), success: function(data) {}, error: function() { closeModal(); alert('Erreur dans l\'envoi du rapport.'); } }); } catch (e) { err = {msg: e.name + ' : ' + e.message, ctx: 'send'} console.error(err) report_JS_error(err, 'reception') alert('Erreur : ' + err.msg) } } // Fired from verification modal for 'all prices' validation function confirmPricesAllValid() { updateType = 'br_valid'; send(); } // Fired from All left is good modal function confirm_all_left_is_good() { // all products left are to be considered as well filled // Iterate over all rows in to_process table_to_process.rows().every( function (rowIdx, tableLoop, rowLoop) { let data = this.data() var value = null if (reception_status == "False"){ value = data.product_qty } else { value = data.price_unit } editProductInfo(data, value); } ); list_to_process = []; table_to_process.rows().remove().draw(); closeModal() } /* TODO: upgrade modal -> disable background scrolling*/ function openFAQ(){ openModal($("div#modal_FAQ_content").html(), function(){}, 'Compris !', true, false); } function openErrorReport(){ openModal($('#templates #modal_error_report').html(), saveErrorReport, 'Confirmer') var textarea = document.getElementById("error_report"); textarea.value = user_comments; textarea.focus(); textarea.setSelectionRange(textarea.value.length,textarea.value.length); } function saveErrorReport() { user_comments = document.getElementById("error_report").value; document.getElementById("search_input").focus(); } $(document).ready(function() { // Get Route parameter var pathArray = window.location.pathname.split('/'); var id = pathArray[pathArray.length-1]; // Disable alert errors from datatables $.fn.dataTable.ext.errMode = 'none'; // Listen for errors in tables with custom behavior $('#table_to_process').on( 'error.dt', function ( e, settings, techNote, message ) { var err_msg = message try { var split = message.split(" ") var row_number = null for (var i = 0; i < split.length; i++) { if (split[i] == "row") row_number = split[i+1] } row_number = row_number.replace(',', '') var row_data = $('#table_to_process').DataTable().row(row_number).data() err_msg += " - Order id: " + row_data.id_po err_msg += " - Product: " + row_data.product_id[1] } catch (e) {} err = {msg: err_msg, ctx: 'datatable: table to_process'} console.error(err) report_JS_error(err, 'reception') } ) ; $('#table_processed').on( 'error.dt', function ( e, settings, techNote, message ) { var err_msg = message try { var split = message.split(" ") var row_number = null for (var i = 0; i < split.length; i++) { if (split[i] == "row") row_number = split[i+1] } row_number = row_number.replace(',', '') var row_data = $('#table_processed').DataTable().row(row_number).data() err_msg += " - Order id: " + row_data.id_po err_msg += " - Product: " + row_data.product_id[1] } catch (e) {} err = {msg: err_msg, ctx: 'datatable: table processed'} console.error(err) report_JS_error(err, 'reception') } ) ; try { // Get order info from local storage (it should be there if process followed) if (Modernizr.localstorage) { // Look for current order in grouped orders in local storage var grouped_orders = JSON.parse(localStorage.getItem('grouped_orders')); if (grouped_orders != null) { for (group of grouped_orders) { for (group_element_id of group) { if (group_element_id == id) { // We're in a group! is_group = true; group_ids = group; } } } } // if not in group, add current order to group if (group_ids.length == 0) { group_ids.push(id); } var stored_order = null; var display_partners_name = []; // for each order in order group for (order_id of group_ids) { // Get order data from local storage stored_order = JSON.parse(localStorage.getItem('order_' + order_id)); // Add order to order list if (stored_order != null) { orders[order_id] = stored_order; //Add each order's already updated and validated products to common list if (stored_order["updated_products"]) updatedProducts = updatedProducts.concat(stored_order["updated_products"]); if (stored_order["valid_products"]) validProducts = validProducts.concat(stored_order["valid_products"]); // Prepare data to display in 'partner name' area display_partners_name.push(stored_order['partner'] + ' du ' + stored_order['date_order']) } } // Set current reception status: take first order's reception_status = orders[Object.keys(orders)[0]].reception_status } // Fetch orders data fetch_data(); if (is_group) { $('#partner_name').html(Object.keys(orders).length + " commandes") // Display order data for each order var msg = ""; for (display_partner_data of display_partners_name) { if (msg != "") { msg += ", " } msg += display_partner_data } $('#container_multiple_partners').append('<h6> ' + msg + '</h6>'); } else { $('#partner_name').html(orders[Object.keys(orders)[0]].partner) } /* Set DOM according to reception status */ if (reception_status == "qty_valid") { // Step 2 // Header document.getElementById('header_step_two').classList.add('step_two_active'); var check_icon = document.createElement('i'); check_icon.className = 'far fa-check-circle'; document.getElementById('header_step_one_content').appendChild(check_icon); // Products lists containers document.getElementById('container_left').style.border = "3px solid #0275D8"; // container qty_checked document.getElementById('container_right').style.border = "3px solid #5CB85C"; // container processed items document.getElementById('header_container_left').innerHTML = "Prix à mettre à jour"; document.getElementById('header_container_right').innerHTML = "Prix mis à jour"; // Edition document.getElementById('edition_header').innerHTML = "Editer les prix" document.getElementById('edition_input_label').innerHTML = "Prix unit." // Validation buttons document.getElementById("valid_all").innerHTML = "<button class='btn--danger full_width_button' id='valid_all_uprices' onclick=\"openModal($('#templates #modal_no_prices').html(), confirmPricesAllValid, 'Confirmer', false);\" disabled>Pas de prix sur le bon de livraison</button>"; document.getElementById("validation_button").innerHTML = "<button class='btn--success full_width_button' id='valid_uprice' onclick=\"pre_send('br_valid')\" disabled>Valider la mise à jour des prix</button>"; // Modal content after validation $("#modal_pricesValidated").load("/reception/reception_pricesValidated"); } else if (reception_status == "False") { // Step 1 document.getElementById('header_step_one').classList.add('step_one_active'); document.getElementById('container_left').style.border = "3px solid #212529"; // container products to process document.getElementById('container_right').style.border = "3px solid #0275D8"; // container qty_checked document.getElementById('header_container_left').innerHTML = "Produits à compter"; document.getElementById('header_container_right').innerHTML = "Produits déjà comptés"; document.getElementById('edition_header').innerHTML = "Editer les quantités" document.getElementById('edition_input_label').innerHTML = "Qté" document.getElementById("valid_all").innerHTML = "<button class='btn--danger full_width_button' id='valid_all_qties' onclick=\"openModal($('#templates #modal_no_qties').html(), setAllQties, 'Confirmer');\" disabled>Il n'y a plus de produits à compter</button>"; document.getElementById("validation_button").innerHTML = "<button class='btn--primary full_width_button' id='valid_qty' onclick=\"pre_send('qty_valid')\" disabled>Valider le comptage des produits</button>"; $("#modal_qtiesValidated").load("/reception/reception_qtiesValidated"); } else { // Extra security, shouldn't get in here document.location.href = "/reception"; } } catch (e) { err = {msg: e.name + ' : ' + e.message, ctx: 'page init'} console.error(err) report_JS_error(err, 'reception') alert("Erreur au chargement de cette commande. Vous allez être redirigé.") back() } // Load modals content $("#modal_FAQ_content").load("/reception/reception_FAQ"); $("#modal_qtiesValidated").load("/reception/reception_qtiesValidated"); $("#modal_pricesValidated").load("/reception/reception_pricesValidated"); // Handling blinking effect var container_edition = document.querySelector('#container_edition'); container_edition.addEventListener('animationend', onAnimationEnd); container_edition.addEventListener('webkitAnimationEnd', onAnimationEnd); function onAnimationEnd(e) { container_edition.classList.remove('blink_me'); } // Disable mousewheel on an input number field when in focus $('#edition_input').on('focus', function (e) { $(this).on('wheel.disableScroll', function (e) { e.preventDefault(); /* Option to possibly enable page scrolling when mouse over the input, but : - deltaY is not in pixels in Firefox - movement not fluid on other browsers var scrollTo = (e.originalEvent.deltaY) + $(document.documentElement).scrollTop(); $(document.documentElement).scrollTop(scrollTo); -> other option to allow scrolling would be to loose input focus with blur(): not acceptable */ }) }).on('blur', function (e) { $(this).off('wheel.disableScroll') }); // client-side validation of numeric inputs, optionally replacing separator sign(s). $("input.number").on("keydown", function (e) { // allow function keys and decimal separators if ( // backspace, delete, tab, escape, enter, comma and . $.inArray(e.keyCode, [46, 8, 9, 27, 13, 110, 188, 190]) !== -1 || // Ctrl/cmd+A, Ctrl/cmd+C, Ctrl/cmd+X ($.inArray(e.keyCode, [65, 67, 88]) !== -1 && (e.ctrlKey === true || e.metaKey === true)) || // home, end, left, right (e.keyCode >= 35 && e.keyCode <= 39)) { /* // optional: replace commas with dots in real-time (for en-US locals) if (e.keyCode === 188) { e.preventDefault(); $(this).val($(this).val() + "."); } // optional: replace decimal points (num pad) and dots with commas in real-time (for EU locals) if (e.keyCode === 110 || e.keyCode === 190) { e.preventDefault(); $(this).val($(this).val() + ","); } */ return; } // block any non-number if ( //Figures entered with Shift + key (59 ==> .) (e.shiftKey && ((e.keyCode < 48 || e.keyCode > 57) && e.keyCode !== 59)) || //Numeric keyboard (!e.shiftKey && (e.keyCode < 96 || e.keyCode > 105)) ) { e.preventDefault(); } }); // 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(){ document.getElementById('search_input').value = ''; $('table.dataTable').DataTable().search('').draw(); select_product_from_bc(barcode); }, 300); } } }); });