Commit e7f80fe7 by Damien Moulard

deal with simultaneous access to same order

parent 979f1cd2
Pipeline #1056 passed with stage
in 20 seconds
......@@ -11,11 +11,33 @@
/* - 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 */
#new_order_area {
margin-bottom: 40px;
}
#new_order_form {
margin-top: 20px;
margin-bottom: 30px;
}
#existing_orders {
......@@ -25,24 +47,25 @@
flex-wrap: wrap;
width: 80%;
margin: 0 auto;
padding-top: 20px;
padding-top: 15px;
}
.order_pill {
border-radius: 30px;
min-width: 200px;
min-height: 40px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding: 8px;
margin: 0 10px 5px 0;
.order_last_update {
font-weight: bold;
}
.order_modified_msg {
font-size: 2rem;
color: #e62720;
}
/* - Main screen */
/* -- Top right action button(s) */
/* -- Top action button(s) */
#back_to_order_selection {
position: absolute;
}
#actions_buttons_area {
position: absolute;
top: 0;
......@@ -108,15 +131,6 @@
.supplier_pill {
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 {
......
......@@ -7,12 +7,19 @@ var suppliers_list = [],
sync = null,
order_doc = {
_id: null,
last_update : {
timestamp: null,
fingerprint: null,
},
products: [],
selected_suppliers: [],
selected_rows: []
};
},
fingerprint = null;
/* - UTILS */
/**
* Reset data that changes between screens
*/
......@@ -22,11 +29,40 @@ function reset_data() {
selected_rows = [],
order_doc = {
_id: null,
last_update : {
timestamp: null,
fingerprint: null,
},
products: [],
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 */
/**
......@@ -494,13 +530,6 @@ function display_products() {
if (cell.hasClass("supplier_input_cell")) {
if (cell.text() == "X") {
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() {
});
// 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) {
selected_rows = [];
products_table.rows().every(function() {
......@@ -619,6 +648,7 @@ function update_main_screen() {
$('#products_table').off('click', 'tbody td .select_product_cb');
$(".remove_supplier_icon").off();
$(".order_name_container").text(order_doc._id);
display_suppliers();
display_products();
......@@ -646,37 +676,23 @@ function update_order_selection_screen() {
$(".order_pill").off();
let existing_orders_container = $("#existing_orders");
existing_orders_container.empty();
dbc.allDocs({
include_docs: true
}).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) {
let template = $("#templates #order_pill_template");
template.find(".pill_order_name").text(row.id);
existing_orders_container.append(template.html());
}
$(".order_pill").on("click", function() {
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);
});
});
$(".order_pill").on("click", order_pill_on_click);
}
})
.catch(function (err) {
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') {
/* - 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
*/
......@@ -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() {
order_doc.products = products;
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) {
if (!err && result !== undefined) {
order_doc._rev = result.rev;
......@@ -757,6 +838,7 @@ function update_order() {
$(document).ready(function() {
fingerprint = new Fingerprint({canvas: true}).get();
$.ajaxSetup({ headers: { "X-CSRFToken": getCookie('csrftoken') } });
openModal();
......@@ -770,10 +852,27 @@ $(document).ready(function() {
});
sync.on('change', function (info) {
console.log(info);
// TODO get current order new data (ou prévenir de changements ? -> pas changer les infos brutalement sans prévenir)
// TODO alert if current doc was deleted
if (info.direction === "pull") {
for (const doc of info.change.docs) {
// 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) {
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);
});
......@@ -789,9 +888,7 @@ $(document).ready(function() {
});
$('#back_to_order_selection').on('click', function() {
reset_data();
update_order_selection_screen();
switch_screen('order_selection');
back();
});
// Order selection screen
......
......@@ -16,14 +16,18 @@
{% block content %}
<div class="page_body">
<div id="select_order_content" class="page_content txtcenter">
<div id="new_order_area">
<h2>Créer une nouvelle commande</h2>
<form id="new_order_form">
<input type="text" id="new_order_name" placeholder="Nom de la commande...">
<button type="submit" class="btn btn--primary">Valider</button>
</form>
</div>
<div id="existing_orders_area">
<h2>Ou, continuer une commande existante</h2>
<div id="existing_orders"></div>
</div>
</div>
<div id="main_content" class="page_content" style="display:none;">
<div id="back_to_order_selection">
......@@ -35,6 +39,7 @@
<div class="header txtcenter">
<h1>Aide à la commande</h1>
<i>Commande : <span class="order_name_container"></span></i>
</div>
<div class="txtcenter" id="supplier_form_container">
......@@ -55,7 +60,7 @@
<div id="templates" style="display:none;">
<div id="supplier_pill_template">
<div class="supplier_pill">
<div class="pill supplier_pill">
<div class="supplier_name_container">
<span class="pill_supplier_name"></span>
<i class="fas fa-times remove_supplier_icon"></i>
......@@ -69,6 +74,20 @@
</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">
<h3>Attention !</h3>
<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