def add(self, product): """ :param product: The order that will be added to the machine :return: Adds the order to the work center to be scheduled """ product.scheduled = True # Sets the order as scheduled self.products[product.id] = product # Adds the order to the work center changeDuration(product, self.availability) # Changes the duration of making the order based on the availability of the work center add_time = getMouldChangeTime(product.moulds) total_time = new_time(self.remainder.year, self.remainder.month, self.remainder.day + (product.time.day - 1), self.remainder.hour + product.time.hour, self.remainder.minute + product.time.minute + add_time, self.remainder.second + product.time.second) add_time = 0 if len(product.combined) > 1: # There are orders combined comb_orders = [] old_insert = product.insert product.combined = order_combined_orders(product, addcolor(product.id), old_insert, comb_orders) for p in product.combined: # For each combined product add the duration and insert change time if len(old_insert) == len(p.insert): bo = True for ins in old_insert: if not ins in p.insert: bo = False if not bo: # There is an insert change add_time += getInsertChangeTime(p.moulds) old_insert = p.insert elif len(old_insert) != len(p.insert): # There is an insert change add_time += getInsertChangeTime(p.moulds) old_insert = p.insert self.remainder = new_time(total_time.year, total_time.month, total_time.day, total_time.hour, total_time.minute + add_time, total_time.second)
def first(self, product): """ :param product: The order to schedule on the work center :return: The order is scheduled as the first order on the work center """ begin = self.m_date # The date that the planning starts end = new_time(self.m_date.year, self.m_date.month + (product.duration.month - 1), self.m_date.day + (product.duration.day - 1), self.m_date.hour + product.duration.hour, self.m_date.minute + product.duration.minute, self.m_date.second + product.duration.second) self.schedule.append([product, begin, end]) # Adds the information for the schedule self.old_insert = product.insert # Changes the last insert used self.old_mould = product.moulds # Changes the last mould used if len(product.combined) > 0: # Schedule orders with the same mould (combined) comb_orders = [] old_insert = product.insert product.combined = order_combined_orders(product, addcolor(product.id), old_insert, comb_orders) for p in product.combined: # Each combined order is planned add_time = 0 if len(self.old_insert) == len(product.insert): # The inserts could be the same (same number of inserts) bo = True for ins in self.old_insert: if not ins in product.insert: bo = False if not bo: # The inserts are different add_time = getInsertChangeTime(p.moulds) self.old_insert = p.insert else: add_time = getInsertChangeTime(p.moulds) self.old_insert = p.insert begin = new_time(end.year, end.month, end.day, end.hour, end.minute + add_time, end.second) end = new_time(begin.year, begin.month, begin.day + (p.duration.day - 1), begin.hour + p.duration.hour, begin.minute + p.duration.minute, begin.second + p.duration.second) self.schedule.append([p, begin, end]) # Information for the schedule self.m_date = end
def mouldChangeCapacity(start_date, end_date): mould_change_capacity = pd.read_excel( 'Mould change capacity.xlsx', header=0) # The amount of mould changes that can be done mould_change_capacity['Date'] = mould_change_capacity['Date'].astype(str) mould_change_capacity = mould_change_capacity.set_index('Date') morning_shift = mould_change_capacity[ 'Morning shift'] # The capacity of the morning shift afternoon_shift = mould_change_capacity[ 'Afternoon shift'] # The capacity of the afternoon shift night_shift = mould_change_capacity[ 'Night shift'] # The capacity of the night shift change_capacity = { } # The dict containing all the mould change capacities of every planning day date = start_date # The date that the planning starts while date <= end_date: if str( date ) in mould_change_capacity.index: # Fill up with the given capacity for each date change_capacity[str(date)] = [ morning_shift[str(date)], afternoon_shift[str(date)], night_shift[str(date)] ] else: change_capacity[str(date)] = [ 4, 3, 3 ] # Fills up the (standard) capacity for each date date = new_time(date.year, date.month, date.day + 1) return change_capacity
def ChangeMould(work_center_id, product, old_mould, m_date, mould_changes, mould_change_capacity): """ :param work_center_id: The number of the work center that the mould is changed on :param product: The product that is the reason the mould needs to be changed :param old_mould: The mould that was previously on the work center :param m_date: The current date and time of the planning of the work center :param mould_changes: The list containg all the mould changes that have already happened :param mould_change_capacity: A list containing the number of mould changes that can still happen for each shift each day :return: The mould change is scheduled and the date and time that the mould change ends is returned """ """ Get a possible datetime for the mould change to start when there is still capacity left """ begin = m_date # The date and time that the mould change begins change = False # True if the mould change can happen at this time according to the capacity while not change: if not str( datetime.datetime(begin.year, begin.month, begin.day) ) in mould_change_capacity.keys( ): # The mould change tries to be scheduled outside the allowed date range return False if 6 <= begin.hour <= 14: # 6am - 2pm if mould_change_capacity[str( datetime.datetime(begin.year, begin.month, begin.day) )][0] > 0: # The capacity allows a mould change mould_change_capacity[str( datetime.datetime( begin.year, begin.month, begin.day))][0] -= 1 # The capacity gets decreased change = True # The mould change will get planned else: begin = new_time(begin.year, begin.month, begin.day, begin.hour + 1, begin.minute, begin.second) elif 14 <= begin.hour <= 22: # 2pm - 10pm if mould_change_capacity[str( datetime.datetime(begin.year, begin.month, begin.day) )][1] > 0: # The capacity allows a mould change mould_change_capacity[str( datetime.datetime(begin.year, begin.month, begin.day))][1] -= 1 change = True else: begin = new_time(begin.year, begin.month, begin.day, begin.hour + 1, begin.minute, begin.second) elif 22 <= begin.hour <= 24 or 0 <= begin.hour <= 6: # 10 pm - 6am if mould_change_capacity[str( datetime.datetime(begin.year, begin.month, begin.day) )][2] > 0: # The capacity allows a mould change mould_change_capacity[str( datetime.datetime(begin.year, begin.month, begin.day))][2] -= 1 change = True else: begin = new_time(begin.year, begin.month, begin.day, begin.hour + 1, begin.minute, begin.second) """ Get the time that the changes of the old and new mould are done """ add_time = getMouldChangeTime(product.moulds, type_when="in") add_time += getMouldChangeTime(old_mould, type_when="out") finished = new_time(begin.year, begin.month, begin.day, begin.hour, begin.minute + add_time, begin.second) """ Find whether there are problems scheduling the mould change If there is a problem, the change will be tried to be scheduled 10 min later """ if not problem( begin, finished, mould_changes ): # There isn't a conflict while changing the mould (only 1 change at a time) mouldChange(begin, finished, mould_changes, work_center_id, product.order, product.moulds, "Change between moulds") else: # There is a conflict while changing the mould at this time if 6 <= begin.hour <= 14: # 6am - 2pm mould_change_capacity[str( datetime.datetime( begin.year, begin.month, begin.day))][0] += 1 # Turn back the change in capacity elif 14 <= begin.hour <= 22: # 2pm - 10pm mould_change_capacity[str( datetime.datetime(begin.year, begin.month, begin.day))][1] += 1 elif 22 <= begin.hour <= 24 or 0 <= begin.hour <= 6: # 10 pm - 6am mould_change_capacity[str( datetime.datetime(begin.year, begin.month, begin.day))][2] += 1 m_date = new_time(begin.year, begin.month, begin.day, begin.hour, begin.minute + 10, begin.second) return ChangeMould( work_center_id, product, old_mould, m_date, mould_changes, mould_change_capacity) # Plan the mould change again return finished # There is no conflict, so return the time when the mould change is done
def scheduleTime(self, product, mould_changes, mould_change_capacity, not_planned, end_date): """ :param product: The order that needs to be scheduled :param mould_changes: The list containing all mould changes :param mould_change_capacity: A dict containing the mould change capacity for each day :param not_planned: :param end_date: :return: Schedules the order on the work center """ begin = self.m_date # The current date of the planning if begin >= end_date: not_planned.append([product.id, "No capacity for order on machine", product.order]) for p in product.combined: not_planned.append([p.id, "No capacity for order on machine in for", p.order]) return """ Schedule mould change if necessary """ if self.old_mould == 'nan' or str(product.moulds) != self.old_mould: # There is a mould change begin = ChangeMould(self.id, product, self.old_mould, self.m_date, mould_changes, mould_change_capacity) # Change the mould if not begin: # The mould change couldn't be scheduled in time with the capacity not_planned.append([product.id, "No capacity for mould change", product.order]) for p in product.combined: not_planned.append([p.id, "No capacity for mould change", p.order]) return self.old_mould = str(product.moulds) # Change the last used mould of the work center """ Insert change if necessary """ if self.schedule != [] and self.old_mould != 'nan' and str(product.moulds) == self.old_mould: # Same mould add_time = 0 if len(self.old_insert) == len(product.insert): bo = True for ins in self.old_insert: if not ins in product.insert: bo = False if not bo: # Insert change add_time = getInsertChangeTime(product.moulds) self.old_insert = product.insert begin = new_time(begin.year, begin. month, begin.day, begin.hour, begin.minute + add_time, begin.second) elif len(self.old_insert) != len(product.insert): # Insert change add_time = getInsertChangeTime(product.moulds) self.old_insert = product.insert begin = new_time(begin.year, begin. month, begin.day, begin.hour, begin.minute + add_time, begin.second) if begin >= end_date: not_planned.append([product.id, "No capacity for order on machine", product.order]) for p in product.combined: not_planned.append([p.id, "No capacity for order on machine", p.order]) return end = new_time(begin.year, begin.month, begin.day + (product.duration.day - 1), begin.hour + product.duration.hour, begin.minute + product.duration.minute, begin.second + product.duration.second) self.schedule.append([product, begin, end]) # Add order to schedule self.m_date = end # Set time of work center if len(product.combined) > 0: # Has Orders with same mould no_capacity = False for p in product.combined: # Schedule each combined order if not no_capacity: begin = end """ Insert change if necessary """ add_time = 0 if len(self.old_insert) == len(p.insert): bo = True for ins in self.old_insert: if not ins in p.insert: bo = False if not bo: # Insert change add_time = getInsertChangeTime(p.moulds) begin = new_time(end.year, end. month, end.day, end.hour, end.minute + add_time, end.second) self.old_insert = p.insert elif len(self.old_insert) != len(p.insert): # Insert change add_time = getInsertChangeTime(p.moulds) begin = new_time(end.year, end. month, end.day, end.hour, end.minute + add_time, end.second) self.old_insert = p.insert end = new_time(begin.year, begin. month, begin.day + (p.duration.day - 1), begin.hour + p.duration.hour, begin.minute + p.duration.minute, begin.second + p.duration.second) if end > end_date: no_capacity = True not_planned.append([p.id, "No capacity for order on machine", p.order]) end = self.m_date else: self.schedule.append([p, begin, end]) # Add order to schedule self.m_date = end # Set time of work center elif no_capacity: not_planned.append([p.id, "No capacity for order on machine", p.order]) self.getUsageTime()
def prioritiseOrdersDf(df, zcs, begin_date, end_date, batchID): """ :param df: The dataframe containing the orders :param zcs: The material info containg the number of machines for each item number :param begin_date: The date that the planning begins :param end_date: The date that the planning end :return: Sorts the dataframe of the orders based on priority """ """ Get the different weights """ connection = db_connection() cursor = connection.cursor( ) # This code gets the weights given to different aspects of the orders cursor.execute('SELECT Weight_1 FROM dbo.Batch WHERE ID = (?)', batchID) (weight_date, ) = cursor.fetchone( ) # The importance of planning before the needed on date cursor.execute('SELECT Weight_2 FROM dbo.Batch WHERE ID = (?)', batchID) (weight_promo, ) = cursor.fetchone() # The importance of planing a promo order cursor.execute('SELECT Weight_3 FROM dbo.Batch WHERE ID = (?)', batchID) (weight_listing, ) = cursor.fetchone() # The importance of plannig a listing order """ Get the cutoff points and the dates of these points """ cursor.execute('SELECT Cutoff_promo FROM dbo.Batch WHERE ID = (?)', batchID) (days_over_end_date_promo, ) = cursor.fetchone( ) # Promo orders x days over the end date can still be planned if days_over_end_date_promo == None: days_over_end_date_promo = 0 cursor.execute('SELECT Cutoff_listing FROM dbo.Batch WHERE ID = (?)', batchID) (days_over_end_date_listing, ) = cursor.fetchone( ) # Listing orders x days over the end date can still be planned if days_over_end_date_listing == None: days_over_end_date_listing = 0 end_date_promo = new_time(end_date.year, end_date.month, end_date.day + days_over_end_date_promo) end_date_listing = new_time(end_date.year, end_date.month, end_date.day + days_over_end_date_listing) """ Check whether the orders are valid If there is a problem the order is removed Otherwise it gets a weight based on different criteria """ n_on = df['needed on'] orig_document = df['Originating document'] material_number = df['Material'] work_center = df['Work center'] order = df['Order'] in_production = df['Start Point'] mould_df = df['Mould'] prio = [] # A list containing the priority of each order amoun = [ ] # A list containing the amount of machines each order is compatible with wrong = [ ] # A list containing the orders that aren't planned and the reason why for i in range(len(df["Material"])): # For each order # The order is not needed before the cutoff point of the planning if (n_on[i] != "nan" and n_on[i] != "None") and ( not (str(orig_document[i]) == 'nan' or str(orig_document[i]) == 'None') ) and n_on[ i] > end_date_promo: # promo with needed on date after allowed promo needed on date df = df.drop([i]) # Removes the order (row) wrong.append([ str(material_number[i]), "Needed on date after planning", str(order[i]) ]) elif (n_on[i] != "nan" and n_on[i] != "None") and str( orig_document[i] ) == 'nan' or str(orig_document[i]) == 'None' and n_on[ i] > end_date_listing: # listing with needed on date after allowed listing needed on date df = df.drop([i]) # Removes the order (row) wrong.append([ str(material_number[i]), "Needed on date after planning", str(order[i]) ]) # The order is a dummy order elif str(material_number[i]) == 'nan' or str( material_number[i] ) == 'None': # If there is no item number --> orders is dummy order if str(work_center[i]) != 'nan' and str( work_center[i] ) != 'None': # There has to be a machine given to plan dummy orders p = 0 # The priority of the order (lower number is planned/prioritized earlier) if n_on[i] == "nan" or n_on[i] == "None": p += (weight_promo + weight_date + weight_listing) elif n_on[i] <= begin_date: p -= weight_date elif n_on[i] <= end_date: p -= (weight_date / 2) else: p += weight_date if not (str(orig_document[i]) == 'nan' or str(orig_document[i]) == 'None'): # If it is a promo order p -= weight_promo # The priority is higher if str(orig_document[i]) == 'nan' or str( orig_document[i] ) == 'None': # If it is a listing order p -= weight_listing if str(in_production[i]) == str( 1): # If the order is already on a machine p -= (weight_promo + weight_date + weight_listing ) # This is most important prio.append(p) amoun.append( 1 ) # There is only one machine that the order can be planned on else: df = df.drop([i]) # Removes the order (row) wrong.append([ str(material_number[i]), "Dummy order has no Work center in input", str(order[i]) ]) # The order is not a dummy order, but the item number isn't in the database elif not str(material_number[i]) in zcs.index: df = df.drop([i]) # Removes the order (row) if mould_df[i] == None or mould_df[i] == 'nan': wrong.append( [str(material_number[i]), "Assembly order", str(order[i])]) else: wrong.append([ str(material_number[i]), "Item unknown - Material/Mould not known to bot", str(order[i]) ]) # The order is a normal order that is in the database else: """ If the order has no mould in the input, we add one from the zcs04 data or the historical data Otherwise the order will be removed """ if str(mould_df[i]) == 'nan' or str( mould_df[i]) == 'None': # No mould is given mould = zcs['Mould'].loc[str(material_number[i])] mould_df[ i] = mould # Adds the mould from the zcs part of the material_info dataframe if str(mould_df[i]) == "nan" or str( mould_df[i]) == 'None': # If there still isn't a mould try: mould = zcs["('Mould', 'unique')"].loc[str( material_number[i])] mould = mould.replace('[', '') mould = mould.replace(']', '') mould = mould.split(', ') mould_df[ i] = mould # Adds the mould from the historical data except: wrong.append([ str(material_number[i]), "Item unknown - No mould", str(order[i]) ]) if str(mould_df[i]) == "nan" or str( mould_df[i] ) == 'None': # If the earlier data couldn't give a mould df = df.drop([i]) # Removes the order (row) wrong.append([ str(material_number[i]), "Order has no mould in the input or database", str(order[i]) ]) else: # There is a mould for this order p = 0 # The priority of the order (lower number is planned/prioritized earlier) if not (str(orig_document[i]) == 'nan' or str(orig_document[i]) == 'None'): # If it is a promo order p = 1 # The priority is higher if str(orig_document[i]) == 'nan' or str( orig_document[i] ) == 'None': # If it is a listing order p = 2 if str(in_production[i]) == str( 1): # If the order is already on a machine p = 0 # This is most important prio.append(p) amoun.append(zcs['Amount'][str(material_number[i])]) df['Priority'] = prio # Adds the priority of each order to the database df['Amount'] = amoun # Adds the amount of compatible machines to each order return sortOrdersDf(df), wrong