def __init__(self, baseModel, bomModel, formType=BATCH, parent=None): super(BatchForm, self).__init__(parent) self.setupUi(self) self.my_parent = parent self.dirty = False self.editing = False self.session = Session() self.query = None self.current_record = None self.record_id = None if formType == BASE: self.baseRadio.setChecked(True) else: self.batchRadio.setChecked(True) self.dateEdit.setDate(self.my_parent.getDate()) baseID = dMax(BaseHeader.base_id) + 1 self.v_baseID_Label.setText(str(baseID)) self.printButton.setEnabled(False) self.baseModel = baseModel self.baseView = modelsandviews.ItemView(self.baseModel, True) self.baseCombo.setModel(self.baseModel) self.baseCombo.setView(self.baseView) self.baseCombo.setModelColumn(1) self.baseCombo.setCurrentIndex(-1) self.baseCombo.view().setFixedWidth(200) self.baseCombo.setEditable(True) self.baseCombo.setInsertPolicy(QComboBox.NoInsert) self.baseTypeCombo = QComboBox(self.frame) self.baseTypeCombo.addItems(("Base", "Flavor")) self.baseTypeCombo.setGeometry(QRect(275, 9, 96, 25)) self.itemModel = bomModel self.detailModel = BaseDetailModel() self.detailView.setModel(self.detailModel) delegate = GenericDelegate(self) delegate.insertDelegate(RMID, ComboDelegate(self.itemModel, True)) delegate.insertDelegate(QTY, NumberDelegate()) self.detailView.setItemDelegate(delegate) self.associatedModel = BaseAssemblyModel() self.associatedView.setModel(self.associatedModel) assoDelegate = GenericDelegate(self) assoDelegate.insertDelegate(1, ComboDelegate(self.baseModel, True)) assoDelegate.insertDelegate(2, NumberDelegate()) self.associatedView.setColumnHidden(0, True) self.associatedView.setItemDelegate(assoDelegate) self.associatedView.horizontalHeader().setStretchLastSection(True) self.changeLayout(False) self.baseRadio.toggled.connect(lambda: self.changeLayout(True)) self.detailModel.dataChanged.connect(lambda: self.autoAddRow(self.detailView, self.detailModel)) self.associatedModel.dataChanged.connect(lambda: self.autoAddRow(self.associatedView, self.associatedModel)) self.multFactorLineedit.editingFinished.connect(self.updateSumTotal) self.baseCombo.currentIndexChanged.connect(self.recallBase) self.multLineedit.editingFinished.connect(self.multiplyQty) self.dateEdit.dateChanged.connect(self.updateModelDate) self.dateEdit.dateChanged.connect(self.setParentDate) self.newButton.clicked.connect(self.clear) self.saveButton.clicked.connect(self.save) self.deleteButton.clicked.connect(self.delete) self.closeButton.clicked.connect(self.accept) self.detailView.doubleClicked.connect(self.findBomID) self.setupConnection()
def __init__(self, baseModel, bomModel, formType=BATCH, parent=None): super(BatchForm, self).__init__(parent) self.setupUi(self) self.my_parent = parent self.dirty = False self.editing = False self.session = Session() self.query = None self.current_record = None self.record_id = None if formType == BASE: self.baseRadio.setChecked(True) else: self.batchRadio.setChecked(True) self.dateEdit.setDate(self.my_parent.getDate()) baseID = dMax(BaseHeader.base_id) + 1 self.v_baseID_Label.setText(str(baseID)) self.printButton.setEnabled(False) self.baseModel = baseModel self.baseView = modelsandviews.ItemView(self.baseModel, True) self.baseCombo.setModel(self.baseModel) self.baseCombo.setView(self.baseView) self.baseCombo.setModelColumn(1) self.baseCombo.setCurrentIndex(-1) self.baseCombo.view().setFixedWidth(200) self.baseCombo.setEditable(True) self.baseCombo.setInsertPolicy(QComboBox.NoInsert) self.baseTypeCombo = QComboBox(self.frame) self.baseTypeCombo.addItems(("Base", "Flavor")) self.baseTypeCombo.setGeometry(QRect(275, 9, 96, 25)) self.itemModel = bomModel self.detailModel = BaseDetailModel() self.detailView.setModel(self.detailModel) delegate = GenericDelegate(self) delegate.insertDelegate(RMID, ComboDelegate(self.itemModel, True)) delegate.insertDelegate(QTY, NumberDelegate()) self.detailView.setItemDelegate(delegate) self.associatedModel = BaseAssemblyModel() self.associatedView.setModel(self.associatedModel) assoDelegate = GenericDelegate(self) assoDelegate.insertDelegate(1, ComboDelegate(self.baseModel, True)) assoDelegate.insertDelegate(2, NumberDelegate()) self.associatedView.setColumnHidden(0, True) self.associatedView.setItemDelegate(assoDelegate) self.associatedView.horizontalHeader().setStretchLastSection(True) self.changeLayout(False) self.baseRadio.toggled.connect(lambda: self.changeLayout(True)) self.detailModel.dataChanged.connect( lambda: self.autoAddRow(self.detailView, self.detailModel)) self.associatedModel.dataChanged.connect( lambda: self.autoAddRow(self.associatedView, self.associatedModel)) self.multFactorLineedit.editingFinished.connect(self.updateSumTotal) self.baseCombo.currentIndexChanged.connect(self.recallBase) self.multLineedit.editingFinished.connect(self.multiplyQty) self.dateEdit.dateChanged.connect(self.updateModelDate) self.dateEdit.dateChanged.connect(self.setParentDate) self.newButton.clicked.connect(self.clear) self.saveButton.clicked.connect(self.save) self.deleteButton.clicked.connect(self.delete) self.closeButton.clicked.connect(self.accept) self.detailView.doubleClicked.connect(self.findBomID) self.setupConnection()
class BatchForm(QDialog, ui_forms.ui_batchform.Ui_BatchForm): localTITLE = 'Base Setup' ### Initializer ============= def __init__(self, baseModel, bomModel, formType=BATCH, parent=None): super(BatchForm, self).__init__(parent) self.setupUi(self) self.my_parent = parent self.dirty = False self.editing = False self.session = Session() self.query = None self.current_record = None self.record_id = None if formType == BASE: self.baseRadio.setChecked(True) else: self.batchRadio.setChecked(True) self.dateEdit.setDate(self.my_parent.getDate()) baseID = dMax(BaseHeader.base_id) + 1 self.v_baseID_Label.setText(str(baseID)) self.printButton.setEnabled(False) self.baseModel = baseModel self.baseView = modelsandviews.ItemView(self.baseModel, True) self.baseCombo.setModel(self.baseModel) self.baseCombo.setView(self.baseView) self.baseCombo.setModelColumn(1) self.baseCombo.setCurrentIndex(-1) self.baseCombo.view().setFixedWidth(200) self.baseCombo.setEditable(True) self.baseCombo.setInsertPolicy(QComboBox.NoInsert) self.baseTypeCombo = QComboBox(self.frame) self.baseTypeCombo.addItems(("Base", "Flavor")) self.baseTypeCombo.setGeometry(QRect(275, 9, 96, 25)) self.itemModel = bomModel self.detailModel = BaseDetailModel() self.detailView.setModel(self.detailModel) delegate = GenericDelegate(self) delegate.insertDelegate(RMID, ComboDelegate(self.itemModel, True)) delegate.insertDelegate(QTY, NumberDelegate()) self.detailView.setItemDelegate(delegate) self.associatedModel = BaseAssemblyModel() self.associatedView.setModel(self.associatedModel) assoDelegate = GenericDelegate(self) assoDelegate.insertDelegate(1, ComboDelegate(self.baseModel, True)) assoDelegate.insertDelegate(2, NumberDelegate()) self.associatedView.setColumnHidden(0, True) self.associatedView.setItemDelegate(assoDelegate) self.associatedView.horizontalHeader().setStretchLastSection(True) self.changeLayout(False) self.baseRadio.toggled.connect(lambda: self.changeLayout(True)) self.detailModel.dataChanged.connect(lambda: self.autoAddRow(self.detailView, self.detailModel)) self.associatedModel.dataChanged.connect(lambda: self.autoAddRow(self.associatedView, self.associatedModel)) self.multFactorLineedit.editingFinished.connect(self.updateSumTotal) self.baseCombo.currentIndexChanged.connect(self.recallBase) self.multLineedit.editingFinished.connect(self.multiplyQty) self.dateEdit.dateChanged.connect(self.updateModelDate) self.dateEdit.dateChanged.connect(self.setParentDate) self.newButton.clicked.connect(self.clear) self.saveButton.clicked.connect(self.save) self.deleteButton.clicked.connect(self.delete) self.closeButton.clicked.connect(self.accept) self.detailView.doubleClicked.connect(self.findBomID) self.setupConnection() ### Form Behaviour setup ============== def setupConnection(self): """ connect every widget on form to the data changed function, to set the form to dirty """ widgets = self.findChildren(QWidget) for widget in widgets: if isinstance(widget, (QLineEdit, QTextEdit)): self.connect(widget, SIGNAL("textEdited(QString)"), self.setDirty) elif isinstance(widget, QComboBox): self.connect(widget, SIGNAL("activated(int)"), self.setDirty) elif isinstance(widget, QCheckBox): self.connect(widget, SIGNAL("stateChanged(int)"), self.setDirty) def changeLayout(self, clrBool): """ setup the form layout, based on type of item user wants to enter""" if self.baseRadio.isChecked(): self.baseTypeCombo.setVisible(True) self.multLineedit.setVisible(False) self.mult_Label.setText('Base Type') self.baseID_Label.setText('Base ID') self.associatedLabel.setVisible(True) self.associatedView.setVisible(True) self.header_label.setText('Create New Base:') self.setStyleSheet("QDialog {Background-color: lightGray ;}") self.localTITLE = 'Base Setup' elif self.batchRadio.isChecked(): self.baseTypeCombo.setVisible(False) self.multLineedit.setVisible(True) self.mult_Label.setText('Multiply Batch') self.baseID_Label.setText('Batch ID') self.associatedLabel.setVisible(False) self.associatedView.setVisible(False) self.header_label.setText('Record Batch:') self.setStyleSheet("QDialog {Background-color: ;}") self.localTITLE = 'Record Batch' self.setWindowTitle(self.localTITLE) if clrBool == True: self.clear() def setDirty(self): if self.baseCombo not in (self.sender(), self.sender().parent()): self.dirty = True self.setWindowTitle("%s - Editing..." % self.localTITLE) def setParentDate(self): date = self.dateEdit.date().toPyDate() self.my_parent.setDate(date) def updateModelDate(self): date = self.dateEdit.date().toPyDate() self.detailModel.updateDate(date) def contextMenuEvent(self, event): menu = QMenu(self) if self.detailView.hasFocus() or self.bom_view.hasFocus(): model = self.detailModel view = self.detailView copyAction = menu.addAction('Copy') pasteAction = menu.addAction('Paste') insertAction = menu.addAction('Insert Line') deleteAction = menu.addAction('Delete Line') copyAction.triggered.connect(self.copy) pasteAction.triggered.connect(self.paste) insertAction.triggered.connect(lambda: self.insertRow(view, model)) deleteAction.triggered.connect(lambda: self.removeRow(view, model)) menu.exec_(event.globalPos()) def copy(self): if self.detailModel.rowCount() <= 1: return selectedItems = self.detailView.selectionModel().selectedIndexes() self.detailModel.copy(selectedItems) def paste(self): row = self.detailView.currentIndex().row() self.detailModel.paste(row) self.updateSumTotal() def autoAddRow(self, view, model): self.updateSumTotal() row = view.currentIndex().row() if model.rowCount() == row + 1: self.insertRow(view, model) def insertRow(self, view, model): if view is not None: index = view.currentIndex() row = index.row() model.insertRows(row) view.setFocus() view.setCurrentIndex(index) def removeRow(self, view, model): if model.rowCount() <= 1: return row = 0 rowsSelected = view.selectionModel().selectedRows() for i in rowsSelected: row = i.row() rows = len(rowsSelected) row = row - rows + 1 model.removeRows(row, rows) self.updateSumTotal() self.setDirty() def findBomID(self): row = self.detailView.currentIndex().row() index = self.detailModel.index(row, 0) self.my_parent.findItem(0, (self, index), self.localTITLE) def enterBOMNo(self, index, bomID): i = 0 ok = True while ok: myIndex = self.detailModel.index(index.row() + i, index.column()) bom = self.detailModel.data(myIndex).toString() if not bom: ok = False i += 1 self.detailView.setCurrentIndex(myIndex) self.detailModel.setData(myIndex, QVariant(bomID)) ### Data and calculations ==================================== def updateSumTotal(self): sum_total = float(self.detailModel.getSumTotal()) sum_qty = float(self.detailModel.getSumQty()) inf_factor = str(self.multFactorLineedit.text()) inf_factor = float(getType(inf_factor)) self.v_cost_Label.setText(str('{:,.2f}'.format(sum_total))) self.v_weight_Label.setText(str('{:,.2f}'.format(sum_qty))) self.v_multFlu_Label.setText(str('{:,.2f}'.format(sum_qty))) self.v_mult1lt_Label.setText(str('{:,.2f}'.format(sum_qty * inf_factor))) self.v_mult15lt_Label.setText(str('{:,.2f}'.format((sum_qty * inf_factor) / 1.5))) self.v_mult2lt_Label.setText(str('{:,.2f}'.format((sum_qty * inf_factor) / 2))) self.v_mult4lt_Label.setText(str('{:,.2f}'.format((sum_qty * inf_factor) / 4))) self.v_mult114lt_Label.setText(str('{:,.2f}'.format((sum_qty * inf_factor) / 11.4))) def multiplyQty(self): # // formula is: newQty = qty (new / old) newValue = self.multLineedit.text() self.multLineedit.undo() oldValue = self.multLineedit.text() self.multLineedit.setText(newValue) if newValue: newValue = float(newValue) else: newValue = 1 if oldValue: oldValue = float(oldValue) else: oldValue = 1 multiplier = newValue / oldValue self.detailModel.updateDetailModel(multiplier) self.updateSumTotal() ## Operations ============== def reject(self): self.accept() def accept(self): if self.dirty: answer = QMessageBox.question(self, "Editing - %s" % self.localTITLE, "Would you like to save your data?", QMessageBox.Yes| QMessageBox.No| QMessageBox.Cancel) if answer == QMessageBox.Cancel: return elif answer == QMessageBox.No: QDialog.accept(self) elif answer == QMessageBox.Yes: self.save() QDialog.accept(self) self.my_parent.formClosed() def checkForJournalID(self): j = dLookup(BatchHeader.journal_id, BatchHeader.batch_id==self.record_id) if j != 'None': return True else: return False def save(self): # // Prepare the items to be recorded qDate = self.dateEdit.date() base_date = qDate.toPyDate() base_type = str(self.baseTypeCombo.currentText()) base_desc = str(self.descLineedit.text()) base_volume = unicode(self.volumeLineedit.text()) inflation_factor = unicode(self.multFactorLineedit.text()) base_memo = str(self.memoTextedit.toPlainText()) base_no = str(self.baseCombo.currentText()) # // do some checks if not base_no: QMessageBox.information(self, 'Save - %s' % self.localTITLE, 'Please specify a Base Number before saving', QMessageBox.Ok) return if not base_volume: QMessageBox.information(self, 'Save - %s' % self.localTITLE, 'Please sepcify a base volume before saving', QMessageBox.Ok) return # // Continue based on form type if self.baseRadio.isChecked(): # // some more checks if not inflation_factor: QMessageBox.information(self, 'Save - %s' % self.localTITLE, 'Please specify an inflation factor before saving', QMessageBox.Ok) return # // check if there are details if self.detailModel.rowCount() <= 1: QMessageBox.information(self, 'Save - %s' % self.localTITLE, 'No details found.', QMessageBox.Ok) return # // do differently if new record or old record if self.editing: # // of old record, update header, delete and redo detail journal_id = self.record_id self.current_record = self.session.query(BaseHeader).filter(BaseHeader.base_id==journal_id) self.current_record.update({'base_date': base_date, 'base_no': base_no, 'base_type': base_type, 'base_desc': base_desc, 'base_volume': base_volume, 'inflation_factor': inflation_factor, 'base_memo': base_memo}) self.session.query(BaseDetail).filter(BaseDetail.base_id==journal_id).delete() self.session.query(AssociatedBase).filter(AssociatedBase.base_id==journal_id).delete() elif not self.editing: # // if new record, get new id number and record header journal_id = dMax(BaseHeader.base_id) + 1 self.session.add(BaseHeader(journal_id, base_date, base_no, base_type, base_desc, base_volume, inflation_factor, base_memo)) # // record detail items = self.detailModel.save(0, journal_id, base_date) associated = self.associatedModel.save(journal_id, 'AssociatedBase') self.session.add_all(associated) elif self.batchRadio.isChecked(): # // some items or a bit different if formType is different, like for batch we need base_id base_id = dLookup(BaseHeader.base_id, BaseHeader.base_no==base_no) multiple = unicode(self.multLineedit.text()) # // check if batch is being edited, or new record if self.editing: #// Check if batch was already used on production if self.checkForJournalID(): if self.checkForJournalID(): QMessageBox.information(self, "Save - %s" % self.localTITLE, "Can't save changes," \ "because it was already used on a production", QMessageBox.Ok) return # // if edited, update header, delete detail so could be redone. journal_id = self.record_id self.current_record = self.session.query(BatchHeader).filter(BatchHeader.batch_id==journal_id) self.current_record.update({'base_id': base_id, 'batch_date': base_date, 'base_volume': base_volume, 'multiple': multiple, 'inflation_factor': inflation_factor, 'batch_memo': base_memo}) self.session.query(BatchDetail).filter(BatchDetail.base_id==journal_id).delete() else: # // if new record, get new id_num, and record new header. journal_id = dMax(BatchHeader.batch_id) + 1 self.session.add(BatchHeader(journal_id, base_id, base_date, base_volume, multiple, inflation_factor, base_memo)) # // record details items = self.detailModel.save(1, journal_id, base_date) # // record details no matter on form type self.session.add_all(items) self.sendToDB() self.my_parent.refreshModels() # // reloads all the models, including batch list model used on production form self.record_id = journal_id self.editing = True self.dirty = False self.setWindowTitle('%s - (Data Saved)' % self.localTITLE) def recallBase(self): """ to fill the detail model when selecting a base, used to edit a base, and to start a new batch """ row = self.baseCombo.currentIndex() if row == -1: return i = self.baseModel.index(row, 0) recordID = self.baseModel.data(i).toInt()[0] self.recall(OTHER, recordID) def recall(self, fType, recordID): # // first find out if the user is in middle of entering data. if self.dirty: answer = QMessageBox.question(self, "Editing - %s" % self.localTITLE, "Would you like to save your data?", QMessageBox.Yes| QMessageBox.Discard| QMessageBox.Cancel) if answer == QMessageBox.Cancel: return elif answer == QMessageBox.Yes: self.save() self.record_id = recordID if fType in (BASE, OTHER): if fType == BASE: self.baseRadio.setChecked(True) row = self.baseCombo.currentIndex() self.changeLayout(False) self.current_record = self.session.query(BaseHeader).filter(BaseHeader.base_id==recordID) for record in self.current_record: self.v_baseID_Label.setText(str(self.record_id)) self.baseCombo.setCurrentIndex(row) base_type = self.baseTypeCombo.findText(record.base_type, Qt.MatchExactly) self.baseTypeCombo.setCurrentIndex(base_type) self.descLineedit.setText(str(record.base_desc)) if fType == BASE: self.dateEdit.setDate(record.base_date) self.volumeLineedit.setText(str(record.base_volume)) self.multFactorLineedit.setText(str(record.inflation_factor)) self.memoTextedit.setText(str(record.base_memo)) baseList = self.session.query(AssociatedBase).filter(AssociatedBase.base_id==recordID) self.associatedModel.load(baseList, True) itemList = self.session.query(BaseDetail).filter(BaseDetail.base_id==recordID) elif fType == BATCH: self.batchRadio.setChecked(True) # // need to block signal, bcs, setChecked triggeres self.clear() where signal is unbocked # // and latter when i do set current indes, it combo emits signal self.baseCombo.blockSignals(True) self.changeLayout(False) self.current_record = self.session.query(BatchHeader).filter(BatchHeader.batch_id==recordID) for record in self.current_record: self.v_baseID_Label.setText(str(self.record_id)) base_no = dLookup(BaseHeader.base_no, BaseHeader.base_id==record.base_id) base_id = self.baseCombo.findText(base_no, Qt.MatchExactly) self.baseCombo.setCurrentIndex(base_id) baseType = dLookup(BaseHeader.base_type, BaseHeader.base_id==record.base_id) base_type = self.baseTypeCombo.findText(baseType, Qt.MatchExactly) self.baseTypeCombo.setCurrentIndex(base_type) baseDesc = dLookup(BaseHeader.base_desc, BaseHeader.base_id==record.base_id) self.descLineedit.setText(str(baseDesc)) self.dateEdit.setDate(record.batch_date) self.volumeLineedit.setText(str(record.base_volume)) self.multLineedit.setText(str(record.multiple)) self.multFactorLineedit.setText(str(record.inflation_factor)) self.memoTextedit.setText(str(record.batch_memo)) itemList = self.session.query(BatchDetail).filter(BatchDetail.base_id==recordID) self.detailModel.load(fType, itemList, self.session) self.updateSumTotal() if fType in (BASE, BATCH): self.editing = True self.baseCombo.blockSignals(False) def delete(self): if not self.record_id: return if self.baseRadio.isChecked(): #need to check if there are batches created with this base, if yes don delete. answer = QMessageBox.question(self, "Delete - %s" % self.localTITLE, "Are you sure you " \ "want to delete Base: %s" % self.descLineedit.text(), QMessageBox.Yes| QMessageBox.No, QMessageBox.NoButton) if answer == QMessageBox.No: return self.session.query(BaseDetail).filter(BaseDetail.base_id==self.record_id).delete() self.session.query(AssociatedBase).filter(AssociatedBase.base_id==self.record_id).delete() elif self.batchRadio.isChecked(): if self.editing == True: if self.checkForJournalID(): QMessageBox.information(self, "Delete - %s" % self.localTITLE, "Can't delete current batch," \ "because it was already used on a production", QMessageBox.Ok) return answer = QMessageBox.question(self, "Delete - %s" % self.localTITLE, "Are you sure you " \ "want to delete batch: %s" % self.descLineedit.text(), QMessageBox.Yes| QMessageBox.No, QMessageBox.NoButton) if answer == QMessageBox.No: return self.session.query(BatchDetail).filter(BatchDetail.base_id==self.record_id).delete() self.current_record.delete() self.sendToDB() self.clear() def sendToDB(self): try: self.session.flush self.session.commit() except Exception, e: self.session.rollback() raise e
class BatchForm(QDialog, ui_forms.ui_batchform.Ui_BatchForm): localTITLE = 'Base Setup' ### Initializer ============= def __init__(self, baseModel, bomModel, formType=BATCH, parent=None): super(BatchForm, self).__init__(parent) self.setupUi(self) self.my_parent = parent self.dirty = False self.editing = False self.session = Session() self.query = None self.current_record = None self.record_id = None if formType == BASE: self.baseRadio.setChecked(True) else: self.batchRadio.setChecked(True) self.dateEdit.setDate(self.my_parent.getDate()) baseID = dMax(BaseHeader.base_id) + 1 self.v_baseID_Label.setText(str(baseID)) self.printButton.setEnabled(False) self.baseModel = baseModel self.baseView = modelsandviews.ItemView(self.baseModel, True) self.baseCombo.setModel(self.baseModel) self.baseCombo.setView(self.baseView) self.baseCombo.setModelColumn(1) self.baseCombo.setCurrentIndex(-1) self.baseCombo.view().setFixedWidth(200) self.baseCombo.setEditable(True) self.baseCombo.setInsertPolicy(QComboBox.NoInsert) self.baseTypeCombo = QComboBox(self.frame) self.baseTypeCombo.addItems(("Base", "Flavor")) self.baseTypeCombo.setGeometry(QRect(275, 9, 96, 25)) self.itemModel = bomModel self.detailModel = BaseDetailModel() self.detailView.setModel(self.detailModel) delegate = GenericDelegate(self) delegate.insertDelegate(RMID, ComboDelegate(self.itemModel, True)) delegate.insertDelegate(QTY, NumberDelegate()) self.detailView.setItemDelegate(delegate) self.associatedModel = BaseAssemblyModel() self.associatedView.setModel(self.associatedModel) assoDelegate = GenericDelegate(self) assoDelegate.insertDelegate(1, ComboDelegate(self.baseModel, True)) assoDelegate.insertDelegate(2, NumberDelegate()) self.associatedView.setColumnHidden(0, True) self.associatedView.setItemDelegate(assoDelegate) self.associatedView.horizontalHeader().setStretchLastSection(True) self.changeLayout(False) self.baseRadio.toggled.connect(lambda: self.changeLayout(True)) self.detailModel.dataChanged.connect( lambda: self.autoAddRow(self.detailView, self.detailModel)) self.associatedModel.dataChanged.connect( lambda: self.autoAddRow(self.associatedView, self.associatedModel)) self.multFactorLineedit.editingFinished.connect(self.updateSumTotal) self.baseCombo.currentIndexChanged.connect(self.recallBase) self.multLineedit.editingFinished.connect(self.multiplyQty) self.dateEdit.dateChanged.connect(self.updateModelDate) self.dateEdit.dateChanged.connect(self.setParentDate) self.newButton.clicked.connect(self.clear) self.saveButton.clicked.connect(self.save) self.deleteButton.clicked.connect(self.delete) self.closeButton.clicked.connect(self.accept) self.detailView.doubleClicked.connect(self.findBomID) self.setupConnection() ### Form Behaviour setup ============== def setupConnection(self): """ connect every widget on form to the data changed function, to set the form to dirty """ widgets = self.findChildren(QWidget) for widget in widgets: if isinstance(widget, (QLineEdit, QTextEdit)): self.connect(widget, SIGNAL("textEdited(QString)"), self.setDirty) elif isinstance(widget, QComboBox): self.connect(widget, SIGNAL("activated(int)"), self.setDirty) elif isinstance(widget, QCheckBox): self.connect(widget, SIGNAL("stateChanged(int)"), self.setDirty) def changeLayout(self, clrBool): """ setup the form layout, based on type of item user wants to enter""" if self.baseRadio.isChecked(): self.baseTypeCombo.setVisible(True) self.multLineedit.setVisible(False) self.mult_Label.setText('Base Type') self.baseID_Label.setText('Base ID') self.associatedLabel.setVisible(True) self.associatedView.setVisible(True) self.header_label.setText('Create New Base:') self.setStyleSheet("QDialog {Background-color: lightGray ;}") self.localTITLE = 'Base Setup' elif self.batchRadio.isChecked(): self.baseTypeCombo.setVisible(False) self.multLineedit.setVisible(True) self.mult_Label.setText('Multiply Batch') self.baseID_Label.setText('Batch ID') self.associatedLabel.setVisible(False) self.associatedView.setVisible(False) self.header_label.setText('Record Batch:') self.setStyleSheet("QDialog {Background-color: ;}") self.localTITLE = 'Record Batch' self.setWindowTitle(self.localTITLE) if clrBool == True: self.clear() def setDirty(self): if self.baseCombo not in (self.sender(), self.sender().parent()): self.dirty = True self.setWindowTitle("%s - Editing..." % self.localTITLE) def setParentDate(self): date = self.dateEdit.date().toPyDate() self.my_parent.setDate(date) def updateModelDate(self): date = self.dateEdit.date().toPyDate() self.detailModel.updateDate(date) def contextMenuEvent(self, event): menu = QMenu(self) if self.detailView.hasFocus() or self.bom_view.hasFocus(): model = self.detailModel view = self.detailView copyAction = menu.addAction('Copy') pasteAction = menu.addAction('Paste') insertAction = menu.addAction('Insert Line') deleteAction = menu.addAction('Delete Line') copyAction.triggered.connect(self.copy) pasteAction.triggered.connect(self.paste) insertAction.triggered.connect(lambda: self.insertRow(view, model)) deleteAction.triggered.connect(lambda: self.removeRow(view, model)) menu.exec_(event.globalPos()) def copy(self): if self.detailModel.rowCount() <= 1: return selectedItems = self.detailView.selectionModel().selectedIndexes() self.detailModel.copy(selectedItems) def paste(self): row = self.detailView.currentIndex().row() self.detailModel.paste(row) self.updateSumTotal() def autoAddRow(self, view, model): self.updateSumTotal() row = view.currentIndex().row() if model.rowCount() == row + 1: self.insertRow(view, model) def insertRow(self, view, model): if view is not None: index = view.currentIndex() row = index.row() model.insertRows(row) view.setFocus() view.setCurrentIndex(index) def removeRow(self, view, model): if model.rowCount() <= 1: return row = 0 rowsSelected = view.selectionModel().selectedRows() for i in rowsSelected: row = i.row() rows = len(rowsSelected) row = row - rows + 1 model.removeRows(row, rows) self.updateSumTotal() self.setDirty() def findBomID(self): row = self.detailView.currentIndex().row() index = self.detailModel.index(row, 0) self.my_parent.findItem(0, (self, index), self.localTITLE) def enterBOMNo(self, index, bomID): i = 0 ok = True while ok: myIndex = self.detailModel.index(index.row() + i, index.column()) bom = self.detailModel.data(myIndex).toString() if not bom: ok = False i += 1 self.detailView.setCurrentIndex(myIndex) self.detailModel.setData(myIndex, QVariant(bomID)) ### Data and calculations ==================================== def updateSumTotal(self): sum_total = float(self.detailModel.getSumTotal()) sum_qty = float(self.detailModel.getSumQty()) inf_factor = str(self.multFactorLineedit.text()) inf_factor = float(getType(inf_factor)) self.v_cost_Label.setText(str('{:,.2f}'.format(sum_total))) self.v_weight_Label.setText(str('{:,.2f}'.format(sum_qty))) self.v_multFlu_Label.setText(str('{:,.2f}'.format(sum_qty))) self.v_mult1lt_Label.setText( str('{:,.2f}'.format(sum_qty * inf_factor))) self.v_mult15lt_Label.setText( str('{:,.2f}'.format((sum_qty * inf_factor) / 1.5))) self.v_mult2lt_Label.setText( str('{:,.2f}'.format((sum_qty * inf_factor) / 2))) self.v_mult4lt_Label.setText( str('{:,.2f}'.format((sum_qty * inf_factor) / 4))) self.v_mult114lt_Label.setText( str('{:,.2f}'.format((sum_qty * inf_factor) / 11.4))) def multiplyQty(self): # // formula is: newQty = qty (new / old) newValue = self.multLineedit.text() self.multLineedit.undo() oldValue = self.multLineedit.text() self.multLineedit.setText(newValue) if newValue: newValue = float(newValue) else: newValue = 1 if oldValue: oldValue = float(oldValue) else: oldValue = 1 multiplier = newValue / oldValue self.detailModel.updateDetailModel(multiplier) self.updateSumTotal() ## Operations ============== def reject(self): self.accept() def accept(self): if self.dirty: answer = QMessageBox.question( self, "Editing - %s" % self.localTITLE, "Would you like to save your data?", QMessageBox.Yes | QMessageBox.No | QMessageBox.Cancel) if answer == QMessageBox.Cancel: return elif answer == QMessageBox.No: QDialog.accept(self) elif answer == QMessageBox.Yes: self.save() QDialog.accept(self) self.my_parent.formClosed() def checkForJournalID(self): j = dLookup(BatchHeader.journal_id, BatchHeader.batch_id == self.record_id) if j != 'None': return True else: return False def save(self): # // Prepare the items to be recorded qDate = self.dateEdit.date() base_date = qDate.toPyDate() base_type = str(self.baseTypeCombo.currentText()) base_desc = str(self.descLineedit.text()) base_volume = unicode(self.volumeLineedit.text()) inflation_factor = unicode(self.multFactorLineedit.text()) base_memo = str(self.memoTextedit.toPlainText()) base_no = str(self.baseCombo.currentText()) # // do some checks if not base_no: QMessageBox.information( self, 'Save - %s' % self.localTITLE, 'Please specify a Base Number before saving', QMessageBox.Ok) return if not base_volume: QMessageBox.information( self, 'Save - %s' % self.localTITLE, 'Please sepcify a base volume before saving', QMessageBox.Ok) return # // Continue based on form type if self.baseRadio.isChecked(): # // some more checks if not inflation_factor: QMessageBox.information( self, 'Save - %s' % self.localTITLE, 'Please specify an inflation factor before saving', QMessageBox.Ok) return # // check if there are details if self.detailModel.rowCount() <= 1: QMessageBox.information(self, 'Save - %s' % self.localTITLE, 'No details found.', QMessageBox.Ok) return # // do differently if new record or old record if self.editing: # // of old record, update header, delete and redo detail journal_id = self.record_id self.current_record = self.session.query(BaseHeader).filter( BaseHeader.base_id == journal_id) self.current_record.update({ 'base_date': base_date, 'base_no': base_no, 'base_type': base_type, 'base_desc': base_desc, 'base_volume': base_volume, 'inflation_factor': inflation_factor, 'base_memo': base_memo }) self.session.query(BaseDetail).filter( BaseDetail.base_id == journal_id).delete() self.session.query(AssociatedBase).filter( AssociatedBase.base_id == journal_id).delete() elif not self.editing: # // if new record, get new id number and record header journal_id = dMax(BaseHeader.base_id) + 1 self.session.add( BaseHeader(journal_id, base_date, base_no, base_type, base_desc, base_volume, inflation_factor, base_memo)) # // record detail items = self.detailModel.save(0, journal_id, base_date) associated = self.associatedModel.save(journal_id, 'AssociatedBase') self.session.add_all(associated) elif self.batchRadio.isChecked(): # // some items or a bit different if formType is different, like for batch we need base_id base_id = dLookup(BaseHeader.base_id, BaseHeader.base_no == base_no) multiple = unicode(self.multLineedit.text()) # // check if batch is being edited, or new record if self.editing: #// Check if batch was already used on production if self.checkForJournalID(): if self.checkForJournalID(): QMessageBox.information(self, "Save - %s" % self.localTITLE, "Can't save changes," \ "because it was already used on a production", QMessageBox.Ok) return # // if edited, update header, delete detail so could be redone. journal_id = self.record_id self.current_record = self.session.query(BatchHeader).filter( BatchHeader.batch_id == journal_id) self.current_record.update({ 'base_id': base_id, 'batch_date': base_date, 'base_volume': base_volume, 'multiple': multiple, 'inflation_factor': inflation_factor, 'batch_memo': base_memo }) self.session.query(BatchDetail).filter( BatchDetail.base_id == journal_id).delete() else: # // if new record, get new id_num, and record new header. journal_id = dMax(BatchHeader.batch_id) + 1 self.session.add( BatchHeader(journal_id, base_id, base_date, base_volume, multiple, inflation_factor, base_memo)) # // record details items = self.detailModel.save(1, journal_id, base_date) # // record details no matter on form type self.session.add_all(items) self.sendToDB() self.my_parent.refreshModels( ) # // reloads all the models, including batch list model used on production form self.record_id = journal_id self.editing = True self.dirty = False self.setWindowTitle('%s - (Data Saved)' % self.localTITLE) def recallBase(self): """ to fill the detail model when selecting a base, used to edit a base, and to start a new batch """ row = self.baseCombo.currentIndex() if row == -1: return i = self.baseModel.index(row, 0) recordID = self.baseModel.data(i).toInt()[0] self.recall(OTHER, recordID) def recall(self, fType, recordID): # // first find out if the user is in middle of entering data. if self.dirty: answer = QMessageBox.question( self, "Editing - %s" % self.localTITLE, "Would you like to save your data?", QMessageBox.Yes | QMessageBox.Discard | QMessageBox.Cancel) if answer == QMessageBox.Cancel: return elif answer == QMessageBox.Yes: self.save() self.record_id = recordID if fType in (BASE, OTHER): if fType == BASE: self.baseRadio.setChecked(True) row = self.baseCombo.currentIndex() self.changeLayout(False) self.current_record = self.session.query(BaseHeader).filter( BaseHeader.base_id == recordID) for record in self.current_record: self.v_baseID_Label.setText(str(self.record_id)) self.baseCombo.setCurrentIndex(row) base_type = self.baseTypeCombo.findText( record.base_type, Qt.MatchExactly) self.baseTypeCombo.setCurrentIndex(base_type) self.descLineedit.setText(str(record.base_desc)) if fType == BASE: self.dateEdit.setDate(record.base_date) self.volumeLineedit.setText(str(record.base_volume)) self.multFactorLineedit.setText(str(record.inflation_factor)) self.memoTextedit.setText(str(record.base_memo)) baseList = self.session.query(AssociatedBase).filter( AssociatedBase.base_id == recordID) self.associatedModel.load(baseList, True) itemList = self.session.query(BaseDetail).filter( BaseDetail.base_id == recordID) elif fType == BATCH: self.batchRadio.setChecked(True) # // need to block signal, bcs, setChecked triggeres self.clear() where signal is unbocked # // and latter when i do set current indes, it combo emits signal self.baseCombo.blockSignals(True) self.changeLayout(False) self.current_record = self.session.query(BatchHeader).filter( BatchHeader.batch_id == recordID) for record in self.current_record: self.v_baseID_Label.setText(str(self.record_id)) base_no = dLookup(BaseHeader.base_no, BaseHeader.base_id == record.base_id) base_id = self.baseCombo.findText(base_no, Qt.MatchExactly) self.baseCombo.setCurrentIndex(base_id) baseType = dLookup(BaseHeader.base_type, BaseHeader.base_id == record.base_id) base_type = self.baseTypeCombo.findText( baseType, Qt.MatchExactly) self.baseTypeCombo.setCurrentIndex(base_type) baseDesc = dLookup(BaseHeader.base_desc, BaseHeader.base_id == record.base_id) self.descLineedit.setText(str(baseDesc)) self.dateEdit.setDate(record.batch_date) self.volumeLineedit.setText(str(record.base_volume)) self.multLineedit.setText(str(record.multiple)) self.multFactorLineedit.setText(str(record.inflation_factor)) self.memoTextedit.setText(str(record.batch_memo)) itemList = self.session.query(BatchDetail).filter( BatchDetail.base_id == recordID) self.detailModel.load(fType, itemList, self.session) self.updateSumTotal() if fType in (BASE, BATCH): self.editing = True self.baseCombo.blockSignals(False) def delete(self): if not self.record_id: return if self.baseRadio.isChecked(): #need to check if there are batches created with this base, if yes don delete. answer = QMessageBox.question(self, "Delete - %s" % self.localTITLE, "Are you sure you " \ "want to delete Base: %s" % self.descLineedit.text(), QMessageBox.Yes| QMessageBox.No, QMessageBox.NoButton) if answer == QMessageBox.No: return self.session.query(BaseDetail).filter( BaseDetail.base_id == self.record_id).delete() self.session.query(AssociatedBase).filter( AssociatedBase.base_id == self.record_id).delete() elif self.batchRadio.isChecked(): if self.editing == True: if self.checkForJournalID(): QMessageBox.information(self, "Delete - %s" % self.localTITLE, "Can't delete current batch," \ "because it was already used on a production", QMessageBox.Ok) return answer = QMessageBox.question(self, "Delete - %s" % self.localTITLE, "Are you sure you " \ "want to delete batch: %s" % self.descLineedit.text(), QMessageBox.Yes| QMessageBox.No, QMessageBox.NoButton) if answer == QMessageBox.No: return self.session.query(BatchDetail).filter( BatchDetail.base_id == self.record_id).delete() self.current_record.delete() self.sendToDB() self.clear() def sendToDB(self): try: self.session.flush self.session.commit() except Exception, e: self.session.rollback() raise e