def set_bom(partno, data): """ Updates the BOM data for the given part number """ ensure_exists(partno) bomdata = list() for item in data: p = item.get('partno') ensure_exists(p) bomdata.append(dict(partno=p, quantity=int(item['quantity']))) result = current_app.mongo.db.stock.update_one( filter={'_id': partno}, update={'$set': {'bom': bomdata}}, upsert=True) if result.modified_count == 0 and result.upserted_id is None: raise RuntimeError('no BOM object modified nor created')
def update_batch(partno, batchname, quantity): """ Updates the given stock batch item, creating it if necessary. Raises an exception if the part number is not valid or if there is a database problem """ if quantity < 0: raise ValueError('A batch cannot have negative quantities') ensure_exists(partno) if quantity == 0 or not batchname: return # nothing to do result = current_app.mongo.db.stock_batches.update_one( filter={ 'partno': partno, 'name': batchname }, update={'$inc': {'quantity': quantity}}, upsert=True ) if result.modified_count == 0 and result.upserted_id is None: raise RuntimeError('no stock batch object modified nor created')
def _import_file(filepath): """ Processes the XLS data, ensures that the part numbers exist (incl. revision) and that all the required fields are set. If something is missing a warning is flashed but processing continues. Returns a tuple (success, headers, data) """ headers, data = read_xls(filepath) success = True if 'partno' not in headers: raise ValueError("'partno' column is missing") if 'serial' not in headers: raise ValueError("'serial' column is missing") if '_id' in headers: raise ValueError("reserved column name: '_id'") if 'comments' in headers: raise ValueError("reserved column name: 'comments'") if 'available' in headers: raise ValueError("reserved column name: 'available'") for idx, item in enumerate(data): try: pn = PartNumber(item.get('partno')) ensure_exists(pn.base_number) if pn.revision is None: raise ValueError('part number requires a revision') serial = item.get('serial') if not serial: raise ValueError('serial number is missing') # transform the serial to a string AFTER checking it exists. Otherwise the string would read 'None' serial = str(serial) if current_app.mongo.db.items.find_one(serial): raise ValueError("serial number '%s' exists already" % serial) reqs = get_requirements(pn) process_requirements(item, reqs) except Exception as e: flash('%s (row %d)' % (e, (idx+2)), 'error') success = False return success, headers, data
def _check_bom(partno, tree=set()): """ Recursively checks that the BOM tree is valid. The tree parameter tracks the parents of the current node, use an empty set for the top-level component """ ensure_exists(partno) # obtain the BOM obj = current_app.mongo.db.stock.find_one(partno) if not obj: return bom = obj.get('bom', list()) if len(bom) == 0: return # recursively check the BOM tree.add(partno) for entry in bom: pn = entry.get('partno') if pn in tree: raise RuntimeError('Infinite loop detected') _check_bom(pn, tree) tree.remove(partno)
def _import_file(filepath): headers, data = read_xls(filepath) success = True if 'quantity' not in headers: raise ValueError("'quantity' column is missing") if 'partno' not in headers: raise ValueError("'partno' column is missing") for idx, item in enumerate(data): try: # the part number must exist # quantity is optional, set as zero if missing ensure_exists(item.get('partno')) qstr = item.get('quantity') if qstr: quantity = int(qstr) else: quantity = 0 if quantity < 0: raise ValueError('quantity must be non-negative') item['quantity'] = quantity except Exception as e: flash('%s (row %d)' % (e, (idx+2)), 'error') success = False return success, headers, data