""" ------------------------------------------------------- This file contains and defines the SupplyChainActor class. ------------------------------------------------------- Author: Tom LaMantia Email: tom@lamantia.mail.utoronto.ca Version: February 7th 2016 ------------------------------------------------------- """ from Settings import * from SupplyChainQueue import SupplyChainQueue import numpy as np STORAGE_COST_PER_UNIT = 0.5 BACKORDER_PENALTY_COST_PER_UNIT = 1 #We can play the full game since no actor is programmed to dump stock near end of game WEEKS_TO_PLAY = 30 QUEUE_DELAY_WEEKS = 2 INITIAL_STOCK = 4 INITIAL_COST = 0 INITIAL_CURRENT_ORDERS = 0 CUSTOMER_INITIAL_ORDERS = 4 CUSTOMER_SUBSEQUENT_ORDERS = 8 TARGET_STOCK = 12 class SupplyChainActor: inv_level = 1 received_ship = 2 on_order_inv = 3 inc_order = 4 placed_order = 5 gameHistory = np.array() def __init__(self, incomingOrdersQueue, outgoingOrdersQueue, incomingDeliveriesQueue, outgoingDeliveriesQueue): """ ------------------------------------------------------- Constructor for the SupplyChainActor class. All other supply chain actors (Retailer, Wholesaler, Distributor, Factory) are derived from this class. ------------------------------------------------------- Preconditions: incomingOrdersQueue - queue for incoming orders. outgoingOrdersQueue - queue for outgoing orders. incomingDeliveriesQueue - queue for incoming deliveries. outgoingDeliveriesQueue - queue for outgoing deliveries. Postconditions: Initializes the SupplyChainActor object in its initial state. ------------------------------------------------------- """ self.currentStock = INITIAL_STOCK self.currentOrders = INITIAL_CURRENT_ORDERS self.costsIncurred = INITIAL_COST self.incomingOrdersQueue = incomingOrdersQueue self.outgoingOrdersQueue = outgoingOrdersQueue self.incomingDeliveriesQueue = incomingDeliveriesQueue self.outgoingDeliveriesQueue = outgoingDeliveriesQueue self.lastOrderQuantity = 0 gameHistory = np.zeros((WEEKS_TO_PLAY, 5)) return def PlaceOutgoingDelivery(self, amountToDeliver): """ ------------------------------------------------------- Places a delivery to the actor one level higher in the supply chain. ------------------------------------------------------- Preconditions: None Postconditions: Places the delivery. Note: the advancement of the queues is handled by the main program. ------------------------------------------------------- """ self.outgoingDeliveriesQueue.PushEnvelope(amountToDeliver) return def PlaceOutgoingOrder(self, weekNum): """ ------------------------------------------------------- Calculates the size of the weekly outgoing order. ------------------------------------------------------- Preconditions: weekNum - the current week number. Postconditions: Calculates the order quantity using an anchor and maintain strategy. ------------------------------------------------------- """ #First weeks are in equilibrium # #HIER EINE REALISTISCHERE HUMAN LIKE ORDER FORMEL if weekNum <= 4: amountToOrder = 4 #After first few weeks, the actor chooses the order. We use "anchor and maintain" strategy. else: #We want to cover any out flows, we know that there are some orders in the pipeline. alpha=np.random.uniform(0.15,0.4) amountToOrder = 0.5 * self.currentOrders if (TARGET_STOCK - self.currentStock) > 0: amountToOrder += TARGET_STOCK - self.currentStock self.outgoingOrdersQueue.PushEnvelope(amountToOrder) self.lastOrderQuantity = amountToOrder self.gameHistory[weekNum][self.received_ship] = amountToOrder return def ReceiveIncomingDelivery(self,weekNum): """ ------------------------------------------------------- Receives a delivery from the actor one level lower in the supply chain. ------------------------------------------------------- Preconditions: None Postconditions: Updates the current stock based on the incoming deliveries queue. ------------------------------------------------------- """ quantityReceived = self.incomingDeliveriesQueue.PopEnvelope() self.gameHistory[weekNum-1][self.received_ship]=quantityReceived if quantityReceived > 0: self.currentStock += quantityReceived ## Hier könnte man das Incoming shipment rauslesen in die matrix return def ReceiveIncomingOrders(self,weekNum): """ ------------------------------------------------------- Receives an incoming order from from the actor one level higher in the supply chain. ------------------------------------------------------- Preconditions: None Postconditions: Updates the current orders based on the incoming deliveries queue. ------------------------------------------------------- """ thisOrder = self.incomingOrdersQueue.PopEnvelope() self.gameHistory[weekNum - 1][self.inc_order] = thisOrder if thisOrder > 0: self.currentOrders += thisOrder return def CalcBeerToDeliver(self): """ ------------------------------------------------------- Calculates how much beer to deliver to the customer. The current stock and number of cases currently on order by the customer are updated from within this function. ------------------------------------------------------- Preconditions: None Postconditions: Returns deliveryQuantitiy - the number of cases to be delivered to the customer. currentOrders, currentStock are updated to reflect this delivery quantity. ------------------------------------------------------- """ deliveryQuantity = 0 #If we can fill the customer's order, we must do it. if self.currentStock >= self.currentOrders: deliveryQuantity = self.currentOrders self.currentStock -= deliveryQuantity self.currentOrders -= deliveryQuantity #If the current stock cannot cover the order, we must fill as much as we can, and back-order the rest. elif self.currentStock >= 0 and self.currentStock < self.currentOrders: deliveryQuantity = self.currentStock self.currentStock = 0 self.currentOrders -= deliveryQuantity return deliveryQuantity def CalcCostForTurn(self): """ ------------------------------------------------------- This function calculates the total costs incurred for the current turn. ------------------------------------------------------- Preconditions: This program must be called LAST in the turn sequence to account for orders taken and deliveries. Postconditions: Returns costsThisTurn - the total cost incurred during this turn. ------------------------------------------------------- """ costsThisTurn = 0 inventoryStorageCost = self.currentStock * STORAGE_COST_PER_UNIT backorderPenaltyCost = self.currentOrders * BACKORDER_PENALTY_COST_PER_UNIT costsThisTurn = inventoryStorageCost + backorderPenaltyCost return costsThisTurn def GetCostIncurred(self): """ ------------------------------------------------------- Returns the total costs incurred. ------------------------------------------------------- Preconditions: None. Postconditions: Returns self.costsIncurred ------------------------------------------------------- """ return self.costsIncurred def GetLastOrderQuantity(self): """ ------------------------------------------------------- Returns the quantity of the last order made. ------------------------------------------------------- Preconditions: None. Postconditions: Returns self.lastOrderQuantity ------------------------------------------------------- """ return self.lastOrderQuantity def CalcEffectiveInventory(self,weekNum): """ ------------------------------------------------------- Returns the effective inventory of the calling SupplyChainActor during the week the method is called. ------------------------------------------------------- Preconditions: None. Postconditions: Returns the effective inventory, which is defined as self.currentStock - self.currentOrders. ------------------------------------------------------- """ effectiveInventory=(self.currentStock - self.currentOrders) self.gameHistory[weekNum - 1][self.inv_level] = effectiveInventory return (self.currentStock - self.currentOrders) def CalcOnOrderInventory(self,weekNum): print("CalcOnOrderInventory") if weekNum>=2: self.gameHistory[weekNum-1][self.on_order_inv]=self.gameHistory[weekNum-2][self.on_order_inv] - self.gameHistory[weekNum - 1][self.received_ship] + self.gameHistory[weekNum-2][self.placed_order] print(self.gameHistory[weekNum-1][self.on_order_inv]) return def GetGameHistory(self): return self.gameHistory