Commit b36613dc by François C.

Modifications pour rendre inventaire plus robuste, pour générer des informations…

Modifications pour rendre inventaire plus robuste, pour générer des informations supplémentaires pour étiquettes rayons cartonnées
parent 802ac8d4
...@@ -153,7 +153,7 @@ class CagetteInventory(models.Model): ...@@ -153,7 +153,7 @@ class CagetteInventory(models.Model):
'products': ids 'products': ids
} }
# Crate inventory file, name is timestamp of creation # Create inventory file, name is timestamp of creation
timestamp = int(time.time()) timestamp = int(time.time())
filename = custom_list_file_path + str(timestamp) + '.json' filename = custom_list_file_path + str(timestamp) + '.json'
with open(filename, 'w+') as outfile: with open(filename, 'w+') as outfile:
......
...@@ -97,7 +97,7 @@ def do_custom_list_inventory(request): ...@@ -97,7 +97,7 @@ def do_custom_list_inventory(request):
else: else:
return JsonResponse({'res': res}) return JsonResponse({'res': res})
@csrf_exempt @csrf_exempt
def generate_inventory_list(request): def generate_inventory_list(request):
"""Responding to Odoo ajax call (no csrf).""" """Responding to Odoo ajax call (no csrf)."""
res = {} res = {}
......
...@@ -46,6 +46,7 @@ class CagetteProduct(models.Model): ...@@ -46,6 +46,7 @@ class CagetteProduct(models.Model):
return res return res
@staticmethod @staticmethod
def get_product_info_for_label_from_template_id(template_id): def get_product_info_for_label_from_template_id(template_id):
"""Get product info for label.""" """Get product info for label."""
...@@ -54,14 +55,26 @@ class CagetteProduct(models.Model): ...@@ -54,14 +55,26 @@ class CagetteProduct(models.Model):
fields = ['barcode', 'product_tmpl_id', 'pricetag_rackinfos', fields = ['barcode', 'product_tmpl_id', 'pricetag_rackinfos',
'price_weight_net', 'price_volume', 'list_price', 'price_weight_net', 'price_volume', 'list_price',
'weight_net', 'volume', 'to_weight'] 'weight_net', 'volume', 'to_weight']
fields += getattr(settings, 'SHELF_LABELS_ADD_FIELDS', []) additionnal_fields = getattr(settings, 'SHELF_LABELS_ADD_FIELDS', [])
return api.search_read('product.product', cond, fields) fields += additionnal_fields
product_data = api.search_read('product.product', cond, fields)
if product_data and 'suppliers' in additionnal_fields:
cond = [['product_tmpl_id.id', '=', template_id]]
fields = ['name']
suppliers = api.search_read('product.supplierinfo', cond, fields)
if suppliers:
suppliers_name = []
for s in suppliers:
suppliers_name.append(s['name'][1])
product_data[0]['suppliers'] = ', '.join(list(set(suppliers_name)))
return product_data
@staticmethod @staticmethod
def generate_label_for_printing(templ_id, directory, price=None, nb=None): def generate_label_for_printing(templ_id, directory, price=None, nb=None):
res = {} res = {}
try: try:
p = CagetteProduct.get_product_info_for_label_from_template_id(templ_id) p = CagetteProduct.get_product_info_for_label_from_template_id(templ_id)
if (p and p[0]['product_tmpl_id'][0] == int(templ_id)): if (p and p[0]['product_tmpl_id'][0] == int(templ_id)):
product = p[0] product = p[0]
txt = '' txt = ''
...@@ -91,6 +104,18 @@ class CagetteProduct(models.Model): ...@@ -91,6 +104,18 @@ class CagetteProduct(models.Model):
coop_logger.error("Generate label : %s %s", templ_id, str(e)) coop_logger.error("Generate label : %s %s", templ_id, str(e))
return res return res
@staticmethod
def register_start_supplier_shortage(product_id, partner_id, date_start):
"""Start a supplier shortage for a product"""
api = OdooAPI()
f = {
'product_id' : product_id,
'partner_id' : partner_id,
'date_start' : date_start,
}
res = api.create('product.supplier.shortage', f)
return res
class CagetteProducts(models.Model): class CagetteProducts(models.Model):
"""Initially used to make massive barcode update.""" """Initially used to make massive barcode update."""
...@@ -166,6 +191,8 @@ class CagetteProducts(models.Model): ...@@ -166,6 +191,8 @@ class CagetteProducts(models.Model):
def get_products_for_label_appli(withCandidate=False): def get_products_for_label_appli(withCandidate=False):
fields = ['sale_ok', 'uom_id', 'barcode', fields = ['sale_ok', 'uom_id', 'barcode',
'name', 'display_name', 'list_price', 'categ_id', 'image_medium'] 'name', 'display_name', 'list_price', 'categ_id', 'image_medium']
if getattr(settings, 'EXPORT_POS_CAT_FOR_SCALES', False) is True:
fields.append('pos_categ_id')
to_weight = CagetteProducts.get_products_to_weight(withCandidate, fields) to_weight = CagetteProducts.get_products_to_weight(withCandidate, fields)
if len(vcats) > 0: if len(vcats) > 0:
vrac = CagetteProducts.get_vrac_products_from_cats(vcats, withCandidate, fields) vrac = CagetteProducts.get_vrac_products_from_cats(vcats, withCandidate, fields)
...@@ -182,6 +209,19 @@ class CagetteProducts(models.Model): ...@@ -182,6 +209,19 @@ class CagetteProducts(models.Model):
fields = ['uom_id', 'display_name','barcode'] fields = ['uom_id', 'display_name','barcode']
return api.search_read('product.product', cond, fields) return api.search_read('product.product', cond, fields)
@staticmethod
def get_pos_categories():
api = OdooAPI()
fields = ['name', 'parent_id', 'sequence', 'image_small']
try:
res = api.search_read('pos.category', [], fields)
except Exception as e:
coop_logger.error('Getting POS categories : %s', str(e))
res = []
return res
@staticmethod @staticmethod
def get_all_barcodes(): def get_all_barcodes():
"""Needs lacagette_products Odoo module to be active.""" """Needs lacagette_products Odoo module to be active."""
...@@ -195,6 +235,12 @@ class CagetteProducts(models.Model): ...@@ -195,6 +235,12 @@ class CagetteProducts(models.Model):
for p in res['list']: for p in res['list']:
# transcode result to compact format (for bandwith save and browser memory) # transcode result to compact format (for bandwith save and browser memory)
# real size / 4 (for 2750 products) # real size / 4 (for 2750 products)
# following 2 lines is only useful for La Cagette (changing uom_id in Database has cascade effects...)
# TODO : Use mapping list in config.py
if p['uom_id'] == 3:
p['uom_id'] = 21
if p['uom_id'] == 20:
p['uom_id'] = 1
result['pdts'][p['barcode']] = [ result['pdts'][p['barcode']] = [
p['display_name'], p['display_name'],
p['sale_ok'], p['sale_ok'],
...@@ -202,6 +248,7 @@ class CagetteProducts(models.Model): ...@@ -202,6 +248,7 @@ class CagetteProducts(models.Model):
p['available_in_pos'], p['available_in_pos'],
p['id'], p['id'],
p['standard_price'], p['standard_price'],
p['list_price'],
p['uom_id']] p['uom_id']]
if 'uoms' in res and 'list' in res['uoms']: if 'uoms' in res and 'list' in res['uoms']:
result['uoms'] = res['uoms']['list'] result['uoms'] = res['uoms']['list']
...@@ -264,18 +311,31 @@ class CagetteProducts(models.Model): ...@@ -264,18 +311,31 @@ class CagetteProducts(models.Model):
@staticmethod @staticmethod
def get_barcode_rules(): def get_barcode_rules():
c = [['type', 'in', ['FF_price_to_weight', 'price', 'price_to_weight', 'product', 'weight' ]], ['barcode_nomenclature_id','=', 1]] result = {'patterns': [], 'aliases': {}}
rules = OdooAPI().search_read('barcode.rule', c, ['pattern'], order="sequence ASC") try:
# As rules are ordered by sequence, let's find where to stop (.* pattern) import re
stop_idx = len(rules) - 1 c = [['type', 'in', ['FF_price_to_weight', 'price', 'price_to_weight', 'product', 'weight', 'alias']], ['barcode_nomenclature_id','=', 1]]
i = 0 rules = OdooAPI().search_read('barcode.rule', c, ['pattern', 'type', 'alias'], order="sequence ASC")
for r in rules: # As rules are ordered by sequence, let's find where to stop (.* pattern)
if r['pattern'] == ".*": stop_idx = len(rules) - 1
stop_idx = i i = 0
i += 1 for r in rules:
if stop_idx > 0: if r['pattern'] == ".*":
rules = rules[:stop_idx - 1] stop_idx = i
return rules i += 1
if stop_idx > 0:
rules = rules[:stop_idx - 1]
for r in rules:
if r['type'] == 'alias':
alias_bc = re.sub('[^0-9]', '', r['pattern'])
if len(alias_bc) > 0:
result['aliases'][alias_bc] = r['alias']
elif '{' in r['pattern'] or '.' in r['pattern']:
result['patterns'].append(r)
except Exception as e:
result['error'] = str(e)
coop_logger.error("Get Barcode Rules : %s", str(e))
return result
@staticmethod @staticmethod
......
...@@ -13,11 +13,12 @@ IFCBarcodes = { ...@@ -13,11 +13,12 @@ IFCBarcodes = {
closeModal(); closeModal();
if (typeof bc_data.res.error == "undefined") { if (typeof bc_data.res.error == "undefined") {
this.patterns = bc_data.res.patterns; this.patterns = bc_data.res.patterns;
this.aliases = bc_data.res.aliases;
this.codes = bc_data.res.list.pdts; this.codes = bc_data.res.list.pdts;
this.uoms = bc_data.res.list.uoms; this.uoms = bc_data.res.list.uoms;
this.keys = bc_data.res.keys; this.keys = bc_data.res.keys;
} else { } else {
this.errors.push(bc_data.error); this.errors.push(bc_data.res.error);
} }
} catch (e) { } catch (e) {
err = {msg: e.name + ' : ' + e.message, ctx: 'retrieve barcodes'}; err = {msg: e.name + ' : ' + e.message, ctx: 'retrieve barcodes'};
...@@ -33,26 +34,33 @@ IFCBarcodes = { ...@@ -33,26 +34,33 @@ IFCBarcodes = {
}, },
get_corresponding_odoo_product: function(bc) { get_corresponding_odoo_product: function(bc) {
//console.log('To analyze :' + bc) //console.log('To analyze :' + bc)
var odoo_product = null;
var index = 0, var index = 0,
pattern_found = false, pattern_found = false,
encoded_value = ''; is_alias = false,
encoded_value = '',
pattern_type = '',
odoo_product = null,
product_data = null;
// Let's find out if it matches a pattern // Let's find out if it matches a pattern
while (index < this.patterns.length -1 && pattern_found === false) { while (index < this.patterns.length -1 && pattern_found === false) {
var pattern = this.patterns[index]; var pattern = this.patterns[index].pattern;
var significant_prefix = pattern.replace(/[^0-9]/g, ''); //remove all but figures var significant_prefix = pattern.replace(/[^0-9]/g, ''); //remove all but figures
if (bc.indexOf(significant_prefix) === 0) { if (bc.indexOf(significant_prefix) === 0) {
// console.log(pattern) /*
For example,
bc = 0493213018809
pattern = 0493...{NNDDD}
*/
//console.log(pattern)
// console.log(bc) // console.log(bc)
//0493...{NNDDD} (pattern) odoo_bc = '';
//0493213018809 (bc)
pattern_found = true; pattern_found = true;
pattern_type = this.patterns[index].type;
pattern = pattern.replace(/[^0-9.ND]/, ''); pattern = pattern.replace(/[^0-9.ND]/, '');
bc = bc.slice(0, -1); // remove original check figure bc = bc.slice(0, -1); // remove original check figure
odoo_bc = '';
// Read pattern character by character // Read pattern character by character
for (var i = 0; i < pattern.length; i++) { for (var i = 0; i < pattern.length; i++) {
if (/[0-9]/.exec(pattern[i])) { if (/[0-9]/.exec(pattern[i])) {
...@@ -72,13 +80,39 @@ IFCBarcodes = { ...@@ -72,13 +80,39 @@ IFCBarcodes = {
index++; index++;
} }
// let's seek "normalized" bc in codes array // let's seek "normalized" bc in codes array or alias map
for (code in this.codes) { for (alias in this.aliases) {
if (code == bc) { if (bc == alias) {
odoo_product = {barcode: code, data: this.codes[code], value: encoded_value}; is_alias = true;
for (barcode in this.codes) {
if (barcode == this.aliases[alias]) {
product_data = this.codes[barcode];
}
}
}
}
if (is_alias === false) {
for (code in this.codes) {
if (code == bc) {
product_data = this.codes[code];
}
}
}
if (product_data !== null) {
p_uom = (this.uoms)[product_data[this.keys.uom_id]];
if (encoded_value.length > 0 && !isNaN(encoded_value)) {
if (p_uom == 'Unit(s)' || p_uom == 'unité') {
encoded_value = parseInt(encoded_value, 10);
} else {
encoded_value = parseFloat(encoded_value);
}
} }
odoo_product = {barcode: bc, data: product_data, rule: pattern_type, value: encoded_value};
} }
//console.log(odoo_product)
return odoo_product; return odoo_product;
} }
}; };
...@@ -93,5 +127,6 @@ init_barcodes = async function() { ...@@ -93,5 +127,6 @@ init_barcodes = async function() {
else else
result = ifcb; result = ifcb;
// console.log(result.patterns) // console.log(result.patterns)
return result; return result;
}; };
...@@ -83,7 +83,13 @@ def labels_appli_csv(request, params): ...@@ -83,7 +83,13 @@ def labels_appli_csv(request, params):
try: try:
if (params == '/wc'): if (params == '/wc'):
withCandidate = True withCandidate = True
with_pos_categories = getattr(settings, 'EXPORT_POS_CAT_FOR_SCALES', False)
products = CagetteProducts.get_products_for_label_appli(withCandidate) products = CagetteProducts.get_products_for_label_appli(withCandidate)
if with_pos_categories is True:
pos_categories = CagetteProducts.get_pos_categories()
else:
pos_categories = []
rows = [] rows = []
for p in products: for p in products:
if (p['sale_ok'] is True): if (p['sale_ok'] is True):
...@@ -96,28 +102,31 @@ def labels_appli_csv(request, params): ...@@ -96,28 +102,31 @@ def labels_appli_csv(request, params):
barcode = '' barcode = ''
if not (barcode.isnumeric()): if not (barcode.isnumeric()):
barcode = '' barcode = ''
p_row = [p['id'], p['display_name'], barcode,
rows.append([p['id'], p['display_name'], barcode, p['list_price'],
p['list_price'], p['categ'],
# p['categ_id'][1], uom,
p['categ'], p['image'].replace("\n", "")]
uom, if with_pos_categories is True:
# p['image'].replace(img_temp_folder, ""), if p['pos_categ_id']:
p['image'].replace("\n", ""), p_row.append(p['pos_categ_id'][0])
# p['available_in_pos'] # ,p['sale_ok'] else:
]) p_row.append('')
rows.append(p_row)
header = ['id', 'nom', 'code-barre', 'prix', header = ['id', 'nom', 'code-barre', 'prix',
'categorie', 'unite', 'image' 'categorie', 'unite', 'image'
# 'en vente', 'sale_ok' # 'en vente', 'sale_ok'
] ]
if with_pos_categories is True and len(pos_categories) > 0:
header.append('id_categorie_pos')
with open(settings.DAV_PATH + '/pos_categories.json', 'w') as outfile:
json.dump(pos_categories, outfile)
os_file = settings.DAV_PATH + '/flv.csv' os_file = settings.DAV_PATH + '/flv.csv'
file_copies = [] file_copies = []
nb = 1 nb = int(getattr(settings, 'FLV_CSV_NB', 1))
if hasattr(settings, 'FLV_CSV_NB'):
nb = int(settings.FLV_CSV_NB)
for i in range(1, nb + 1): for i in range(1, nb + 1):
file_copies.append(settings.DAV_PATH + '/flv_' + str(i) + '.csv') file_copies.append(settings.DAV_PATH + '/flv_' + str(i) + '.csv')
...@@ -133,6 +142,8 @@ def labels_appli_csv(request, params): ...@@ -133,6 +142,8 @@ def labels_appli_csv(request, params):
file.close() file.close()
for c in file_copies: for c in file_copies:
copyfile(os_file, c) copyfile(os_file, c)
except Exception as e: except Exception as e:
res['error'] = str(e) res['error'] = str(e)
return JsonResponse({'res': res}) return JsonResponse({'res': res})
...@@ -176,14 +187,14 @@ def get_all_barcodes(request): ...@@ -176,14 +187,14 @@ def get_all_barcodes(request):
'available_in_pos': 3, 'available_in_pos': 3,
'id': 4, 'id': 4,
'standard_price': 5, 'standard_price': 5,
'uom_id': 6 'list_price': 6,
'uom_id': 7
} }
rules = CagetteProducts.get_barcode_rules() rules = CagetteProducts.get_barcode_rules()
res['patterns'] = rules['patterns']
res['aliases'] = rules['aliases']
res['time'] = int(round(time.time() * 1000)) - start res['time'] = int(round(time.time() * 1000)) - start
res['patterns'] = []
for r in rules:
if '{' in r['pattern'] or '.' in r['pattern']:
res['patterns'].append(r['pattern'])
except Exception as e: except Exception as e:
coop_logger.error("products_barcodes : %s", str(e)) coop_logger.error("products_barcodes : %s", str(e))
res['error'] = str(e) res['error'] = str(e)
......
...@@ -27,7 +27,7 @@ class Shelf(models.Model): ...@@ -27,7 +27,7 @@ class Shelf(models.Model):
self.o_api = OdooAPI() self.o_api = OdooAPI()
def get(self): def get(self):
res ={} res = {}
try: try:
c = [['id', '=', self.id]] c = [['id', '=', self.id]]
f = [] f = []
...@@ -200,6 +200,12 @@ class Shelf(models.Model): ...@@ -200,6 +200,12 @@ class Shelf(models.Model):
filename = tmp_inv_file_prefix + str(self.id) + '.json' filename = tmp_inv_file_prefix + str(self.id) + '.json'
os.remove(filename) os.remove(filename)
lockfilename = tmp_inv_file_prefix + str(self.id) + '.lock'
try:
os.remove(lockfilename)
except Exception as e:
pass
return True return True
except Exception as e: except Exception as e:
return False return False
...@@ -220,6 +226,24 @@ class Shelf(models.Model): ...@@ -220,6 +226,24 @@ class Shelf(models.Model):
first_inventory = json.load(json_file) first_inventory = json.load(json_file)
except Exception as e: except Exception as e:
coop_logger.error("Unable to process first step file : %s", e) coop_logger.error("Unable to process first step file : %s", e)
import errno
raise FileExistsError(errno.ENOENT, os.strerror(errno.ENOENT), filename)
lockfilename = tmp_inv_file_prefix + str(self.id) + '.lock'
# Look for lock file: if exists, first step file is being processed so stop here
try:
with open(lockfilename) as lock_file:
return {'error': 'First step file busy', 'busy': True}
except Exception as e:
pass
# Verification passed, create the lock file to indicate first step file is being processed
try:
with open(lockfilename, 'w') as lock_file:
json.dump({}, lock_file)
except Exception as e:
coop_logger.error("Unable to create lock file : %s", e)
if first_inventory: if first_inventory:
# if poducts in saved data # if poducts in saved data
......
...@@ -106,14 +106,18 @@ function handle_blinking_effect(element) { ...@@ -106,14 +106,18 @@ function handle_blinking_effect(element) {
// When edition event is fired // When edition event is fired
function edit_event(clicked) { function edit_event(clicked) {
// Remove from origin table // Remove from origin table
var row_data = null;
if (editing_origin == 'to_process') { if (editing_origin == 'to_process') {
let row = table_to_process.row(clicked.parents('tr')); let row = table_to_process.row(clicked.parents('tr'));
let row_data = row.data();
row_data = row.data();
remove_from_toProcess(row); remove_from_toProcess(row);
} else { } else {
let row = table_processed.row(clicked.parents('tr')); let row = table_processed.row(clicked.parents('tr'));
let row_data = row.data();
row_data = row.data();
remove_from_processed(row); remove_from_processed(row);
} }
...@@ -430,7 +434,7 @@ function pre_send() { ...@@ -430,7 +434,7 @@ function pre_send() {
// Proceed with inventory: send the request to the server // Proceed with inventory: send the request to the server
function send() { function send() {
if (is_time_to('submit_inv_qties')) { if (is_time_to('submit_inv_qties')) {
// Loading on // Loading on
var wz = $('#main-waiting-zone').clone(); var wz = $('#main-waiting-zone').clone();
wz.find('.msg').text("Patience, cela peut prendre de nombreuses minutes s'il y a une centaine de produits"); wz.find('.msg').text("Patience, cela peut prendre de nombreuses minutes s'il y a une centaine de produits");
...@@ -440,6 +444,7 @@ function send() { ...@@ -440,6 +444,7 @@ function send() {
shelf.user_comments = user_comments; shelf.user_comments = user_comments;
var url = "../do_" + originView + "_inventory"; var url = "../do_" + originView + "_inventory";
var call_begin_at = new Date().getTime();
$.ajaxSetup({ headers: { "X-CSRFToken": getCookie('csrftoken') } }); $.ajaxSetup({ headers: { "X-CSRFToken": getCookie('csrftoken') } });
$.ajax({ $.ajax({
...@@ -475,14 +480,59 @@ function send() { ...@@ -475,14 +480,59 @@ function send() {
// Clear local storage before leaving // Clear local storage before leaving
localStorage.removeItem(originView + '_' + shelf.id); localStorage.removeItem(originView + '_' + shelf.id);
}, },
error: function(data) { // 500 error has been thrown error: function(jqXHR, textStatus) { // 500 error has been thrown or web server sent a timeout
if (typeof data.responseJSON != 'undefined' && typeof data.responseJSON.error != 'undefined') { if (jqXHR.status == 504) {
console.log(data.responseJSON.error); /*
django is to long to respond.
Let it the same time laps before asking if the process is well done
*/
var now = new Date().getTime();
setTimeout(
function() {
$.ajax({
type: 'GET',
url: '../inventory_process_state/' + shelf.id,
success: function(rData) {
if ('res' in rData && 'state' in rData.res) {
if (shelf.inventory_status == 'step1_done' && rData.res.state != 'step1_done') {
// shelf inventory has been already done
localStorage.removeItem(originView + '_' + shelf.id);
closeModal();
back();
} else {
console.log('Still in process : need to call recursively to make other calls');
}
} else {
console.log(rData);
}
}
});
}
, now - call_begin_at
);
} else if (jqXHR.status == 500) {
var message = "Erreur lors de la sauvegarde des données. " +
"Pas de panique, les données de l'inventaire n'ont pas été perdues ! " +
"Merci de contacter un salarié et de réessayer plus tard.";
if (typeof jqXHR.responseJSON != 'undefined' && typeof jqXHR.responseJSON.error != 'undefined') {
//console.log(jqXHR.responseJSON.error);
if ('busy' in jqXHR.responseJSON) {
message = "Inventaire en cours de traitement.";
} else if (jqXHR.responseJSON.error == 'FileExistsError') {
//step1 file has been found => previous request succeeded
message = "Les données avaient déjà été transmises....";
// Clear local storage before leaving
localStorage.removeItem(originView + '_' + shelf.id);
}
}
closeModal();
alert(message);
back();
} }
closeModal();
alert("Erreur lors de la sauvegarde des données. " +
"Pas de panique, les données de l'inventaire n'ont pas été perdues ! " +
"Merci de contacter un salarié et de réessayer plus tard.");
} }
}); });
} else { } else {
......
...@@ -8,6 +8,7 @@ urlpatterns = [ ...@@ -8,6 +8,7 @@ urlpatterns = [
url(r'^$', views.index), url(r'^$', views.index),
url(r'^shelf_view/([0-9]+)$', views.shelf_view), url(r'^shelf_view/([0-9]+)$', views.shelf_view),
url(r'^shelf_inventory/([0-9]+)$', views.shelf_inventory), url(r'^shelf_inventory/([0-9]+)$', views.shelf_inventory),
url(r'^inventory_process_state/([0-9]+)$', views.inventory_process_state),
url(r'^all$', views.all), url(r'^all$', views.all),
url(r'^get_shelves_extra_data$', views.get_shelves_extra_data), url(r'^get_shelves_extra_data$', views.get_shelves_extra_data),
url(r'^(?P<shelf_id>\d+)$', views.shelf_data), url(r'^(?P<shelf_id>\d+)$', views.shelf_data),
......
...@@ -13,7 +13,7 @@ def index(request): ...@@ -13,7 +13,7 @@ def index(request):
"""Main shelf page""" """Main shelf page"""
shelfs = Shelfs.get_all() shelfs = Shelfs.get_all()
# TODO : Make the distinction beetween active and inactive products # TODO : Make the distinction beetween active and inactive products
for s in shelfs : for s in shelfs:
s['shelf_value'] = -1 s['shelf_value'] = -1
context = {'title': 'Rayons', context = {'title': 'Rayons',
...@@ -107,8 +107,29 @@ def add_product(request, shelf_id): ...@@ -107,8 +107,29 @@ def add_product(request, shelf_id):
return JsonResponse({'res': res}) return JsonResponse({'res': res})
def inventory_process_state(request, shelf_id):
res = {}
try:
s = Shelf(shelf_id)
s_data = s.get()
res['state'] = s_data['inventory_status']
except Exception as e:
res['error'] = str(e)
coop_logger.error("Inventory process state : %s", str(e))
if 'error' in res:
return JsonResponse(res, status=500)
else:
return JsonResponse({'res': res})
def do_shelf_inventory(request): def do_shelf_inventory(request):
"""Process shelf inventory""" """Process shelf inventory"""
"""
If many products are implied, the whole process could last many minutes.
During this time, user can submit data again.
This is managed with 'busy' message returned by Shelf.get_full_inventory_data method
Web server can also return a timeout message during this time.
This is managed by sending a query to above "get_process_state" (within browser ajax error capture)
"""
res = {} res = {}
# TODO : manage error strings array instead of one string # TODO : manage error strings array instead of one string
try: try:
...@@ -121,7 +142,8 @@ def do_shelf_inventory(request): ...@@ -121,7 +142,8 @@ def do_shelf_inventory(request):
'name': shelf_data['name'] + ' - ' + inventory_date.strftime("%d/%m/%Y"), 'name': shelf_data['name'] + ' - ' + inventory_date.strftime("%d/%m/%Y"),
'shelf_id': shelf_data['id'], 'shelf_id': shelf_data['id'],
'user_comments': shelf_data['user_comments'], 'user_comments': shelf_data['user_comments'],
'products': shelf_data['list_processed'] 'products': shelf_data['list_processed'],
'status': shelf_data['inventory_status']
} }
try: try:
filename = 'data/inventories_backup/' filename = 'data/inventories_backup/'
...@@ -129,20 +151,26 @@ def do_shelf_inventory(request): ...@@ -129,20 +151,26 @@ def do_shelf_inventory(request):
filename += "__" + str(shelf_data['id']) + '.json' filename += "__" + str(shelf_data['id']) + '.json'
with open(filename, 'w') as outfile: with open(filename, 'w') as outfile:
json.dump(shelf_data, outfile) json.dump(shelf_data, outfile)
except: except Exception as serr:
pass coop_logger.error("Inventory backup failure : %s", str(serr))
try: try:
if shelf_data['inventory_status'] == '' : if shelf_data['inventory_status'] == '':
# First step: save first products count in temp file # First step: save first products count in temp file
res = m.save_tmp_inventory(inventory_data) res = m.save_tmp_inventory(inventory_data)
else : else:
inventory_data['date'] = inventory_date inventory_data['date'] = inventory_date
inventory_data['shelf_name'] = shelf_data['name'] inventory_data['shelf_name'] = shelf_data['name']
inventory_data['shelf_num'] = shelf_data['sort_order'] inventory_data['shelf_num'] = shelf_data['sort_order']
# Get data from step 1 # Get data from step 1
full_inventory_data = m.get_full_inventory_data(inventory_data) full_inventory_data = m.get_full_inventory_data(inventory_data)
if 'error' in full_inventory_data:
res['error'] = full_inventory_data['error']
if 'busy' in full_inventory_data:
res['busy'] = True
return JsonResponse(res, status=500)
# Proceed with inventory # Proceed with inventory
res['inventory'] = CagetteInventory.update_stock_with_shelf_inventory_data(full_inventory_data) res['inventory'] = CagetteInventory.update_stock_with_shelf_inventory_data(full_inventory_data)
...@@ -173,7 +201,7 @@ def do_shelf_inventory(request): ...@@ -173,7 +201,7 @@ def do_shelf_inventory(request):
except Exception as e: except Exception as e:
# Don't validate if error anywhere in inventory process # Don't validate if error anywhere in inventory process
res['error'] = {'inventory' : str(e)} res['error'] = type(e).__name__
coop_logger.error("Shelf inv. : %s", str(e)) coop_logger.error("Shelf inv. : %s", str(e))
except Exception as err_json: except Exception as err_json:
res['error'] = "Unable to parse received JSON" res['error'] = "Unable to parse received JSON"
......
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