'rule_ids': fields.one2many('barcode.rule','barcode_nomenclature_id','Rules', help='The list of barcode rules'),
}
- # returns the checksum of the ean, or -1 if the ean has not the correct length, ean must be a string
+ # returns the checksum of the ean13, or -1 if the ean has not the correct length, ean must be a string
def ean_checksum(self, ean):
code = list(ean)
if len(code) != 13:
total = oddsum * 3 + evensum
return int((10 - total % 10) % 10)
- # Returns true if the ean is a valid EAN codebar number by checking the control digit.
- # ean must be a string
- def check_ean(self, ean):
- return re.match(re.compile('\d+$'), ean) and (self.ean_checksum(ean) == int(ean[len(ean)-1]))
-
# Returns a valid zero padded ean13 from an ean prefix. the ean prefix must be a string.
def sanitize_ean(self, ean):
ean = ean[0:13]
ean = ean + (13-len(ean))*'0'
return ean[0:12] + str(self.ean_checksum(ean))
- # Attempts to interpret an ean (string encoding an ean)
- # It will check its validity then return an object containing various
- # information about the ean.
+ # Attempts to interpret an barcode (string encoding a barcode)
+ # It will return an object containing various information about the barcode.
# most importantly :
- # - code : the ean
- # - type : the type of the ean:
- # 'price' | 'weight' | 'product' | 'cashier' | 'client' | 'discount' | 'error'
+ # - code : the barcode
+ # - type : the type of the barcode:
+ # 'price' | 'weight' | 'product' | 'cashier' | 'client' | 'discount' | 'lot' |
+ # 'package' | 'location' | 'error'
# - value : if the id encodes a numerical value, it will be put there
- # - base_code : the ean code with all the encoding parts set to zero; the one put on
+ # - base_code : the barcode code with all the encoding parts set to zero; the one put on
# the product in the backend
- def parse_ean(self, ean):
- parse_result = {'encoding': 'ean13', 'type': 'error', 'code': ean, 'base_code': ean, 'value': 0}
-
- rules = []
- for rule in self.rule_ids:
- rules.append({'type': rule.type, 'sequence': rule.sequence, 'pattern': rule.pattern})
+ def parse_ean(self, barcode):
+ parsed_result = {
+ 'encoding': '',
+ 'type': 'error',
+ 'code': barcode,
+ 'base_code': barcode,
+ 'value': 0}
- if not self.check_ean(ean):
- return parse_result
-
- def is_number(char):
- n = ord(char)
- return n >= 48 and n <= 57
-
- def match_pattern(ean,pattern):
+ def match_pattern(barcode,pattern):
+ if(len(barcode) < len(pattern.replace('{','').replace('}',''))):
+ return False # match of this pattern is impossible
+ numerical_content = False
+ j=0
for i in range(len(pattern)):
p = pattern[i]
- e = ean[i]
- if is_number(p) and p != e:
+ if p == '{' or p == '}':
+ numerical_content = not numerical_content
+ continue
+
+ if not numerical_content and p != '*' and p != barcode[j]:
return False
+ j+=1
return True
- def get_value(ean,pattern):
+ def get_value(barcode,pattern):
value = 0
decimals = 0
+ numerical_content = False
+ j = 0
for i in range(len(pattern)):
p = pattern[i]
- v = int(ean[i])
+ if not numerical_content and p != "{":
+ j+=1
+ continue
+ elif p == "{":
+ numerical_content = True
+ continue
+ elif p == "}":
+ break;
+
+ v = int(barcode[j])
if p == 'N':
value *= 10
value += v
elif p == 'D': #FIXME precision ....
decimals += 1
value += v * pow(10,-decimals)
+ j+=1
return value
- def get_basecode(ean,pattern):
+ def get_basecode(barcode,pattern,encoding):
base = ''
+ numerical_content = False
+ j = 0
for i in range(len(pattern)):
p = pattern[i]
- v = ean[i]
- if p == '*' or is_number(p):
- base += v
- else:
+ if p == '{' or p == '}':
+ numerical_content = not numerical_content
+ continue
+
+ if numerical_content:
base += '0'
- return self.sanitize_ean(base)
+ else:
+ base += barcode[j]
+ j+=1
- for rule in rules:
- if match_pattern(ean, rule['pattern']):
- parse_result['type'] = rule['type']
- parse_result['value'] = get_value(ean, rule['pattern'])
- parse_result['base_code'] = get_basecode(ean, rule['pattern'])
- return parse_result
+ for i in range(j, len(barcode)): # Read the rest of the barcode
+ base += barcode[i]
+ if encoding == "ean13":
+ base = self.sanitize_ean(base)
+ return base
- return parse_result
+ rules = []
+ for rule in self.rule_ids:
+ rules.append({'type': rule.type, 'encoding': rule.encoding, 'sequence': rule.sequence, 'pattern': rule.pattern})
+
+ for rule in rules:
+ if match_pattern(barcode, rule['pattern']):
+ parsed_result['encoding'] = rule['encoding']
+ parsed_result['type'] = rule['type']
+ parsed_result['value'] = get_value(barcode, rule['pattern'])
+ parsed_result['base_code'] = get_basecode(barcode, rule['pattern'], parsed_result['encoding'])
+ return parsed_result
+ return parsed_result
class barcode_rule(osv.osv):
_name = 'barcode.rule'
def process_barcode_from_ui(self, cr, uid, picking_id, barcode_str, visible_op_ids, context=None):
'''This function is called each time there barcode scanner reads an input'''
- lot_obj = self.pool.get('stock.production.lot')
- package_obj = self.pool.get('stock.quant.package')
- product_obj = self.pool.get('product.product')
stock_operation_obj = self.pool.get('stock.pack.operation')
- stock_location_obj = self.pool.get('stock.location')
answer = {'filter_loc': False, 'operation_id': False}
# Barcode Nomenclatures
return answer # TODO: return specific error?
else:
barcode_nom = rec.barcode_nomenclature_id
- parse_result = barcode_nom.parse_ean(barcode_str)
+ parsed_result = barcode_nom.parse_ean(barcode_str)
+
+ #check if the barcode is a weighted barcode or simply a product
+ if parsed_result['type'] in ['weight', 'product', 'package']:
+ weight=-1
+ if parsed_result['type'] == 'weight':
+ domain = ['|', ('ean13', '=', parsed_result['base_code']), ('default_code', '=', barcode_str)]
+ weight=parsed_result['value']
+ obj = self.pool.get('product.product')
+ id_in_operation = 'product_id'
+ elif parsed_result['type'] == 'product':
+ domain = ['|', ('ean13', '=', barcode_str), ('default_code', '=', barcode_str)]
+ obj = self.pool.get('product.product')
+ id_in_operation = 'product_id'
+ else:
+ domain = [('name', '=', barcode_str)]
+ obj = self.pool.get('stock.quant.package')
+ id_in_operation = 'package_id'
- #check if the barcode is a weighted barcode
- if parse_result['type'] == 'weight':
- matching_product_ids = product_obj.search(cr, uid, ['|', ('ean13', '=', parse_result['base_code']), ('default_code', '=', barcode_str)], context=context)
+ matching_product_ids = obj.search(cr, uid, domain, context=context)
if matching_product_ids:
- op_id = stock_operation_obj._search_and_increment(cr, uid, picking_id, [('product_id', '=', matching_product_ids[0])], filter_visible=True, visible_op_ids=visible_op_ids, weight=parse_result['value'], increment=True, context=context)
+ op_id = stock_operation_obj._search_and_increment(cr, uid, picking_id, [(id_in_operation, '=', matching_product_ids[0])], filter_visible=True, visible_op_ids=visible_op_ids, weight=weight, increment=True, context=context)
answer['operation_id'] = op_id
return answer
- else:
- print "Weighted barcode but product not found" #TODO: what to do here?
-
- #check if the barcode correspond to a location
- matching_location_ids = stock_location_obj.search(cr, uid, [('loc_barcode', '=', barcode_str)], context=context)
- if matching_location_ids:
- #if we have a location, return immediatly with the location name
- location = stock_location_obj.browse(cr, uid, matching_location_ids[0], context=None)
- answer['filter_loc'] = stock_location_obj._name_get(cr, uid, location, context=None)
- answer['filter_loc_id'] = matching_location_ids[0]
- return answer
- #check if the barcode correspond to a product
- matching_product_ids = product_obj.search(cr, uid, ['|', ('ean13', '=', barcode_str), ('default_code', '=', barcode_str)], context=context)
- if matching_product_ids:
- op_id = stock_operation_obj._search_and_increment(cr, uid, picking_id, [('product_id', '=', matching_product_ids[0])], filter_visible=True, visible_op_ids=visible_op_ids, increment=True, context=context)
- answer['operation_id'] = op_id
- return answer
+
#check if the barcode correspond to a lot
- matching_lot_ids = lot_obj.search(cr, uid, [('name', '=', barcode_str)], context=context)
- if matching_lot_ids:
- lot = lot_obj.browse(cr, uid, matching_lot_ids[0], context=context)
- op_id = stock_operation_obj._search_and_increment(cr, uid, picking_id, [('product_id', '=', lot.product_id.id), ('lot_id', '=', lot.id)], filter_visible=True, visible_op_ids=visible_op_ids, increment=True, context=context)
- answer['operation_id'] = op_id
- return answer
- #check if the barcode correspond to a package
- matching_package_ids = package_obj.search(cr, uid, [('name', '=', barcode_str)], context=context)
- if matching_package_ids:
- op_id = stock_operation_obj._search_and_increment(cr, uid, picking_id, [('package_id', '=', matching_package_ids[0])], filter_visible=True, visible_op_ids=visible_op_ids, increment=True, context=context)
- answer['operation_id'] = op_id
- return answer
+ elif parsed_result['type'] == 'lot':
+ lot_obj = self.pool.get('stock.production.lot')
+ matching_lot_ids = lot_obj.search(cr, uid, [('name', '=', barcode_str)], context=context)
+ if matching_lot_ids:
+ lot = lot_obj.browse(cr, uid, matching_lot_ids[0], context=context)
+ op_id = stock_operation_obj._search_and_increment(cr, uid, picking_id, [('product_id', '=', lot.product_id.id), ('lot_id', '=', lot.id)], filter_visible=True, visible_op_ids=visible_op_ids, increment=True, context=context)
+ answer['operation_id'] = op_id
+ return answer
+
+ #check if the barcode correspond to a location
+ elif parsed_result['type'] == 'location':
+ stock_location_obj = self.pool.get('stock.location')
+ matching_location_ids = stock_location_obj.search(cr, uid, [('loc_barcode', '=', barcode_str)], context=context)
+ if matching_location_ids:
+ #if we have a location, return immediatly with the location name
+ location = stock_location_obj.browse(cr, uid, matching_location_ids[0], context=None)
+ answer['filter_loc'] = stock_location_obj._name_get(cr, uid, location, context=None)
+ answer['filter_loc_id'] = matching_location_ids[0]
+ return answer
+
return answer
def action_done(self, cr, uid, ids, context=None):
""" Process completely the moves given as ids and if all moves are done, it will finish the picking.
"""
- print "Action done"
context = context or {}
picking_obj = self.pool.get("stock.picking")
quant_obj = self.pool.get("stock.quant")
op = self.copy(cr, uid, pack_op.id, {'product_qty': pack_op.qty_done, 'qty_done': pack_op.qty_done}, context=context)
self.write(cr, uid, [pack_op.id], {'product_qty': pack_op.product_qty - pack_op.qty_done, 'qty_done': 0, 'lot_id': False}, context=context)
processed_ids.append(op)
+ print "Nb processed: " + str(len(processed_ids))
self.write(cr, uid, processed_ids, {'processed': 'true'}, context=context)
def create_and_assign_lot(self, cr, uid, id, name, context=None):
op_obj = self.browse(cr, uid, operation_id, context=context)
qty = op_obj.qty_done
if increment:
- if weight == -1: # button + pressed
- if op_obj.product_qty != qty:
+ if weight == -1: # increment by 1
+ if qty < op_obj.product_qty:
qty = min(qty+1, op_obj.product_qty);
else:
qty += 1
'product_qty': 0,
'location_id': picking.location_id.id,
'location_dest_id': picking.location_dest_id.id,
- 'qty_done': weight,
+ 'qty_done': weight if weight != -1 else 1,
}
for key in domain:
var_name, dummy, value = key