def testInitMissing(self): # confirm argument testing try: t = 'rack_no' _ = Bin(side='a', bin_no=1, item=1, count=10) raise ValueError('missing {} SBE exception'.format(t)) except ValueError: print(t) sys.exit(-1) except Exception: pass try: t = 'bin_no' _ = Bin(rack_no=1, side='a', item=1, count=10) raise ValueError('missing {} SBE exception'.format(t)) except ValueError: print(t) sys.exit(-1) except Exception: pass try: t = 'side' _ = Bin(rack_no=1, bin_no=1, item=1, count=10) raise ValueError('missing {} SBE exception'.format(t)) except ValueError: print(t) sys.exit(-1) except Exception: pass
def testBinLocation(self): bl1 = Bin.Bin_Location(1, 'a', 1) bl2 = Bin.Bin_Location(1, 'a', 1) self.assertEqual(bl1, bl2, '{} SBE equal {}'.format(bl1, bl2)) bl2 = Bin.Bin_Location(1, 'a', 2) self.assertNotEqual(bl1, bl2, '{} SBE not equal {}'.format(bl1, bl2)) self.assertLess(bl1, bl2, '{} SBE LT {}'.format(bl1, bl2))
def update_bin(cls, location, item_no, qty): ''' add or subtract qty in bin at location if item being updated != item in bin at location, bin.__item, bin.__count = item_no, qty Assumption: if called to update bin with new item, then all inbins with old item will be replaced everywhere. Use Bin.__stock_bin to update individual bins but be sure to only update bin instances that live in Inventory ''' assert isinstance( location, Bin.Bin_Location ), 'location SBE instance of Bin.Bin_Location, is {}'.format( location.__class__) assert isinstance(qty, int), 'qty mst be int' assert isinstance(item_no, int) and item_no > 0, 'item_no must be int > 0' b = Bin.get_bin_by_location(location) if b is None: b = Bin(rack_no=location.rack, side=location.side, bin_no=location.bin_no) if b.item != item_no: try: cls.__stock[item_no].discard(location) except: pass b.stock_bin(item_no, qty) cls.__stock[item_no].add(b.location) pass
def loc_to_loc_distance(self, from_loc, to_loc): '''Manhattan distance, not Euclidian call with two Bin class instances ''' assert isinstance(from_loc, Bin.Bin_Location) and isinstance(to_loc, Bin.Bin_Location),\ 'both arguments must be instance of Bin class' from_bin = Bin.get_bin_by_location(from_loc) to_bin = Bin.get_bin_by_location(to_loc) return bin_to_bin_distance(*sorted((from_bin, to_bin)))
def testGetBinByLocation(self): # confirm initialization of attributes b = Bin(rack_no=1, side='b', bin_no=5, item=2, count=10) location = b.location b = Bin.get_bin_by_location(location) self.assertEqual( (1, 'b', 5), (location.rack, location.side, location.bin_no),\ 'bin rack_no, side, bin_no SBE (1, "b", 5), is {}'\ .format((location.rack, location.side, location.bin_no))) self.assertEqual((6, 2), (b.lat, b.long), \ 'bin lat/long SBE {}, is{}'.format((2, 0), (b.lat, b.long))) b = Bin(rack_no=1, side='a', bin_no=1, item=1, count=10) location = b.location b = Bin.get_bin_by_location(location) self.assertEqual((1, 'a', 1), (location.rack, location.side, location.bin_no),\ 'bin rack_no, side, bin_no SBE (1, "a", a), is {}'\ .format((location.rack, location.side, location.bin_no))) self.assertEqual((2, 1), (b.lat, b.long), \ 'bin lat/long SBE {}, is{}'.format((2, 0), (b.lat, b.long))) b = Bin.get_bin_by_location(location) b.stock_bin( item_no=2, item_count=30) # removes prior item (1) replacing with item 2 self.assertEqual((2, 1, 1, 'a', 30), (b.item, b.bin_no, b.rack_no, b.bin_side, b.count),\ 'item and count SBE (1, 30), is {}'.format((b.item, b.count)))
def testAddItem(self): b = Bin(rack_no=1, side='b', bin_no=2) itm_no = 3 qty = 30 i = Inventory() i.clear() i.update_bin(location=b.location, item_no=itm_no, qty=qty) self.assertEqual(i.get_stock_qty(location=b.location), (itm_no, qty), \ "item {} at {} SBE qty {}, is {}".format(itm_no, qty, b.location, i.get_stock_qty(location=b.location))) b = Bin.get_bin_by_location(b.location) self.assertEqual(b.item, itm_no, \ 'location ({} item/qty SBE {}, is {}'.format(b.location, (itm_no, qty), (b.item, b.count)))
def testClear(self): b = Bin(rack_no=1, side='a', bin_no=1) b.__count = 0 i = Inventory() i.clear() Inventory.update_bin(location=b.location, item_no=1, qty=10) self.assertEqual( len(i.stock), 1, 'SBE only 1 item in inventory stock, is {}'.format(len(i.stock))) i.clear() self.assertEqual( len(i.stock), 0, 'SBE no1 items in inventory stock after clear, is {}'.format( len(i.stock)))
def testInit(self): b = Bin(rack_no=1, side='b', bin_no=3) self.assertEqual(b.rack_no, 1, 'rack_no SBE 1, is {}'.format(b.rack_no)) self.assertEqual(b.bin_no, 3, 'bin_no SBE 3, is {}'.format(b.bin_no)) self.assertEqual(b.bin_side, 'b', 'bin_no SBE "b", is {}'.format(b.bin_side)) self.assertEqual( b.location, Bin.Bin_Location(1, 'b', 3), 'bin_no SBE {}, is {}'.format(Bin.Bin_Location(1, 'b', 3), b.location)) self.assertEqual(b.lat, 4, 'bin_no SBE 4, is {}'.format(b.lat)) self.assertEqual(b.long, 2, 'bin_no SBE 2, is {}'.format(b.long)) self.assertIsNone(b.item, 'item SBE None, is {}'.format(b.item)) self.assertEqual(b.count, 0, 'bin_no SBE 0, is {}'.format(b.count))
def __init__(self, racks=None, bins=None): if type(self).__instance is None: # Initialization assert isinstance(racks, int) and racks > 0, \ 'number of racks must be int > 0' assert isinstance(bins, int) and bins > 0, \ 'number of bins must be int > 0' type(self).__instance = self dock_rack = round((racks / 2) + .1) # friggin "Banker's rounding! self.__dock = Bin(rack_no=dock_rack, side='a', bin_no=0) self.__dock.nearest_cap = self.__dock self.__dock.nearest_cap_distance = 0 self.__racks_bins = (racks, bins) self.__racks = [ Rack(rack_no=x, bin_count=bins) for x in range(1, racks + 1, 1) ] self.__bins = [ list(r.bins_a.values()) + list(r.bins_b.values()) for r in self.__racks ][0] else: self.__dict__ = Warehouse.__instance.__dict__
def nearest_cap(self, b): (dist_bottom, dist_top) = (b.bin_no, self.bin_count - b.bin_no + 1) if dist_bottom > dist_top: bin_no = self.bin_count + 1 else: bin_no = 0 return Bin(rack_no=self.rack_no, side=b.bin_side, bin_no=bin_no)
def __init__(self, wh, order): ''' Constructor ''' assert isinstance(order, Order), 'order must be instance of Order' self.__order = order self.__order_lines = order.lines self.warehouse = wh # pick up singleton self.__pick_bins = set() self.__pick_items = set() for line in self.order_lines: item_locations = self.warehouse.stock[line.item_no] if len(item_locations) == 0: # silently ignore items not in inventory # but monkey-patch note that item not in inventory line.status = 'not in inventory' else: self.__pick_items.add(line.item_no) for item_location in item_locations: self.__pick_bins.add( Bin.get_bin_by_location(item_location)) self.__route = OrderedDict() self.__route_distance = 0 self.__calc_route()
def testUpdateStock(self): r_no = 3 i_no = 3 location = Bin.Bin_Location(rack_no=r_no, side='a', bin_no=1) i = Inventory() i.clear() i.update_bin(item_no=i_no, location=location, qty=10) self.assertEqual(Inventory.__repr__(Inventory()), str(Inventory()), '__repr__ != __string__') self.assertEqual(len(i.stock), 1, 'inventory SBE empty, found {} items'\ .format(len(i.stock)))
def __repr__(self): if len(self.stock.values()) > 0: qty = sum([ sum( Bin.get_bin_by_location(loc).count for loc in Inventory.__stock[itm]) for itm in Inventory.__stock.keys() ]) else: qty = 0 return 'Inventory: {:,d} items, {:,d} total quantity'\ .format(len(self.stock), qty)
def get_stock_qty(cls, item_no=None, location=None): ''' First, if location is not None return bin.count @ location, otherwise check item_no is not None If item_no is not None, return quantity of item_no at all location. If both item_no and location are None or both are Not None, error ''' assert item_no is not None or location is not None, 'either item_no or location are not None' assert item_no is None or location is None, \ 'either item_no or location are not None, NOT both' if location is not None: b = Bin.get_bin_by_location(location) return ( b.item, b.count ) # it is caller's responsibility to check b.item == item_no elif item_no is None or item_no not in cls.__stock: # item_no is not None by assertion above return (item_no, 0) else: return (item_no, sum([ Bin.get_bin_by_location(loc).count for loc in cls.__stock[item_no] ]))
def testDropBin(self): # del Bin.__bin_locations[location] Bin.clear() self.assertEqual( len(Bin.bin_locations), 0, 'clear method should reset class list of prior Bin instances') bl1 = Bin(rack_no=1, side='a', bin_no=1) bl2 = Bin(rack_no=1, side='a', bin_no=2) self.assertEqual(len(Bin.bin_locations), 2, 'class list of Bin instances SBE len 2, is {}'\ .format(len(Bin.bin_locations))) Bin.drop_bin(bl1.location) self.assertEqual(len(Bin.bin_locations), 1, 'class list of Bin instances SBE len 1 after drop_bin, is {}'\ .format(len(Bin.bin_locations))) self.assertEqual(bl2, Bin.get_bin_by_location(bl2.location), 'bin at {} should still be in bin instance list after drop'\ .format(bl2.location))
def testBinsDistance(self): # print('testBinsDistance') b1 = Bin(rack_no=1, side='b', bin_no=1) b2 = Bin(rack_no=1, side='a', bin_no=5) pr = PickRoute(Test.wh, self.o) d = pr.bin_to_bin_distance(b1, b2) print('from {} to {} dist: {}'.format(b1.location, b2.location, d)) #expected = 16 #self.assertEqual(d, expected, '{} to {} SBE [], is {}'\ # .format(b1.location, b2.location, expected, d)) b1 = Bin(rack_no=1, side='b', bin_no=1) b2 = Bin(rack_no=2, side='a', bin_no=1) pr = PickRoute(Test.wh, self.o) d = pr.bin_to_bin_distance(b1, b2) print('from {} to {} dist: {}'.format(b1.location, b2.location, d)) #expected = 16 #self.assertEqual(d, expected, '{} to {} SBE [], is {}'\ # .format(b1.location, b2.location, expected, d)) b1 = Bin(rack_no=1, side='a', bin_no=4) b2 = Bin(rack_no=4, side='b', bin_no=5) pr = PickRoute(Test.wh, self.o) d = pr.bin_to_bin_distance(b1, b2) print('from {} to {} dist: {}'.format(b1.location, b2.location, d)) #expected = 16 #self.assertEqual(d, expected, '{} to {} SBE [], is {}'\ # .format(b1.location, b2.location, expected, d)) b1 = Bin(rack_no=3, side='a', bin_no=0) b2 = Bin(rack_no=4, side='b', bin_no=5) pr = PickRoute(Test.wh, self.o) d = pr.bin_to_bin_distance(b1, b2) print('from dock {} to {} dist: {}'.format(b1.location, b2.location, d))
def __init__(self, rack_no, bin_count): assert isinstance(rack_no, int) and rack_no > 0,\ 'rack_no must be int > 0' assert isinstance(bin_count, int) and bin_count > 0,\ 'bin_count must be int > 0' self.__rack_no = rack_no self.__bin_count = bin_count self.__top_cap_lat = bin_count + 2 # always with fixed # of bins self.__bottom_cap_lat = 1 # always self.__bins_a = dict() # access via bin_no self.__bins_b = dict() # access via bin_no for bin_no in range(1, bin_count + 1, 1): b = Bin(rack_no=self.rack_no, side='a', bin_no=bin_no) b.nearest_cap = self.nearest_cap(b) b.nearest_cap_distance = int( abs(b.lat_long - b.nearest_cap.lat_long).sum()) self.__bins_a[bin_no] = b b = Bin(rack_no=self.rack_no, side='b', bin_no=bin_no) b.nearest_cap = self.nearest_cap(b) b.nearest_cap_distance = int( abs(b.lat_long - b.nearest_cap.lat_long).sum()) self.__bins_b[bin_no] = b
def testUpdateStockSeparateSides(self): b = Bin(rack_no=1, side='a', bin_no=1) b.__count = 0 i = Inventory() i.clear() Inventory.update_bin(location=b.location, item_no=1, qty=10) self.assertEqual(Inventory.__repr__(Inventory()), str(Inventory()), '__repr__ != __string__') self.assertEqual( len(i.stock), 1, 'inventory SBE empty, found {} items'.format(len(i.stock))) self.assertEqual(Bin.get_bin_by_location(b.location).count, 10, 'location ({} item SBE 10, is {}'\ .format(b.location, Bin.get_bin_by_location(b.location))) b = Bin(rack_no=1, side='b', bin_no=2) location = b.location i.update_bin(location=location, item_no=1, qty=20) (itm, q) = i.get_stock_qty(location=location) self.assertEqual( itm, 1, 'item at location {} SBE 1, is {}'.format(location, itm)) self.assertEqual( q, 20, "item {} at {} SBE qty 20, is {}".format(1, location, q))
def testExceptions(self): b = Bin(rack_no=1, side='a', bin_no=1, item=1, count=10) try: b.rack_no = 2 raise ValueError('trying to set rack_no should raise exception') except ValueError as ve: print(ve) sys.exit(-1) except: pass try: b.bin_no = 2 raise ValueError('trying to set bin_no should raise exception') except ValueError as ve: print(ve) sys.exit(-1) except: pass try: b.bin_side = 'b' raise ValueError('trying to set bin_side should raise exception') except ValueError as ve: print(ve) sys.exit(-1) except: pass try: b.location = (1, 'a', 1) raise ValueError('trying to set location should raise exception') except ValueError as ve: print(ve) sys.exit(-1) except: pass try: b.lat = (1, 'a', 1) raise ValueError('trying to set lat should raise exception') except ValueError as ve: print(ve) sys.exit(-1) except: pass try: b.long = (1, 'a', 1) raise ValueError('trying to set long should raise exception') except ValueError as ve: print(ve) sys.exit(-1) except: pass try: b.item = (1, 'a', 1) raise ValueError('trying to set item should raise exception') except ValueError as ve: print(ve) sys.exit(-1) except: pass try: b.count = (1, 'a', 1) raise ValueError('trying to set count should raise exception') except ValueError as ve: print(ve) sys.exit(-1) except: pass
def get_location_bin(cls, location): assert isinstance( location, Bin.Bin_Location ), 'location must be an Bin.Bin_Location, is {}'.format(location) b = Bin.get_bin_by_location(location) return b