Commit e84f47f2 by Damien Moulard

merge couchdb in reception

parents ac8536c7 983b0430
Pipeline #1105 passed with stage
in 1 minute 22 seconds
...@@ -20,7 +20,8 @@ COUCHDB = { ...@@ -20,7 +20,8 @@ COUCHDB = {
'inventory': 'inventory', 'inventory': 'inventory',
'envelops': 'envelop', 'envelops': 'envelop',
'shop': 'shopping_carts', 'shop': 'shopping_carts',
'orders': 'orders_test' 'orders': 'orders_test',
'reception': 'reception_test',
} }
} }
......
...@@ -11,6 +11,10 @@ input[type="number"] { ...@@ -11,6 +11,10 @@ input[type="number"] {
} }
/* INDEX */ /* INDEX */
.group_line {
margin-bottom: 5px;
}
#orders tbody tr { #orders tbody tr {
cursor: pointer; cursor: pointer;
} }
...@@ -31,6 +35,15 @@ input[type="number"] { ...@@ -31,6 +35,15 @@ input[type="number"] {
margin-bottom: 1em; margin-bottom: 1em;
} }
.order_last_update {
font-weight: bold;
}
.order_modified_msg {
font-size: 2rem;
color: #e62720;
}
/* PRODUITS */ /* PRODUITS */
.page_body { .page_body {
height: 100%; height: 100%;
......
var order = { var orders = [],
order = {
'id' : null 'id' : null
}, },
table_orders = null, table_orders = null,
callback_update = false, callback_update = false,
callback_report = false, callback_report = false,
selection_type = null, selection_type = null,
saved_groups = []; order_groups = {
_id: 'grouped_orders',
groups: []
},
dbc = null,
sync = null,
fingerprint = null;
/* UTILS */ /* UTILS */
// Wait for both ajax callbacks for reloading to avoid a js error /**
// -> reloading when ajax call not answered causes a popup to appear, can be confusing * Difference between two dates
function reload() { * @param {Date} date1
if (callback_update && callback_report) * @param {Date} date2
document.location.reload(); * @returns difference object
} */
function dates_diff(date1, date2) {
var diff = {};
var tmp = date2 - date1;
function goto(id) { tmp = Math.floor(tmp/1000);
document.location.href = "produits/" + id; diff.sec = tmp % 60;
}
/* tmp = Math.floor((tmp-diff.sec)/60);
* Go to Products page for an existing group diff.min = tmp % 60;
* params :
* i : index of group in 'saved_groups' array
*/
function group_goto(i) {
// Make sure all group's orders are saved in local storage
for (j in saved_groups[i]) {
set_local_storage(saved_groups[i][j]);
}
// go to one of group's order Products page tmp = Math.floor((tmp-diff.min)/60);
goto(saved_groups[i][0].id); diff.hours = tmp % 24;
}
/* tmp = Math.floor((tmp-diff.hours)/24);
* Set local storage for given order diff.days = tmp;
*/
function set_local_storage(order_data) {
if (Modernizr.localstorage) {
var stored_order = JSON.parse(localStorage.getItem('order_' + order_data.id));
// Set local storage if key doesn't exist return diff;
if (stored_order == null) {
localStorage.setItem("order_" + order_data.id, JSON.stringify(order_data));
}
}
} }
/* /**
* Remove from local storage orders that have a wrong status * Wait for both ajax callbacks for reloading to avoid a js error
* (-> order has been updated elsewhere) * -> reloading when ajax call not answered causes a popup to appear, which can be confusing
*/ */
function clean_local_storage() { function reload() {
var stored_order = null; if (callback_update && callback_report)
document.location.reload();
// Loop through local storage }
for (key of Object.keys(localStorage)) {
if (key.startsWith('order_')) {
stored_order = JSON.parse(localStorage.getItem(key));
// Loop through orders in table to find match
var i = 0;
var found = false;
while (i < table_orders.rows().data().length && !found) { /**
var uptodate_order = table_orders.rows(i).data()[0]; * Check for concurent access to same order before going to reception page.
* @param {Int} id
*/
function check_before_goto(id) {
const order_doc_id = 'order_' + id;
// If status in local storage is wrong dbc.get(order_doc_id).then((doc) => {
if (stored_order.id == uptodate_order.id if (doc.last_update.fingerprint !== null && doc.last_update.fingerprint !== fingerprint) {
&& stored_order.reception_status != uptodate_order.reception_status) { time_diff = dates_diff(new Date(doc.last_update.timestamp), new Date());
diff_str = ``;
// Remove from local storage if (time_diff.days !== 0) {
localStorage.removeItem("order_" + uptodate_order.id); diff_str += `${time_diff.days} jour(s), `;
}
if (time_diff.hours !== 0) {
diff_str += `${time_diff.hours} heure(s), `;
}
if (time_diff.min !== 0) {
diff_str += `${time_diff.min} min, `;
}
diff_str += `${time_diff.sec}s`;
// Evolution: warn user (order modified elsewhere, local data has been deleted) let modal_order_access = $('#templates #modal_order_access');
found = true;
}
i++; modal_order_access.find(".order_last_update").text(diff_str);
}
if (!found) { openModal(
// Remove too if order isn't in server data modal_order_access.html(),
localStorage.removeItem("order_" + stored_order.id); () => {
} goto(id);
},
'Valider'
);
} else {
goto(id);
} }
} })
.catch((err) => {
console.log(err);
});
} }
function create_groups_from_server_data() { function goto(id) {
// Get array of stored grouped orders document.location.href = "produits/" + id;
var grouped_orders = JSON.parse(localStorage.getItem('grouped_orders')); }
// Create if not exists /**
if (grouped_orders == null) { * Go to Products page for an existing group
grouped_orders = []; * @param {int} group_index index of group in groups array
} else { */
// Remove from server data groups already in local storage function group_goto(group_index) {
for (stored_group of grouped_orders) { // Make sure a couchdb document exists for all group's orders
for (sg_order_item of stored_group) { for (let i in order_groups.groups[group_index]) {
for (i in server_stored_groups) { let order_data = null;
if (server_stored_groups[i].includes(sg_order_item)) {
server_stored_groups.splice(i, 1); // Find order data
break; for (let order of orders) {
} if (order.id == order_groups.groups[group_index][i]) {
} order_data = order;
} }
} }
create_order_doc(order_data);
} }
// Add server groups to stored groups // go to first order
grouped_orders = grouped_orders.concat(server_stored_groups); check_before_goto(order_groups.groups[group_index][0]);
localStorage.setItem('grouped_orders', JSON.stringify(grouped_orders));
} }
/* /**
* If there are groups in local storage, extract them from the table, set the groups actions. * Create a couchdb document for an order if it doesn't exist
* @param {Object} order_data
* @param {Boolean} goto if true, go to order page
*/ */
function extract_grouped_orders() { function create_order_doc(order_data, go_to_order = false) {
var saved_grouped_orders = JSON.parse(localStorage.getItem('grouped_orders')); const order_doc_id = 'order_' + order_data.id;
var groups_to_delete = []; // indexes
// if there are grouped orders
if (saved_grouped_orders != null) {
// for each group
for (group_index in saved_grouped_orders) {
var g = [];
// for each order in group
for (group_element_id of saved_grouped_orders[group_index]) {
// Look for order in datatable
for (var i = 0; i < table_orders.rows().data().length; i++) {
if (group_element_id == table_orders.rows(i).data()[0].id) {
var order = table_orders.rows(i).data()[0];
g.push(order);
// remove raw from table dbc.get(order_doc_id).then(() => {
table_orders.rows(i).remove() if (go_to_order === true) {
.draw(); check_before_goto(order_data.id);
}
})
.catch(function (err) {
// Create if doesn't exist
if (err.status === 404) {
let order_doc = { ...order_data };
order_doc._id = order_doc_id;
order_doc.last_update = {
timestamp: Date.now(),
fingerprint: fingerprint
};
dbc.put(order_doc).then(() => {
if (go_to_order === true) {
goto(order_data.id);
} }
} })
} .catch((err) => {
error = {
// No order found, delete group and skip the rest msg: 'Erreur dans la creation de la commande dans couchdb',
if (g.length == 0) { ctx: 'create_order_doc',
groups_to_delete.push(group_index); details: err
continue; };
} report_JS_error(error, 'reception');
console.log(error);
// Display group });
document.getElementById("container_groups").hidden = false;
var group_row = "<ul> <li> Commandes de ";
for (i in g) {
if (i == g.length-1) { // last element of list
group_row += "<b>" + g[i].partner + "</b> du " + g[i].date_order + " : ";
} else {
group_row += "<b>" + g[i].partner + "</b> du " + g[i].date_order + ", ";
}
}
if (g[0].reception_status == 'False') {
group_row += "<button class='btn--primary' onClick='group_goto("
+ saved_groups.length
+ ")'>Compter les produits</button>";
} else {
group_row += "<button class='btn--success' onClick='group_goto("
+ saved_groups.length
+ ")'>Mettre à jour les prix</button>";
} }
});
group_row += "</li>";
$('#groups_items').append(group_row);
saved_groups.push(g);
}
}
if (groups_to_delete.length > 0) {
for (index of groups_to_delete) {
saved_grouped_orders.splice(index, 1);
}
localStorage.setItem('grouped_orders', JSON.stringify(saved_grouped_orders));
}
} }
/* ACTIONS */ /* ACTIONS */
// Validate all prices of an order /**
* Validate all prices of an order
*/
function validatePrices() { function validatePrices() {
// Loading on // Loading on
openModal(); openModal();
...@@ -210,9 +187,19 @@ function validatePrices() { ...@@ -210,9 +187,19 @@ function validatePrices() {
contentType: "application/json; charset=utf-8", contentType: "application/json; charset=utf-8",
data: JSON.stringify(update_data), data: JSON.stringify(update_data),
success: function() { success: function() {
localStorage.removeItem("order_" + order["id"]); // Remove order
callback_update = true; dbc.get(`order_${order['id']}`).then((doc) => {
reload(); return dbc.remove(doc);
})
.then(() => {
callback_update = true;
reload();
})
.catch((err) => {
// No doc found
console.log(err);
reload();
});
}, },
error: function() { error: function() {
closeModal(); closeModal();
...@@ -251,91 +238,117 @@ function validatePrices() { ...@@ -251,91 +238,117 @@ function validatePrices() {
}); });
} }
/**
// Action fired when orders are grouped (new group) * Action fired when orders are grouped (new group)
* @returns
*/
function group_action() { function group_action() {
var pswd = prompt('Merci de demander à un.e salarié.e le mot de passe pour fusionner ces commandes.'); let pswd = prompt('Merci de demander à un.e salarié.e le mot de passe pour fusionner ces commandes.');
if (pswd == merge_orders_pswd) { // Minimum security level // Minimum security level
// Use local storage to pass order data to next page if (pswd == merge_orders_pswd) {
if (Modernizr.localstorage) { let selected_data = table_orders.rows('.selected').data();
var selected_data = table_orders.rows('.selected').data(); let group_ids = [];
var group_ids = [];
// Select orders id for (let i = 0; i < selected_data.length; i++) {
for (var i = 0; i < selected_data.length; i++) { // Select group orders id
group_ids.push(selected_data[i].id); group_ids.push(selected_data[i].id);
}
// Notify server that group is created // Create doc for each group order if doesn't exist
$.ajax({ create_order_doc(selected_data[i]);
type: "POST", }
url: "/reception/save_order_group",
dataType: "json",
traditional: true,
contentType: "application/json; charset=utf-8",
data: JSON.stringify(group_ids),
success: function() {
var min_id = 9999999;
for (var i = 0; i < selected_data.length; i++) {
// get smallest id
if (selected_data[i].id < min_id) {
min_id = selected_data[i].id;
}
// Add each order to local storage group_ids.sort();
set_local_storage(selected_data[i]);
}
// Get array of grouped orders // Save group
var grouped_orders = JSON.parse(localStorage.getItem('grouped_orders')); order_groups.groups.push(group_ids);
dbc.put(order_groups, (err) => {
if (!err) {
goto(group_ids[0]);
} else {
alert("Une erreur est survenue lors de la création du groupe. Veuillez ré-essayer plus tard svp.");
console.log(err);
}
});
// Create if not exists } else if (pswd == null) {
if (grouped_orders == null) { return;
grouped_orders = []; } else {
} alert('Mauvais mot de passe !');
}
}
// Add group /* DISPLAY */
grouped_orders.push(group_ids);
// store grouped orders array /**
localStorage.setItem('grouped_orders', JSON.stringify(grouped_orders)); * Display the order groups.
* Remove the grouped orders from the order table to prevent grouping in multiple groups.
*/
function display_grouped_orders() {
if (table_orders !== null) {
$('#groups_items').empty();
let groups_display_content = "<ul>";
for (let group_index in order_groups.groups) {
let group_orders = [];
// Extract every order in the groups from the orders table
for (group_order_id of order_groups.groups[group_index]) {
// Look for order in datatable"
for (let i = 0; i < table_orders.rows().data().length; i++) {
if (group_order_id == table_orders.rows(i).data()[0].id) {
var order = table_orders.rows(i).data()[0];
// Go to products page of order with smallest id group_orders.push(order);
goto(min_id);
}, // remove table row
error: function(data) { table_orders.rows(i).remove()
if (data != null && data.status == 409) { .draw();
alert("Un groupe a déjà été formé sur un autre poste "
+ "avec au moins l'une des commandes sélectionnées. Merci de rafraichir la page.");
} }
} }
}); }
// Display group
document.getElementById("container_groups").hidden = false;
let group_row = `<li class="group_line"> Commandes de `;
} else { for (let i in group_orders) {
alert("Le local storage n'est pas disponible. Merci de contacter un.e salarié.e !"); if (i == group_orders.length-1) { // last element of list
} group_row += "<b>" + group_orders[i].partner + "</b> du " + group_orders[i].date_order + " : ";
} else {
group_row += "<b>" + group_orders[i].partner + "</b> du " + group_orders[i].date_order + ", ";
}
}
} else if (pswd == null) { if (group_orders[0].reception_status == 'False') {
return; group_row += "<button class='btn--primary' onClick='group_goto("
} else { + group_index
alert('Mauvais mot de passe !'); + ")'>Compter les produits</button>";
} else {
group_row += "<button class='btn--success' onClick='group_goto("
+ group_index
+ ")'>Mettre à jour les prix</button>";
}
group_row += "</li>";
groups_display_content += group_row;
}
$('#container_groups').show();
$('#groups_items').append(groups_display_content);
} }
} }
/**
$(document).ready(function() { * Display the main orders table
openModal(); */
function display_orders_table() {
$.ajaxSetup({ headers: { "X-CSRFToken": getCookie('csrftoken') } }); if (table_orders) {
table_orders.clear().destroy();
// Set date format for DataTable so date ordering can work $('#orders').empty();
$.fn.dataTable.moment('D/M/Y'); }
table_orders = $('#orders').DataTable({ table_orders = $('#orders').DataTable({
ajax: "get_list_orders", data: orders,
columns:[ columns:[
{ {
data:"id", data:"id",
...@@ -417,13 +430,7 @@ $(document).ready(function() { ...@@ -417,13 +430,7 @@ $(document).ready(function() {
] ]
], ],
iDisplayLength: 25, iDisplayLength: 25,
language: {url : '/static/js/datatables/french.json'}, language: {url : '/static/js/datatables/french.json'}
initComplete: function() { // After data is loaded
clean_local_storage();
create_groups_from_server_data();
extract_grouped_orders();
closeModal();
}
}); });
// Set rows event on click // Set rows event on click
...@@ -482,12 +489,10 @@ $(document).ready(function() { ...@@ -482,12 +489,10 @@ $(document).ready(function() {
document.getElementById("group_action").hidden = true; document.getElementById("group_action").hidden = true;
} }
} else if (this.cellIndex == 4) { // Click on last cell button -> go to products page } else if (this.cellIndex == 4) { // Click on last cell button -> go to products page
// Extra security if order with a different status gets lost in here // Click action only for specific reception status
if (row_data.reception_status == "qty_valid" || row_data.reception_status == "False") { if (row_data.reception_status == "qty_valid" || row_data.reception_status == "False") {
// Use local storage to pass order data to next page // Use couchdb to pass order data to next page
set_local_storage(row_data); create_order_doc(row_data, true);
goto(row_data.id);
} }
} else if (this.cellIndex == 3 && row_data.reception_status == "qty_valid") { } else if (this.cellIndex == 3 && row_data.reception_status == "qty_valid") {
// If 'update prices' step, click on before-last cell -> validate all prices // If 'update prices' step, click on before-last cell -> validate all prices
...@@ -502,6 +507,112 @@ $(document).ready(function() { ...@@ -502,6 +507,112 @@ $(document).ready(function() {
.search(jQuery.fn.DataTable.ext.type.search.string(this.value)) .search(jQuery.fn.DataTable.ext.type.search.string(this.value))
.draw(); .draw();
}); });
}
$(document).ready(function() {
openModal();
$.ajaxSetup({ headers: { "X-CSRFToken": getCookie('csrftoken') } });
fingerprint = new Fingerprint({canvas: true}).get();
// Init couchdb
dbc = new PouchDB(couchdb_dbname),
sync = PouchDB.sync(couchdb_dbname, couchdb_server, {
live: true,
retry: true,
auto_compaction: false
});
// On distant changes
sync.on('change', function (info) {
// If important data changed somewhere else, update local data
let need_to_reload = false;
if (info.direction === "pull") {
for (let doc of info.change.docs) {
if (doc._id === "grouped_orders") {
// If groups doc changed, update local groups
need_to_reload = true;
order_groups = doc;
} else if ("_deleted" in doc && doc._deleted === true) {
// If order was deleted, delete it locally
try {
const deleted_order_id = parseInt(doc._id.split('_')[1]);
let index = orders.findIndex(order => order.id == deleted_order_id);
if (index !== -1) {
orders.splice(index, 1);
need_to_reload = true;
}
} catch (error) {
console.log(error);
}
} else {
// Find updated order in local orders & update it if reception status changed
let index = orders.findIndex(order => order.id == doc.id);
if (index !== -1 && orders[index].reception_status !== doc.reception_status) {
orders[index] = doc;
need_to_reload = true;
break;
}
}
}
}
if (need_to_reload) {
display_orders_table();
display_grouped_orders();
}
}).on('error', function (err) {
console.log(err);
});
// Get or create order groups doc
dbc.get("grouped_orders").then((doc) => {
order_groups = doc;
})
.catch(function (err) {
console.log(err);
if (err.status === 404) {
// Create if doesn't exist
dbc.put(order_groups, (err, result) => {
if (!err) {
order_groups._rev = result.rev;
} else {
console.log("document pour les groupes déjà créé");
console.log(err);
}
});
}
});
// Set date format for DataTable so date ordering can work
$.fn.dataTable.moment('D/M/Y');
// Get orders
$.ajax({
type: 'GET',
url: "/reception/get_list_orders",
dataType:"json",
traditional: true,
contentType: "application/json; charset=utf-8",
success: function(data) {
orders = data.data;
display_orders_table();
display_grouped_orders();
closeModal();
},
error: function(data) {
err = {msg: "erreur serveur lors de la récupération des commandes", ctx: 'get_list_orders'};
if (typeof data.responseJSON != 'undefined' && typeof data.responseJSON.error != 'undefined') {
err.msg += ' : ' + data.responseJSON.error;
}
report_JS_error(err, 'orders');
closeModal();
alert('Erreur lors de la récupération des commandes, rechargez la page plus tard.');
}
});
}); });
...@@ -13,9 +13,9 @@ Sémantiquement, ici : ...@@ -13,9 +13,9 @@ Sémantiquement, ici :
* Associative array of current order(s) * Associative array of current order(s)
* If more than 1 element: group of orders * If more than 1 element: group of orders
* If 1 element: single order * If 1 element: single order
* -> check for Object.keys(orders).length to know if we're in a group case
*/ */
var orders = {}, var orders = {},
is_group = false,
group_ids = []; group_ids = [];
var reception_status = null, var reception_status = null,
...@@ -32,6 +32,9 @@ var reception_status = null, ...@@ -32,6 +32,9 @@ var reception_status = null,
updateType = "", // step 1: qty_valid; step2: br_valid updateType = "", // step 1: qty_valid; step2: br_valid
barcodes = null; // Barcodes stored locally barcodes = null; // Barcodes stored locally
var dbc = null,
sync = null,
fingerprint = null;
/* UTILS */ /* UTILS */
...@@ -112,12 +115,56 @@ function select_product_from_bc(barcode) { ...@@ -112,12 +115,56 @@ function select_product_from_bc(barcode) {
return 0; return 0;
} }
/**
* Update couchdb order
* @param {int} order_id
*/
function update_distant_order(order_id) {
orders[order_id].last_update = {
timestamp: Date.now(),
fingerprint: fingerprint
};
dbc.put(orders[order_id], (err, result) => {
if (!err && result !== undefined) {
orders[order_id]._rev = result.rev;
} else {
alert("Erreur lors de la sauvegarde de la commande... Si l'erreur persiste contactez un administrateur svp.");
console.log(err);
}
});
}
/**
* Update distant orders with local data
* @param {int} order_id
*/
function update_distant_orders() {
for (let order_id in orders) {
orders[order_id].last_update = {
timestamp: Date.now(),
fingerprint: fingerprint
};
}
dbc.bulkDocs(Object.values(orders)).then((response) => {
// Update rev of current orders after their update
for (let doc of response) {
let order_id = doc.id.split('_')[1];
orders[order_id]._rev = doc.rev;
}
})
.catch((err) => {
console.log(err);
});
}
/* INIT */ /* INIT */
// Get order(s) data from server // Get order(s) data from server
function fetch_data() { function fetch_data() {
try { try {
$.ajaxSetup({ headers: { "X-CSRFToken": getCookie('csrftoken') } });
$.ajax({ $.ajax({
type: 'POST', type: 'POST',
url: '../get_orders_lines', url: '../get_orders_lines',
...@@ -198,7 +245,7 @@ function initLists() { ...@@ -198,7 +245,7 @@ function initLists() {
document.getElementById("valid_all_uprices").disabled = false; document.getElementById("valid_all_uprices").disabled = false;
} }
// Set lists with local storage content // Set processed and to_process lists based on saved data
for (var i = 0; i < updatedProducts.length; i++) { for (var i = 0; i < updatedProducts.length; i++) {
let product = updatedProducts[i]; let product = updatedProducts[i];
...@@ -276,7 +323,7 @@ function initLists() { ...@@ -276,7 +323,7 @@ function initLists() {
defaultContent: "<select class='select_product_action'><option value=''></option><option value='supplier_shortage'>Rupture fournisseur</option></select>", defaultContent: "<select class='select_product_action'><option value=''></option><option value='supplier_shortage'>Rupture fournisseur</option></select>",
className:"dt-body-center", className:"dt-body-center",
orderable: false, orderable: false,
visible: display_autres visible: display_autres === "True"
} }
], ],
rowId : "product_id.0", rowId : "product_id.0",
...@@ -356,7 +403,7 @@ function initLists() { ...@@ -356,7 +403,7 @@ function initLists() {
title:"Autres", title:"Autres",
className:"dt-body-center", className:"dt-body-center",
orderable: false, orderable: false,
visible: display_autres, visible: display_autres === "True",
render: function (data, type, full) { render: function (data, type, full) {
let disabled = (full.supplier_shortage) ? "disabled" : ''; let disabled = (full.supplier_shortage) ? "disabled" : '';
...@@ -391,17 +438,18 @@ function initLists() { ...@@ -391,17 +438,18 @@ function initLists() {
$('#table_to_process tbody').on('click', 'a#toProcess_line_valid', function () { $('#table_to_process tbody').on('click', 'a#toProcess_line_valid', function () {
if (is_time_to('reception_direct_valid_order_line', 500)) { if (is_time_to('reception_direct_valid_order_line', 500)) {
try { try {
var row = table_to_process.row($(this).parents('tr')); let row = table_to_process.row($(this).parents('tr'));
var data = row.data(); let data = row.data();
add_to_processed(data); add_to_processed(data);
remove_from_toProcess(row, data); remove_from_toProcess(row, data);
// Update local storage of product's order // Update product's order
if (!orders[data.id_po]['valid_products']) if (!orders[data.id_po]['valid_products']) {
orders[data.id_po]['valid_products'] = []; orders[data.id_po]['valid_products'] = [];
}
orders[data.id_po]['valid_products'].push(data['id']); orders[data.id_po]['valid_products'].push(data['id']);
localStorage.setItem("order_" + data.id_po, JSON.stringify(orders[data.id_po])); update_distant_order(data.id_po);
// Reset search // Reset search
document.getElementById('search_input').value = ''; document.getElementById('search_input').value = '';
...@@ -726,8 +774,8 @@ function set_supplier_shortage(row, product, from_processed = false) { ...@@ -726,8 +774,8 @@ function set_supplier_shortage(row, product, from_processed = false) {
} }
add_to_processed(product); add_to_processed(product);
// Update local storage of product's order // Update product's order
localStorage.setItem("order_" + product.id_po, JSON.stringify(orders[product.id_po])); update_distant_order(product.id_po);
// Reset search // Reset search
document.getElementById('search_input').value = ''; document.getElementById('search_input').value = '';
...@@ -803,9 +851,12 @@ function clearLineEdition() { ...@@ -803,9 +851,12 @@ function clearLineEdition() {
/** /**
* Update a product info : qty or unit price * Update a product info : qty or unit price
* If 'value' is set, use it as new value * @param {Object} productToEdit
* @param {Float} value if set, use it as new value
* @param {Boolean} batch if true, don't update couchdb data here
* @returns
*/ */
function editProductInfo (productToEdit, value = null) { function editProductInfo (productToEdit, value = null, batch = false) {
try { try {
// Check if the product is already in the 'updated' list // Check if the product is already in the 'updated' list
var index = searchUpdatedProduct(); var index = searchUpdatedProduct();
...@@ -863,16 +914,16 @@ function editProductInfo (productToEdit, value = null) { ...@@ -863,16 +914,16 @@ function editProductInfo (productToEdit, value = null) {
if (firstUpdate) { if (firstUpdate) {
updatedProducts.push(productToEdit); updatedProducts.push(productToEdit);
/* Update local storage of product order */
// Create 'updated_products' list in order if not exists // Create 'updated_products' list in order if not exists
if (!orders[productToEdit.id_po]['updated_products']) if (!orders[productToEdit.id_po]['updated_products']) {
orders[productToEdit.id_po]['updated_products'] = []; orders[productToEdit.id_po]['updated_products'] = [];
}
// Add product to order's updated products if first update // Add product to order's updated products if first update
orders[productToEdit.id_po]['updated_products'].push(productToEdit); orders[productToEdit.id_po]['updated_products'].push(productToEdit);
// May have been directly validated then updated from processed list // May have been directly validated then updated from processed list
// -> then: remove from 'valid_products' list // -> remove from 'valid_products' list
for (i in orders[productToEdit.id_po]['valid_products']) { for (i in orders[productToEdit.id_po]['valid_products']) {
if (orders[productToEdit.id_po]['valid_products'][i] == productToEdit['id']) { if (orders[productToEdit.id_po]['valid_products'][i] == productToEdit['id']) {
orders[productToEdit.id_po]['valid_products'].splice(i, 1); orders[productToEdit.id_po]['valid_products'].splice(i, 1);
...@@ -888,8 +939,10 @@ function editProductInfo (productToEdit, value = null) { ...@@ -888,8 +939,10 @@ function editProductInfo (productToEdit, value = null) {
} }
} }
// Update local storage of product order if (batch === false) {
localStorage.setItem("order_" + productToEdit.id_po, JSON.stringify(orders[productToEdit.id_po])); // Update product order
update_distant_order(productToEdit.id_po);
}
add_to_processed(productToEdit); add_to_processed(productToEdit);
} catch (e) { } catch (e) {
...@@ -916,16 +969,17 @@ function setAllQties() { ...@@ -916,16 +969,17 @@ function setAllQties() {
table_to_process.rows().every(function () { table_to_process.rows().every(function () {
var data = this.data(); var data = this.data();
editProductInfo(data, 0); editProductInfo(data, 0, true);
return true; return true;
}); });
list_to_process = []; list_to_process = [];
table_to_process.rows().remove() table_to_process.rows().remove()
.draw(); .draw();
}
// Batch update orders
update_distant_orders();
}
/* ACTIONS */ /* ACTIONS */
...@@ -1017,7 +1071,6 @@ function pre_send(type) { ...@@ -1017,7 +1071,6 @@ function pre_send(type) {
function data_validation() { function data_validation() {
openModal(); openModal();
$.ajaxSetup({ headers: { "X-CSRFToken": getCookie('csrftoken') } });
$.ajax({ $.ajax({
type: "POST", type: "POST",
url: "../data_validation", url: "../data_validation",
...@@ -1059,6 +1112,7 @@ function send() { ...@@ -1059,6 +1112,7 @@ function send() {
// Loading on // Loading on
openModal(); openModal();
/* Prepare data for orders update */
// Only send to server the updated lines // Only send to server the updated lines
var update_data = { var update_data = {
update_type: updateType, update_type: updateType,
...@@ -1072,7 +1126,8 @@ function send() { ...@@ -1072,7 +1126,8 @@ function send() {
// for each updated product, add it to its order list // for each updated product, add it to its order list
for (i in updatedProducts) { for (i in updatedProducts) {
// if product was in different orders
/* ---> The following part concerns products found in different orders */
if ('other_orders_data' in updatedProducts[i]) { if ('other_orders_data' in updatedProducts[i]) {
// for each other order of product // for each other order of product
for (other_order_data of updatedProducts[i].other_orders_data) { for (other_order_data of updatedProducts[i].other_orders_data) {
...@@ -1129,13 +1184,44 @@ function send() { ...@@ -1129,13 +1184,44 @@ function send() {
orders[other_order_data.id_po]['updated_products'].push(product_copy); orders[other_order_data.id_po]['updated_products'].push(product_copy);
} }
} }
/* <--- */
// Add product to order's prod list // Add product to order's prod list
prod_order_id = updatedProducts[i].id_po; prod_order_id = updatedProducts[i].id_po;
update_data.orders[prod_order_id]['po'].push(updatedProducts[i]); update_data.orders[prod_order_id]['po'].push(updatedProducts[i]);
} }
$.ajaxSetup({ headers: { "X-CSRFToken": getCookie('csrftoken') } }); /* Create the error report */
// Send changes between items to process and processed items
var error_report_data = {
'group_amount_total' : 0,
'update_type' : updateType,
'updated_products' : updatedProducts,
'user_comments': user_comments,
'orders' : []
};
for (let i in orders) {
error_report_data.group_amount_total += orders[i].amount_total;
error_report_data.orders.push(orders[i]);
}
// Send request for error report
$.ajax({
type: "POST",
url: "../save_error_report",
dataType: "json",
traditional: true,
contentType: "application/json; charset=utf-8",
data: JSON.stringify(error_report_data),
success: function() {},
error: function() {
closeModal();
alert('Erreur dans l\'envoi du rapport.');
}
});
/* Update orders */
$.ajax({ $.ajax({
type: "PUT", type: "PUT",
url: "../update_orders", url: "../update_orders",
...@@ -1147,8 +1233,9 @@ function send() { ...@@ -1147,8 +1233,9 @@ function send() {
closeModal(); closeModal();
try { try {
// If step 1 (counting), open pop-up with procedure explanation // If step 1 (counting)
if (reception_status == "False") { if (reception_status == "False") {
/* Open pop-up with procedure explanation */
var barcodes_to_print = false; var barcodes_to_print = false;
// Select products with local barcode and without barcode, when qty > 0 // Select products with local barcode and without barcode, when qty > 0
...@@ -1178,9 +1265,9 @@ function send() { ...@@ -1178,9 +1265,9 @@ function send() {
} }
// Set order(s) name in popup DOM // Set order(s) name in popup DOM
if (Object.keys(orders).length == 1) { // Single order if (Object.keys(orders).length === 1) { // Single order
document.getElementById("order_ref").innerHTML = orders[Object.keys(orders)[0]].name; document.getElementById("order_ref").innerHTML = orders[Object.keys(orders)[0]].name;
} else { } else { // group
document.getElementById("success_order_name_container").hidden = true; document.getElementById("success_order_name_container").hidden = true;
document.getElementById("success_orders_name_container").hidden = false; document.getElementById("success_orders_name_container").hidden = false;
...@@ -1205,13 +1292,35 @@ function send() { ...@@ -1205,13 +1292,35 @@ function send() {
openModal( openModal(
$('#modal_qtiesValidated').html(), $('#modal_qtiesValidated').html(),
function() { back,
document.location.href = "/reception";
},
'Retour à la liste des commandes', 'Retour à la liste des commandes',
true, true,
false false
); );
/* Not last step: update distant data */
for (let order_id in orders) {
// Save current step updated data
orders[order_id].previous_steps_data = {};
orders[order_id].previous_steps_data[reception_status] = {
updated_products: orders[order_id].updated_products || []
};
orders[order_id].reception_status = updateType;
// Unlock order
orders[order_id].last_update = {
timestamp: null,
fingerprint: null
};
// Delete temp data
delete orders[order_id].valid_products;
delete orders[order_id].updated_products;
}
dbc.bulkDocs(Object.values(orders)).catch((err) => {
console.log(err);
});
} else { } else {
// Print etiquettes with new prices // Print etiquettes with new prices
if (updatedProducts.length > 0) { if (updatedProducts.length > 0) {
...@@ -1220,49 +1329,48 @@ function send() { ...@@ -1220,49 +1329,48 @@ function send() {
openModal( openModal(
$('#templates #modal_pricesValidated').html(), $('#templates #modal_pricesValidated').html(),
function() { back,
document.location.href = "/reception";
},
'Retour à la liste des commandes', 'Retour à la liste des commandes',
true, true,
false false
); );
}
// Go back to to_process list if modal closed /* Last step: Clear distant data */
$('#modal_closebtn_top').on('click', function () { // Delete orders doc
document.location.href = "/reception"; for (let order_id in orders) {
}); orders[order_id]._deleted = true;
}
$('#modal_closebtn_bottom').on('click', function () { // Remove orders group
document.location.href = "/reception"; dbc.get("grouped_orders").then((doc) => {
}); let couchdb_update_data = Object.values(orders);
// Clear local storage before leaving // We're in a group, remove it & update groups doc
for (order_id in orders) { if (Object.keys(orders).length > 1) {
localStorage.removeItem("order_" + order_id); let groups_doc = doc;
}
// Delete group(s) let first_order_id = parseInt(Object.keys(orders)[0]);
if (is_group) {
var grouped_orders = JSON.parse(localStorage.getItem('grouped_orders')); for (let i in groups_doc.groups) {
if (groups_doc.groups[i].includes(first_order_id)) {
// Remove all groups containing these orders groups_doc.groups.splice(i, 1);
for (order_id in orders) { break;
search:
for (var h = 0; i < grouped_orders.length; h++) {
for (var j = 0; j < grouped_orders[h].length; j++) {
if (grouped_orders[h][j] == order_id) {
grouped_orders.splice(h);
break search;
} }
} }
couchdb_update_data.push(groups_doc);
} }
}
localStorage.setItem('grouped_orders', JSON.stringify(grouped_orders)); return dbc.bulkDocs(couchdb_update_data);
})
.catch(function (err) {
console.log(err);
});
} }
// Back if modal closed
$('#modal_closebtn_top').on('click', back);
$('#modal_closebtn_bottom').on('click', back);
} catch (ee) { } catch (ee) {
err = {msg: ee.name + ' : ' + ee.message, ctx: 'callback update_orders'}; err = {msg: ee.name + ' : ' + ee.message, ctx: 'callback update_orders'};
console.error(err); console.error(err);
...@@ -1274,34 +1382,6 @@ function send() { ...@@ -1274,34 +1382,6 @@ function send() {
alert('Erreur lors de la sauvegarde des données.'); 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) { } catch (e) {
err = {msg: e.name + ' : ' + e.message, ctx: 'send'}; err = {msg: e.name + ' : ' + e.message, ctx: 'send'};
console.error(err); console.error(err);
...@@ -1329,17 +1409,19 @@ function confirm_all_left_is_good() { ...@@ -1329,17 +1409,19 @@ function confirm_all_left_is_good() {
} else { } else {
value = data.price_unit; value = data.price_unit;
} }
editProductInfo(data, value); editProductInfo(data, value, true);
return true; return true;
}); });
list_to_process = []; list_to_process = [];
table_to_process.rows().remove() table_to_process.rows().remove()
.draw(); .draw();
// Batch update orders
update_distant_orders();
closeModal(); closeModal();
} }
/* TODO: upgrade modal
-> disable background scrolling*/
function openFAQ() { function openFAQ() {
openModal($("div#modal_FAQ_content").html(), function() {}, 'Compris !', true, false); openModal($("div#modal_FAQ_content").html(), function() {}, 'Compris !', true, false);
} }
...@@ -1367,10 +1449,10 @@ function openErrorReport() { ...@@ -1367,10 +1449,10 @@ function openErrorReport() {
function saveErrorReport() { function saveErrorReport() {
user_comments = document.getElementById("error_report").value; user_comments = document.getElementById("error_report").value;
// Save comment in local storage, in all orders // Save comments in all orders
for (order_id of Object.keys(orders)) { for (order_id of Object.keys(orders)) {
orders[order_id].user_comments = user_comments; orders[order_id].user_comments = user_comments;
localStorage.setItem("order_" + order_id, JSON.stringify(orders[order_id])); update_distant_order(order_id);
} }
document.getElementById("search_input").focus(); document.getElementById("search_input").focus();
...@@ -1382,199 +1464,91 @@ var get_barcodes = async function() { ...@@ -1382,199 +1464,91 @@ var get_barcodes = async function() {
}; };
$(document).ready(function() {
$.ajaxSetup({ headers: { "X-CSRFToken": getCookie('csrftoken') } });
// Load barcodes
get_barcodes();
// 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() * Init the page according to order(s) data (texts, colors, events...)
.row(row_number) *
.data(); * @param {Array} partners_display_data
*/
err_msg += " - Order id: " + row_data.id_po; function init_dom(partners_display_data) {
err_msg += " - Product: " + row_data.product_id[1]; // Back button
} catch (e) { $('#back_button').on('click', function () {
console.log(e); // Liberate current orders
for (let order_id in orders) {
orders[order_id].last_update = {
timestamp: null,
fingerprint: null
};
} }
err = {msg: err_msg, ctx: 'datatable: table to_process'}; dbc.bulkDocs(Object.values(orders)).then((response) => {
console.error(err); back();
report_JS_error(err, 'reception'); })
.catch((err) => {
console.log(err);
});
}); });
$('#table_processed').on('error.dt', function (e, settings, techNote, message) { // Grouped orders
var err_msg = message; if (Object.keys(orders).length > 1) {
$('#partner_name').html(Object.keys(orders).length + " commandes");
try { // Display order data for each order
var split = message.split(" "); var msg = "";
var row_number = null;
for (var i = 0; i < split.length; i++) { for (display_partner_data of partners_display_data) {
if (split[i] == "row") if (msg != "") {
row_number = split[i+1]; msg += ", ";
} }
msg += display_partner_data;
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) {
console.log(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;
// Load user comments from local storage, get it from first order
user_comments = orders[Object.keys(orders)[0]].user_comments || "";
}
// 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);
} }
$('#container_multiple_partners').append('<h6> ' + msg + '</h6>');
} else {
$('#partner_name').html(orders[Object.keys(orders)[0]].partner);
}
/* Set DOM according to reception status */ /* Set DOM according to reception status */
if (reception_status == "qty_valid") { // Step 2 if (reception_status == "qty_valid") { // Step 2
// Header // Header
document.getElementById('header_step_two').classList.add('step_two_active'); document.getElementById('header_step_two').classList.add('step_two_active');
var check_icon = document.createElement('i'); var check_icon = document.createElement('i');
check_icon.className = 'far fa-check-circle'; check_icon.className = 'far fa-check-circle';
document.getElementById('header_step_one_content').appendChild(check_icon); document.getElementById('header_step_one_content').appendChild(check_icon);
// Products lists containers // Products lists containers
document.getElementById('container_left').style.border = "3px solid #0275D8"; // container qty_checked 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('container_right').style.border = "3px solid #5CB85C"; // container processed items
document.getElementById('header_container_left').innerHTML = "Prix à mettre à jour"; document.getElementById('header_container_left').innerHTML = "Prix à mettre à jour";
document.getElementById('header_container_right').innerHTML = "Prix mis à jour"; document.getElementById('header_container_right').innerHTML = "Prix mis à jour";
// Edition // Edition
document.getElementById('edition_header').innerHTML = "Editer les prix"; document.getElementById('edition_header').innerHTML = "Editer les prix";
document.getElementById('edition_input_label').innerHTML = "Prix unit."; document.getElementById('edition_input_label').innerHTML = "Prix unit.";
// Validation buttons // 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("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>"; 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 content after validation
$("#modal_pricesValidated").load("/reception/reception_pricesValidated"); $("#modal_pricesValidated").load("/reception/reception_pricesValidated");
} else if (reception_status == "False") { // Step 1 } else if (reception_status == "False") { // Step 1
document.getElementById('header_step_one').classList.add('step_one_active'); 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_left').style.border = "3px solid #212529"; // container products to process
document.getElementById('container_right').style.border = "3px solid #0275D8"; // container qty_checked document.getElementById('container_right').style.border = "3px solid #0275D8"; // container qty_checked
document.getElementById('header_container_left').innerHTML = "Produits à compter"; document.getElementById('header_container_left').innerHTML = "Produits à compter";
document.getElementById('header_container_right').innerHTML = "Produits déjà comptés"; document.getElementById('header_container_right').innerHTML = "Produits déjà comptés";
document.getElementById('edition_header').innerHTML = "Editer les quantités"; document.getElementById('edition_header').innerHTML = "Editer les quantités";
document.getElementById('edition_input_label').innerHTML = "Qté"; 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("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>"; 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"); $("#modal_qtiesValidated").load("/reception/reception_qtiesValidated");
} else { } else {
// Extra security, shouldn't get in here // Extra security, shouldn't get in here: reception status not valid
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(); back();
} }
...@@ -1597,16 +1571,6 @@ $(document).ready(function() { ...@@ -1597,16 +1571,6 @@ $(document).ready(function() {
$('#edition_input').on('focus', function () { $('#edition_input').on('focus', function () {
$(this).on('wheel.disableScroll', function (e) { $(this).on('wheel.disableScroll', function (e) {
e.preventDefault(); 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 () { .on('blur', function () {
...@@ -1695,4 +1659,191 @@ $(document).ready(function() { ...@@ -1695,4 +1659,191 @@ $(document).ready(function() {
.draw(); .draw();
select_product_from_bc(barcode); select_product_from_bc(barcode);
}); });
}
$(document).ready(function() {
$.ajaxSetup({ headers: { "X-CSRFToken": getCookie('csrftoken') } });
fingerprint = new Fingerprint({canvas: true}).get();
// Load barcodes
get_barcodes();
// Get Route parameter
let pathArray = window.location.pathname.split('/');
let id = pathArray[pathArray.length-1];
// Init couchdb
dbc = new PouchDB(couchdb_dbname),
sync = PouchDB.sync(couchdb_dbname, couchdb_server, {
live: true,
retry: true,
auto_compaction: false
});
sync.on('change', function (info) {
if (info.direction === "pull") {
for (const doc of info.change.docs) {
// Redirect if one of the current order is being modified somewhere else
if (String(doc.id) in orders && orders[doc.id]._rev !== doc._rev) {
alert("Un autre navigateur est en train de modifier cette commande ! Vous allez être redirigé.e.");
back();
}
}
}
}).on('error', function (err) {
if (err.status === 409) {
alert("Une erreur de synchronisation s'est produite, la commande a sûrement été modifiée sur un autre navigateur. Vous allez être redirigé.e.");
back();
}
console.log('erreur sync');
console.log(err);
});
// 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) {
console.log(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) {
console.log(e);
}
err = {msg: err_msg, ctx: 'datatable: table processed'};
console.error(err);
report_JS_error(err, 'reception');
});
/* Get order info from couchdb */
// Get order groups
let order_groups = [];
dbc.get("grouped_orders").then((doc) => {
order_groups = doc.groups;
for (let group of order_groups) {
for (group_order_id of group) {
if (group_order_id == id) {
// We're in a group!
group_ids = group;
}
}
}
// if not in group, add current order to group
if (group_ids.length == 0) {
group_ids.push(id);
}
let partners_display_data = [];
dbc.allDocs({
include_docs: true
}).then(function (result) {
// for each order in the group
for (let order_id of group_ids) {
// find order
let order = result.rows.find(el => el.id == 'order_' + order_id);
order = order.doc;
orders[order_id] = order;
// Add each order's already updated and validated products to common list
if (order["updated_products"]) {
updatedProducts = updatedProducts.concat(order["updated_products"]);
}
if (order["valid_products"]) {
validProducts = validProducts.concat(order["valid_products"]);
}
// Prepare data to display in 'partner name' area
partners_display_data.push(order['partner'] + ' du ' + order['date_order']);
}
// Set current reception status: take first order's
reception_status = orders[Object.keys(orders)[0]].reception_status;
// Load saved user comments, get it from first order
user_comments = orders[Object.keys(orders)[0]].user_comments || "";
// Indicate that these orders are used in this navigator
update_distant_orders();
// Fetch orders data
fetch_data();
init_dom(partners_display_data);
})
.catch(function (e) {
let msg = ('message' in e && 'name' in e) ? e.name + ' : ' + e.message : '';
err = {msg, ctx: 'page init - get orders from couchdb', details: e};
console.error(err);
report_JS_error(err, 'reception');
// Should be there, redirect
alert("Erreur au chargement de cette commande. Vous allez être redirigé.");
back();
});
})
.catch(function (e) {
let msg = ('message' in e && 'name' in e) ? e.name + ' : ' + e.message : '';
err = {msg, ctx: 'page init - get grouped orders', details: e};
console.error(err);
report_JS_error(err, 'reception');
// Should be there, redirect
alert("Erreur au chargement de cette commande. Vous allez être redirigé.");
back();
});
}); });
...@@ -16,6 +16,5 @@ urlpatterns = [ ...@@ -16,6 +16,5 @@ urlpatterns = [
url(r'^reception_qtiesValidated', views.reception_qtiesValidated), url(r'^reception_qtiesValidated', views.reception_qtiesValidated),
url(r'^reception_pricesValidated', views.reception_pricesValidated), url(r'^reception_pricesValidated', views.reception_pricesValidated),
# url(r'^update_order_status/([0-9]+)$', views.tmp_update_order_status), # url(r'^update_order_status/([0-9]+)$', views.tmp_update_order_status),
url(r'^po_process_picking$', views.po_process_picking), url(r'^po_process_picking$', views.po_process_picking)
url(r'^save_order_group$', views.save_order_group)
] ]
...@@ -27,17 +27,12 @@ def as_text(value): ...@@ -27,17 +27,12 @@ def as_text(value):
def home(request): def home(request):
"""Page de selection de la commande suivant un fournisseurs""" """Page de selection de la commande suivant un fournisseurs"""
# Get grouped orders stored on the server
try:
with open('temp/grouped_order.json', 'r') as json_file:
saved_groups = json.load(json_file)
except Exception:
saved_groups = []
context = { context = {
'title': 'Reception', 'title': 'Reception',
'merge_orders_pswd': settings.RECEPTION_MERGE_ORDERS_PSWD, 'merge_orders_pswd': settings.RECEPTION_MERGE_ORDERS_PSWD,
'server_stored_groups' : saved_groups 'couchdb_server': settings.COUCHDB['url'],
'db': settings.COUCHDB['dbs']['reception'],
'POUCHDB_VERSION': getattr(settings, 'POUCHDB_VERSION', '')
} }
template = loader.get_template('reception/index.html') template = loader.get_template('reception/index.html')
...@@ -75,10 +70,14 @@ def get_list_orders(request): ...@@ -75,10 +70,14 @@ def get_list_orders(request):
def produits(request, id): def produits(request, id):
""" Gets Order details """ """ Gets Order details """
context = {'title': 'Réception des produits', context = {
"TOOLS_SERVER": settings.TOOLS_SERVER, 'title': 'Réception des produits',
"DISPLAY_AUTRES": getattr(settings, 'DISPLAY_COL_AUTRES', True), "TOOLS_SERVER": settings.TOOLS_SERVER,
} 'couchdb_server': settings.COUCHDB['url'],
'db': settings.COUCHDB['dbs']['reception'],
'POUCHDB_VERSION': getattr(settings, 'POUCHDB_VERSION', ''),
"DISPLAY_AUTRES": getattr(settings, 'DISPLAY_COL_AUTRES', True),
}
fixed_barcode_prefix = '0490' fixed_barcode_prefix = '0490'
if hasattr(settings, 'RECEPTION_PB'): if hasattr(settings, 'RECEPTION_PB'):
...@@ -133,40 +132,6 @@ def data_validation(request): ...@@ -133,40 +132,6 @@ def data_validation(request):
coop_logger.error("Orders data validation : %s", str(e)) coop_logger.error("Orders data validation : %s", str(e))
return JsonResponse({'error': str(e)}, status=500) return JsonResponse({'error': str(e)}, status=500)
def save_order_group(request):
"""
When an order group is created, save it to force group these orders later.
Raise an error if one of the orders is already in a group.
"""
order_ids = json.loads(request.body.decode())
try:
try:
# Check if any of the orders attempted to be grouped is already in a group
with open('temp/grouped_order.json', 'r') as json_file:
saved_groups = json.load(json_file)
for order_id in order_ids:
for group in saved_groups:
if order_id in group:
# Found in a group, stop
msg = 'One of the orders is already in a group'
return JsonResponse({'message': msg}, status=409)
except Exception:
saved_groups = []
# All good, save group
with open('temp/grouped_order.json', 'w+') as json_file:
saved_groups.append(order_ids)
json.dump(saved_groups, json_file)
msg = 'Group saved'
return JsonResponse({'message': msg})
except Exception as e:
print(str(e))
return JsonResponse({'message': str(e)}, status=500)
def update_orders(request): def update_orders(request):
"""Update orders lines: quantity and unit prices""" """Update orders lines: quantity and unit prices"""
...@@ -257,6 +222,7 @@ def update_orders(request): ...@@ -257,6 +222,7 @@ def update_orders(request):
# Remove order's group # Remove order's group
try: try:
# TODO remove from couchdb orders & group (here?)
if os.path.exists('temp/grouped_order.json'): if os.path.exists('temp/grouped_order.json'):
with open('temp/grouped_order.json', 'r') as json_file: with open('temp/grouped_order.json', 'r') as json_file:
saved_groups = json.load(json_file) saved_groups = json.load(json_file)
...@@ -272,6 +238,7 @@ def update_orders(request): ...@@ -272,6 +238,7 @@ def update_orders(request):
except Exception as e: except Exception as e:
# no saved groups # no saved groups
print(str(e)) print(str(e))
# TODO else if first step, save first step data (here?)
else: else:
coop_logger.error("update_orders errors : %s", str(errors)) coop_logger.error("update_orders errors : %s", str(errors))
rep = JsonResponse(answer_data, safe=False) rep = JsonResponse(answer_data, safe=False)
...@@ -281,7 +248,7 @@ def update_orders(request): ...@@ -281,7 +248,7 @@ def update_orders(request):
# """ Method used for tests purposes: Reset an order status """ # """ Method used for tests purposes: Reset an order status """
# m = CagetteReception(id_po) # m = CagetteReception(id_po)
# m.update_order_status(id_po, False) # m.update_order_status(id_po, False)
#
# return JsonResponse({'id_po': id_po}) # return JsonResponse({'id_po': id_po})
def save_error_report(request): def save_error_report(request):
...@@ -300,7 +267,7 @@ def save_error_report(request): ...@@ -300,7 +267,7 @@ def save_error_report(request):
orders_partner = "" orders_partner = ""
group_ids = [] group_ids = []
for i, order in enumerate(data['orders']) : for i, order in enumerate(data['orders']) :
# list of temp files: 1 report per reception # list of temp files: 1 report per order & group
data['orders'][i]['temp_file_name'] = "temp/" + order['name'] + "_rapport-reception_temp.xlsx" data['orders'][i]['temp_file_name'] = "temp/" + order['name'] + "_rapport-reception_temp.xlsx"
group_ids.append(order['id']) group_ids.append(order['id'])
...@@ -391,7 +358,7 @@ def save_error_report(request): ...@@ -391,7 +358,7 @@ def save_error_report(request):
# Create report with data from steps 1 & 2 # Create report with data from steps 1 & 2
else: elif data['update_type'] == 'br_valid':
for order in data['orders']: for order in data['orders']:
# Read step 1 data from temp file # Read step 1 data from temp file
data_qties = {} data_qties = {}
...@@ -423,7 +390,8 @@ def save_error_report(request): ...@@ -423,7 +390,8 @@ def save_error_report(request):
# Clear step 1 temp file # Clear step 1 temp file
os.remove(order['temp_file_name']) os.remove(order['temp_file_name'])
except: except:
data_comment_s1 = "Rapport de la première étape absent !" data_comment_s1 = "Données de la première étape absentes !"
# Add data from step 2 # Add data from step 2
data_full = [] data_full = []
error_total = 0 error_total = 0
...@@ -484,6 +452,7 @@ def save_error_report(request): ...@@ -484,6 +452,7 @@ def save_error_report(request):
# no updated products, do nothing # no updated products, do nothing
print("Error while updating products") print("Error while updating products")
print(exp) print(exp)
# Add remaining products, the ones edited only in step 1 # Add remaining products, the ones edited only in step 1
for product in data_qties.values(): for product in data_qties.values():
item = { item = {
......
...@@ -11,7 +11,6 @@ ...@@ -11,7 +11,6 @@
<script type="text/javascript" src="{% static 'js/datatables/dataTables.plugins.js' %}"></script> <script type="text/javascript" src="{% static 'js/datatables/dataTables.plugins.js' %}"></script>
<script type="text/javascript" src="{% static 'js/moment.min.js' %}"></script> <script type="text/javascript" src="{% static 'js/moment.min.js' %}"></script>
<script type="text/javascript" src="{% static 'js/datatables/dataTables.plugin.moment_sorting.js' %}"></script> <script type="text/javascript" src="{% static 'js/datatables/dataTables.plugin.moment_sorting.js' %}"></script>
<script type="text/javascript" src="{% static 'js/reception_index.js' %}?v="></script>
{% endblock %} {% endblock %}
{% block content %} {% block content %}
...@@ -31,7 +30,6 @@ ...@@ -31,7 +30,6 @@
<div id="groups_items"></div> <div id="groups_items"></div>
</div> </div>
<br>
<div id="grouped_action"> <div id="grouped_action">
<button type="button" class='btn--primary' id='group_action' onclick="group_action()" hidden>Compter les produits des commandes sélectionnées</button> <button type="button" class='btn--primary' id='group_action' onclick="group_action()" hidden>Compter les produits des commandes sélectionnées</button>
</div> </div>
...@@ -48,13 +46,30 @@ ...@@ -48,13 +46,30 @@
<p>Êtez-vous sûr ?</p> <p>Êtez-vous sûr ?</p>
<hr /> <hr />
</div> </div>
<div id="modal_order_access">
<h3>Attention !</h3>
<br/>
<p class="order_modified_msg">
Un autre navigateur a commencé à réceptionner cette commande il y a <span class="order_last_update"></span>.
</p><br/>
<p>
Si quelqu'un d'autre que vous est à l'origine de cette opération et que celle-ci est récente,
nous conseillons fortement de ne pas accéder à la commande afin d'éviter les conflits.
</p><br/>
<p>Voulez-vous quand même y accéder ?</p>
<hr/>
</div>
</div> </div>
<br/> <br/>
<script src="{% static "js/all_common.js" %}?v="></script> <script src="{% static "js/all_common.js" %}?v="></script>
<script src="{% static 'js/pouchdb.min'|add:POUCHDB_VERSION|add:'.js' %}"></script>
<script type="text/javascript"> <script type="text/javascript">
var merge_orders_pswd = '{{merge_orders_pswd}}'; var merge_orders_pswd = '{{merge_orders_pswd}}';
var server_stored_groups = {{server_stored_groups}}; var couchdb_dbname = '{{db}}';
var couchdb_server = '{{couchdb_server}}' + couchdb_dbname;
</script> </script>
<script src="{% static "js/common.js" %}?v="></script> <script type="text/javascript" src="{% static 'js/reception_index.js' %}?v="></script>
{% endblock %} {% endblock %}
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
{% endif %} {% endif %}
<div class="page_body"> <div class="page_body">
<header class="flex-container"> <header class="flex-container">
<button class="right btn--danger" onclick="back()">Retour</button> <button class="right btn--danger" id="back_button">Retour</button>
<div class="w33 arrow-block txtcenter" id="header_step_one"> <div class="w33 arrow-block txtcenter" id="header_step_one">
<h4 id="header_step_one_content">Produits à compter </h4> <h4 id="header_step_one_content">Produits à compter </h4>
</div> </div>
...@@ -180,10 +180,14 @@ ...@@ -180,10 +180,14 @@
</div> </div>
<br/> <br/>
</div> </div>
<script src="{% static 'js/pouchdb.min'|add:POUCHDB_VERSION|add:'.js' %}"></script>
<script type="text/javascript"> <script type="text/javascript">
var tools_server = '{{TOOLS_SERVER}}' var tools_server = '{{TOOLS_SERVER}}'
var fixed_barcode_prefix = '{{FIXED_BARCODE_PREFIX}}' var fixed_barcode_prefix = '{{FIXED_BARCODE_PREFIX}}'
var display_autres = {{DISPLAY_AUTRES}}; var couchdb_dbname = '{{db}}';
var couchdb_server = '{{couchdb_server}}' + couchdb_dbname;
var display_autres = "{{DISPLAY_AUTRES}}";
</script> </script>
<script src="{% static "js/all_common.js" %}?v="></script> <script src="{% static "js/all_common.js" %}?v="></script>
<script src='{% static "js/barcodes.js" %}?v='></script> <script src='{% static "js/barcodes.js" %}?v='></script>
......
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