class EditSaleProdMudule(QDialog, Ui_Dialog): def __init__(self, autoid=None, snid=None, parent=None): super(EditSaleProdMudule, self).__init__(parent) self.setupUi(self) if '53' not in user.powers: self.close() if user.powers['53'] == 0: self.close() self.power = '{:03b}'.format(user.powers['53']) if self.power[1] == '0': self.pushButton_accept.setVisible(False) self.pushButton_cancel.setVisible(False) self.autoid = autoid self.snid = snid self.SC = SaleController() self.PC = ProductController() self.ori_detail = dict() self.new_detail = dict() row = ('autoid', 'prodid', 'prodname', 'spec', 'package') key = ('prodid', 'prodname', 'commonname', 'inputcode') row_name = ("id", "产品编号", "产品名称", "含量规格", "包装规格") self.lineEdit_product.setup('Productdictionary', row, key, row_name, None, 620, 190) self.set_validator() if self.autoid is not None: self.get_detail() def get_detail(self): key_dict = {'autoid': self.autoid} detail_list = self.SC.get_salenotegoods(False, *VALUES_TUPLE_PROD, **key_dict) if not len(detail_list): return self.ori_detail = detail_list[0] self.lineEdit_product.setText(self.ori_detail['prodid'] + ' ' + self.ori_detail['prodname']) self.label_spec.setText(self.ori_detail['spec']) self.label_package.setText(self.ori_detail['package']) self.lineEdit_amount.setText(to_str(self.ori_detail['saleamount'])) self.label_unit.setText(self.ori_detail['spunit']) def set_validator(self): doubleValitor = QDoubleValidator() doubleValitor.setBottom(0) self.lineEdit_amount.setValidator(doubleValitor) @pyqtSlot(str) def on_lineEdit_product_textChanged(self, p_str): if len(p_str.split(' ')) != 2 and p_str != '': return id, name = p_str.split(' ') if p_str != '' else ('', '') key_dict = {'prodid': id, 'prodname': name} res = self.PC.get_product_or_stuff_dictionary(0, False, *VALUES_TUPLE_PRODDICT, **key_dict) if len(res): prod_detail = res[0] self.label_spec.setText(prod_detail['spec']) self.label_package.setText(prod_detail['package']) self.label_unit.setText(prod_detail['spunit']) try: if id != self.ori_detail['prodid'] or name != self.ori_detail[ 'prodname']: self.new_detail['prodid'] = id self.new_detail['prodname'] = name self.new_detail['spec'] = prod_detail['spec'] self.new_detail['package'] = prod_detail['package'] self.new_detail['spunit'] = prod_detail['spunit'] else: try: del self.new_detail['prodid'] del self.new_detail['prodname'] del self.new_detail['spec'] del self.new_detail['package'] del self.new_detail['spunit'] except KeyError: pass except KeyError: self.new_detail['prodid'] = id self.new_detail['prodname'] = name self.new_detail['spec'] = prod_detail['spec'] self.new_detail['package'] = prod_detail['package'] self.new_detail['spunit'] = prod_detail['spunit'] @pyqtSlot(str) def on_lineEdit_amount_textChanged(self, p_str): try: p_num = decimal.Decimal(p_str) if p_num != self.ori_detail['saleamount']: self.new_detail['saleamount'] = p_num else: try: del self.new_detail['saleamount'] except KeyError: pass except KeyError: self.new_detail['saleamount'] = p_num except decimal.InvalidOperation: pass @pyqtSlot() def on_pushButton_accept_clicked(self): if not len(self.new_detail): return saleamount = self.lineEdit_amount.text() if saleamount in ('0', ''): msg = MessageBox(self, text="销售数量不能为空") msg.show() return if self.autoid is None and self.snid is not None: self.new_detail['snid'] = self.snid self.SC.update_salenotegoods(self.autoid, **self.new_detail) self.accept() @pyqtSlot() def on_pushButton_cancel_clicked(self): self.close()
class EditProducingplan(QDialog, Ui_Dialog): created = pyqtSignal(int) def __init__(self, autoid=None, parent=None): super(EditProducingplan, self).__init__(parent) self.setupUi(self) # if '20' not in user.powers: # self.close() # self.accept_button.setVisible(False) # self.cancel_button.setVisible(False) # self.pushButton_audit.setVisible(False) # if user.powers['20'] == 0: # self.close() # self.power = '{:03b}'.format(user.powers['20']) # if self.power[1] == '0': # self.accept_button.setVisible(False) # self.cancel_button.setVisible(False) # self.pushButton_audit.setVisible(False) self.PC = ProductController() self.WC = WarehouseController() self.autoid = autoid self.prod_id = 0 self.ori_detail = {} self.new_detail = {} self.detail = {} self.stuff_list = [] self.stuff_repository = [] self.no_enough_stuff_list = [] self.treewidget_meterial.hideColumn(1) self.treeWidget_package.hideColumn(1) # 公式错误信息 self.errormsg = [] self.prodname.setup(DB_TABLE[0], PRODUCT_VALUE_TUPLE, PRODUCT_KEY, VALUE_NAME, None, 650, 250) self.prodname.getItem.connect(self.setproduct) self.set_validator() if autoid is not None: self.get_detail() self.set_treewidget_formula((0, 1, 2), self.treewidget_meterial) self.set_treewidget_formula((3, 4), self.treeWidget_package) else: self.makedate.setDate(QDate.currentDate()) def set_validator(self): doubleValitor = QDoubleValidator() doubleValitor.setBottom(0) doubleValitor.setDecimals(2) doubleValitor.setNotation(QDoubleValidator.StandardNotation) self.planamount.setValidator(doubleValitor) def setproduct(self, qtreeitem: QTreeWidgetItem): self.prod_id = qtreeitem.text(0) self.commonname.setText(qtreeitem.text(3)) self.spec.setText(qtreeitem.text(4)) self.package_2.setText(qtreeitem.text(5)) if self.prod_id: # flag:产品的类型,0成品,1半成品,2退货, 3验证 flag = self.productkind.currentIndex() key_dict = {'autoid': self.prod_id} res = self.PC.get_product_or_stuff_dictionary( flag, False, **key_dict) if res: self.unit.setText(res[0].spunit) if flag in (0, 1): lineid = res[0].plid elif flag == 2: lineid = res[0].wplid elif flag == 3: lineid = res[0].vplid else: lineid = 0 if lineid: productline = ProductLineConroller() pline = productline.get_productline(lineid, flag) if pline: self.prodline.setText(pline[0].linename) self.productworkshop.setText(pline[0].deptid + ' ' + pline[0].deptname) def set_autoid(self, autoid: int): self.autoid = autoid # 查询autoid对应的记录,并关联到表格中 self.get_detail() self.new_detail.clear() def get_detail(self): res = self.PC.get_producingplan(autoid=self.autoid) if res: # 把生产指令的内容填入表格中 self.set_data(res[0]) self.ori_detail = model_to_dict(res[0]) self.detail = self.ori_detail else: errordialig = QErrorMessage(self) errordialig.setWindowTitle("错误") # 初始化编辑生产指令的内容 def set_data(self, detail): self.productkind.setCurrentIndex(detail.pltype) self.prodname.setText(detail.prodid + ' ' + detail.prodname) self.commonname.setText(detail.commonname) self.spec.setText(detail.spec) self.package_2.setText(detail.package) self.planamount.setText(str(detail.planamount)) self.unit.setText(detail.spunit) self.batchno.setText(detail.batchno) self.makedate.setDate( QDate(detail.makedate) if type(detail.makedate) is datetime.date else user.now_date) self.remarks.setText(detail.remark) lineid = detail.lineid if lineid: productline = ProductLineConroller() pline = productline.get_productline(lineid, detail.pltype) if pline: self.prodline.setText(pline[0].linename) self.productworkshop.setText(pline[0].deptid + ' ' + pline[0].deptname) self.new_detail['linename'] = pline[0].linename self.new_detail['workshopid'] = pline[0].deptid self.new_detail['workshopname'] = pline[0].deptname def set_treewidget_formula(self, stufftype=(0, 1, 2), qtree=None): prodtype = 1 if self.productkind.currentIndex() == 1 else 0 qtree.clear() condition = { 'prodid': self.prod_id, 'stufftype__in': stufftype, 'prodtype': prodtype } # 获取配方 self.formula = self.PC.get_data(6, False, *VALUES_TUPLE_PD, **condition) if not len(self.formula): return stuffkind_list = self.formula.values_list('stuffkind', flat=True) condition_sk = {'stuffkind__in': stuffkind_list, 'amount__gt': 0} self.stuff_repository = self.WC.get_data(2, False, *VALUES_TUPLE_SD, **condition_sk) for it in self.stuff_repository: condition_lock = {'srid': it['autoid']} drawamount_list = self.PC.get_data( 7, True, *VALUES_TUPLE_SL, **condition_lock).exclude(ppid=self.autoid) it['realamount'] = it['amount'] - sum(drawamount_list) for item in self.formula: parent_treeitem = QTreeWidgetItem(qtree) parent_treeitem.setText(0, item['stuffkind']) parent_treeitem.setText(2, item['formula']) stuffkind = item['stuffkind'] condition_sf = {'stuffkind': stuffkind, 'amount__gt': 0} # 获取库存 stuffrepository = self.WC.get_data(2, False, *VALUES_TUPLE_SD, **condition_sf) if not len(stuffrepository): brush = QBrush(1) brush.setColor(QColor(255, 85, 0)) for i in range(0, 13): parent_treeitem.setBackground(i, brush) # Decimal(rnd(eval(presexpression, evalenv(self)), # precision)) parent_treeitem.setText( 6, str(self.no_stuffrep_count_presamount(item)) + item['presunit']) self.no_enough_stuff_list.append(stuffkind) continue draw_status = self.draw_stuff(item) if not draw_status: self.no_enough_stuff_list.append(stuffkind) brush = QBrush(1) brush.setColor(QColor(255, 255, 127)) for i in range(1, 13): parent_treeitem.setBackground(i, brush) for it in stuffrepository: condition_lock = {'srid': it['autoid']} drawamount_list = self.PC.get_data(7, True, *VALUES_TUPLE_SL, **condition_lock) qtreeitem = QTreeWidgetItem(parent_treeitem) qtreeitem.setText(1, str(it['autoid'])) qtreeitem.setText(0, it['stuffname']) qtreeitem.setText(3, it['batchno']) qtreeitem.setText(4, str(it['amount'])) qtreeitem.setText(5, str(sum(drawamount_list))) for sr in self.stuff_list: if it['autoid'] == sr['autoid']: qtreeitem.setText( 7, str(sr['newpracamount']) + item['pracunit']) qtreeitem.setText( 8, str(sr['drawamount']) + item['drawunit']) parent_treeitem.setText( 6, str(sr['presamount']) + item['presunit']) break if stufftype == (0, 1, 2): qtreeitem.setText(9, str(it['content']) + it['cunit']) qtreeitem.setText(10, str(it['water']) + '%') qtreeitem.setText(11, str(it['rdensity'])) qtreeitem.setText(12, str(it['impurity'])) qtree.expandAll() qtree.resizeColumnToContents(0) for i in range(2, 13 if stufftype == (0, 1, 2) else 9): qtree.resizeColumnToContents(i) qtree.collapseAll() def no_stuffrep_count_presamount(self, item): stuffkind = item['stuffkind'] precision = item['precision'] loss = item['loss'] # 处理产品信息的变量,去除系统变量 presexpression = self.reckon_expression(item['presexpression'], 1) # 计划量 try: presamount = Decimal( rnd(eval(presexpression, evalenv(self)), precision)) return presamount except SyntaxError: if stuffkind + ' 计划量' not in self.errormsg: self.errormsg.append(stuffkind + ' 计划量') return 0 # 系统根据配方自动领料 def draw_stuff(self, item): stuffkind = item['stuffkind'] precision = item['precision'] loss = item['loss'] # 处理产品信息的变量,去除系统变量 presexpression = self.reckon_expression(item['presexpression'], 1) # 计划量 try: presamount = Decimal( rnd(eval(presexpression, evalenv(self)), precision)) except SyntaxError: if stuffkind + ' 计划量' not in self.errormsg: self.errormsg.append(stuffkind + ' 计划量') presamount = 0 # 实际量公式,去除系统变量 pracexpression = self.reckon_expression(item['pracexpression'], 1) # 领取量公式,去除系统变量 drawexpression = self.reckon_expression(item['drawexpression'], 1) # 计算领料量,返回领料情况res, 和标记:是否已经领购料 res = self.reckon_drawamount(stuffkind, presamount, precision, pracexpression, drawexpression, loss) if len(res): self.stuff_list_additem(res) return self.is_drawamount_enough(stuffkind, presamount) # 判断领取的物料是否足够 def is_drawamount_enough(self, stuffkind, presamount): new_presamount = 0 for item in self.stuff_list: if item['stuffkind'] == stuffkind: new_presamount += item['newpresamount'] return True if new_presamount >= presamount else False # 把领取的物料加到领料记录中,如果发现重复的情况则替换旧的记录 def stuff_list_additem(self, newitems): for newitem in newitems: flat = 0 for item in self.stuff_list: if newitem['autoid'] == item['autoid']: # item = newitem flat = 1 break if flat == 0: self.stuff_list.append(newitem) # 计算系统变量 def reckon_expression(self, expression, iterdepth): # iterdepth:迭代深度,超过50则抛出RuntimeError # 产品信息变量,ex: @planamount@, @spec@, @package@ if iterdepth > 50: raise RuntimeError pattern = re.findall(r'@[%?!()()::.#\w]*@', expression) for item in pattern: # 引用其他物料 if len(item[1:-1].split('.')) == 2: var_name, var_item = item[1:-1].split('.') value = Decimal('0') # 标记是否找到了对应的物料 find_stuff_flag = 0 for stuff in self.stuff_list: if stuff['stuffkind'] == var_name: find_stuff_flag = 1 if var_item == '计划量': value = stuff[VAR_ITEM[var_item]] expression = expression.replace(item, str(value)) break else: value += stuff[VAR_ITEM[var_item]] expression = expression.replace(item, str(value)) # 没有找到对应的物料则再本领料单中继续寻找 if find_stuff_flag == 0: for item in self.formula: try: if item['stuffkind'] == var_name: # stuffkind = item.text(2) precision = item['precision'] loss = item['loss'] # 处理产品信息的变量,去除系统变量 presexpression = self.reckon_expression( item['presexpression'], iterdepth + 1) # 计划量 try: presamount = Decimal( rnd( eval(presexpression, evalenv(self)), precision)) except SyntaxError: if var_name + ' 计划量' not in self.errormsg: self.errormsg.append(var_name + ' 计划量') presamount = 0 # 把计划量加到产品信息变量中 # self.detail['presamount'] = presamount # 实际量公式,去除系统变量 pracexpression = self.reckon_expression( item['pracexpression'], iterdepth + 1) # 领取量公式,去除系统变量 drawexpression = self.reckon_expression( item['drawexpression'], iterdepth + 1) # 计算领料量,返回领料情况res, 和标记:是否已经领购料 res = self.reckon_drawamount( var_name, presamount, precision, pracexpression, drawexpression, loss) if len(res): self.stuff_list_additem(res) # self.is_drawamount_enough() expression = self.reckon_expression( expression, iterdepth + 1) except RuntimeError: break # 引用生产指令的参数 else: key = item.replace('@', '') if key in self.detail: expression = expression.replace(item, str(self.detail[key])) # pattern_1 = re.findall(r'@[%?!()()::.#\w]*@', expression) return expression # 计算实际量 def reckon_pracamount(self, autoid, presamount, precision, expression): # stuffkind: 物料种类 # presamount: 计划量 # expression: 实际量的公式 stuff_detail = [] # 最终要领取的批次和实际量 # 分析公式,获取变量 pattern = re.findall(r'@\w*@', expression) # 把变量设置为对应的值 for item in self.stuff_repository: if autoid != item['autoid']: continue for key in pattern: k = key.replace('@', '') if k == 'presamount': expression = expression.replace(key, str(presamount)) elif k in item: expression = expression.replace(key, str(item[k])) elif k in self.detail: expression = expression.replace(key, str(self.detail[k])) try: pracamount = Decimal( rnd(eval(expression, evalenv(self)), precision)) except SyntaxError: if item['stuffkind'] + ' 实际量' not in self.errormsg: self.errormsg.append(item['stuffkind'] + ' 实际量') pracamount = 0 item['pracamount'] = pracamount # 计算领取量 # stuffkindorsrid: 根据flat决定类型, True是物料种类,False是srid # presamount: 计划量 # precision: 计算结果精度 # prac_expression: 实际量公式 # draw_expression: 领取公式 # loss: 损耗限度 # flat: 是否需要继续领下一批物料,默认为True即继续领下一批物料, # False则不再领取下一批物料 def reckon_drawamount(self, stuffkindorsrid, presamount, precision, prac_expression, draw_expression, loss=0, flat=True): # 要领取的物料批次 draw_list = [] # 已经领取了的量 has_drawamount = 0 # 分析公式,获取变量 pattern = re.findall(r'@\w*@', draw_expression) # 把变量设置为对应的值 for item in self.stuff_repository: item['presamount'] = presamount new_expression = draw_expression if has_drawamount != 0: presamount -= has_drawamount has_drawamount = 0 if stuffkindorsrid != (item['stuffkind'] if flat else str(item['autoid'])): continue item['loss'] = loss item['newpresamount'] = presamount item['precision'] = precision # 算出该批次对应的实际量 self.reckon_pracamount(item['autoid'], presamount, precision, prac_expression) for key in pattern: k = key.replace('@', '') if k in item: new_expression = new_expression.replace(key, str(item[k])) elif k in self.detail: new_expression = new_expression.replace( key, str(self.detail[k])) try: drawamount = Decimal( rnd(eval(new_expression, evalenv(self)), precision)) except SyntaxError: if stuffkindorsrid + ' 领取量' not in self.errormsg: self.errormsg.append(stuffkindorsrid + ' 领取量') drawamount = 0 continue if item['realamount'] >= drawamount: item['drawamount'] = drawamount item['newpracamount'] = item['pracamount'] draw_list.append(item) break else: # 转化为计划量 = 领取量 * 计划量 / 实际量 has_drawamount = Decimal( rnd(item['realamount'] * presamount / item['pracamount'], precision)) item['newpresamount'] = has_drawamount item['newpracamount'] = rnd(item['realamount'], precision) item['drawamount'] = rnd(item['realamount'], precision) draw_list.append(item) if not flat: # 指定库存记录时,默认按领够料处理 break return draw_list # 产品种类改变时 @pyqtSlot(int) def on_productkind_currentIndexChanged(self, p_int): if p_int in (0, 2, 3): self.prodname.setup(DB_TABLE[0], PRODUCT_VALUE_TUPLE, PRODUCT_KEY, VALUE_NAME, None, 650, 250) else: self.prodname.setup(DB_TABLE[1], STUFF_VALUE_TUPLE, STUFF_KEY, VALUE_NAME, None, 650, 250) # 修改计划量时触发 @pyqtSlot() def on_planamount_editingFinished(self): p_str = self.planamount.text() planamount = Decimal(p_str) if p_str != '' else 0 try: if planamount != self.ori_detail['planamount']: self.new_detail['planamount'] = planamount self.detail['planamount'] = planamount else: try: del self.new_detail['planamount'] except KeyError: pass except KeyError: self.new_detail['planamount'] = planamount self.detail['planamount'] = planamount self.stuff_list = [] self.stuff_repository = [] self.no_enough_stuff_list = [] self.set_treewidget_formula((0, 1, 2), self.treewidget_meterial) self.set_treewidget_formula((3, 4), self.treeWidget_package) # 修改批号时触发 @pyqtSlot(str) def on_batchno_textEdited(self, p_str): try: if p_str != self.ori_detail['batchno']: self.new_detail['batchno'] = p_str else: try: del self.new_detail['batchno'] except KeyError: pass except KeyError: self.new_detail['batchno'] = p_str # 修改生产日期时触发 @pyqtSlot(QDate) def on_makedate_dateChanged(self, q_date): p_date = q_date.toPyDate() try: if p_date != self.ori_detail['makedate']: self.new_detail['makedate'] = p_date else: try: del self.new_detail['makedate'] except KeyError: pass except KeyError: self.new_detail['makedate'] = p_date # 修改备注时触发 @pyqtSlot(str) def on_remarks_textChanged(self, p_str): try: if p_str != self.ori_detail['remark']: self.new_detail['remark'] = p_str else: try: del self.new_detail['remark'] except KeyError: pass except KeyError: self.new_detail['remark'] = p_str @pyqtSlot() def on_accept_button_clicked(self): if self.prodname.flat == 0: text = "没有找到对应的产品信息,请修改后重试!" informative = "选择好产品名称后请不要再修改,否则将导致系统无法找到正确的产品!" errordialig = MessageBox(self, text=text, informative=informative) errordialig.exec() self.prodname.setFocus() return if len(self.no_enough_stuff_list): text = "以下物料不足!" informative = ";\n".join(self.no_enough_stuff_list) errordialig = MessageBox(self, text=text, informative=informative, yes_text="继续下达指令") res = errordialig.exec() if res == 65536: self.prodname.setFocus() return # 有修改过数据 if self.new_detail: try: # 修改过记录,把当前的人员和日期存入修改记录中 self.new_detail['instructorid'] = user.user_id self.new_detail['instructorname'] = user.user_name self.new_detail['plandate'] = user.now_date self.new_detail['deptid'] = user.dept_id self.new_detail['deptname'] = user.dept_name self.new_detail['bpconstitutorid'] = user.user_id self.new_detail['bpconstitutorname'] = user.user_name self.new_detail['bpconsdate'] = user.now_date # autoid不为空,则为修改记录 # 否则为插入记录 if self.autoid: self.PC.update_producingplan(autoid=self.autoid, **self.new_detail) condition = {'ppid': self.autoid} self.PC.delete_data(7, condition) else: prodtype = self.productkind.currentIndex() prod_id = self.prodname.namelist.currentItem().text(0) self.new_detail['id'] = prod_id ppid = self.PC.update_producingplan(prodtype=prodtype, **self.new_detail) self.autoid = ppid self.created.emit(self.autoid) for item in self.stuff_list: detail = { 'ppid': self.autoid, 'srid': item['autoid'], 'drawamount': item['drawamount'], 'stuffkind': item['stuffkind'] } self.PC.update_data(7, **detail) self.accept() except Exception as e: SaveExcept(e, "提交生产指令时出错", **self.new_detail) else: self.close() @pyqtSlot() def on_cancel_button_clicked(self): self.close() @pyqtSlot() def on_pushButton_audit_clicked(self): if len(self.no_enough_stuff_list): text = "以下物料不足!无法执行指令!" informative = ";\n".join(self.no_enough_stuff_list) errordialig = MessageBox(self, text=text, informative=informative) errordialig.exec() return if self.autoid is None: self.new_detail['instructorid'] = user.user_id self.new_detail['instructorname'] = user.user_name self.new_detail['plandate'] = user.now_date self.new_detail['deptid'] = user.dept_id self.new_detail['deptname'] = user.dept_name self.new_detail['bpconstitutorid'] = user.user_id self.new_detail['bpconstitutorname'] = user.user_name self.new_detail['bpconsdate'] = user.now_date self.new_detail['status'] = 1 self.new_detail['statustime'] = user.now_time self.new_detail['warrantorid'] = user.user_id self.new_detail['warrantorname'] = user.user_name self.new_detail['warrantdate'] = user.now_date self.new_detail['qadate'] = user.now_date self.new_detail['bpwarrantorid'] = user.user_id self.new_detail['bpwarrantorname'] = user.user_name self.new_detail['bpwarrantdate'] = user.now_date if self.autoid is None: prodtype = self.productkind.currentIndex() prod_id = self.prodname.namelist.currentItem().text(0) self.new_detail['id'] = prod_id ppid = self.PC.update_producingplan(prodtype=prodtype, **self.new_detail) self.autoid = ppid self.created.emit(self.autoid) # self.PC.update_data(3, **self.new_detail) else: condition = {'autoid': self.autoid} self.PC.update_data(3, condition, **self.new_detail) for item in self.stuff_list: if item['drawamount'] == 0: continue detail = { 'ppid': self.autoid, 'srid': item['autoid'], 'drawamount': item['drawamount'], 'stuffkind': item['stuffkind'] } self.PC.update_data(7, **detail) self.accept()