class Base(QMainWindow): """ Esta clase sirve de base para todos aquellos formularios que siguen el estandar de dos pestañas, una para navegación y otra para edición """ orientation = QPrinter.Portrait pageSize = QPrinter.Letter web = "" def __init__(self, parent, own_toolbar=False): """ @param parent: El widget padre de esta ventana @param own_toolbar: Si este widget dibujara su toolbar en el padre o en el mismo @type parent: QWidget @type own_toolbar: bool """ super(Base, self).__init__(parent) self.user = user.LoggedUser self._status = True self.parentWindow = parent self.own_toolbar = own_toolbar self.database = QSqlDatabase.database() """ @type: QSqlDatabase @ivar: La base de datos a la cual se conecta el sistema """ self.mapper = QDataWidgetMapper(self) u""" @type: QDataWidgetMapper @ivar: El mapper que se encarga de asignar los datos del modelo de navegación a los distintos widgets """ self.printProgressBar = QProgressBar(self) self.webview = QWebView() """ @ivar: EL objeto webview usado para cargar los reportes @type: QWebView """ self.loaded = False """ @ivar: Si se pudo o no cargar un reporte @type: bool """ self.startUi() self.editmodel = None self.printer = QPrinter() self._status = False def startUi(self): """ Iniciar todos los elementos graficos """ self.setupUi(self) if not self.own_toolbar: self.parent().addToolBar(self.toolBar) self.removeToolBar(self.toolBar) settings = QSettings() self.restoreState(settings.value(self.windowTitle() + "/State").toByteArray()) """ @ivar: El MainWindow al que pertenece este widget """ self.createActions() self.printProgressBar.setVisible(False) _tab1shortcut = QShortcut(QKeySequence("Ctrl+1"), self, functools.partial(self.tabWidget.setCurrentIndex, 0)) _tab2shortcut = QShortcut(QKeySequence("Ctrl+2"), self, functools.partial(self.tabWidget.setCurrentIndex, 1)) self.mapper.currentIndexChanged[int].connect(self.updateDetailFilter) self.actionCut.setVisible(False) self.actionPaste.setVisible(False) self.actionCopy.setVisible(False) def closeEvent(self, event): u""" Guardar el tamaño, la posición en la pantalla y la posición de la barra de tareas Preguntar si realmente se desea cerrar la pestaña cuando se esta en modo edición """ if not self.status: if ( not QMessageBox.question( self, qApp.organizationName(), u"¿Está seguro que desea salir?", QMessageBox.Yes | QMessageBox.No ) == QMessageBox.Yes ): event.ignore() # Guardar el tamaño y la posición settings = QSettings() settings.setValue(self.windowTitle() + "/Geometry", self.saveGeometry()) if not self.own_toolbar: self.parent().mdiArea().parent().parent().removeToolBar(self.toolBar) def editCell(self): """ Editar la celda actualmente seleccionada de self.tableedit """ self.tabledetails.edit(self.tabledetails.selectionModel().currentIndex()) @pyqtSlot(QDateTime) @if_edit_model def on_dtPicker_dateTimeChanged(self, datetime): """ Cambiar el tipo de cambio del modelo de edición si cambia la fecha @param datetime: La fecha contenida en self.dtPicker @type datetime: QDateTime """ query = QSqlQuery() try: if not self.database.isOpen(): if not self.database.open(): raise Exception( "No se pudo conectar a la base de " + "datos para recuperar los tipos " + "de cambio" ) q = """ SELECT idtc, tasa FROM tiposcambio WHERE fecha = %s LIMIT 1 """ % datetime.toString( "yyyyMMdd" ) if not query.exec_(q): raise UserWarning("No se pudieron recuperar los tipos de " + "cambio") if not query.size() == 1: logging.critical(u"La consulta para obtener tipos de " + "cambio no devolvio exactamente un valor") raise UserWarning(u"Hubo un error al obtener los tipos " + "de cambio") query.first() self.editmodel.exchangeRateId = query.value(0).toInt()[0] self.editmodel.exchangeRate = Decimal(query.value(1).toString()) # self.editmodel.setData( self.editmodel.index( 0, 0 ), self.editmodel.index( 0, 0 ).data() ) self.editmodel.datetime = datetime except UserWarning as inst: QMessageBox.critical(self, qApp.organizationName(), unicode(inst)) self.dtPicker.setDateTime(self.editmodel.datetime) logging.error(inst) logging.error(query.lastError().text()) except Exception as inst: QMessageBox.critical(self, qApp.organizationName(), u"Hubo un error al obtener los tipos de" + " cambio") logging.critical(query.lastError().text()) logging.critical(inst) self.dtPicker.setDateTime(self.editmodel.datetime) def navigate(self, to): """ Esta funcion se encarga de navegar entro los distintos documentos @param to: es una string que puede tomar los valores 'next' 'previous' 'first' 'last' """ if self.mapper.currentIndex != -1: row = self.mapper.currentIndex() if to == "next": row += 1 if row >= self.navproxymodel.rowCount(): row = self.navproxymodel.rowCount() - 1 self.mapper.setCurrentIndex(row) elif to == "previous": if row <= 1: row = 0 else: row = row - 1 self.mapper.setCurrentIndex(row) elif to == "first": self.mapper.toFirst() elif to == "last": self.mapper.toLast() else: self.mapper.toLast()() if self.tabledetails != None: self.tabledetails.resizeColumnsToContents() self.tabledetails.horizontalHeader().setStretchLastSection(True) self.tablenavigation.selectRow(self.mapper.currentIndex()) def updateDetailFilter(self, _index): """ Esta función se debe implementar en los formularios para que al navegar se actualize el filtro de la tabla detalles @param index: Este es el indice del mapper en el que actualmente se encuentra navegando @type index: int """ QMessageBox.information(self, qApp.organizationName(), u"Esta parte del sistema no ha " + "sido implementada") raise NotImplementedError() def loadModels(self): """ Esta función se ejecuta en el constructor del formulario mediante un QTimer, carga los formularios por primera vez """ self.updateModels() self.navigate("last") self.status = True def _setStatus(self, stat): """ @param stat: False = editando, True = navegando @type stat: bool """ self._status = stat self.setControls(self._status) def _getStatus(self): """ esta propiedad cambia entre navegar y editar """ return self._status status = property(_getStatus, _setStatus) @pyqtSlot(unicode) def on_txtSearch_textChanged(self, searchstring): """ Cambiar el filtro para el navigation model @param searchstring: Es el contenido por el cual se va a filtrar el modelo de navegación @type searchstring: string """ self.navproxymodel.setFilterFixedString(searchstring) @pyqtSlot(QModelIndex) def on_tablenavigation_doubleClicked(self, index): """ Al hacer doble click en la tabla de navegación el se cambia a la pestaña detalles mostrando el documento seleccionado @param index: El indice de la tabla en la que se dio doble click @type index: QModelIndex """ self.mapper.setCurrentIndex(index.row()) self.tabWidget.setCurrentIndex(0) @pyqtSlot(QModelIndex) def on_tablenavigation_clicked(self, index): self.mapper.setCurrentIndex(index.row()) def save(self, ask=True): """ Guardar el documento actual @param ask: Si se deberia o no preguntar al usuario si esta seguro antes de proceder @type ask: bool """ if ( ask == False or QMessageBox.question( self, qApp.organizationName(), u"¿Esta seguro que desea guardar?", QMessageBox.Yes | QMessageBox.No ) == QMessageBox.Yes ): if self.editmodel.valid: if self.editmodel.save(): QMessageBox.information(self, qApp.organizationName(), u"El documento se ha guardado con éxito") self.editmodel = None self.updateModels() self.navigate("last") self.status = True else: QMessageBox.critical(self, qApp.organizationName(), "Ha ocurrido un error al guardar el documento") else: try: QMessageBox.warning(self, qApp.organizationName(), self.editmodel.validError) except AttributeError: QMessageBox.warning( self, qApp.organizationName(), u"El documento no puede guardarse" + " ya que la información no esta" + " completa", ) def setControls(self, unused_status): """ Habilitar o deshabilitar los controles según status @param status: @type status: bool """ QMessageBox.information(self, qApp.organizationName(), u"Esta parte del sistema no ha sido implementada") raise NotImplementedError() def addLine(self): """ añadir una linea a table edit, solo se llama directamente en una ocasion, al comenzar la edicion de un documento """ row = self.editmodel.rowCount() self.editmodel.insertRows(row) def createAction(self, text, slot=None, shortcut=None, icon=None, tip=None, checkable=False, signal="triggered"): """ Crear un objeto acción @param text: El texto de la acción @type text: string @param slot: El slot que se ejecutara cuando se dispare esta acción @type slot: callable @param shortcut: El acceso directo que tiene asignada esta acción @type shortcut: QKeySequence @param icon: El icono de esta acción @type icon: string @param tip: El tooltip que tendra esta acción @type tip: string @param checkable: Si esta acción es checkable o no @type checkable: bool @param signal: La señal en la que esta acción ejecutara el slot @type signal: string @rtype: QAction """ action = QAction(text, self) if icon is not None: if type(icon) == QIcon: action.setIcon(icon) else: action.setIcon(QIcon(icon)) if shortcut is not None: action.setShortcut(shortcut) if tip is not None: action.setToolTip(tip) action.setStatusTip(tip) if slot is not None: getattr(action, signal).connect(slot) if checkable: action.setCheckable(True) return action def newDocument(self): """ Empezar la edición de un nuevo documento """ QMessageBox.information(self, qApp.organizationName(), u"Esta parte del sistema no ha sido implementada") raise NotImplementedError() def cancel(self): """ Cancelar la edición del nuevo documento """ QMessageBox.information(self, qApp.organizationName(), u"Esta parte del sistema no ha sido implementada") raise NotImplementedError() @property def printIdentifier(self): """ La identificación de este documento para reporte, normalmente sera el iddocumento o el ndocimpreso @rtype:string """ raise NotImplementedError(u"printIdentifier debe implementarse para " + "poder imprimir") def preview(self): """ Muestra el dialogo de vista previa de impresión """ try: printer = QPrinter() printer.setOrientation(self.orientation) printer.setPageSize(self.pageSize) web = self.web + self.printIdentifier report = reports.frmReportes(web, printer, self) report.exec_() except NotImplementedError as inst: QMessageBox.information( self, qApp.organizationName(), u"No se ha implementado la función de impresión para este modulo" ) logging.error(unicode(inst)) except UserWarning as inst: QMessageBox.critical(self, qApp.organizationName(), unicode(inst)) logging.error(unicode(inst)) except Exception as inst: QMessageBox.critical(self, qApp.organizationName(), "Hubo un error al intentar mostrar su reporte") logging.critical(unicode(inst)) def printDocument(self): """ Imprime el documento actual """ try: base = reports.Reports.url if base == "": raise UserWarning(u"No existe una configuración para el " + "servidor de reportes") self.printer.setOrientation(self.orientation) self.printer.setPageSize(self.pageSize) web = base + self.web + self.printIdentifier + "&uname=" + self.user.user + "&hash=" + self.user.hash self.loaded = False self.webview.load(QUrl(web)) self.webview.loadFinished[bool].connect(self.on_webview_loadFinished) self.webview.loadProgress[int].connect(self.on_webview_loadProgress) except NotImplementedError as inst: logging.error(unicode(inst)) QMessageBox.information( self, qApp.organizationName(), u"La función de impresión no se ha " + "implementado para este modulo" ) except UserWarning as inst: logging.error(unicode(inst)) QMessageBox.critical(self, qApp.organizationName(), unicode(inst)) except Exception as inst: logging.critical(unicode(inst)) QMessageBox.critical(self, qApp.organizationName(), "Hubo un problema al intentar imprimir" + " su reporte") def on_webview_loadProgress(self, progress): """ Muestra el progreso de la carga del reporte en un progressBar """ self.printProgressBar.setValue(progress) def on_webview_loadFinished(self, status): if self.printProgressBar.isVisible(): self.printProgressBar.hide() if not status: QMessageBox.critical(self, qApp.organizationName(), "El reporte no se pudo cargar") logging.error("No se pudo cargar el reporte") self.loaded = True printdialog = QPrintDialog(self.printer, self) if printdialog.exec_() == QDialog.Accepted: self.webview.print_(self.printer) del self.webview def deleteRow(self): """ Funcion usada para borrar lineas de la tabla """ index = self.tabledetails.currentIndex() if not index.isValid(): return row = index.row() self.editmodel.removeRows(row, 1) self.updateLabels() def updateLabels(self): """ Este metodo se llama para actualizar las etiquetas de totales en el formulario """ raise NotImplementedError() def createActions(self): """ Crea las acciones predefinidas del sistema """ self.actionNew = self.createAction( text="Nuevo", tip="Crear un nuevo documento", icon=QIcon.fromTheme("document-new", QIcon(":/icons/res/document-new.png")), shortcut="Ctrl+n", slot=self.newDocument, ) self.actionPreview = self.createAction( text="Previsualizar", tip=u"Vista de impresión del documento", icon=QIcon.fromTheme("document-preview", QIcon(":/icons/res/document-preview.png")), shortcut="Ctrl+p", slot=self.preview, ) self.actionPrint = self.createAction( text="Imprimir", tip="Imprimir el documento", icon=QIcon.fromTheme("document-print", QIcon(":/icons/res/document-print.png")), slot=self.printDocument, ) self.actionSave = self.createAction( text="Guardar", tip="Guardar el documento", icon=QIcon.fromTheme("document-save", QIcon(":/icons/res/document-save.png")), shortcut="Ctrl+g", slot=self.save, ) self.actionCancel = self.createAction( text="Cancelar", tip=u"Cancelar la creación del nuevo documento", icon=QIcon.fromTheme("dialog-cancel", QIcon(":/icons/res/dialog-cancel.png")), shortcut="Esc", slot=self.cancel, ) # edicion, TODO: QUE FUNCIONEN ESTAS ACCIONES self.actionCopy = self.createAction( text="Copiar", icon=QIcon.fromTheme("edit-copy", QIcon(":/icons/res/edit-copy.png")), shortcut="Ctrl+c" ) self.actionCut = self.createAction( text="Cortar", icon=QIcon.fromTheme("edit-cut", QIcon(":/icons/res/edit-cut.png")), shortcut="Ctrl+x" ) self.actionPaste = self.createAction(text="Pegar", icon=":/icons/res/edit-paste.png", shortcut="Ctrl+v") # navegación self.actionGoFirst = self.createAction( text="Primer documento", tip="Ir al primer documento", icon=QIcon.fromTheme("go-first", QIcon(":/icons/res/go-first.png")), slot=functools.partial(self.navigate, "first"), ) self.actionGoPrevious = self.createAction( text="Documento anterior", tip="Ir al documento anterior", icon=QIcon.fromTheme("go-previous", QIcon(":/icons/res/go-previous.png")), slot=functools.partial(self.navigate, "previous"), ) self.actionGoLast = self.createAction( text="Ultimo documento", tip="Ir al ultimo documento", icon=QIcon.fromTheme("go-last", QIcon(":/icons/res/go-last.png")), slot=functools.partial(self.navigate, "last"), ) self.actionGoNext = self.createAction( text="Documento siguiente", tip="Ir al siguiente documento", icon=QIcon.fromTheme("go-next", QIcon(":/icons/res/go-next.png")), slot=functools.partial(self.navigate, "next"), ) self.actionDeleteRow = self.createAction( text="Borrar la fila", icon=QIcon.fromTheme("edit-delete", QIcon(":/icons/res/edit-delete.png")), slot=self.deleteRow, ) self.addActionsToToolBar() def addActionsToToolBar(self): """ Añade las acciones predefinidas a la barra de tareas """ self.toolBar.addActions( [self.actionNew, self.actionPreview, self.actionPrint, self.actionSave, self.actionCancel] ) self.toolBar.addSeparator() self.toolBar.addActions( [self.actionGoFirst, self.actionGoPrevious, self.actionGoLast, self.actionGoNext, self.actionGoLast] ) @pyqtSlot() @if_edit_model def on_txtObservations_textChanged(self): """ Asignar las observaciones al editmodel """ self.editmodel.observations = self.txtObservations.toPlainText().strip()
class MainWindow(QMainWindow, fatture_ui.Ui_MainWindow): FIRST, PREV, NEXT, LAST = range(4) def __init__(self, parent=None): super(MainWindow, self).__init__(parent) self.setupUi(self) self.setupMenu() self.restoreWinSettings() self.editindex = None self.filename = None self.db = QSqlDatabase.addDatabase("QSQLITE") self.loadInitialFile() self.setupUiSignals() def mmUpdate(self): row = self.mapper.currentIndex() id = self.mModel.data(self.mModel.index(row,MID)).toString() self.sModel.setFilter("mmid=%s" % id) self.sModel.select() self.sTableView.setColumnHidden(SID, True) self.sTableView.setColumnHidden(SMID, True) def addDdtRecord(self): if not self.db.isOpen(): self.statusbar.showMessage( "Database non aperto...", 5000) return row = self.mModel.rowCount() self.mapper.submit() self.mModel.insertRow(row) self.mapper.setCurrentIndex(row) self.dateEdit.setDate(QDate.currentDate()) self.dateEdit.setFocus() self.mmUpdate() def delDdtRecord(self): if not self.db.isOpen(): self.statusbar.showMessage( "Database non aperto...", 5000) return row = self.mapper.currentIndex() if row == -1: self.statusbar.showMessage( "Nulla da cancellare...", 5000) return record = self.mModel.record(row) id = record.value(MID).toInt()[0] fatt = record.value(MDOC).toString() if(QMessageBox.question(self, "Cancella Scaffale", "Vuoi cancellare il ddt N': {0} ?".format(fatt), QMessageBox.Yes|QMessageBox.No) == QMessageBox.No): self.statusbar.showMessage( "Cancellazione ddt annullata...", 5000) return # cancella scaffale self.mModel.removeRow(row) self.mModel.submitAll() if row + 1 >= self.mModel.rowCount(): row = self.mModel.rowCount() - 1 self.mapper.setCurrentIndex(row) if self.mModel.rowCount() == 0: self.cauLineEdit.setText(QString("")) self.noteLineEdit.setText(QString("")) self.ddtLineEdit.setText(QString("")) self.cliComboBox.setCurrentIndex(-1) # cancella tutti gli articoli che si riferiscono # allo scaffale cancellato self.sModel.setFilter("mmid=%s" % id) self.sModel.select() self.sModel.removeRows(0, self.sModel.rowCount()) self.sModel.submitAll() self.statusbar.showMessage( "Cancellazione eseguita...", 5000) self.mmUpdate() def addDettRecord(self): if not self.db.isOpen(): self.statusbar.showMessage( "Database non aperto...", 5000) return rowfatt = self.mapper.currentIndex() record = self.mModel.record(rowfatt) masterid = record.value(MID).toInt()[0] if masterid < 1: self.statusbar.showMessage( "Scaffale non valido o non confermato...", 5000) self.dateEdit.setFocus() return # aggiunge la nuova riga alla vista self.sModel.submitAll() self.sModel.select() row = self.sModel.rowCount() self.sModel.insertRow(row) self.sModel.setData(self.sModel.index(row, SMID), QVariant(masterid)) self.sModel.setData(self.sModel.index(row, SQT), QVariant(1)) self.sModel.setData(self.sModel.index(row, SDESC), QVariant("")) self.sModel.setData(self.sModel.index(row, SIMP), QVariant(0.0)) self.sModel.setData(self.sModel.index(row, SIVA), QVariant(20.0)) self.editindex = self.sModel.index(row, SQT) self.sTableView.setCurrentIndex(self.editindex) self.sTableView.edit(self.editindex) def delDettRecord(self): if not self.db.isOpen(): self.statusbar.showMessage( "Database non aperto...", 5000) return selrows = self.sItmSelModel.selectedRows() if not selrows: self.statusbar.showMessage( "No articles selected to delete...", 5000) return if(QMessageBox.question(self, "Cancellazione righe", "Vuoi cancellare: {0} righe?".format(len(selrows)), QMessageBox.Yes|QMessageBox.No) == QMessageBox.No): return QSqlDatabase.database().transaction() query = QSqlQuery() query.prepare("DELETE FROM fattslave WHERE id = :val") for i in selrows: if i.isValid(): query.bindValue(":val", QVariant(i.data().toInt()[0])) query.exec_() QSqlDatabase.database().commit() self.sModel.revertAll() self.mmUpdate() def setupMenu(self): # AboutBox self.connect(self.action_About, SIGNAL("triggered()"), self.showAboutBox) # FileNew self.connect(self.action_New_File, SIGNAL("triggered()"), self.newFile) # FileLoad self.connect(self.action_Load_File, SIGNAL("triggered()"), self.openFile) # Edit customers self.connect(self.action_Add_Customers, SIGNAL("triggered()"), self.editCustomers) def editCustomers(self): relpath = os.path.dirname(__file__) if relpath: relpath = "%s/" % relpath subprocess.call(['python',os.path.join("%s../clienti/" % relpath, "clienti.py")]) self.setupModels() self.setupMappers() self.setupTables() self.mmUpdate() def showAboutBox(self): dlg = aboutfatt.AboutBox(self) dlg.exec_() def creaStrutturaDB(self): query = QSqlQuery() if not ("tipofatt" in self.db.tables()): if not query.exec_("""CREATE TABLE tipofatt ( id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE NOT NULL, tfatt VARCHAR(50) NOT NULL)"""): QMessageBox.warning(self, "Gestione Fatture", QString("Creazione tabella tipofatt fallita!")) return False else: # aggiungi voci !!!! query.exec_("""INSERT INTO tipofatt VALUES (NULL,'Fattura Semplice')""") query.exec_("""INSERT INTO tipofatt VALUES (NULL,'Fattura Accompagnatoria')""") query.exec_("""INSERT INTO tipofatt VALUES (NULL,'Nota Accredito')""") if not ("fattmaster" in self.db.tables()): if not query.exec_("""CREATE TABLE fattmaster ( id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE NOT NULL, data DATE NOT NULL, doc VARCHAR(50) NOT NULL, idtdoc INTEGER NOT NULL, idcli INTEGER NOT NULL, tpag VARCHAR(50) NOT NULL DEFAULT 'Contanti', causale VARCHAR(200), note VARCHAR(200))"""): QMessageBox.warning(self, "Gestione Fatture", QString("Creazione tabella master fallita!")) return False if not ("fattslave" in self.db.tables()): if not query.exec_("""CREATE TABLE fattslave ( id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE NOT NULL, qt INTEGER NOT NULL DEFAULT '1', desc VARCHAR(200) NOT NULL, imp DOUBLE NOT NULL DEFAULT '0.0', iva DOUBLE NOT NULL DEFAULT '20.0', mmid INTEGER NOT NULL, FOREIGN KEY (mmid) REFERENCES master)"""): QMessageBox.warning(self, "Gestione Fatture", QString("Creazione tabella slave fallita!")) return False QMessageBox.information(self, "Gestione Fatture", QString("Database Creato!")) return True if not ("clienti" in self.db.tables()): if not query.exec_("""CREATE TABLE clienti ( id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE NOT NULL, ragsoc VARCHAR(200) NOT NULL, indirizzo VARCHAR(200) NOT NULL, piva VARCHAR(15), cf VARCHAR(15), tel VARCHAR(30), fax VARCHAR(30), cell VARCHAR(30), email VARCHAR(50))"""): QMessageBox.warning(self, "Gestione Fatture", QString("Creazione tabella clienti fallita!")) return False return True def loadFile(self, fname=None): if fname is None: return if self.db.isOpen(): self.db.close() self.db.setDatabaseName(QString(fname)) if not self.db.open(): QMessageBox.warning(self, "Gestione Fatture", QString("Database Error: %1") .arg(db.lastError().text())) else: if not self.creaStrutturaDB(): return self.filename = unicode(fname) self.setWindowTitle("Gestione Fatture - %s" % self.filename) self.setupModels() self.setupMappers() self.setupTables() #self.setupItmSignals() self.restoreTablesSettings() self.mmUpdate() def loadInitialFile(self): settings = QSettings() fname = unicode(settings.value("Settings/lastFile").toString()) if fname and QFile.exists(fname): self.loadFile(fname) def openFile(self): dir = os.path.dirname(self.filename) \ if self.filename is not None else "." fname = QFileDialog.getOpenFileName(self, "Gestione Fatture - Scegli database", dir, "*.db") if fname: self.loadFile(fname) def newFile(self): dir = os.path.dirname(self.filename) \ if self.filename is not None else "." fname = QFileDialog.getSaveFileName(self, "Gestione Fatture - Scegli database", dir, "*.db") if fname: self.loadFile(fname) def restoreWinSettings(self): settings = QSettings() self.restoreGeometry( settings.value("MainWindow/Geometry").toByteArray()) def restoreTablesSettings(self): settings = QSettings(self) # per la tablelview for column in range(1, self.sModel.columnCount()-1): width = settings.value("Settings/sTableView/%s" % column, QVariant(60)).toInt()[0] self.sTableView.setColumnWidth(column, width if width > 0 else 60) def keyPressEvent(self, event): if event.key() == Qt.Key_Down: self.addDettRecord() else: QMainWindow.keyPressEvent(self, event) def closeEvent(self, event): self.mapper.submit() settings = QSettings() settings.setValue("MainWindow/Geometry", QVariant( self.saveGeometry())) if self.filename is not None: settings.setValue("Settings/lastFile", QVariant(self.filename)) if self.db.isOpen(): # salva larghezza colonne tabella for column in range(1, self.sModel.columnCount()-1): width = self.sTableView.columnWidth(column) if width: settings.setValue("Settings/sTableView/%s" % column, QVariant(width)) self.db.close() del self.db def setupModels(self): """ Initialize all the application models """ # setup slaveModel self.sModel = MyQSqlTableModel(self) self.sModel.setTable(QString("fattslave")) self.sModel.setHeaderData(SID, Qt.Horizontal, QVariant("ID")) self.sModel.setHeaderData(SQT, Qt.Horizontal, QVariant("Qt")) self.sModel.setHeaderData(SDESC, Qt.Horizontal, QVariant("Descrizione")) self.sModel.setHeaderData(SIMP, Qt.Horizontal, QVariant("Importo")) self.sModel.setHeaderData(SIVA, Qt.Horizontal, QVariant("Iva")) self.sModel.setHeaderData(SMID, Qt.Horizontal, QVariant("idlegato")) self.sModel.setEditStrategy(QSqlTableModel.OnRowChange) self.sModel.select() # setup masterModel self.mModel = QSqlRelationalTableModel(self) self.mModel.setTable(QString("fattmaster")) self.mModel.setSort(MDATA, Qt.AscendingOrder) self.mModel.setRelation(MIDCLI, QSqlRelation("clienti", "id", "ragsoc")) self.mModel.setRelation(MIDTDOC, QSqlRelation("tipofatt", "id", "tfatt")) self.mModel.select() def setupMappers(self): ''' Initialize all the application mappers ''' self.mapper = QDataWidgetMapper(self) self.mapper.setSubmitPolicy(QDataWidgetMapper.ManualSubmit) self.mapper.setModel(self.mModel) self.mapper.setItemDelegate(QSqlRelationalDelegate(self)) self.mapper.addMapping(self.dateEdit, MDATA) self.mapper.addMapping(self.fattLineEdit, MDOC) relationModel = self.mModel.relationModel(MIDTDOC) relationModel.setSort(1, Qt.AscendingOrder) relationModel.select() self.tipoFattComboBox.setModel(relationModel) self.tipoFattComboBox.setModelColumn(relationModel.fieldIndex("tfatt")) self.mapper.addMapping(self.tipoFattComboBox, MIDTDOC) relationModel = self.mModel.relationModel(MIDCLI) relationModel.setSort(CRAGSOC, Qt.AscendingOrder) relationModel.select() self.cliComboBox.setModel(relationModel) self.cliComboBox.setModelColumn(relationModel.fieldIndex("ragsoc")) self.mapper.addMapping(self.cliComboBox, MIDCLI) self.mapper.addMapping(self.tipoPagLineEdit, MPAG) self.mapper.addMapping(self.cauLineEdit, MCAU) self.mapper.addMapping(self.noteLineEdit, MNOTE) self.mapper.toFirst() def setupTables(self): """ Initialize all the application tablesview """ self.sTableView.setModel(self.sModel) self.sTableView.setColumnHidden(SID, True) self.sTableView.setColumnHidden(SMID, True) self.sTableView.setWordWrap(True) self.sTableView.resizeRowsToContents() self.sTableView.setAlternatingRowColors(True) self.sItmSelModel = QItemSelectionModel(self.sModel) self.sTableView.setSelectionModel(self.sItmSelModel) self.sTableView.setSelectionBehavior(QTableView.SelectRows) self.sTableView.setTabKeyNavigation(False) self.myDelegate = MyQSqlRelationalDelegate(self) self.sTableView.setItemDelegate(self.myDelegate) self.connect(self.myDelegate, SIGNAL("addDettRecord()"), self.addDettRecord) def setupUiSignals(self): self.connect(self.printPushButton, SIGNAL("clicked()"), self.printFatt) self.connect(self.addMPushButton, SIGNAL("clicked()"), self.addDdtRecord) self.connect(self.delMPushButton, SIGNAL("clicked()"), self.delDdtRecord) self.connect(self.addSPushButton, SIGNAL("clicked()"), self.addDettRecord) self.connect(self.delSPushButton, SIGNAL("clicked()"), self.delDettRecord) self.connect(self.firstMPushButton, SIGNAL("clicked()"), lambda: self.saveRecord(MainWindow.FIRST)) self.connect(self.prevMPushButton, SIGNAL("clicked()"), lambda: self.saveRecord(MainWindow.PREV)) self.connect(self.nextMPushButton, SIGNAL("clicked()"), lambda: self.saveRecord(MainWindow.NEXT)) self.connect(self.lastMPushButton, SIGNAL("clicked()"), lambda: self.saveRecord(MainWindow.LAST)) def saveRecord(self, where): if not self.db.isOpen(): self.statusbar.showMessage( "Database non aperto...", 5000) return row = self.mapper.currentIndex() self.mapper.submit() self.sModel.revertAll() if where == MainWindow.FIRST: row=0 elif where == MainWindow.PREV: row = 0 if row <= 1 else row - 1 elif where == MainWindow.NEXT: row += 1 if row >= self.mModel.rowCount(): row = self.mModel.rowCount() -1 elif where == MainWindow.LAST: row = self.mModel.rowCount()- 1 self.mapper.setCurrentIndex(row) self.mmUpdate() def printFatt(self): ''' Print Inventory ''' if not self.db.isOpen(): self.statusbar.showMessage( "Database non aperto...", 5000) return def makeFATT(copia="Copia Cliente"): qmaster = QSqlQuery() qcli = QSqlQuery() qslave = QSqlQuery() curidx = self.mapper.currentIndex() currec = self.mModel.record(curidx) masterid = currec.value("id").toInt()[0] qmaster.exec_("SELECT id,data,doc,idtdoc,idcli,causale,note " "FROM fattmaster WHERE doc = '%s'" % (currec.value("doc").toString())) qmaster.next() curcli = qmaster.value(4).toInt()[0] qcli.exec_("SELECT id,ragsoc,indirizzo,piva " "FROM clienti WHERE id = %d" % (curcli)) qslave.exec_("SELECT mmid,qt,desc,imp,iva " "FROM fattslave WHERE mmid = '%s'" % (masterid)) qcli.next() # variabili utili alla stampa del report datadoc = currec.value("data").toDate().toString(DATEFORMAT) causaledoc = currec.value("causale").toString() notedoc = currec.value("note").toString() tipodoc = currec.value(3).toString() numdoc = currec.value("doc").toString() cliragsoc = qcli.value(1).toString() cliind = qcli.value(2).toString() clipiva = qcli.value(3).toString() from reportlab.pdfgen.canvas import Canvas from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle from reportlab.lib.units import cm from reportlab.lib.enums import TA_LEFT,TA_RIGHT,TA_CENTER from reportlab.platypus import Spacer, SimpleDocTemplate, Table, TableStyle, Paragraph, KeepTogether from reportlab.rl_config import defaultPageSize from reportlab.lib import colors from reportlab.lib.pagesizes import letter, A4 from reportlab.lib import textsplit PAGE_WIDTH, PAGE_HEIGHT=defaultPageSize styles = getSampleStyleSheet() styleN = styles['Normal'] styleH = styles['Heading1'] styleH.alignment=TA_CENTER Elements = [] #add some flowables p=Paragraph ps=ParagraphStyle Author = "Stefano Zamprogno" URL = "http://www.zamprogno.it/" email = "*****@*****.**" pageinfo = "%s / %s" % (Author, email) def myLaterPages(c, doc): c.saveState() c.setFont("Times-Bold", 82) c.rotate(45) c.setFillColorRGB(0.9,0.9,0.9) c.drawString(11*cm,2*cm, copia) c.rotate(-45) c.setFillColorRGB(0,0,0) # HEADER if tipodoc == "Fattura Accompagnatoria": subt = 0 else: subt = 3 c.setLineWidth(0.1*cm) c.setStrokeColorRGB(0,0,0) c.line(1.8*cm,(6.2-subt)*cm,19.5*cm,(6.2-subt)*cm) c.setStrokeColorRGB(0.5,0.5,0.5) c.line(1.9*cm,(6.1-subt)*cm,19.6*cm,(6.1-subt)*cm) # cerchi carta c.circle(0.9*cm,6*cm,0.3*cm, fill=1) c.circle(0.9*cm,24*cm,0.3*cm, fill=1) c.setFont("Times-Bold", 14) c.drawCentredString(5*cm, 28*cm, r1) c.setFont("Times-Bold", 9) c.drawCentredString(5*cm, 27.5*cm, r2) c.drawCentredString(5*cm, 27*cm, r3) c.drawCentredString(5*cm, 26.5*cm, r4) c.drawCentredString(5*cm, 26*cm, r5) # numero ddt e descrizione copia c.setFont("Times-Bold", 12) c.drawCentredString(18*cm, 28*cm, "DOC N: %s" % (numdoc)) c.setFont("Times-Bold", 7) c.drawCentredString(18*cm, 27.6*cm, "(%s)" % (copia)) c.drawCentredString(18*cm, 27.2*cm, "%s" % (tipodoc.toUpper())) # Data e causale c.setFont("Times-Bold", 10) c.drawString(1.8*cm, 25*cm, "Data:") c.drawString(1.8*cm, 24.5*cm, "Causale:") c.setFont("Times-Roman", 10) c.drawString(4*cm, 25*cm, unicode(datadoc)) c.drawString(4*cm, 24.5*cm, unicode(causaledoc)) # Cliente c.setFont("Times-Bold", 10) c.drawString(11*cm, 25*cm, "Destinatario:") c.setFont("Times-Roman", 10) c.drawCentredString(16*cm, 25*cm, unicode(cliragsoc)) c.drawCentredString(16*cm, 24.5*cm, unicode(cliind)) c.drawCentredString(16*cm, 24*cm, unicode(clipiva)) # FOOTER c.setFont("Times-Bold", 10) c.setLineWidth(0.01*cm) c.drawString(1.8*cm, (5.5-subt)*cm, "Note:") c.setFont("Times-Roman", 10) strt = (5.5-subt)*cm for i in textsplit.wordSplit(unicode(notedoc),6*cm, "Times-Roman", 10): c.drawString(3*cm, strt, i[1]) strt -= 0.5*cm if tipodoc == "Fattura Accompagnatoria": c.setFont("Times-Bold", 10) c.drawString(12*cm, 5.5*cm, "Data inizio trasporto:") c.line(15.5*cm,5.4*cm,19*cm,5.4*cm) c.drawString(12*cm, 5*cm, "Aspetto dei beni:") c.line(15*cm,4.9*cm,19*cm,4.9*cm) c.drawString(12*cm, 4.5*cm, "Numero colli:") c.line(15*cm,4.4*cm,19*cm,4.4*cm) c.drawString(12*cm, 3.8*cm, "Conducente:") c.line(15*cm,3.7*cm,19*cm,3.7*cm) c.drawString(12*cm, 3*cm, "Destinatario:") c.line(15*cm,2.9*cm,19*cm,2.9*cm) c.drawString(1.8*cm, 4*cm, "Trasporto a Mezzo:") c.line(2.3*cm,3*cm,7*cm,3*cm) # note pie' pagina c.setFont('Times-Roman',9) c.drawString(12.4*cm, 1.5*cm, "Pagina %d %s" % (doc.page, pageinfo)) c.restoreState() # crea il body del ddt data = [['Qt', 'Descrizione dei beni, natura e qualità', 'Importo', 'IVA'],] totimp = 0 totiva = 0 totesiva = 0 while qslave.next(): if qslave.value(4).toDouble()[0]!= 0: totimp += qslave.value(3).toDouble()[0] totiva += (qslave.value(3).toDouble()[0]* qslave.value(4).toDouble()[0] / 100.0) else: totesiva += qslave.value(3).toDouble()[0] data.append([qslave.value(1).toInt()[0], p(unicode(qslave.value(2).toString()), ps(name='Normal')), "€ %.2f" % qslave.value(3).toDouble()[0], "%.2f %%" % qslave.value(4).toDouble()[0]]) Elements.append(Table(data,colWidths=(1*cm,12.5*cm,2*cm,2*cm),repeatRows=1, style=( ['LINEBELOW', (0,0), (-1,0), 1, colors.black], ['BACKGROUND',(0,0),(-1,0), colors.lightgrey], ['GRID',(0,0),(-1,-1), 0.2, colors.black], ['FONT', (0, 0), (-1, 0), 'Helvetica-Bold', 10], ['VALIGN', (0,0), (-1,-1), 'TOP'], ['ALIGN', (0,0), (-1,0), 'CENTER'], ['ALIGN', (2,1), (3,-1), 'RIGHT'], ))) summary = [] summary.append(Spacer(0.5*cm, 0.5*cm)) summary.append(Paragraph("<para align=right><b>___________________________________" "</b></para>", styleN)) summary.append(Paragraph("<para align=right><b>TOTALE IMPONIBILE: " "€ %.2f</b></para>" % totimp, styleN)) summary.append(Paragraph("<para align=right><b>TOTALE IVA: " "€ %.2f</b></para>" % totiva, styleN)) summary.append(Paragraph("<para align=right><b>TOTALE Es.IVA: " "€ %.2f</b></para>" % totesiva, styleN)) summary.append(Spacer(0.5*cm, 0.5*cm)) summary.append(Paragraph("<para align=right><b>TOTALE GENERALE: " "€ %.2f</b></para>" % (totesiva+totimp+totiva), styleN)) Elements.append(KeepTogether(summary)) # 'depure' numddt numdoc = numdoc.replace("/",".") if tipodoc == "Fattura Accompagnatoria": doc = SimpleDocTemplate(os.path.join(os.path.dirname(__file__), "fatt%s.%s.pdf" % (numdoc, copia.replace(" ","."))),topMargin=6.2*cm, bottomMargin=6.2*cm) else: doc = SimpleDocTemplate(os.path.join(os.path.dirname(__file__), "fatt%s.%s.pdf" % (numdoc, copia.replace(" ","."))),topMargin=6.2*cm, bottomMargin=3*cm) doc.build(Elements,onFirstPage=myLaterPages,onLaterPages=myLaterPages) subprocess.Popen(['gnome-open',os.path.join(os.path.dirname(__file__), "fatt%s.%s.pdf" % (numdoc, copia.replace(" ",".")))]) if self.copiaCliCheckBox.isChecked(): makeFATT() if self.copiaIntCheckBox.isChecked(): makeFATT(copia="Copia Interna") if self.copiaVettCheckBox.isChecked(): makeFATT(copia="Copia Vettore")
class MainWindow(QMainWindow, magazzino_ui.Ui_MainWindow): FIRST, PREV, NEXT, LAST = range(4) Clipboard = [] # lista di oggetti def __init__(self, parent=None): super(MainWindow, self).__init__(parent) self.setupUi(self) self.setupMenu() self.restoreWinSettings() self.editindex = None self.filename = None self.db = QSqlDatabase.addDatabase("QSQLITE") self.loadInitialFile() self.setupUiSignals() def keyPressEvent(self, event): if event.key() == Qt.Key_Down: self.addDettRecord() else: QMainWindow.keyPressEvent(self, event) def creaStrutturaDB(self): query = QSqlQuery() if not ("magamaster" in self.db.tables()): if not query.exec_("""CREATE TABLE magamaster ( id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE NOT NULL, scaff VARCHAR(10) NOT NULL)"""): QMessageBox.warning(self, "Magazzino", QString("Creazione tabella fallita!")) return False if not ("magaslave" in self.db.tables()): if not query.exec_("""CREATE TABLE magaslave ( id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE NOT NULL, datains DATE NOT NULL, abbi VARCHAR(50), angro VARCHAR(50), desc VARCHAR(100), qt INTEGER NOT NULL DEFAULT '1', imp DOUBLE NOT NULL DEFAULT '0.0', equiv VARCHAR(100), mmid INTEGER NOT NULL, fatt VARCHAR(50), note VARCHAR(200), FOREIGN KEY (mmid) REFERENCES magamaster)"""): QMessageBox.warning(self, "Magazzino", QString("Creazione tabella fallita!")) return False QMessageBox.information(self, "Magazzino", QString("Database Creato!")) return True def loadFile(self, fname=None): if fname is None: return if self.db.isOpen(): self.db.close() self.db.setDatabaseName(QString(fname)) if not self.db.open(): QMessageBox.warning(self, "Magazzino", QString("Database Error: %1") .arg(self.db.lastError().text())) else: if not self.creaStrutturaDB(): return self.filename = unicode(fname) self.setWindowTitle("Gestione Magazzino - %s" % self.filename) self.setupModels() self.setupMappers() self.setupTables() #self.setupItmSignals() self.restoreTablesSettings() self.mmUpdate() def loadInitialFile(self): settings = QSettings() fname = unicode(settings.value("Settings/lastFile").toString()) if fname and QFile.exists(fname): self.loadFile(fname) def openFile(self): dir = os.path.dirname(self.filename) \ if self.filename is not None else "." fname = QFileDialog.getOpenFileName(self, "Gestione Magazzino - Scegli database", dir, "*.db") if fname: self.loadFile(fname) def newFile(self): dir = os.path.dirname(self.filename) \ if self.filename is not None else "." fname = QFileDialog.getSaveFileName(self, "Gestione Magazzino - Scegli database", dir, "*.db") if fname: self.loadFile(fname) def setupMenu(self): # AboutBox self.connect(self.actionA_bout, SIGNAL("triggered()"), self.showAboutBox) # FileNew self.connect(self.action_New_File, SIGNAL("triggered()"), self.newFile) # FileLoad self.connect(self.action_Load_File, SIGNAL("triggered()"), self.openFile) def showAboutBox(self): dlg = aboutmaga.AboutBox(self) dlg.exec_() def printInventory(self): ''' Print Inventory ''' if not self.db.isOpen(): self.statusbar.showMessage( "Database non aperto...", 5000) return querygrp = QSqlQuery() querydett = QSqlQuery() querygrp.exec_("SELECT abbi,qt,imp,sum(qt*imp) " "FROM magaslave GROUP BY abbi") querydett.prepare("SELECT datains,abbi,angro,desc,qt,imp " "FROM magaslave WHERE abbi = :abbi AND " "qt > 0 ORDER BY datains") from reportlab.pdfgen.canvas import Canvas from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle from reportlab.lib.units import cm from reportlab.lib.enums import TA_LEFT,TA_RIGHT,TA_CENTER from reportlab.platypus import Spacer, SimpleDocTemplate from reportlab.platypus import Table, TableStyle, Paragraph from reportlab.rl_config import defaultPageSize from reportlab.lib import colors PAGE_WIDTH, PAGE_HEIGHT=defaultPageSize styles = getSampleStyleSheet() styleN = styles['Normal'] styleH = styles['Heading1'] styleH.alignment=TA_CENTER Elements = [] #add some flowables p=Paragraph ps=ParagraphStyle Title = unicode(self.prtTitleLineEdit.text()) Year = unicode(self.prtDateLineEdit.text()) Author = "Stefano Zamprogno" URL = "http://www.zamprogno.it/" email = "*****@*****.**" pageinfo = "%s / %s / %s" % (Author, email, Title) def myFirstPage(canvas, doc): canvas.saveState() canvas.setStrokeColorRGB(0.50,0.50,0.50) canvas.setLineWidth(10) canvas.line(45,72,45,PAGE_HEIGHT-72) #canvas.setFont('Times-Bold',16) #canvas.drawCentredString(3*cm, 1.5*cm,Title) canvas.setFont('Times-Roman',9) canvas.drawString(3*cm, 1.5*cm, "First Page / %s" % pageinfo) canvas.restoreState() def myLaterPages(canvas, doc): canvas.saveState() canvas.setStrokeColorRGB(0.50,0.50,0.50) canvas.setLineWidth(5) canvas.line(45,72,45,PAGE_HEIGHT-72) canvas.setFont('Times-Roman',9) canvas.drawString(3*cm, 1.5*cm, "Page %d %s" % (doc.page, pageinfo)) canvas.restoreState() Elements.append(Paragraph(Title, styleH)) Elements.append(Paragraph(Year,styleN)) Elements.append(Spacer(0.5*cm, 0.5*cm)) tot=0 while querygrp.next(): tot += querygrp.value(3).toDouble()[0] querydett.bindValue(":abbi", QVariant(querygrp.value(0).toString())) querydett.exec_() data = [['Abbi', 'Angro', 'Descrizione', 'Qt', 'Imp'],] while querydett.next(): data.append([ p(unicode(querydett.value(1).toString()), ps(name='Normal')), p(unicode(querydett.value(2).toString()), ps(name='Normal')), p(unicode(querydett.value(3).toString()), ps(name='Normal')), querydett.value(4).toInt()[0], unicode("%.2f" % querydett.value(5).toDouble()[0])]) data.append([None, None, unicode("GRUPPO '%s'" % querygrp.value(0).toString()), unicode("Subtotale:"), unicode("€ %.2f" % querygrp.value(3).toDouble()[0])]) Elements.append(Table(data,repeatRows=1, style=(['LINEBELOW', (3,-2), (-1,-2), 1, colors.black], ['LINEBELOW', (0,0), (-1,0), 1, colors.black], ['ALIGN', (1,0), (3,-1),'CENTER'], ['ALIGN', (4,0), (-1,0),'RIGHT'], ['VALIGN', (0,0), (-1,-1), 'TOP'], ['ALIGN', (4,0), (-1,-1), 'RIGHT'], # ['TEXTCOLOR', (0,0), (-1,0), # colors.red], ['BACKGROUND',(0,0),(-1,0), colors.lightgrey], ['GRID',(0,0),(-1,-1), 0.2, colors.black], ['FONT', (0, 0), (-1, 0), 'Helvetica-Bold', 10], ['FONT', (3, -1), (3, -1), 'Helvetica-Bold', 10]))) Elements.append(Spacer(0.5*cm, 0.5*cm)) Elements.append(Paragraph("<para align=right><b>TOTALE GENERALE:" "€ %.2f</b></para>" % tot, styleN)) doc = SimpleDocTemplate(os.path.join(os.path.dirname(__file__), 'mydoc.pdf')) doc.build(Elements,onFirstPage=myFirstPage, onLaterPages=myLaterPages) subprocess.Popen(['gnome-open',os.path.join(os.path.dirname(__file__), 'mydoc.pdf')]) def setupMappers(self): ''' Initialize all the application mappers ''' self.mapper = QDataWidgetMapper(self) self.mapper.setModel(self.mModel) self.mapper.addMapping(self.scaffLineEdit, SCAFF) self.mapper.setSubmitPolicy(QDataWidgetMapper.ManualSubmit) self.mapper.toFirst() def setupTables(self): """ Initialize all the application tablesview """ self.sTableView.setModel(self.sModel) self.sTableView.setItemDelegate(MSDelegate(self)) self.sTableView.setColumnHidden(ID, True) self.sTableView.setColumnHidden(MMID, True) self.sTableView.setWordWrap(True) self.sTableView.resizeRowsToContents() self.sTableView.setAlternatingRowColors(True) self.sItmSelModel = QItemSelectionModel(self.sModel) self.sTableView.setSelectionModel(self.sItmSelModel) self.sTableView.setSelectionBehavior(QTableView.SelectRows) #self.sTableView.setTabKeyNavigation(True) self.fTableView.setModel(self.fModel) self.fTableView.setColumnHidden(ID, True) self.fTableView.setWordWrap(True) self.fTableView.resizeRowsToContents() self.fTableView.setAlternatingRowColors(True) self.fItmSelModel = QItemSelectionModel(self.fModel) self.fTableView.setSelectionModel(self.fItmSelModel) def setupModels(self): """ Initialize all the application models """ # setup slaveModel self.sModel = ssModel(self) self.sModel.setTable(QString("magaslave")) self.sModel.setHeaderData(ID, Qt.Horizontal, QVariant("ID")) self.sModel.setHeaderData(DATAINS, Qt.Horizontal, QVariant("DataIns")) self.sModel.setHeaderData(ABBI, Qt.Horizontal, QVariant("Abbi")) self.sModel.setHeaderData(ANGRO, Qt.Horizontal, QVariant("Angro")) self.sModel.setHeaderData(DESC, Qt.Horizontal, QVariant("Desc")) self.sModel.setHeaderData(QT, Qt.Horizontal, QVariant("Qt")) self.sModel.setHeaderData(IMP, Qt.Horizontal, QVariant("Imp")) self.sModel.setHeaderData(EQUIV, Qt.Horizontal, QVariant("Equiv")) self.sModel.setHeaderData(MMID, Qt.Horizontal, QVariant("ScaffId")) self.sModel.setHeaderData(FATT, Qt.Horizontal, QVariant("Fatt")) self.sModel.setHeaderData(NOTE, Qt.Horizontal, QVariant("Note")) self.sModel.setSort(DATAINS, Qt.AscendingOrder) self.sModel.setEditStrategy(QSqlTableModel.OnRowChange) self.sModel.select() # setup masterModel self.mModel = QSqlTableModel(self) self.mModel.setTable(QString("magamaster")) self.mModel.setSort(SCAFF, Qt.AscendingOrder) self.mModel.setHeaderData(ID, Qt.Horizontal, QVariant("ID")) self.mModel.setHeaderData(SCAFF, Qt.Horizontal, QVariant("Scaff")) self.mModel.select() # setup findModel self.fModel = QSqlRelationalTableModel(self) self.fModel.setTable(QString("magaslave")) self.fModel.setHeaderData(ID, Qt.Horizontal, QVariant("ID")) self.fModel.setHeaderData(DATAINS, Qt.Horizontal, QVariant("DataIns")) self.fModel.setHeaderData(ABBI, Qt.Horizontal, QVariant("Abbi")) self.fModel.setHeaderData(ANGRO, Qt.Horizontal, QVariant("Angro")) self.fModel.setHeaderData(DESC, Qt.Horizontal, QVariant("Desc")) self.fModel.setHeaderData(QT, Qt.Horizontal, QVariant("Qt")) self.fModel.setHeaderData(IMP, Qt.Horizontal, QVariant("Imp")) self.fModel.setHeaderData(EQUIV, Qt.Horizontal, QVariant("Equiv")) self.fModel.setHeaderData(MMID, Qt.Horizontal, QVariant("ScaffId")) self.fModel.setHeaderData(FATT, Qt.Horizontal, QVariant("Fatt")) self.fModel.setHeaderData(NOTE, Qt.Horizontal, QVariant("Note")) self.fModel.setSort(MMID, Qt.AscendingOrder) self.fModel.setRelation(MMID, QSqlRelation("magamaster", "id", "scaff")) self.fModel.select() def clipCopy(self): self.Clipboard = self.sTableView.selectedIndexes() selrows = self.sItmSelModel.selectedRows() # TODO : da usare: selrows = self.sItmSelModel.selectedRows() print(selrows, len(selrows)) print(len(self.Clipboard)) # FIXME : bla bla bla def clipDel(self): self.delDettRecord() def clipPaste(self): pass def ctxtMenu(self, point): menu = QMenu(self) copyAction = menu.addAction("&Copy") self.connect(copyAction, SIGNAL("triggered()"), self.clipCopy) delAction = menu.addAction("&Del") self.connect(delAction, SIGNAL("triggered()"), self.clipDel) if len(self.Clipboard) > 0: pasteAction = menu.addAction("&Paste") self.connect(pasteAction, SIGNAL("triggered()"), self.clipPaste) menu.exec_(self.sTableView.mapToGlobal(point)) def setupUiSignals(self): self.sTableView.setContextMenuPolicy(Qt.CustomContextMenu) self.connect(self.sTableView, SIGNAL( "customContextMenuRequested(const QPoint &)"), self.ctxtMenu) self.connect(self.scaffLineEdit, SIGNAL("returnPressed()"), lambda: self.saveRecord(MainWindow.FIRST)) self.connect(self.findLineEdit, SIGNAL("returnPressed()"), self.globalFilter) self.connect(self.printPushButton, SIGNAL("clicked()"), self.printInventory) self.connect(self.createFilterPushButton, SIGNAL("clicked()"), self.createFilter) self.connect(self.findPushButton, SIGNAL("clicked()"), self.applyFilter) self.connect(self.gSearchPushButton, SIGNAL("clicked()"), self.globalFilter) self.connect(self.addscaffPushButton, SIGNAL("clicked()"), self.addScaffRecord) self.connect(self.adddettPushButton, SIGNAL("clicked()"), self.addDettRecord) self.connect(self.deldettPushButton, SIGNAL("clicked()"), self.delDettRecord) self.connect(self.delscaffPushButton, SIGNAL("clicked()"), self.delScaffRecord) self.connect(self.scaffFirstPushButton, SIGNAL("clicked()"), lambda: self.saveRecord(MainWindow.FIRST)) self.connect(self.scaffPrevPushButton, SIGNAL("clicked()"), lambda: self.saveRecord(MainWindow.PREV)) self.connect(self.scaffNextPushButton, SIGNAL("clicked()"), lambda: self.saveRecord(MainWindow.NEXT)) self.connect(self.scaffLastPushButton, SIGNAL("clicked()"), lambda: self.saveRecord(MainWindow.LAST)) def globalFilter(self): if not self.db.isOpen(): self.statusbar.showMessage( "Database non aperto...", 5000) return txt = self.findLineEdit.text() qry = ("(datains like '%s') OR " "(abbi like '%s') OR " "(angro like '%s') OR " "(desc like '%s') OR " "(equiv like '%s') OR" "(fatt like '%s') OR" "(note like '%s')") % ((txt,)*7) self.fModel.setFilter(qry) self.updateFilter() def updateFilter(self): self.fModel.select() self.fTableView.setColumnHidden(ID, True) def applyFilter(self): if not self.db.isOpen(): self.statusbar.showMessage( "Database non aperto...", 5000) return self.fModel.setFilter(self.findLineEdit.text()) self.updateFilter() def createFilter(self): if not self.db.isOpen(): self.statusbar.showMessage( "Database non aperto...", 5000) return headerDef = ("datains VARCHAR(100)", "abbi VARCHAR(100)", "angro VARCHAR(100)", "desc VARCHAR(100)", "qt VARCHAR(100)", "imp VARCHAR(100)", "equiv VARCHAR(100)", "fatt VARCHAR(100)", "note VARCHAR(100)") dlg = filterdialog.FilterDialog(headerDef, QSqlDatabase.database(), self) if(dlg.exec_()): self.findLineEdit.setText(dlg.filterDone() if dlg.filterDone() else "") self.applyFilter() #~ def editEsc(self, idxcur, idxold): #~ if self.editindex and self.editindex.isValid(): #~ if idxcur.row() != self.editindex.row(): #~ self.sModel.revertAll() #~ self.editindex = None def mmUpdate(self): row = self.mapper.currentIndex() id = self.mModel.data(self.mModel.index(row,ID)).toString() self.sModel.setFilter("mmid=%s" % id) self.sModel.select() self.sTableView.setColumnHidden(ID, True) self.sTableView.setColumnHidden(MMID, True) def saveRecord(self, where): if not self.db.isOpen(): self.statusbar.showMessage( "Database non aperto...", 5000) return row = self.mapper.currentIndex() self.mapper.submit() self.sModel.revertAll() if where == MainWindow.FIRST: row=0 elif where == MainWindow.PREV: row = 0 if row <= 1 else row - 1 elif where == MainWindow.NEXT: row += 1 if row >= self.mModel.rowCount(): row = self.mModel.rowCount() -1 elif where == MainWindow.LAST: row = self.mModel.rowCount()- 1 self.mapper.setCurrentIndex(row) self.mmUpdate() def addScaffRecord(self): if not self.db.isOpen(): self.statusbar.showMessage( "Database non aperto...", 5000) return row = self.mModel.rowCount() self.mapper.submit() self.mModel.insertRow(row) self.mapper.setCurrentIndex(row) self.scaffLineEdit.setFocus() self.mmUpdate() def addDettRecord(self): if not self.db.isOpen(): self.statusbar.showMessage( "Database non aperto...", 5000) return rowscaff = self.mapper.currentIndex() record = self.mModel.record(rowscaff) masterid = record.value(ID).toInt()[0] if masterid < 1: self.statusbar.showMessage( "Scaffale non valido o non confermato...", 5000) self.scaffLineEdit.setFocus() return # aggiunge la nuova riga alla vista self.sModel.submitAll() self.sModel.select() row = self.sModel.rowCount() self.sModel.insertRow(row) if row > 1: precfatt = self.sModel.data(self.sModel.index(row-1, FATT)) else: precfatt = '' if row > 1: lastData = self.sModel.data(self.sModel.index(row-1, DATAINS)) else: lastData = '' self.sModel.setData(self.sModel.index(row, MMID), QVariant(masterid)) self.sModel.setData(self.sModel.index(row, QT), QVariant(1)) self.sModel.setData(self.sModel.index(row, IMP), QVariant(0.0)) self.sModel.setData(self.sModel.index(row, FATT), QVariant(precfatt)) self.editindex = self.sModel.index(row, DATAINS) self.sTableView.setCurrentIndex(self.editindex) self.sTableView.edit(self.editindex) def delDettRecord(self): if not self.db.isOpen(): self.statusbar.showMessage( "Database non aperto...", 5000) return selrows = self.sItmSelModel.selectedRows() if not selrows: self.statusbar.showMessage( "No articles selected to delete...", 5000) return if(QMessageBox.question(self, "Cancella Articoli", "Vuoi cancellare: {0} articoli?".format(len(selrows)), QMessageBox.Yes|QMessageBox.No) == QMessageBox.No): return QSqlDatabase.database().transaction() query = QSqlQuery() query.prepare("DELETE FROM magaslave WHERE id = :val") for i in selrows: if i.isValid(): query.bindValue(":val", QVariant(i.data().toInt()[0])) query.exec_() QSqlDatabase.database().commit() self.sModel.revertAll() self.mmUpdate() def delScaffRecord(self): if not self.db.isOpen(): self.statusbar.showMessage( "Database non aperto...", 5000) return row = self.mapper.currentIndex() if row == -1: self.statusbar.showMessage( "Nulla da cancellare...", 5000) return record = self.mModel.record(row) id = record.value(ID).toInt()[0] scaff = record.value(SCAFF).toString() if(QMessageBox.question(self, "Cancella Scaffale", "Vuoi cancellare lo scaffale: {0} ?".format(scaff), QMessageBox.Yes|QMessageBox.No) == QMessageBox.No): self.statusbar.showMessage( "Cancellazione scaffale annullata...", 5000) return # cancella scaffale self.mModel.removeRow(row) self.mModel.submitAll() if row + 1 >= self.mModel.rowCount(): row = self.mModel.rowCount() - 1 self.mapper.setCurrentIndex(row) if self.mModel.rowCount() == 0: self.scaffLineEdit.setText(QString("")) # cancella tutti gli articoli che si riferiscono # allo scaffale cancellato self.sModel.setFilter("mmid=%s" % id) self.sModel.select() self.sModel.removeRows(0, self.sModel.rowCount()) self.sModel.submitAll() self.statusbar.showMessage( "Cancellazione eseguita...", 5000) self.mmUpdate() def restoreTablesSettings(self): settings = QSettings(self) if self.saveTableGeometryCheckBox.isChecked(): # per la tabella slave for c in range(1, self.sModel.columnCount()-1): width = settings.value("Settings/sTableView/%s" % c, QVariant(60)).toInt()[0] self.sTableView.setColumnWidth(c, width if width > 0 else 60) # per la tabella find for c in range(1, self.fModel.columnCount()): width = settings.value("Settings/fTableView/%s" % c, QVariant(60)).toInt()[0] self.fTableView.setColumnWidth(c, width if width > 0 else 60) def restoreWinSettings(self): settings = QSettings() self.prtTitleLineEdit.setText(QString(settings.value( "Settings/printTitle", QVariant( "Situazione Magazzino - TIME di Stefano Zamprogno")).toString())) self.prtDateLineEdit.setText(QString(settings.value( "Settings/printDate", QVariant( "Al 31/12/2008")).toString())) self.saveWinPosCheckBox.setChecked( settings.value("Settings/saveWinPos", QVariant(True)).toBool()) self.saveTableGeometryCheckBox.setChecked( settings.value("Settings/saveTableGeometry", QVariant(True)).toBool()) self.restoreGeometry( settings.value("MainWindow/Geometry").toByteArray()) def closeEvent(self, event): settings = QSettings() if self.filename is not None: settings.setValue("Settings/lastFile", QVariant(self.filename)) settings.setValue("MainWindow/Geometry", QVariant( self.saveGeometry())) settings.setValue("Settings/saveWinPos", QVariant( self.saveWinPosCheckBox.isChecked())) settings.setValue("Settings/saveTableGeometry", QVariant( self.saveTableGeometryCheckBox.isChecked())) settings.setValue("Settings/printTitle", QVariant( self.prtTitleLineEdit.text())) settings.setValue("Settings/printDate", QVariant( self.prtDateLineEdit.text())) if self.db.isOpen(): # salva larghezza colonne tabella slave for c in range(1, self.sModel.columnCount()-1): width = self.sTableView.columnWidth(c) if width: settings.setValue("Settings/sTableView/%s" % c, QVariant(width)) # salva larghezza colonne tabella find for c in range(1, self.fModel.columnCount()): width = self.fTableView.columnWidth(c) if width: settings.setValue("Settings/fTableView/%s" % c, QVariant(width)) self.db.close() del self.db