Commit 16387e04 by Damien Moulard Committed by Alexis Aoun

sync with couchdb to keep data

parent 2063ad4f
...@@ -2,16 +2,56 @@ ...@@ -2,16 +2,56 @@
position: relative; position: relative;
} }
#form_container { .page_content {
margin-top: 30px; position: absolute;
top: 0;
left: 0;
right: 0;
} }
#products_table_filter{ /* - Common */
text-align: right !important;
/* - Order selection screen */
#new_order_form {
margin-top: 20px;
margin-bottom: 30px;
} }
#products_table_filter input{ #existing_orders {
height: 40px; display: flex;
justify-content: center;
align-items: center;
flex-wrap: wrap;
width: 80%;
margin: 0 auto;
padding-top: 20px;
}
.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;
}
/* - Main screen */
/* -- Top right action button(s) */
#actions_buttons_area {
position: absolute;
top: 0;
right: 0;
}
/* -- Supplier form */
#supplier_form_container {
margin-top: 30px;
} }
#supplier_input { #supplier_input {
...@@ -20,17 +60,13 @@ ...@@ -20,17 +60,13 @@
border-radius: 5px; border-radius: 5px;
} }
.product_qty_input { /* -- Table */
width: 100px; #products_table_filter{
} text-align: right !important;
.product_not_from_supplier {
background-color: #e7e9ed;
cursor: pointer;
} }
.product_name, .supplier_name { #products_table_filter input{
font-weight: bold; height: 40px;
} }
#table_header_select_all{ #table_header_select_all{
...@@ -44,10 +80,24 @@ ...@@ -44,10 +80,24 @@
margin-left: 5px; margin-left: 5px;
} }
.product_qty_input {
width: 100px;
}
.product_not_from_supplier {
background-color: #e7e9ed;
cursor: pointer;
}
.product_name, .supplier_name {
font-weight: bold;
}
.select_product_cb { .select_product_cb {
cursor: pointer; cursor: pointer;
} }
/* -- Suppliers list */
#suppliers_container { #suppliers_container {
display: flex; display: flex;
justify-content: center; justify-content: center;
...@@ -73,10 +123,4 @@ ...@@ -73,10 +123,4 @@
color: red; color: red;
margin-left: 5px; margin-left: 5px;
cursor: pointer; cursor: pointer;
} }
\ No newline at end of file
#actions_buttons_area {
position: absolute;
top: 0;
right: 0;
}
...@@ -2,7 +2,33 @@ var suppliers_list = [], ...@@ -2,7 +2,33 @@ var suppliers_list = [],
products_table = null, products_table = null,
products = [], products = [],
selected_suppliers = [], selected_suppliers = [],
selected_rows = []; selected_rows = [],
dbc = null,
sync = null,
order_doc = {
_id: null,
products: [],
selected_suppliers: [],
selected_rows: []
};
/**
* Reset data that changes between screens
*/
function reset_data() {
products = [],
selected_suppliers = [],
selected_rows = [],
order_doc = {
_id: null,
products: [],
selected_suppliers: [],
selected_rows: []
};
}
/* - SUPPLIERS */
/** /**
* Add a supplier to the selected suppliers list. * Add a supplier to the selected suppliers list.
...@@ -47,8 +73,9 @@ function add_supplier() { ...@@ -47,8 +73,9 @@ function add_supplier() {
contentType: "application/json; charset=utf-8", contentType: "application/json; charset=utf-8",
success: function(data) { success: function(data) {
save_supplier_products(supplier, data.res.products); save_supplier_products(supplier, data.res.products);
update_display(); update_main_screen();
$("#supplier_input").val(""); $("#supplier_input").val("");
update_order();
closeModal(); closeModal();
}, },
error: function(data) { error: function(data) {
...@@ -83,7 +110,8 @@ function remove_supplier(supplier_id) { ...@@ -83,7 +110,8 @@ function remove_supplier(supplier_id) {
// Remove products only associated to this product // Remove products only associated to this product
products = products.filter(product => product.suppliers.length > 0); products = products.filter(product => product.suppliers.length > 0);
update_display(); update_main_screen();
update_order();
} }
...@@ -192,6 +220,84 @@ function is_product_related_to_supplier(product, supplier) { ...@@ -192,6 +220,84 @@ function is_product_related_to_supplier(product, supplier) {
return product.suppliers.find(s => s.id === supplier.id) !== undefined; return product.suppliers.find(s => s.id === supplier.id) !== undefined;
} }
/* - INVENTORY */
/**
* Create an inventory with the selected lines in the table
*/
function generate_inventory() {
if (products_table !== null) {
const selected_data = products_table.rows('.selected').data();
if (selected_data.length == 0) {
alert("Veuillez sélectionner les produits à inventorier en cochant les cases sur la gauche du tableau.");
} else {
data = {
lines: [],
partners_id: [],
type: 'product_templates'
};
for (var i = 0; i < selected_data.length; i++) {
const product = products.find(p => p.id == selected_data[i].id);
data.lines.push(product.id);
for (const supplier of product.suppliers) {
if (data.partners_id.indexOf(supplier.id) === -1) {
data.partners_id.push(supplier.id);
}
}
}
let modal_create_inventory = $('#templates #modal_create_inventory');
modal_create_inventory.find(".inventory_products_count").text(data.lines.length);
openModal(
modal_create_inventory.html(),
() => {
$.ajax({
type: "POST",
url: "/inventory/generate_inventory_list",
dataType: "json",
traditional: true,
contentType: "application/json; charset=utf-8",
data: JSON.stringify(data),
success: () => {
unselect_all_rows();
// Give time for modal to fade
setTimeout(function() {
$.notify(
"Inventaire créé !",
{
globalPosition:"top left",
className: "success"
}
);
}, 500);
},
error: function(data) {
let msg = "erreur serveur lors de la création de l'inventaire".
err = {msg: msg, ctx: 'generate_inventory'};
if (typeof data.responseJSON != 'undefined' && typeof data.responseJSON.error != 'undefined') {
err.msg += ' : ' + data.responseJSON.error;
}
report_JS_error(err, 'orders');
alert("Erreur lors de la création de l'inventaire. Réessayez plus tard.");
}
});
},
'Valider'
);
}
}
}
/* - DISPLAY */
/** /**
* Create a string to represent a supplier column in product data * Create a string to represent a supplier column in product data
* @returns String * @returns String
...@@ -207,9 +313,10 @@ function display_suppliers() { ...@@ -207,9 +313,10 @@ function display_suppliers() {
let supplier_container = $("#suppliers_container"); let supplier_container = $("#suppliers_container");
$("#suppliers_container").empty(); $("#suppliers_container").empty();
$(".remove_supplier_icon").off();
for (supplier of selected_suppliers) { for (supplier of selected_suppliers) {
let template = $("#templates #supplier_pill"); let template = $("#templates #supplier_pill_template");
template.find(".pill_supplier_name").text(supplier.display_name); template.find(".pill_supplier_name").text(supplier.display_name);
template.find(".remove_supplier_icon").attr('id', `remove_supplier_${supplier.id}`); template.find(".remove_supplier_icon").attr('id', `remove_supplier_${supplier.id}`);
...@@ -236,8 +343,6 @@ function display_suppliers() { ...@@ -236,8 +343,6 @@ function display_suppliers() {
}); });
} }
/* DATATABLE */
/** /**
* @param {array} product_ids if set, return formatted data for these products only * @param {array} product_ids if set, return formatted data for these products only
* @returns Array of formatted data for datatable data setup * @returns Array of formatted data for datatable data setup
...@@ -354,13 +459,13 @@ function prepare_datatable_columns() { ...@@ -354,13 +459,13 @@ function prepare_datatable_columns() {
* Display the Datatable containing the products * Display the Datatable containing the products
*/ */
function display_products() { function display_products() {
// Empty datatable if already exists
if (products.length == 0) { if (products.length == 0) {
$('.main').hide(); $('.main').hide();
return -1; return -1;
} }
// Empty datatable if it already exists
if (products_table) { if (products_table) {
products_table.clear().destroy(); products_table.clear().destroy();
$('#products_table').empty(); $('#products_table').empty();
...@@ -417,6 +522,7 @@ function display_products() { ...@@ -417,6 +522,7 @@ function display_products() {
const supplier_id = id_split[3]; const supplier_id = id_split[3];
save_product_supplier_qty(prod_id, supplier_id, val); save_product_supplier_qty(prod_id, supplier_id, val);
update_order();
} }
}); });
...@@ -504,13 +610,15 @@ function unselect_all_rows() { ...@@ -504,13 +610,15 @@ function unselect_all_rows() {
} }
/** /**
* Update DOM display * Update DOM display on main screen
*/ */
function update_display() { function update_main_screen() {
// Remove listener before recreating them // Remove listener before recreating them
$('#products_table').off('input', 'tbody td .product_qty_input');
$('#products_table').off('click', 'tbody .product_not_from_supplier'); $('#products_table').off('click', 'tbody .product_not_from_supplier');
$('#products_table').off('click', 'thead th #select_all_products_cb'); $('#products_table').off('click', 'thead th #select_all_products_cb');
$('#products_table').off('click', 'tbody td .select_product_cb'); $('#products_table').off('click', 'tbody td .select_product_cb');
$(".remove_supplier_icon").off();
display_suppliers(); display_suppliers();
display_products(); display_products();
...@@ -531,82 +639,172 @@ function update_display() { ...@@ -531,82 +639,172 @@ function update_display() {
} }
} }
function generate_inventory() { /**
if (products_table !== null) { * Update DOM display on the order selection screen
const selected_data = products_table.rows('.selected').data(); */
function update_order_selection_screen() {
// Remove listener before recreating them
$(".order_pill").off();
if (selected_data.length == 0) { let existing_orders_container = $("#existing_orders");
alert("Veuillez sélectionner les produits à inventorier en cochant les cases sur la gauche du tableau.");
} else {
data = {
lines: [],
partners_id: [],
type: 'product_templates'
};
for (var i = 0; i < selected_data.length; i++) { existing_orders_container.empty();
const product = products.find(p => p.id == selected_data[i].id);
data.lines.push(product.id); dbc.allDocs({
for (const supplier of product.suppliers) { include_docs: true
if (data.partners_id.indexOf(supplier.id) === -1) { }).then(function (result) {
data.partners_id.push(supplier.id); for (let row of result.rows) {
} let template = $("#templates #order_pill_template");
}
}
let modal_create_inventory = $('#templates #modal_create_inventory'); template.find(".pill_order_name").text(row.id);
modal_create_inventory.find(".inventory_products_count").text(data.lines.length); existing_orders_container.append(template.html());
}
openModal( $(".order_pill").on("click", function() {
modal_create_inventory.html(), let order_name_container = $(this).find('.pill_order_name');
() => { let doc_id = $(order_name_container).text();
$.ajax({
type: "POST", dbc.get(doc_id).then((doc) => {
url: "/inventory/generate_inventory_list", order_doc = doc;
dataType: "json", products = order_doc.products;
traditional: true, selected_suppliers = order_doc.selected_suppliers;
contentType: "application/json; charset=utf-8", selected_rows = order_doc.selected_rows;
data: JSON.stringify(data),
success: () => { update_main_screen();
unselect_all_rows(); 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) {
alert('Erreur lors de la synchronisation des commandes. Vous pouvez créer une nouvelle commande.');
console.log(err);
});
}
// Give time for modal to fade /**
setTimeout(function() { * Switch screen between order selection & main screens
$.notify( * @param {String} direction target screen
"Inventaire créé !", */
{ function switch_screen(direction = 'main_screen') {
globalPosition:"top left", let oldBox = null;
className: "success" let newBox = null;
} let outerWidth = null;
);
}, 500);
},
error: function(data) {
let msg = "erreur serveur lors de la création de l'inventaire".
err = {msg: msg, ctx: 'generate_inventory'};
if (typeof data.responseJSON != 'undefined' && typeof data.responseJSON.error != 'undefined') { if (direction == 'main_screen') {
err.msg += ' : ' + data.responseJSON.error; oldBox = $("#select_order_content");
} newBox = $("#main_content");
report_JS_error(err, 'orders');
alert("Erreur lors de la création de l'inventaire. Réessayez plus tard."); outerWidth = oldBox.outerWidth(true);
} } else {
}); oldBox = $("#main_content");
}, newBox = $("#select_order_content");
'Valider'
); outerWidth = - oldBox.outerWidth(true);
}
} }
// Display the new box and place it on the right of the screen
newBox.css({ "left": outerWidth + "px", "right": -outerWidth + "px", "display": "" });
// Make the old content slide to the left
oldBox.animate({ "left": -outerWidth + "px", "right": outerWidth + "px" }, 800, function() {
// Hide old content after animation
oldBox.css({ "left": "", "right": "", "display": "none" });
});
// Slide new box to regular place
newBox.animate({ "left": "", "right": "" }, 800);
}
/* - ORDER */
/**
* Create an order in couchdb if the name doesn't exist
*/
function create_order() {
const order_name = $("#new_order_name").val();
order_doc._id = order_name;
dbc.put(order_doc, function callback(err, result) {
if (!err) {
order_doc._rev = result.rev;
switch_screen();
} else {
if (err.status == 409) {
alert("Une commande porte déjà ce nom !");
}
console.log(err);
}
});
} }
/**
* Update an existing order in couchdb
*/
function update_order() {
order_doc.products = products;
order_doc.selected_suppliers = selected_suppliers;
order_doc.selected_rows = selected_rows;
dbc.put(order_doc, function callback(err, result) {
if (!err && result !== undefined) {
order_doc._rev = result.rev;
} else {
alert("Erreur lors de la sauvegarde de la commande... Si l'erreur persiste contactez un administrateur svp.");
console.log(err);
}
});
}
$(document).ready(function() { $(document).ready(function() {
$.ajaxSetup({ headers: { "X-CSRFToken": getCookie('csrftoken') } }); $.ajaxSetup({ headers: { "X-CSRFToken": getCookie('csrftoken') } });
openModal(); openModal();
// 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) {
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
}).on('error', function (err) {
console.log('erreur sync');
console.log(err);
});
// Main screen listeners
$("#supplier_form").on("submit", function(e) {
e.preventDefault();
add_supplier();
});
$("#do_inventory").on("click", function() {
generate_inventory();
});
$('#back_to_order_selection').on('click', function() {
reset_data();
update_order_selection_screen();
switch_screen('order_selection');
});
// Order selection screen
update_order_selection_screen();
$("#new_order_form").on("submit", function(e) {
e.preventDefault();
create_order();
});
// Get suppliers // Get suppliers
$.ajax({ $.ajax({
type: 'GET', type: 'GET',
...@@ -635,13 +833,4 @@ $(document).ready(function() { ...@@ -635,13 +833,4 @@ $(document).ready(function() {
alert('Erreur lors de la récupération des fournisseurs, rechargez la page plus tard'); alert('Erreur lors de la récupération des fournisseurs, rechargez la page plus tard');
} }
}); });
$("#supplier_form").on("submit", function(e) {
e.preventDefault();
add_supplier();
});
$("#do_inventory").on("click", function() {
generate_inventory();
});
}); });
...@@ -16,6 +16,8 @@ def index(request): ...@@ -16,6 +16,8 @@ def index(request):
def helper(request): def helper(request):
context = { context = {
'title': 'Aide à la commande', 'title': 'Aide à la commande',
'couchdb_server': settings.COUCHDB['url'],
'db': settings.COUCHDB['dbs']['orders']
} }
template = loader.get_template('orders/helper.html') template = loader.get_template('orders/helper.html')
......
...@@ -19,7 +19,8 @@ COUCHDB = { ...@@ -19,7 +19,8 @@ COUCHDB = {
'member': 'coops', 'member': 'coops',
'inventory': 'inventory', 'inventory': 'inventory',
'envelops': 'envelop', 'envelops': 'envelop',
'shop': 'shopping_carts' 'shop': 'shopping_carts',
'orders': 'orders_test'
} }
} }
......
...@@ -15,70 +15,97 @@ ...@@ -15,70 +15,97 @@
{% block content %} {% block content %}
<div class="page_body"> <div class="page_body">
<div id="actions_buttons_area"> <div id="select_order_content" class="page_content txtcenter">
<button type="button" class='btn--primary' id="do_inventory">Faire un inventaire</button> <h2>Créer une nouvelle commande</h2>
</div> <form id="new_order_form">
<input type="text" id="new_order_name" placeholder="Nom de la commande...">
<div class="header txtcenter"> <button type="submit" class="btn btn--primary">Valider</button>
<h1>Aide à la commande</h1>
</div>
<div class="txtcenter" id="form_container">
<form action="javascript:;" id="supplier_form">
<input type="text" name="supplier" id="supplier_input" placeholder="Rechercher un fournisseur par son nom">
<button type="submit" class='btn--primary'>Ajouter le fournisseur</button>
</form> </form>
<h2>Ou, continuer une commande existante</h2>
<div id="existing_orders"></div>
</div> </div>
<div class="txtcenter" id="suppliers_container"></div> <div id="main_content" class="page_content" style="display:none;">
<div id="back_to_order_selection">
<div class="main" style="display:none;"> <button type="button" class="btn--danger"><i class="fas fa-arrow-left"></i>&nbsp; Retour</button>
<div class="table_area">
<table id="products_table" class="display" cellspacing="0" width="100%"></table>
</div> </div>
</div> <div id="actions_buttons_area">
</div> <button type="button" class='btn--primary' id="do_inventory">Faire un inventaire</button>
</div>
<div id="templates" style="display:none;">
<div id="supplier_pill"> <div class="header txtcenter">
<div class="supplier_pill"> <h1>Aide à la commande</h1>
<div class="supplier_name_container"> </div>
<span class="pill_supplier_name"></span>
<i class="fas fa-times remove_supplier_icon"></i> <div class="txtcenter" id="supplier_form_container">
<form action="javascript:;" id="supplier_form">
<input type="text" name="supplier" id="supplier_input" placeholder="Rechercher un fournisseur par son nom">
<button type="submit" class='btn--primary'>Ajouter le fournisseur</button>
</form>
</div>
<div class="txtcenter" id="suppliers_container"></div>
<div class="main" style="display:none;">
<div class="table_area">
<table id="products_table" class="display" cellspacing="0" width="100%"></table>
</div> </div>
</div> </div>
</div> </div>
<div id="modal_remove_supplier"> <div id="templates" style="display:none;">
<h3>Attention !</h3> <div id="supplier_pill_template">
<p> <div class="supplier_pill">
Vous vous apprêtez à supprimer le fournisseur <span class="supplier_name"></span> de la sélection.<br/> <div class="supplier_name_container">
Les produits associés uniquement à ce fournisseur seront supprimés du tableau.<br/> <span class="pill_supplier_name"></span>
Les données renseignées dans la colonne de ce fournisseur seront perdues. <i class="fas fa-times remove_supplier_icon"></i>
</p> </div>
<p>Êtez-vous sûr ?</p> </div>
<hr/> </div>
</div>
<div id="modal_attach_product_to_supplier">
<h3>Attention !</h3>
<p>
Vous vous apprêtez à associer le produit <span class="product_name"></span> au fournisseur <span class="supplier_name"></span>.<br/>
L'association sera sauvegardée dès que vous aurez cliqué sur "Valider".<br/>
</p>
<p>Êtez-vous sûr ?</p>
<hr/>
</div>
<div id="modal_create_inventory"> <div id="order_pill_template">
<p> <div class="pill order_pill btn btn--primary">
Vous vous apprêtez à créer un inventaire de <span class="inventory_products_count"></span> produits. <span class="pill_order_name"></span>
</p> </div>
<p>Êtez-vous sûr ?</p> </div>
<hr/>
<div id="modal_remove_supplier">
<h3>Attention !</h3>
<p>
Vous vous apprêtez à supprimer le fournisseur <span class="supplier_name"></span> de la sélection.<br/>
Les produits associés uniquement à ce fournisseur seront supprimés du tableau.<br/>
Les données renseignées dans la colonne de ce fournisseur seront perdues.
</p>
<p>Êtez-vous sûr ?</p>
<hr/>
</div>
<div id="modal_attach_product_to_supplier">
<h3>Attention !</h3>
<p>
Vous vous apprêtez à associer le produit <span class="product_name"></span> au fournisseur <span class="supplier_name"></span>.<br/>
L'association sera sauvegardée dès que vous aurez cliqué sur "Valider".<br/>
</p>
<p>Êtez-vous sûr ?</p>
<hr/>
</div>
<div id="modal_create_inventory">
<p>
Vous vous apprêtez à créer un inventaire de <span class="inventory_products_count"></span> produits.
</p>
<p>Êtez-vous sûr ?</p>
<hr/>
</div>
</div> </div>
</div> </div>
<script src="{% static "js/pouchdb.min.js" %}"></script>
<script type="text/javascript">
var couchdb_dbname = '{{db}}';
var couchdb_server = '{{couchdb_server}}' + couchdb_dbname;
</script>
<script src="{% static "js/all_common.js" %}?v="></script> <script src="{% static "js/all_common.js" %}?v="></script>
<script type="text/javascript" src="{% static 'js/orders_helper.js' %}?v="></script> <script type="text/javascript" src="{% static 'js/orders_helper.js' %}?v="></script>
{% endblock %} {% endblock %}
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