Beispiel #1
0
 def testSingletonDefaultDict(self):
     i = Inventory()
     i.clear()
     i2 = Inventory()
     self.assertIs(i.stock, i2.stock, 'singleton test fails')
     self.assertEqual(len(i.stock), 0, 'inventory SBE empty, found {} items'\
                                     .format(i.stock.keys()))
Beispiel #2
0
 def testExceptions(self):
     i = Inventory()
     i.clear()
     try:
         i.stock = dict()
         raise ValueError('stock rack_no should have raised exception')
     except ValueError as v:
         print(v)
         sys.exit(-1)
     except Exception as e:
         pass
Beispiel #3
0
 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)))
Beispiel #4
0
    def testStockingRackBins(self):
        Inventory.clear()
        Warehouse.clear()
        wh = Warehouse(5, 5)

        for i, (r, s, bn) in enumerate(
                product(range(1, 5 + 1, 1), list('ab'), range(1, 5 + 1, 1))):
            if s == 'a':
                b = wh.racks[r - 1].bins_a[bn]
            else:  # s == 'b'
                b = wh.racks[r - 1].bins_b[bn]
            wh.update_stock(i + 1, (i + 1) * 10, b.location)
            _, q = wh.get_stock_qty(i + 1)
            self.assertEqual(
                q, (i + 1) * 10,
                'inventory qty for item {}  item SBE {}, is {}'.format(
                    i, (i + 1) * 10, q))
Beispiel #5
0
 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)))
Beispiel #6
0
 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)))
Beispiel #7
0
    def testStockingRackBins(self):
        Inventory.clear()

        r = Rack(rack_no=1, bin_count=5)
        for b in r.bins_a.values():
            b.stock_bin(item_no=b.bin_no, item_count=b.bin_no * 10)
        for b in r.bins_b.values():
            b.stock_bin(item_no=b.bin_no, item_count=b.bin_no * 20)

        for b in r.bins_a.values():
            self.assertEqual(
                b.item, b.bin_no,
                'bin @ {}  item SBE {}, is {}'.format(b.location, b.bin_no,
                                                      b.item))
            self.assertEqual(
                b.count, b.bin_no * 10,
                'bin @ {}  count SBE {}, is {}'.format(b.location,
                                                       b.bin_no * 10, b.count))
        for b in r.bins_b.values():
            self.assertEqual(
                b.item, b.bin_no,
                'bin @ {}  item SBE {}, is {}'.format(b.location, b.bin_no,
                                                      b.item))
            self.assertEqual(
                b.count, b.bin_no * 20,
                'bin @ {}  count SBE {}, is {}'.format(b.location,
                                                       b.bin_no * 20, b.count))
        inv = Inventory()
        # Inventory.__stock[item_no][location]
        for b in r.bins_a.values():
            (i, q) = inv.get_stock_qty(location=b.location)
            self.assertEqual(
                (i, q), (b.item, b.count),
                'inventory item/qty for bin @ {}  item SBE {}, is {}'.format(
                    b.location, (b.item, b.count), (i, q)))
        for b in r.bins_b.values():
            (i, q) = inv.get_stock_qty(location=b.location)
            self.assertEqual(
                (i, q), (b.item, b.count),
                'inventory qty for bin @ {}  item SBE {}, is {}'.format(
                    b.location, (b.item, b.count), (i, q)))
Beispiel #8
0
class Test(unittest.TestCase):
    Warehouse.clear()
    wh = Warehouse(5, 5)
    rack_count, bin_count = wh.racks_bins
    bins_total = rack_count * bin_count * 2

    inv = Inventory()
    num_items = bins_total
    o = None
    order_lines = 5
    setup_calls = 0

    
    def setUp(self):
        Test.setup_calls += 1
        # print('setup call number {}'.format(Test.setup_calls))
        
        np.random.seed(42)
        
        Test.wh = Test.wh.reset(5, 5)
        self.wh = Test.wh
        Test.inv.clear()
        rsb = [(r, s, b) for r, s, b in product(range(1, 5 + 1, 1),
                                                list('ab'),
                                                range(1, 5 + 1, 1))]
        np.random.seed(42)
        np.random.shuffle(rsb)
        for i, (r, s, bn) in enumerate(rsb):
            if s == 'a':
                b = self.wh.racks[r - 1].bins_a[bn]
            else: # s == 'b'
                b = self.wh.racks[r - 1].bins_b[bn]
            self.wh.update_stock(i + 1, (i + 1) * 10, b.location)


        np.random.seed(42)
        Test.o = Order()
        np.random.seed(42)
        for i, q in zip(np.random.choice(range(1, Test.num_items + 1), size=Test.order_lines, replace=False),
                        np.random.randint(1, Test.num_items + 1, size=Test.order_lines)):
            Test.o.add_line(item_no=int(i), qty=int(q))

        racks = self.wh.racks
        b = racks[0].bins_a[1]
        self.assertEqual(b.item, 26, 'rack 1, bin @ {}, item SBE 26, is {}'.format(b.location, b.item))
        # print(b)
        b = racks[1].bins_a[1]
        self.assertEqual(b.item, 41, 'rack 1, bin @ {}, item SBE 41, is {}'.format(b.location, b.item))
        # print(b)
        b = racks[1].bins_b[1]
        self.assertEqual(b.item, 20, 'rack 1, bin @ {}, item SBE 29, is {}'.format(b.location, b.item))
        # print(b)
        


    def tearDown(self):
        pass


    def testInit(self):
        # print('testInit')
        pr = PickRoute(Test.wh, self.o)
        self.assertEqual(len(pr.wh.racks), 5, 'warehouse should have 5 racks, is {}'.format(len(pr.wh.racks)))
        self.assertEqual(len(self.o.lines), Test.order_lines, 'order lines SBE {}, is {}'.format(Test.order_lines,
                                                                                                 len(self.o.lines)))
        self.assertEqual(len(pr.pick_bins), Test.order_lines, \
                            'order pick_bins SBE {}, is {}'.format(Test.order_lines,
                                                                   len(pr.pick_bins)))
        
        
    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))
        #expected = 16
        #self.assertEqual(d, expected, '{} to {} SBE [], is {}'\
        #                    .format(b1.location, b2.location, expected, d))

        
    def testRoute(self):
        # print('testRoute')
        np.random.seed(42)
        pr = PickRoute(Test.wh, self.o)
        expected_steps = 46
        if pr.route_distance != expected_steps:
            print('route distance {:d} SBE {} {}'.format(pr.route_distance,
                                                         expected_steps,
                                                         'maybe next time?' \
                                                         if pr.route_distance != expected_steps \
                                                         else ''))
        # print(os.path.curdir)
        # I'm missing a random.seed somewhere
        self.assertEqual(pr.route_distance, expected_steps,
                         'route_distince SBE {}, is {}'\
                            .format(expected_steps, pr.route_distance))
Beispiel #9
0
class Warehouse:
    '''
A warehouse has inventory, racks, and a dock. Racks contain bins. Warehouse assigns a
lat / long to bins to allow computation of distance traveled from one bin to another.

The init args are:
    racks, int > 0 for how many racks are in warehouse
    bins, int > 0 for how many bins are in each rack
    
Assumptions:
    coordinates of warehouse's lower-left corner is (0, 0)
    dock is single location with lat == 0 and long centered WRT number of racks 
    bins_a[1] and bins_[1] are for bin 1
    shortest route from one bin to another goes through the rack end (cap) closest to the destination bin
'''

    __instance = None
    __inventory = Inventory()

    @classmethod
    def clear(cls):
        Inventory.clear()

    @classmethod
    def reset(cls, racks, bins):
        cls.__instance = None  # clear __instance so __init__ doen't fail
        cls.__instance = Warehouse(
            racks=racks, bins=bins)  # Now the initialization can be called
        Inventory.clear()
        return cls.__instance

    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 __repr__(self):
        return '''racks: {}, dock (lat, long): {}, inventory has {:,d} item_no, {:,d} quantities'''\
                .format(len(self.__racks), (self.__dock.lat, self.__dock.long),
                        len(Warehouse.__inventory.stock),
                        sum(b.count for b in Bin.bin_locations.values()))

    @classmethod
    def update_stock(cls, item_no, qty, location):
        '''
        Use Inventory.update_stock if called w/o location or with location == None so qty will be divided among bins holding item
        Use Inventory.update_bin if called with location
'''
        assert isinstance(
            location, Bin.Bin_Location
        ), 'update_stock SBE called with nlocation = None or instance of Bin_Location'
        cls.__inventory.update_bin(location, item_no, qty)

    def get_stock_qty(self, item_no):
        return Warehouse.__inventory.get_stock_qty(item_no)

    @property
    def racks(self):
        return self.__racks

    @racks.setter
    def racks(self, *args):
        assert 1 == 0, 'racks attribute set by init only'
        return

    @property
    def racks_bins(self):
        return self.__racks_bins

    @racks_bins.setter
    def racks_bins(self, args):
        assert 0 == 1, 'number of racks and bins fixed at instantiation'

    @property
    def dock(self):
        return self.__dock

    @dock.setter
    def dock(self, *arg):
        assert 1 == 0, 'dock lat/long set by init only'

    @property
    def stock(self):
        return Warehouse.__inventory.stock

    @property
    def inventory(self):
        return self.__inventory

    @inventory.setter
    def inventory(self, args):
        raise RuntimeError('inventory attribute set by init')
Beispiel #10
0
 def reset(cls, racks, bins):
     cls.__instance = None  # clear __instance so __init__ doen't fail
     cls.__instance = Warehouse(
         racks=racks, bins=bins)  # Now the initialization can be called
     Inventory.clear()
     return cls.__instance
Beispiel #11
0
 def clear(cls):
     Inventory.clear()
class Rack:
    '''
	Instantiation:
		Rack(rack_no = int > 0, bin_count = int > 0)
		
	Method Notes:
		bins_a and bins_b are dicts of bins and accessed by bin_no as key
'''

    _inventory = Inventory()

    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 __repr__(self):
        return 'rack_no {}, bin_count: {}, top_cap_lat: {:2d}, bottom_cap_lat: {}'\
          .format(self.__rack_no, self.__bin_count, \
            self.__top_cap_lat, self.__bottom_cap_lat)

    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)

    @property
    def rack_no(self):
        return self.__rack_no

    @rack_no.setter
    def rack_no(self, *arg, **varg):
        raise RuntimeError('rack_no is {} and can not be reset'.format(
            self.rack_no))

    @property
    def bins_a(self):
        return self.__bins_a

    @bins_a.setter
    def bins_a(self, *arg):
        raise RuntimeError('setting bin arrays by init')

    @property
    def bins_b(self):
        return self.__bins_b

    @bins_b.setter
    def bins_b(self, *arg):
        raise RuntimeError('setting bin arrays by init')

    @property
    def bin_count(self):
        return self.__bin_count

    @bin_count.setter
    def bin_count(self, *argv):
        raise RuntimeError('bin_count only gets set when adding bin(s)')
class Order:
    """
	Order contains order_lines which contain order_items
	
	Assumptions:
		It is permissable to add items to order that are not in Inventory
"""
    class OrderItem:
        '''
		OrderItem is class for contents of order line item
'''
        def __init__(self, line_no, item_no, qty, status='ordered'):
            self.__line_no = line_no
            self.__item_no = item_no
            self.__qty = qty
            self.__status = status

        def __repr__(self):
            return 'line_no: {}, item_no: {}, qty: {}, line status: {}'.format(
                self.line_no, self.item_no, self.qty, self.status)

        @property
        def line_no(self):
            return self.__line_no

        @property
        def item_no(self):
            return self.__item_no

        @property
        def qty(self):
            return self.__qty

        @property
        def status(self):
            return self.__status

        @status.setter
        def status(self, stat):
            self.__status = stat

    ##############################
    # Order class variabiles

    __last_order_no = 0

    __inventory = Inventory()

    @classmethod
    def clear(cls):
        '''
		clear needed to keep unit tests independent
'''
        cls.__last_order_no = 0
        pass  # for debugging

    @classmethod
    def last_order_no(cls):
        return cls.__last_order_no

    def __init__(self):
        Order.__last_order_no += 1
        self.__order_no__ = 0 + Order.__last_order_no
        self.__lines = []
        self.__last_line_no = 0

    def add_line(self, item_no=None, qty=None):
        assert item_no is not None,\
         'Order Line SBE instantiated with item_no and qty'
        assert isinstance(item_no, int) and item_no > 0,\
         'item_no must be int > 0, is {}'.format(item_no)
        assert isinstance(qty, int) and qty > 0,\
         'qty must be int > 0, is {}'.format(qty)

        # not sure I'm ready for this assert:
        # assert item_no in Order.__inventory, 'attemted to add item not in inventory: {}'.format(item_no)

        self.__last_line_no += 1
        line = Order.OrderItem(0 + self.__last_line_no, item_no, qty,
                               'ordered')
        self.__lines.append((line))

    def __repr__(self):
        return ('order_no: {}, {} lines'.format(self.__order_no__,
                                                len(self.__lines)))

    @property
    def order_no(self):
        return self.__order_no__

    @property
    def lines(self):
        return self.__lines
Beispiel #14
0
 def testReprStr(self):
     i = Inventory()
     r = i.__repr__()
     s = i.__str__()
     self.assertEqual(r, s, 'repr "{}" not eq str "{}"'.format(r, s))
Beispiel #15
0
    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 setUp(self):
     Inventory.clear()