''' LaborDtl.py ''' from Pyro.EventService.Clients import Publisher from GeneratedPy.GenLaborDtl import GenLaborDtl from GeneratedPy.GenScrapCode import GenScrapCode from sndcs_common.DateTimeMixin import DateTimeMixin from sndcs.Config import config class LaborDtl(GenLaborDtl, DateTimeMixin, Publisher): def __init__(self): GenLaborDtl.__init__(self) Publisher.__init__(self) self.eventservice._release() # Get the Pyro namespace from the config self.namespace = config.get("pyro", "namespace", "sndcs") ### Utilities ### def formattedDescription(self): """Return a formatted description of the current labordtl""" if self.operation(): return self.operation().formattedDescription() elif self.indirect(): return self.indirect().description() else: return None def dataDict(self): """Return a keyed dictionary of the laborDtl's info""" data = {} data["labordtl_id"] = self.serialNum() if self.operation(): data["operation_id"] = self.operation().serialNum() else: data["operation_id"] = None if self.indirect(): data["indirect_id"] = self.indirect().serialNum() else: data["indirect_id"] = None data["activeTrans"] = self.activeTrans() data["posted"] = self.posted() data["jobType"] = self.jobType() data["startStamp"] = self.startStamp() data["formattedDescription"] = self.formattedDescription() if self.operation(): if self.operation().unitOfMeasure(): data["unitOfMeasure"] = self.operation().unitOfMeasure().code() else: data["unitOfMeasure"] = None else: data["unitOfMeasure"] = None if self.operation(): qty_complete = self.operation().qtyComplete() if not qty_complete: data["currentComplete"] = 0 else: data["currentComplete"] = qty_complete else: data["currentComplete"] = 0 if self.operation(): data["operationComplete"] = self.operation().complete() else: data["operationComplete"] = 0 if self.operation(): jobHed = self.operation().assembly().jobHed() if jobHed.notes(): note = jobHed.notes()[0].note().body() data["jobhed_note"] = note else: data["jobhed_note"] = None else: data["jobhed_note"] = None return data def completeParentObjects(self, complete_stamp = None, completed_by = None): """ Check if an operations parent objects (assembly, jobhed) should be completed. """ operation = self.operation() if not operation: return if not operation.complete(): return if not complete_stamp: complete_stamp = self.now() # Check if the parent assembly has any open operations assembly = operation.assembly() needs_completed = True for x in assembly.operations(): if not x.complete(): needs_completed = False break if needs_completed: assembly.setComplete(1) assembly.setCompleteStamp(complete_stamp) if completed_by: assembly.setCompletedBy(completed_by) from sndcs.Store import store store.saveChanges() # Check if the parent jobhed has any open assemblies jobhed = assembly.jobHed() needs_completed = True for x in jobhed.assemblies(): if not x.complete(): needs_completed = False break if needs_completed: jobhed.setComplete(1) jobhed.setCompleteStamp(complete_stamp) if completed_by: jobhed.setCompletedBy(completed_by) from sndcs.Store import store store.saveChanges() ### Ending activities ### def end(self, end_date_time = None, terminal_id = None, activity_percentage = None, qty_complete = None, qty_scrap = None, notes = None, opr_complete = None, completed_by = None, scrap_codes = None, suspend = 0): assert self.activeTrans() if not end_date_time: end_date_time = self.now() # If suspended don't set end datetime because that was already set when the record was suspended. if self.activeTrans() <> 2: self.setEndStamp(end_date_time) if terminal_id: self.setEndTerminal(terminal_id) if activity_percentage: self.setActivityPercentage(activity_percentage) # If this was previously suspended we need to go back and set the activity percentage for the prevLaborDtls prev = self.prevLaborDtl() while prev: prev.setActivityPercentage(activity_percentage) prev = prev.prevLaborDtl() if qty_complete: self.setQtyComplete(float(qty_complete)) # Add the quantity complete to the operation's total current_complete = self.operation().qtyComplete() if current_complete: self.operation().setCascadeQtyComplete(current_complete + float(qty_complete)) else: self.operation().setCascadeQtyComplete(float(qty_complete)) if qty_scrap: self.setQtyScrap(float(qty_scrap)) # Add the quantity scrap to the operation's total current_scrap = self.operation().qtyScrap() if current_scrap: self.operation().setQtyScrap(current_scrap + float(qty_scrap)) else: self.operation().setQtyScrap(float(qty_scrap)) if scrap_codes: for k,v in scrap_codes.items(): from ScrapCodeFactory import ScrapCodeFactory new = ScrapCodeFactory().new() new.setJobHed(self.operation().assembly().jobHed()) new.setCode(k) new.setQtyScrap(v) self.addToScrapCode(new) if notes: from NoteByLaborDtlFactory import NoteByLaborDtlFactory note = NoteByLaborDtlFactory().new(notes) self.addToNotes(note) if opr_complete: self.operation().setCascadeComplete(1) self.operation().setCompleteStamp(end_date_time) self.operation().setCompletedBy(completed_by) # Send out message that operation was completed self.publish(self.namespace + "_operation_complete", {"serialNum": self.operation().serialNum(), "operation": self.operation().number(), "assembly": self.operation().assembly().number() } ) self.eventservice._release() elif opr_complete == 0: self.operation().setComplete(0) self.operation().setCompleteStamp(None) self.operation().setCompletedBy(None) if suspend: self.setActiveTrans(2) else: self.setActiveTrans(0) from sndcs.Store import store store.saveChanges() employee = self.laborHed().employee() if self.jobType() == "Indirect": if not suspend: # It's possible that we are ending a LUNCH or BREAK if the user didn't explicitly lunch or break out if self.indirect().code() == "LUNCH": self.publish(self.namespace + "_lunch_out", {"serialNum":employee.serialNum(), "empId":employee.empId(), "properName":employee.properName(), "endStamp":end_date_time, "endTerminal":terminal_id, "activity":{"serialNum":self.serialNum(), "indirect":self.indirect().code(), "description":self.indirect().formattedDescription()}}) self.eventservice._release() elif self.indirect().code() == "BREAK": self.publish(self.namespace + "_break_out", {"serialNum":employee.serialNum(), "empId":employee.empId(), "properName":employee.properName(), "endStamp":end_date_time, "endTerminal":terminal_id, "activity":{"serialNum":self.serialNum(), "indirect":self.indirect().code(), "description":self.indirect().formattedDescription()}}) self.eventservice._release() else: self.publish(self.namespace + "_indirect_stop", {"serialNum":employee.serialNum(), "empId":employee.empId(), "properName":employee.properName(), "endStamp":end_date_time, "endTerminal":terminal_id, "activity":{"serialNum":self.serialNum(), "indirect":self.indirect().code(), "description":self.indirect().formattedDescription()}}) self.eventservice._release() else: self.publish(self.namespace + "_indirect_suspend", {"serialNum":employee.serialNum(), "empId":employee.empId(), "properName":employee.properName(), "suspendStamp":end_date_time, "suspendTerminal":terminal_id, "activity":{"serialNum":self.serialNum(), "indirect":self.indirect().code(), "description":self.indirect().formattedDescription()}}) self.eventservice._release() elif self.jobType() == "Production": if not suspend: self.publish(self.namespace + "_production_stop", {"serialNum":employee.serialNum(), "empId":employee.empId(), "properName":employee.properName(), "endStamp":end_date_time, "endTerminal":terminal_id, "activity":{"serialNum":self.serialNum(), "operation":self.operation().number(), "operation_id":self.operation().serialNum(), "description":self.operation().formattedDescription(), "job_num":self.operation().assembly().jobHed().number(), "qty_complete":self.qtyComplete(), "qty_scrap":self.qtyScrap(), "activity_percentage":self.activityPercentage(), "complete":self.operation().complete()}}) self.eventservice._release() #self.publish(self.namespace + "_production_stop", {"serialNum":employee.serialNum(), "empId":employee.empId(), "properName":employee.properName(), "endStamp":end_date_time, "endTerminal":terminal_id, "activity":{"serialNum":self.serialNum(), "operation":self.operation().number(), "operation_id":self.operation().serialNum(), "description":self.operation().formattedDescription()}}) #self.eventservice._release() else: self.publish(self.namespace + "_production_suspend", {"serialNum":employee.serialNum(), "empId":employee.empId(), "properName":employee.properName(), "endStamp":end_date_time, "endTerminal":terminal_id, "activity":{"serialNum":self.serialNum(), "operation":self.operation().number(), "operation_id":self.operation().serialNum(), "description":self.operation().formattedDescription()}}) self.eventservice._release() elif self.jobType() == "Setup": if not suspend: self.publish(self.namespace + "_setup_stop", {"serialNum":employee.serialNum(), "empId":employee.empId(), "properName":employee.properName(), "endStamp":end_date_time, "endTerminal":terminal_id, "activity":{"serialNum":self.serialNum(), "operation":self.operation().number(), "operation_id":self.operation().serialNum(), "description":self.operation().formattedDescription()}}) self.eventservice._release() else: self.publish(self.namespace + "_setup_suspend", {"serialNum":employee.serialNum(), "empId":employee.empId(), "properName":employee.properName(), "endStamp":end_date_time, "endTerminal":terminal_id, "activity":{"serialNum":self.serialNum(), "operation":self.operation().number(), "operation_id":self.operation().serialNum(), "description":self.operation().formattedDescription()}}) self.eventservice._release() # If the operation was completed we need to check if the assembly and the jobhed should be completed too if opr_complete: self.completeParentObjects(end_date_time, completed_by) ### Suspending and resuming activites ### def resume(self, terminal_id = None, start_stamp = None): new = self.clone() from Store import store # Couldn't put this up at the top because I was getting weird errors store.addObject(new) new.setActiveTrans(1) if not start_stamp: start_stamp = self.now() new.setStartStamp(start_stamp) new.setEndStamp(None) new.setStartTerminal(terminal_id) new.setEndTerminal(None) new.setQtyComplete(None) new.setQtyScrap(None) new.setActivityPercentage(None) new.setPrevLaborDtl(self) new.laborHed()._laborDtls = None # clear out cache... probably a better way to do this self.setEndTerminal(terminal_id) self.setActiveTrans(0) # We will call store.saveChanges from laborHed so we will maintain data integrity in case something goes wrong during the suspend # Unfortunately we need to call store.saveChanges from here so the new laborDtl has a serialNumber to send out store.saveChanges() employee = self.laborHed().employee() if new.jobType() == "Indirect": self.publish(self.namespace + "_indirect_resume", {"serialNum":employee.serialNum(), "empId":employee.empId(), "properName":employee.properName(), "resumeStamp":start_stamp, "suspendTerminal":terminal_id, "activity":{"serialNum":new.serialNum(), "indirect":new.indirect().code(), "description":new.indirect().formattedDescription()}}) self.eventservice._release() elif new.jobType() == "Production": self.publish(self.namespace + "_production_resume", {"serialNum":employee.serialNum(), "empId":employee.empId(), "properName":employee.properName(), "resumeStamp":start_stamp, "suspendTerminal":terminal_id, "activity":{"serialNum":new.serialNum(), "operation":new.operation().number(), "operation_id":new.operation().serialNum(), "description":new.operation().formattedDescription()}}) self.eventservice._release() elif new.jobType() == "Setup": self.publish(self.namespace + "_setup_resume", {"serialNum":employee.serialNum(), "empId":employee.empId(), "properName":employee.properName(), "resumeStamp":start_stamp, "suspendTerminal":terminal_id, "activity":{"serialNum":new.serialNum(), "operation":new.operation().number(), "operation_id":new.operation().serialNum(), "description":new.operation().formattedDescription()}}) self.eventservice._release()