Commit c7ae8642 by Damien Moulard

sync with couchdb to keep data

parent bb3b8ebf
......@@ -2,16 +2,56 @@
position: relative;
}
#form_container {
margin-top: 30px;
.page_content {
position: absolute;
top: 0;
left: 0;
right: 0;
}
#products_table_filter{
text-align: right !important;
/* - Common */
/* - Order selection screen */
#new_order_form {
margin-top: 20px;
margin-bottom: 30px;
}
#products_table_filter input{
height: 40px;
#existing_orders {
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 {
......@@ -20,17 +60,13 @@
border-radius: 5px;
}
.product_qty_input {
width: 100px;
}
.product_not_from_supplier {
background-color: #e7e9ed;
cursor: pointer;
/* -- Table */
#products_table_filter{
text-align: right !important;
}
.product_name, .supplier_name {
font-weight: bold;
#products_table_filter input{
height: 40px;
}
#table_header_select_all{
......@@ -44,10 +80,24 @@
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 {
cursor: pointer;
}
/* -- Suppliers list */
#suppliers_container {
display: flex;
justify-content: center;
......@@ -74,9 +124,3 @@
margin-left: 5px;
cursor: pointer;
}
\ No newline at end of file
#actions_buttons_area {
position: absolute;
top: 0;
right: 0;
}
......@@ -2,7 +2,33 @@ var suppliers_list = [],
products_table = null,
products = [],
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.
......@@ -47,8 +73,9 @@ function add_supplier() {
contentType: "application/json; charset=utf-8",
success: function(data) {
save_supplier_products(supplier, data.res.products);
update_display();
update_main_screen();
$("#supplier_input").val("");
update_order();
closeModal();
},
error: function(data) {
......@@ -83,7 +110,8 @@ function remove_supplier(supplier_id) {
// Remove products only associated to this product
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) {
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
* @returns String
......@@ -207,9 +313,10 @@ function display_suppliers() {
let supplier_container = $("#suppliers_container");
$("#suppliers_container").empty();
$(".remove_supplier_icon").off();
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(".remove_supplier_icon").attr('id', `remove_supplier_${supplier.id}`);
......@@ -236,8 +343,6 @@ function display_suppliers() {
});
}
/* DATATABLE */
/**
* @param {array} product_ids if set, return formatted data for these products only
* @returns Array of formatted data for datatable data setup
......@@ -354,13 +459,13 @@ function prepare_datatable_columns() {
* Display the Datatable containing the products
*/
function display_products() {
// Empty datatable if already exists
if (products.length == 0) {
$('.main').hide();
return -1;
}
// Empty datatable if it already exists
if (products_table) {
products_table.clear().destroy();
$('#products_table').empty();
......@@ -417,6 +522,7 @@ function display_products() {
const supplier_id = id_split[3];
save_product_supplier_qty(prod_id, supplier_id, val);
update_order();
}
});
......@@ -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
$('#products_table').off('input', 'tbody td .product_qty_input');
$('#products_table').off('click', 'tbody .product_not_from_supplier');
$('#products_table').off('click', 'thead th #select_all_products_cb');
$('#products_table').off('click', 'tbody td .select_product_cb');
$(".remove_supplier_icon").off();
display_suppliers();
display_products();
......@@ -531,82 +639,172 @@ function update_display() {
}
}
function generate_inventory() {
if (products_table !== null) {
const selected_data = products_table.rows('.selected').data();
/**
* Update DOM display on the order selection screen
*/
function update_order_selection_screen() {
// Remove listener before recreating them
$(".order_pill").off();
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'
};
let existing_orders_container = $("#existing_orders");
for (var i = 0; i < selected_data.length; i++) {
const product = products.find(p => p.id == selected_data[i].id);
existing_orders_container.empty();
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);
}
}
dbc.allDocs({
include_docs: true
}).then(function (result) {
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());
}
let modal_create_inventory = $('#templates #modal_create_inventory');
$(".order_pill").on("click", function() {
let order_name_container = $(this).find('.pill_order_name');
let doc_id = $(order_name_container).text();
modal_create_inventory.find(".inventory_products_count").text(data.lines.length);
dbc.get(doc_id).then((doc) => {
order_doc = doc;
products = order_doc.products;
selected_suppliers = order_doc.selected_suppliers;
selected_rows = order_doc.selected_rows;
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();
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) {
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() {
$.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'};
/**
* Switch screen between order selection & main screens
* @param {String} direction target screen
*/
function switch_screen(direction = 'main_screen') {
let oldBox = null;
let newBox = null;
let outerWidth = null;
if (typeof data.responseJSON != 'undefined' && typeof data.responseJSON.error != 'undefined') {
err.msg += ' : ' + data.responseJSON.error;
}
report_JS_error(err, 'orders');
if (direction == 'main_screen') {
oldBox = $("#select_order_content");
newBox = $("#main_content");
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");
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" });
});
},
'Valider'
);
// 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() {
$.ajaxSetup({ headers: { "X-CSRFToken": getCookie('csrftoken') } });
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
$.ajax({
type: 'GET',
......@@ -635,13 +833,4 @@ $(document).ready(function() {
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):
def helper(request):
context = {
'title': 'Aide à la commande',
'couchdb_server': settings.COUCHDB['url'],
'db': settings.COUCHDB['dbs']['orders']
}
template = loader.get_template('orders/helper.html')
......
......@@ -13,7 +13,8 @@ COUCHDB = {
'member': 'coops',
'inventory': 'inventory',
'envelops': 'envelop',
'shop': 'shopping_carts'
'shop': 'shopping_carts',
'orders': 'orders_test'
}
}
......
......@@ -15,6 +15,20 @@
{% block content %}
<div class="page_body">
<div id="select_order_content" class="page_content txtcenter">
<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>
<h2>Ou, continuer une commande existante</h2>
<div id="existing_orders"></div>
</div>
<div id="main_content" class="page_content" style="display:none;">
<div id="back_to_order_selection">
<button type="button" class="btn--danger"><i class="fas fa-arrow-left"></i>&nbsp; Retour</button>
</div>
<div id="actions_buttons_area">
<button type="button" class='btn--primary' id="do_inventory">Faire un inventaire</button>
</div>
......@@ -23,7 +37,7 @@
<h1>Aide à la commande</h1>
</div>
<div class="txtcenter" id="form_container">
<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>
......@@ -37,10 +51,10 @@
<table id="products_table" class="display" cellspacing="0" width="100%"></table>
</div>
</div>
</div>
</div>
<div id="templates" style="display:none;">
<div id="supplier_pill">
<div id="templates" style="display:none;">
<div id="supplier_pill_template">
<div class="supplier_pill">
<div class="supplier_name_container">
<span class="pill_supplier_name"></span>
......@@ -49,6 +63,12 @@
</div>
</div>
<div id="order_pill_template">
<div class="pill order_pill btn btn--primary">
<span class="pill_order_name"></span>
</div>
</div>
<div id="modal_remove_supplier">
<h3>Attention !</h3>
<p>
......@@ -77,8 +97,15 @@
<p>Êtez-vous sûr ?</p>
<hr/>
</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 type="text/javascript" src="{% static 'js/orders_helper.js' %}?v="></script>
{% 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