Commit 130904b7 by Damien Moulard Committed by Alexis Aoun

deal with simultaneous access to same order

parent f7e55202
...@@ -11,11 +11,33 @@ ...@@ -11,11 +11,33 @@
/* - Common */ /* - Common */
.pill {
border-radius: 30px;
min-width: 200px;
min-height: 35px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding: 8px 15px 8px 15px;
margin: 0 10px 5px 0;
}
.disabled {
background-color: #c9cbce;
}
.disabled:hover {
background-color: #a1a2a3;
}
/* - Order selection screen */ /* - Order selection screen */
#new_order_area {
margin-bottom: 40px;
}
#new_order_form { #new_order_form {
margin-top: 20px; margin-top: 20px;
margin-bottom: 30px;
} }
#existing_orders { #existing_orders {
...@@ -25,24 +47,25 @@ ...@@ -25,24 +47,25 @@
flex-wrap: wrap; flex-wrap: wrap;
width: 80%; width: 80%;
margin: 0 auto; margin: 0 auto;
padding-top: 20px; padding-top: 15px;
} }
.order_pill { .order_last_update {
border-radius: 30px; font-weight: bold;
min-width: 200px; }
min-height: 40px;
display: flex; .order_modified_msg {
flex-direction: column; font-size: 2rem;
justify-content: center; color: #e62720;
align-items: center;
padding: 8px;
margin: 0 10px 5px 0;
} }
/* - Main screen */ /* - Main screen */
/* -- Top right action button(s) */ /* -- Top action button(s) */
#back_to_order_selection {
position: absolute;
}
#actions_buttons_area { #actions_buttons_area {
position: absolute; position: absolute;
top: 0; top: 0;
...@@ -108,15 +131,6 @@ ...@@ -108,15 +131,6 @@
.supplier_pill { .supplier_pill {
background-color: #e7e9ed; background-color: #e7e9ed;
border-radius: 50px;
width: 200px;
min-height: 35px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding: 8px;
margin-right: 10px;
} }
.remove_supplier_icon { .remove_supplier_icon {
......
...@@ -7,12 +7,19 @@ var suppliers_list = [], ...@@ -7,12 +7,19 @@ var suppliers_list = [],
sync = null, sync = null,
order_doc = { order_doc = {
_id: null, _id: null,
last_update : {
timestamp: null,
fingerprint: null,
},
products: [], products: [],
selected_suppliers: [], selected_suppliers: [],
selected_rows: [] selected_rows: []
}; },
fingerprint = null;
/* - UTILS */
/** /**
* Reset data that changes between screens * Reset data that changes between screens
*/ */
...@@ -22,11 +29,40 @@ function reset_data() { ...@@ -22,11 +29,40 @@ function reset_data() {
selected_rows = [], selected_rows = [],
order_doc = { order_doc = {
_id: null, _id: null,
last_update : {
timestamp: null,
fingerprint: null,
},
products: [], products: [],
selected_suppliers: [] selected_suppliers: []
}; };
} }
/**
* Difference between two dates
* @param {Date} date1
* @param {Date} date2
* @returns difference object
*/
function dates_diff(date1, date2) {
var diff = {}
var tmp = date2 - date1;
tmp = Math.floor(tmp/1000);
diff.sec = tmp % 60;
tmp = Math.floor((tmp-diff.sec)/60);
diff.min = tmp % 60;
tmp = Math.floor((tmp-diff.min)/60);
diff.hours = tmp % 24;
tmp = Math.floor((tmp-diff.hours)/24);
diff.days = tmp;
return diff;
}
/* - SUPPLIERS */ /* - SUPPLIERS */
/** /**
...@@ -494,13 +530,6 @@ function display_products() { ...@@ -494,13 +530,6 @@ function display_products() {
if (cell.hasClass("supplier_input_cell")) { if (cell.hasClass("supplier_input_cell")) {
if (cell.text() == "X") { if (cell.text() == "X") {
cell.addClass('product_not_from_supplier'); cell.addClass('product_not_from_supplier');
} else {
// TODO: supplier shortage cell coloring, when supplier shortage usecase is defined
// let val = parseFloat(cell.find('.product_qty_input').val());
// if (!isNaN(val) && val < 0) {
// cell.addClass( 'product_supplier_shortage' );
// }
} }
} }
} }
...@@ -554,7 +583,7 @@ function display_products() { ...@@ -554,7 +583,7 @@ function display_products() {
}); });
// Select row(s) on checkbox change // Select row(s) on checkbox change
$('#products_table').on('click', 'thead th #select_all_products_cb', function () { $(products_table.table().header()).on('click', 'th #select_all_products_cb', function () {
if (this.checked) { if (this.checked) {
selected_rows = []; selected_rows = [];
products_table.rows().every(function() { products_table.rows().every(function() {
...@@ -619,6 +648,7 @@ function update_main_screen() { ...@@ -619,6 +648,7 @@ function update_main_screen() {
$('#products_table').off('click', 'tbody td .select_product_cb'); $('#products_table').off('click', 'tbody td .select_product_cb');
$(".remove_supplier_icon").off(); $(".remove_supplier_icon").off();
$(".order_name_container").text(order_doc._id);
display_suppliers(); display_suppliers();
display_products(); display_products();
...@@ -646,37 +676,23 @@ function update_order_selection_screen() { ...@@ -646,37 +676,23 @@ function update_order_selection_screen() {
$(".order_pill").off(); $(".order_pill").off();
let existing_orders_container = $("#existing_orders"); let existing_orders_container = $("#existing_orders");
existing_orders_container.empty(); existing_orders_container.empty();
dbc.allDocs({ dbc.allDocs({
include_docs: true include_docs: true
}).then(function (result) { }).then(function (result) {
if (result.rows.length === 0) {
existing_orders_container.append(`<i>Aucune commande en cours...</i>`);
} else {
for (let row of result.rows) { for (let row of result.rows) {
let template = $("#templates #order_pill_template"); let template = $("#templates #order_pill_template");
template.find(".pill_order_name").text(row.id); template.find(".pill_order_name").text(row.id);
existing_orders_container.append(template.html()); existing_orders_container.append(template.html());
} }
$(".order_pill").on("click", function() { $(".order_pill").on("click", order_pill_on_click);
let order_name_container = $(this).find('.pill_order_name'); }
let doc_id = $(order_name_container).text();
dbc.get(doc_id).then((doc) => {
order_doc = doc;
products = order_doc.products;
selected_suppliers = order_doc.selected_suppliers;
update_main_screen();
switch_screen();
})
.catch(function (err) {
alert('Erreur lors de la récupération de la commande. Si l\'erreur persiste, contactez un administrateur svp.');
console.log(err);
});
});
}) })
.catch(function (err) { .catch(function (err) {
alert('Erreur lors de la synchronisation des commandes. Vous pouvez créer une nouvelle commande.'); alert('Erreur lors de la synchronisation des commandes. Vous pouvez créer une nouvelle commande.');
...@@ -718,6 +734,65 @@ function switch_screen(direction = 'main_screen') { ...@@ -718,6 +734,65 @@ function switch_screen(direction = 'main_screen') {
/* - ORDER */ /* - ORDER */
function goto_main_screen(doc) {
order_doc = doc;
products = order_doc.products;
selected_suppliers = order_doc.selected_suppliers;
update_order()
update_main_screen();
switch_screen();
}
function back() {
reset_data();
update_order_selection_screen();
switch_screen('order_selection');
}
/**
* Event fct: on click on an order button
*/
function order_pill_on_click() {
let order_name_container = $(this).find('.pill_order_name');
let doc_id = $(order_name_container).text();
dbc.get(doc_id).then((doc) => {
if (doc.last_update.fingerprint !== fingerprint) {
time_diff = dates_diff(new Date(doc.last_update.timestamp), new Date())
diff_str = ``
if (time_diff.days !== 0) {
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`
let modal_order_access = $('#templates #modal_order_access');
modal_order_access.find(".order_last_update").text(diff_str);
openModal(
modal_order_access.html(),
() => {
goto_main_screen(doc)
},
'Valider'
);
} else {
goto_main_screen(doc)
}
})
.catch(function (err) {
alert('Erreur lors de la récupération de la commande. Si l\'erreur persiste, contactez un administrateur svp.');
console.log(err);
});
}
/** /**
* Create an order in couchdb if the name doesn't exist * Create an order in couchdb if the name doesn't exist
*/ */
...@@ -739,12 +814,18 @@ function create_order() { ...@@ -739,12 +814,18 @@ function create_order() {
} }
/** /**
* Update an existing order in couchdb * Update order data of an existing order in couchdb
*/ */
function update_order() { function update_order() {
order_doc.products = products; order_doc.products = products;
order_doc.selected_suppliers = selected_suppliers; order_doc.selected_suppliers = selected_suppliers;
// Save that current user last updated the order
order_doc.last_update = {
timestamp: Date.now(),
fingerprint: fingerprint,
};
dbc.put(order_doc, function callback(err, result) { dbc.put(order_doc, function callback(err, result) {
if (!err && result !== undefined) { if (!err && result !== undefined) {
order_doc._rev = result.rev; order_doc._rev = result.rev;
...@@ -757,6 +838,7 @@ function update_order() { ...@@ -757,6 +838,7 @@ function update_order() {
$(document).ready(function() { $(document).ready(function() {
fingerprint = new Fingerprint({canvas: true}).get();
$.ajaxSetup({ headers: { "X-CSRFToken": getCookie('csrftoken') } }); $.ajaxSetup({ headers: { "X-CSRFToken": getCookie('csrftoken') } });
openModal(); openModal();
...@@ -770,10 +852,27 @@ $(document).ready(function() { ...@@ -770,10 +852,27 @@ $(document).ready(function() {
}); });
sync.on('change', function (info) { sync.on('change', function (info) {
console.log(info); if (info.direction === "pull") {
// TODO get current order new data (ou prévenir de changements ? -> pas changer les infos brutalement sans prévenir) for (const doc of info.change.docs) {
// TODO alert if current doc was deleted // If current order was modified somewhere else
if (order_doc._id === doc._id && order_doc._rev !== doc._rev) {
$.notify(
"Un autre navigateur est en train de modifier cette commande !",
{
globalPosition:"top right",
className: "error"
}
);
back();
break;
}
}
}
}).on('error', function (err) { }).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('erreur sync');
console.log(err); console.log(err);
}); });
...@@ -789,9 +888,7 @@ $(document).ready(function() { ...@@ -789,9 +888,7 @@ $(document).ready(function() {
}); });
$('#back_to_order_selection').on('click', function() { $('#back_to_order_selection').on('click', function() {
reset_data(); back();
update_order_selection_screen();
switch_screen('order_selection');
}); });
// Order selection screen // Order selection screen
......
...@@ -16,14 +16,18 @@ ...@@ -16,14 +16,18 @@
{% block content %} {% block content %}
<div class="page_body"> <div class="page_body">
<div id="select_order_content" class="page_content txtcenter"> <div id="select_order_content" class="page_content txtcenter">
<div id="new_order_area">
<h2>Créer une nouvelle commande</h2> <h2>Créer une nouvelle commande</h2>
<form id="new_order_form"> <form id="new_order_form">
<input type="text" id="new_order_name" placeholder="Nom de la commande..."> <input type="text" id="new_order_name" placeholder="Nom de la commande...">
<button type="submit" class="btn btn--primary">Valider</button> <button type="submit" class="btn btn--primary">Valider</button>
</form> </form>
</div>
<div id="existing_orders_area">
<h2>Ou, continuer une commande existante</h2> <h2>Ou, continuer une commande existante</h2>
<div id="existing_orders"></div> <div id="existing_orders"></div>
</div> </div>
</div>
<div id="main_content" class="page_content" style="display:none;"> <div id="main_content" class="page_content" style="display:none;">
<div id="back_to_order_selection"> <div id="back_to_order_selection">
...@@ -35,6 +39,7 @@ ...@@ -35,6 +39,7 @@
<div class="header txtcenter"> <div class="header txtcenter">
<h1>Aide à la commande</h1> <h1>Aide à la commande</h1>
<i>Commande : <span class="order_name_container"></span></i>
</div> </div>
<div class="txtcenter" id="supplier_form_container"> <div class="txtcenter" id="supplier_form_container">
...@@ -55,7 +60,7 @@ ...@@ -55,7 +60,7 @@
<div id="templates" style="display:none;"> <div id="templates" style="display:none;">
<div id="supplier_pill_template"> <div id="supplier_pill_template">
<div class="supplier_pill"> <div class="pill supplier_pill">
<div class="supplier_name_container"> <div class="supplier_name_container">
<span class="pill_supplier_name"></span> <span class="pill_supplier_name"></span>
<i class="fas fa-times remove_supplier_icon"></i> <i class="fas fa-times remove_supplier_icon"></i>
...@@ -69,6 +74,20 @@ ...@@ -69,6 +74,20 @@
</div> </div>
</div> </div>
<div id="modal_order_access">
<h3>Attention !</h3>
<br/>
<p class="order_modified_msg">
Un autre navigateur a modifié 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 la modification 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 id="modal_remove_supplier"> <div id="modal_remove_supplier">
<h3>Attention !</h3> <h3>Attention !</h3>
<p> <p>
......
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