Commit f8b23369 by Damien Moulard

INV: save UTC time & display according to locale timezone (+ linting)

parent 4f963d49
Pipeline #2211 passed with stage
in 3 minutes 48 seconds
...@@ -6,7 +6,7 @@ from products.models import CagetteProducts ...@@ -6,7 +6,7 @@ from products.models import CagetteProducts
from inventory.models import CagetteInventory from inventory.models import CagetteInventory
import os import os
from datetime import date, datetime from datetime import date, datetime, timezone
from openpyxl import Workbook from openpyxl import Workbook
from openpyxl.styles import Alignment, Font from openpyxl.styles import Alignment, Font
from statistics import * from statistics import *
...@@ -196,7 +196,7 @@ class Shelf(models.Model): ...@@ -196,7 +196,7 @@ class Shelf(models.Model):
def set_begin_inventory_datetime(self): def set_begin_inventory_datetime(self):
res = {} res = {}
now = datetime.now().isoformat() now = datetime.now(timezone.utc).isoformat() # save UTC time
f = {'ongoing_inv_start_datetime': now} f = {'ongoing_inv_start_datetime': now}
try: try:
......
...@@ -58,12 +58,13 @@ function back() { ...@@ -58,12 +58,13 @@ function back() {
function get_added_qties_sum(item) { function get_added_qties_sum(item) {
let total = null; let total = null;
function add(accumulator, a) { // for array sum function add(accumulator, a) { // for array sum
result = 0; result = 0;
if (a) { if (a) {
if (item.uom_id[1] == "kg") { if (item.uom_id[1] == "kg") {
if (typeof a === "string") { if (typeof a === "string") {
a = a.replace(',','.') a = a.replace(',', '.');
} }
result = parseFloat(accumulator) + parseFloat(a); result = parseFloat(accumulator) + parseFloat(a);
result = result.toFixed(3); result = result.toFixed(3);
...@@ -71,17 +72,19 @@ function get_added_qties_sum(item) { ...@@ -71,17 +72,19 @@ function get_added_qties_sum(item) {
result = parseInt(accumulator, 10) + parseInt(a, 10); result = parseInt(accumulator, 10) + parseInt(a, 10);
} }
} }
return result; return result;
} }
if (typeof item.added_qties != "undefined" && item.added_qties.length > 0) { if (typeof item.added_qties != "undefined" && item.added_qties.length > 0) {
total = item.added_qties.reduce(add); total = item.added_qties.reduce(add);
} }
return total; return total;
} }
function barcode_analyzer(chars) { function barcode_analyzer(chars) {
let barcode = chars; let barcode = chars;
if (barcode && barcode.length >=13) { if (barcode && barcode.length >=13) {
barcode = barcode.substring(barcode.length-13); barcode = barcode.substring(barcode.length-13);
} else if (barcode && barcode.length == 12 && barcode.indexOf('0') !== 0) { } else if (barcode && barcode.length == 12 && barcode.indexOf('0') !== 0) {
...@@ -125,23 +128,24 @@ function refresh() { ...@@ -125,23 +128,24 @@ function refresh() {
function select_product_from_bc(barcode) { function select_product_from_bc(barcode) {
var found = null, var found = null,
qty = null; qty = null;
if (isValidEAN13(barcode)) { if (isValidEAN13(barcode)) {
var scannedProduct = barcodes.get_corresponding_odoo_product(barcode); var scannedProduct = barcodes.get_corresponding_odoo_product(barcode);
if (scannedProduct === null) { if (scannedProduct === null) {
alert("Le code-barre " + barcode + " ne correspond à aucun article connu."); alert("Le code-barre " + barcode + " ne correspond à aucun article connu.");
return -1; return -1;
} else { } else {
barcode = scannedProduct.barcode; barcode = scannedProduct.barcode;
if (scannedProduct.rule.length > 0 && scannedProduct.rule != "product") { if (scannedProduct.rule.length > 0 && scannedProduct.rule != "product") {
qty = scannedProduct.qty; qty = scannedProduct.qty;
}
} }
}
} }
if (editing_item === null) { if (editing_item === null) {
$.each(list_to_process, function(i, e) { $.each(list_to_process, function(i, e) {
if (e.barcode == barcode) { if (e.barcode == barcode) {
found = e; found = e;
...@@ -155,14 +159,18 @@ function select_product_from_bc(barcode) { ...@@ -155,14 +159,18 @@ function select_product_from_bc(barcode) {
found = e; found = e;
if (qty) { if (qty) {
let message = "Attention, ce produit a déjà été compté.\n"; let message = "Attention, ce produit a déjà été compté.\n";
message += "La quantité " + qty + " n'a pas été ajoutée !\n"; message += "La quantité " + qty + " n'a pas été ajoutée !\n";
// temporary add read qty and recorded one to added_qties to compute sum // temporary add read qty and recorded one to added_qties to compute sum
found.added_qties = [qty, found.qty] found.added_qties = [
qty,
found.qty
];
message += "Le total serait " + get_added_qties_sum(found); message += "Le total serait " + get_added_qties_sum(found);
alert(message); alert(message);
qty = null; qty = null;
} }
editing_origin = 'processed'; editing_origin = 'processed';
} }
}); });
...@@ -173,17 +181,20 @@ function select_product_from_bc(barcode) { ...@@ -173,17 +181,20 @@ function select_product_from_bc(barcode) {
setLineEdition(found, qty); setLineEdition(found, qty);
if (editing_origin === 'to_process') { if (editing_origin === 'to_process') {
let row = table_to_process.row($('tr#'+found.id)); let row = table_to_process.row($('tr#'+found.id));
remove_from_toProcess(row); remove_from_toProcess(row);
} else { } else {
let row = table_processed.row($('tr#'+found.id)); let row = table_processed.row($('tr#'+found.id));
remove_from_processed(row); remove_from_processed(row);
} }
} else { } else {
console.log('Code barre introuvable'); console.log('Code barre introuvable');
} }
} else if (barcode == editing_item.barcode && qty){ } else if (barcode == editing_item.barcode && qty) {
// We scan the same product as the current one // We scan the same product as the current one
let edition_input = $('#edition_input'); let edition_input = $('#edition_input');
if (typeof editing_item.added_qties == "undefined") { if (typeof editing_item.added_qties == "undefined") {
editing_item.added_qties = [edition_input.val()]; editing_item.added_qties = [edition_input.val()];
} }
...@@ -354,40 +365,42 @@ function editProductInfo (productToEdit, value = null) { ...@@ -354,40 +365,42 @@ function editProductInfo (productToEdit, value = null) {
function record_products_shelf_on_server(data) { function record_products_shelf_on_server(data) {
return new Promise(resolve => { return new Promise(resolve => {
$.ajax({ $.ajax({
type: "POST", type: "POST",
url: "/shelfs/change_products_shelfs", url: "/shelfs/change_products_shelfs",
dataType: "json", dataType: "json",
data: JSON.stringify(data), data: JSON.stringify(data),
traditional: true, traditional: true,
contentType: "application/json; charset=utf-8", contentType: "application/json; charset=utf-8",
success: function(data) { success: function(data) {
if (typeof data.res !== "undefined" && typeof data.res.done !== "undefined") if (typeof data.res !== "undefined" && typeof data.res.done !== "undefined")
resolve(data.res.done); resolve(data.res.done);
else else
resolve(null);
},
error: function() {
alert("Impossible de mettre à jour les données");
resolve(null); resolve(null);
} },
}); error: function() {
alert("Impossible de mettre à jour les données");
resolve(null);
}
});
}); });
} }
// call on change_shelf_btn click action // call on change_shelf_btn click action
async function open_change_shelf_modal() { async function open_change_shelf_modal() {
selected_products_for_shelf_change = []; selected_products_for_shelf_change = [];
$('.select_product_cb:checked').each(function(idx,elt){ $('.select_product_cb:checked').each(function(idx, elt) {
const row = $(elt).closest('tr'); const row = $(elt).closest('tr');
selected_products_for_shelf_change.push(table_to_process.row(row).data())
selected_products_for_shelf_change.push(table_to_process.row(row).data());
}); });
if (selected_products_for_shelf_change.length > 0) { if (selected_products_for_shelf_change.length > 0) {
/* /*
As button is not shown if no product is selected, should be always true As button is not shown if no product is selected, should be always true
But, with CSS changes, it could happen that length == 0 But, with CSS changes, it could happen that length == 0
*/ */
let shelfs = await get_all_shelfs(); let shelfs = await get_all_shelfs();
if (shelfs !== null) { if (shelfs !== null) {
let modal_content = $('#templates #change_shelf_form').clone(), let modal_content = $('#templates #change_shelf_form').clone(),
shelf_selector = $('<select>').addClass('shelf_selection'), shelf_selector = $('<select>').addClass('shelf_selection'),
...@@ -395,46 +408,50 @@ async function open_change_shelf_modal() { ...@@ -395,46 +408,50 @@ async function open_change_shelf_modal() {
/* construct shelfs selector */ /* construct shelfs selector */
// first of all, sort by name // first of all, sort by name
shelfs.sort((a,b) => (a.name > b.name) ? 1 : ((b.name > a.name) ? -1 : 0)); shelfs.sort((a, b) => (a.name > b.name) ? 1 : ((b.name > a.name) ? -1 : 0));
// if ahead_shelfs_ids is not empty, put them ahead // if ahead_shelfs_ids is not empty, put them ahead
if (ahead_shelfs_ids.length > 0) { if (ahead_shelfs_ids.length > 0) {
let to_move = {}, let to_move = {},
idx = 0; idx = 0;
// find index of shelfs to move // find index of shelfs to move
shelfs.forEach((shelf) => {
shelfs.forEach((shelf) => {
if (ahead_shelfs_ids.indexOf(shelf.id) > -1) { if (ahead_shelfs_ids.indexOf(shelf.id) > -1) {
to_move[shelf.id] = idx; to_move[shelf.id] = idx;
} }
idx += 1; idx += 1;
}); });
// Respecting ahead_shelfs_ids order, move shelf ahead // Respecting ahead_shelfs_ids order, move shelf ahead
// splice can not be used, since more than 1 elt could be involved // splice can not be used, since more than 1 elt could be involved
let ahead_elts = []; let ahead_elts = [];
ahead_shelfs_ids.forEach((shelf_id) => {
ahead_shelfs_ids.forEach((shelf_id) => {
let shelf = shelfs[to_move[shelf_id]]; let shelf = shelfs[to_move[shelf_id]];
ahead_elts.push(shelf);
}); ahead_elts.push(shelf);
//remove ahead elts });
shelfs = shelfs.filter((item) => {return !ahead_elts.includes(item.id)}); //remove ahead elts
// put them ahead by concatenation shelfs = shelfs.filter((item) => {
shelfs = ahead_elts.concat(shelfs); return !ahead_elts.includes(item.id);
});
// put them ahead by concatenation
shelfs = ahead_elts.concat(shelfs);
} }
shelfs.forEach( shelfs.forEach((shelf) => {
(shelf) => { let option = $('<option>')
let option = $('<option>') .val(shelf.id)
.val(shelf.id) .text(shelf.name + ' (' + shelf.sort_order + ')');
.text(shelf.name + ' (' + shelf.sort_order + ')');
shelf_selector.append(option); shelf_selector.append(option);
}); });
/* add product rows */ /* add product rows */
selected_products_for_shelf_change.forEach( selected_products_for_shelf_change.forEach((product) => {
(product) => { let tr = $('<tr>').attr('data-id', product.id)
let tr = $('<tr>').attr('data-id',product.id) .append($('<td>').text(product.name))
.append($('<td>').text(product.name)) .append($('<td>').append(shelf_selector.clone()));
.append($('<td>').append(shelf_selector.clone()));
table.append(tr); table.append(tr);
}); });
openModal( openModal(
...@@ -444,24 +461,27 @@ async function open_change_shelf_modal() { ...@@ -444,24 +461,27 @@ async function open_change_shelf_modal() {
make_change = async () => { make_change = async () => {
// Prepare data to be transmitted to server to be recorded // Prepare data to be transmitted to server to be recorded
let data = []; let data = [];
$('.overlay-content table tbody tr').each(function(idx,e){
$('.overlay-content table tbody tr').each(function(idx, e) {
data.push({ data.push({
product_id : $(e).data('id'), product_id : $(e).data('id'),
shelf_id : $(e).find('select').val() shelf_id : $(e).find('select')
}); .val()
});
}); });
const update_result = await record_products_shelf_on_server(data); const update_result = await record_products_shelf_on_server(data);
if (update_result !== null) { if (update_result !== null) {
update_result.forEach( update_result.forEach((product_id) => {
(product_id) => { remove_from_toProcess(table_to_process.row($('tr#'+product_id)));
remove_from_toProcess(table_to_process.row($('tr#'+product_id))); });
});
let message = "L'opération a bien réussi."; let message = "L'opération a bien réussi.";
if (update_result.length !== data.length) { if (update_result.length !== data.length) {
message = "L'opération a partiellement réussi.\n"; message = "L'opération a partiellement réussi.\n";
message += (data.length - update_result.length) + " produit(s) non déplacé(s)."; message += (data.length - update_result.length) + " produit(s) non déplacé(s).";
//TODO: display which products changes were in error //TODO: display which products changes were in error
} }
$.notify( $.notify(
message, message,
{ {
...@@ -470,16 +490,16 @@ async function open_change_shelf_modal() { ...@@ -470,16 +490,16 @@ async function open_change_shelf_modal() {
} }
); );
} }
} };
make_change(); make_change();
} }
}, },
'Changer les produits de rayons' 'Changer les produits de rayons'
); );
} else { } else {
alert("Les informations des autres rayons n'ont pas pu être récupérées.") alert("Les informations des autres rayons n'ont pas pu être récupérées.");
} }
} }
} }
...@@ -508,15 +528,15 @@ function initLists() { ...@@ -508,15 +528,15 @@ function initLists() {
columns_to_process.push({data:"id", title: "id", visible: false}); columns_to_process.push({data:"id", title: "id", visible: false});
} else { } else {
columns_to_process.push({ columns_to_process.push({
title: `<div id="table_header_select_all" class="txtcenter"> title: `<div id="table_header_select_all" class="txtcenter">
<input type="checkbox" id="select_all_products_cb" name="select_all_products_cb" value="all"> <input type="checkbox" id="select_all_products_cb" name="select_all_products_cb" value="all">
</div>`, </div>`,
className: "dt-body-center", className: "dt-body-center",
orderable: false, orderable: false,
render: function (data) { render: function (data) {
return `<input type="checkbox" class="select_product_cb" />`; return `<input type="checkbox" class="select_product_cb" />`;
}, },
width: "4%"}); width: "4%"});
} }
columns_to_process = columns_to_process.concat([ columns_to_process = columns_to_process.concat([
{data:"name", title:"Produit", width: "60%"}, {data:"name", title:"Produit", width: "60%"},
...@@ -1123,6 +1143,7 @@ function init() { ...@@ -1123,6 +1143,7 @@ function init() {
}); });
if ($(this).val().length > 0) { if ($(this).val().length > 0) {
let reset_icon = $("#reset_to_previous_qty"); let reset_icon = $("#reset_to_previous_qty");
reset_icon.show(); reset_icon.show();
reset_icon.off(); reset_icon.off();
reset_icon.on("click", reset_previous_value); reset_icon.on("click", reset_previous_value);
...@@ -1132,6 +1153,7 @@ function init() { ...@@ -1132,6 +1153,7 @@ function init() {
}) })
.on('blur', function () { .on('blur', function () {
const current_val = $(this).val(); const current_val = $(this).val();
$(this).off('wheel.disableScroll'); $(this).off('wheel.disableScroll');
if (editing_item !== null) { if (editing_item !== null) {
...@@ -1140,16 +1162,20 @@ function init() { ...@@ -1140,16 +1162,20 @@ function init() {
if (typeof editing_item.added_qties !== "undefined") { if (typeof editing_item.added_qties !== "undefined") {
// total may have been affected by manual typing // total may have been affected by manual typing
const total = get_added_qties_sum(editing_item); const total = get_added_qties_sum(editing_item);
if (current_val != total) { if (current_val != total) {
// add difference in added_qties array // add difference in added_qties array
editing_item.added_qties.push(current_val - total); editing_item.added_qties.push(current_val - total);
} }
} else { } else {
// Init added_qties to take change into account // Init added_qties to take change into account
editing_item.added_qties = [editing_item.qty, current_val - editing_item.qty]; editing_item.added_qties = [
editing_item.qty,
current_val - editing_item.qty
];
} }
} }
editing_item.qty = current_val; editing_item.qty = current_val;
} }
}); });
...@@ -1214,8 +1240,9 @@ function init() { ...@@ -1214,8 +1240,9 @@ function init() {
$(document).on('scan.pos.barcode', function(event) { $(document).on('scan.pos.barcode', function(event) {
//access `event.code` - barcode data //access `event.code` - barcode data
var barcode = event.code; var barcode = event.code;
barcode_analyzer(barcode); barcode_analyzer(barcode);
}); });
} }
...@@ -1259,5 +1286,5 @@ $(document).ready(function() { ...@@ -1259,5 +1286,5 @@ $(document).ready(function() {
get_shelf_data(); get_shelf_data();
} }
get_barcodes(); get_barcodes();
}); });
...@@ -355,36 +355,37 @@ var is_product_in_shelf_adding_queue_list = function(testing_pid) { ...@@ -355,36 +355,37 @@ var is_product_in_shelf_adding_queue_list = function(testing_pid) {
}; };
var printProduct = function () { var printProduct = function () {
let clicked = $(this); let clicked = $(this);
let tr_to_print = clicked.closest('tr'); let tr_to_print = clicked.closest('tr');
let barcode = tr_to_print.data('bc') let barcode = tr_to_print.data('bc');
openModal(); openModal();
try { try {
$.ajax({
url: '/products/get_product_data',
data: {'barcode': barcode}
})
.done(function(res) {
var product = res.product
var product_tmpl_id = product.product_tmpl_id[0]
$.ajax({ $.ajax({
url: '/products/label_print/' + product_tmpl_id url: '/products/get_product_data',
}) data: {'barcode': barcode}
.done(function(res_print) {
closeModal();
if ("error" in res_print.res) {
console.log(res_print.res);
alert('Une erreur est survenue...');
} else {
alert('Impression lancée');
}
}) })
}) .done(function(res) {
} catch(e) { var product = res.product;
closeModal(); var product_tmpl_id = product.product_tmpl_id[0];
alert('Une erreur est survenue...');
} $.ajax({
url: '/products/label_print/' + product_tmpl_id
})
.done(function(res_print) {
closeModal();
if ("error" in res_print.res) {
console.log(res_print.res);
alert('Une erreur est survenue...');
} else {
alert('Impression lancée');
}
});
});
} catch (e) {
closeModal();
alert('Une erreur est survenue...');
}
}; };
......
...@@ -29,6 +29,13 @@ function init_datatable() { ...@@ -29,6 +29,13 @@ function init_datatable() {
else { else {
var date = new Date(data); var date = new Date(data);
// Get local timezone offset in minutes
const offset = date.getTimezoneOffset();
// Add offset to saved time.
// offset is negative if the local time zone is ahead of UTC.
date.setTime(date.getTime() - offset * 60 * 1000);
return `${date.toLocaleDateString('fr-FR')} ${date.toLocaleTimeString('fr-FR')}`; return `${date.toLocaleDateString('fr-FR')} ${date.toLocaleTimeString('fr-FR')}`;
} }
} }
......
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