예제 #1
0
    async def post(self, user):

        # Id of the user being reported
        try:
            target = int(self.get_argument('target', False))
        except:
            raise CustomError(reason="Target user not provided",
                              status_code=404)
            logger.error(
                "Id of target couldn't be converted to int or is not present")

        user_target = await self.application.objects.get(UserProfile,
                                                         id=target)

        if not user_target:
            raise CustomError(reason="Target provided is not valid",
                              status_code=404)

        # Id of the user reporting
        reporter = user.id

        # Message of the report
        message = self.get_param('message', default="")

        # Reason of the report
        reason = self.get_param('reason', default="Not expecified")

        report = Report.create(target=user_target,
                               reporter=reporter,
                               message=message,
                               reason=reason)

        resp.body = json.dumps(report.json())
        resp.status = falcon.HTTP_200
예제 #2
0
    def on_post(self, req, resp):
        target = req.get_param_as_int('target', required=True, min=0)
        reporter = req.context['user']
        message = req.get_param('message', default="")
        reason = req.get_param('reason', required=True)

        user_target = UserProfile.get_or_none(id=target)

        if user_target and reason in topics:
            report = Report.create(target=user_target,
                                   reporter=reporter,
                                   message=message,
                                   reason=reason)

            resp.body = json.dumps(report.json())
            resp.status = falcon.HTTP_200
        else:
            resp.status = falcon.HTTP_400
            resp.body = json.dumps({"Error": "Bad topic or no target"})
예제 #3
0
class MainWindow(QMainWindow, Ui_mainWindow):
    """
    Main Application Window
    """
    def __init__(self, parent=None):
        """
        Initialize MainWindow class
        """
        super(MainWindow, self).__init__(parent)
        self.setupUi(self)
        thread = QThread()
        thread.currentThread().setObjectName(__appname__)
        configfn.check_config_folder()  # Check appdata folder in users home

        self.textWorkdate.setText(datetime.date.today().isoformat()
                                  )  # initialize workdate to current date

        self._archivedOrderlines = OrderLine()  # Initialize Detail object
        self._archivedVisits = Visit()  # Initialize Visit object
        self._contacts = Contact()  # Initialize Contact object
        self._customers = Customer()  # Initialize Customer object
        self._employees = Employee()  # Initialize Employee object
        self._orderLines = OrderLine()
        self._products = Product()  # Initialize Product object
        self._reports = Report()  # Initialize Report object
        self._settings = Settings()  # Initialize Settings object
        self._visits = Visit()

        self.buttonArchiveContacts.clicked.connect(self.archive_contacts)
        self.buttonArchiveCustomer.clicked.connect(self.archive_customer)
        self.buttonArchiveVisit.clicked.connect(self.archive_visit)

        self.buttonCreateContact.clicked.connect(self.create_contact)
        self.buttonCreateCustomer.clicked.connect(self.create_customer)
        self.buttonCreateReport.clicked.connect(self.create_report)
        self.buttonCreateVisit.clicked.connect(self.load_visit)

        self.buttonGetCustomers.clicked.connect(self.get_customers)
        self.buttonGetPricelist.clicked.connect(self.get_pricelist)

        self.toolButtonArchiveSettings.clicked.connect(self.archive_settings)
        self.toolButtonCustomer.clicked.connect(self.show_page_customer)
        self.toolButtonCustomers.clicked.connect(self.show_page_customers)
        self.toolButtonCustomerVisits.clicked.connect(
            self.show_page_customer_visits)
        self.toolButtonExit.clicked.connect(self.app_exit)
        self.toolButtonInfo.clicked.connect(self.show_page_info)
        self.toolButtonPricelist.clicked.connect(self.show_page_pricelist)
        self.toolButtonReport.clicked.connect(self.show_page_report)
        self.toolButtonReports.clicked.connect(self.show_page_reports)
        self.toolButtonSettings.clicked.connect(self.show_page_settings)
        self.toolButtonCustomerVisit.clicked.connect(self.show_page_visit)

        self.toolButtonDeleteSalesData.clicked.connect(self.zero_database)
        self.toolButtonExportDatabase.clicked.connect(self.data_export)
        self.toolButtonImportCsvData.clicked.connect(
            self.show_csv_import_dialog)
        self.toolButtonImportDatabase.clicked.connect(self.data_import)

        self.widgetCustomers.currentItemChanged.connect(
            self.on_customer_changed)
        self.widgetCustomers.itemDoubleClicked.connect(
            self.on_customer_double_clicked)

        self.widgetArchivedVisits.currentItemChanged.connect(
            self.on_visit_changed)
        self.widgetArchivedVisits.setColumnHidden(0, True)

        self.widgetArchivedOrderLines.setColumnWidth(0, 30)
        self.widgetArchivedOrderLines.setColumnWidth(1, 30)
        self.widgetArchivedOrderLines.setColumnWidth(2, 100)
        self.widgetArchivedOrderLines.setColumnWidth(3, 150)
        self.widgetArchivedOrderLines.setColumnWidth(4, 60)
        self.widgetArchivedOrderLines.setColumnWidth(5, 40)

        self.widgetCustomers.setColumnHidden(0, True)  # ID
        self.widgetCustomers.setColumnWidth(1, 100)
        self.widgetCustomers.setColumnWidth(2, 100)
        self.widgetCustomers.setColumnWidth(3, 100)
        self.widgetCustomers.setColumnWidth(4, 250)
        self.widgetCustomers.setColumnWidth(5, 60)

        self.widgetPricelist.setColumnWidth(0, 70)
        self.widgetPricelist.setColumnWidth(1, 100)
        self.widgetPricelist.setColumnWidth(2, 150)
        self.widgetPricelist.setColumnWidth(3, 50)
        self.widgetPricelist.setColumnWidth(4, 50)
        self.widgetPricelist.setColumnWidth(5, 50)
        self.widgetPricelist.setColumnWidth(6, 50)
        self.widgetPricelist.setColumnWidth(7, 50)
        self.widgetPricelist.setColumnWidth(8, 50)
        self.widgetPricelist.setColumnWidth(9, 50)
        self.widgetPricelist.setColumnWidth(10, 50)
        self.widgetPricelist.setColumnWidth(11, 50)
        self.widgetPricelist.setColumnWidth(12, 50)

        self.widgetReports.setColumnHidden(0, True)  # ID
        self.widgetReports.setColumnWidth(1, 80)  # rep_date
        self.widgetReports.setColumnWidth(2, 60)  # visits
        self.widgetReports.setColumnWidth(3, 60)  # sale day
        self.widgetReports.setColumnWidth(4, 60)  # demo day
        self.widgetReports.setColumnWidth(5, 100)  # turnover day
        self.widgetReports.setColumnWidth(6, 50)  # km
        # self.widgetReports column 7                # supervisor

        self.widgetReportVisits.setColumnWidth(0, 150)
        self.widgetReportVisits.setColumnWidth(1, 100)
        self.widgetReportVisits.setColumnWidth(2, 100)
        self.widgetReportVisits.setColumnWidth(3, 60)

        self.populate_customer_list()
        self.populate_price_list()

        try:
            cid = self._settings.settings["cust_idx"]
            if self._customers.lookup_by_id(cid):
                try:
                    self.widgetCustomers.setCurrentIndex(
                        self.widgetCustomers.indexFromItem(
                            self.widgetCustomers.findItems(str(
                                self._customers.customer["customer_id"]),
                                                           Qt.MatchExactly,
                                                           column=0)[0]))
                    self.toolButtonCustomer.click()
                except KeyError:
                    pass
        except KeyError:
            return

        self._reports.load(workdate=self.textWorkdate.text())
        self.populate_report_list()
        self.populate_report_visit_list()
        self.toolButtonReport.click()

    def closeEvent(self, event):
        """
        Slot for close event signal
        Args:
            event:

        intended use is warning about unsaved data
        """
        # TODO handle close event
        self.app_exit()

    def display_sync_status(self):
        """
        Update status fields
        """
        try:
            self.textCustomerLocalDate.setText(self._settings.settings["lsc"])
            self.textPricelistLocalDate.setText(self._settings.settings["lsp"])
            self.textCustomerServerDate.setText(self._settings.settings["sac"])
            self.textPricelistServerDate.setText(
                self._settings.settings["sap"])
        except KeyError:
            pass

    def populate_archived_visit_details(self):
        """
        Populate the details list based on the line visit
        """
        self.widgetArchivedOrderLines.clear()

        self.labelArchivedApprovedText.setText("")
        self.labelArchivedSendText.setText("")
        self.textArchivedOrderPoNumber.setText("")
        self.textArchivedOrderSale.setText("")
        self.textArchivedOrderSas.setText("")
        self.textArchivedOrderTotal.setText("")
        self.textArchivedVisitNote.setText("")

        items = []
        try:
            self.labelArchivedSendText.setText(
                utils.bool2dk(
                    utils.int2bool(self._archivedVisits.visit["po_sent"])))
            self.labelArchivedApprovedText.setText(
                utils.bool2dk(
                    utils.int2bool(self._archivedVisits.visit["po_approved"])))
            self.textArchivedOrderPoNumber.setText(
                self._archivedVisits.visit["po_number"])
            self.textArchivedOrderSale.setText(
                str(self._archivedVisits.visit["po_sale"]))
            self.textArchivedOrderSas.setText(
                str(self._archivedVisits.visit["po_sas"]))
            self.textArchivedOrderTotal.setText(
                str(self._archivedVisits.visit["po_total"]))
            self.textArchivedVisitNote.setText(
                self._archivedVisits.visit["visit_note"])

            self._archivedOrderlines.list_ = self._archivedVisits.visit[
                "visit_id"]
            for line in self._archivedOrderlines.list_:
                item = QTreeWidgetItem([
                    line["linetype"],
                    str(line["pcs"]), line["sku"], line["text"],
                    str(line["price"]),
                    str(line["discount"]), line["linenote"]
                ])
                items.append(item)
        except KeyError:
            pass
        except IndexError:
            pass
        self.widgetArchivedOrderLines.addTopLevelItems(items)

    def populate_archived_visits(self):
        """
        Populate the visitlist based on the active customer
        """
        self.widgetArchivedVisits.clear()

        items = []
        try:
            self._archivedVisits.list_by_customer(
                self._customers.customer["customer_id"])

            for visit in self._archivedVisits.visits:
                item = QTreeWidgetItem([
                    str(visit["visit_id"]), visit["visit_date"],
                    visit["po_buyer"], visit["prod_demo"], visit["prod_sale"],
                    visit["po_note"]
                ])
                items.append(item)
                if visit["visit_date"] == self.textWorkdate.text():
                    self.toolButtonCustomerVisit.setEnabled(True)

        except IndexError:
            pass
        except KeyError:
            pass
        self.widgetArchivedVisits.addTopLevelItems(items)

    def populate_contact_list(self):
        """
        Populate the contactlist based on currently selected customer
        """
        # load contacts
        self.widgetCustomerContacts.clear()
        items = []
        try:
            self._contacts.list_ = self._customers.customer["customer_id"]
            for c in self._contacts.list_:
                item = QTreeWidgetItem(
                    [c["name"], c["department"], c["phone"], c["email"]])
                items.append(item)
        except IndexError:
            pass
        except KeyError:
            pass

        self.widgetCustomerContacts.addTopLevelItems(items)

    def populate_customer_list(self):
        """
        Populate customer list
        """

        self.widgetCustomers.clear()  # shake the tree for leaves
        items = []  # temporary list
        try:
            for c in self._customers.customers:
                item = QTreeWidgetItem([
                    str(c["customer_id"]), c["account"], c["phone1"],
                    c["phone2"], c["company"], c["zipcode"], c["city"]
                ])
                items.append(item)
        except (IndexError, KeyError):
            pass
        # assign Widgets to Tree
        self.widgetCustomers.addTopLevelItems(items)
        self.widgetCustomers.setSortingEnabled(True)  # enable sorting

    def populate_price_list(self):
        """
        Populate widgetPricelist
        """
        self.widgetPricelist.clear()
        pricelist = []
        try:
            for product in self._products.products:
                item = QTreeWidgetItem([
                    product["item"], product["sku"], product["name1"],
                    str(product["price"]).format("#.##"),
                    str(product["d2"]).format("#.##"),
                    str(product["d4"]).format("#.##"),
                    str(product["d6"]).format("#.##"),
                    str(product["d8"]).format("#.##"),
                    str(product["d12"]).format("#.##"),
                    str(product["d24"]).format("#.##"),
                    str(product["d48"]).format("#.##"),
                    str(product["d96"]).format("#.##"),
                    str(product["net"]).format("#.##")
                ])
                pricelist.append(item)
        except IndexError as i:
            print("IndexError: {}".format(i))
        except KeyError as k:
            print("KeyError: {}".format(k))
        self.widgetPricelist.addTopLevelItems(pricelist)
        self.widgetPricelist.setSortingEnabled(True)

    def populate_report_list(self):
        """
        Populate widgetReports
        """
        self.widgetReports.clear()
        reports = []
        try:
            for report in self._reports.reports:
                item = QTreeWidgetItem([
                    str(report["report_id"]), report["rep_date"],
                    str(report["newvisitday"] + report["recallvisitday"]),
                    str(report["newdemoday"] + report["recalldemoday"]),
                    str(report["newsaleday"] + report["recallsaleday"]),
                    str(report["newturnoverday"] +
                        report["recallturnoverday"] +
                        report["sasturnoverday"]),
                    str(report["kmevening"] - report["kmmorning"]),
                    report["supervisor"]
                ])
                reports.append(item)
        except (IndexError, KeyError):
            pass
        self.widgetReports.addTopLevelItems(reports)

    def populate_report_visit_list(self):
        """
        Populate widgetReportVisits
        """
        self.widgetReportVisits.clear()
        items = []
        try:
            self._visits.list_by_date(self.textWorkdate.text())
            for v in self._visits.visits:
                c = self._customers.lookup_by_id(v["customer_id"])
                if c:
                    item = QTreeWidgetItem([
                        self._customers.customer["company"], v["prod_demo"],
                        v["prod_sale"], v["po_total"]
                    ])
                    items.append(item)
        except (IndexError, KeyError):
            pass
        self.widgetReportVisits.addTopLevelItems(items)

    def populate_settings_page(self):
        """
        Populate settings page
        :return:
        """
        try:
            self.textAppUserMail.setText(self._settings.settings["usermail"])
            self.textAppUserPass.setText(self._settings.settings["userpass"])
            self.textAppUserCountry.setText(
                self._settings.settings["usercountry"])
            self.textAppDataServer.setText(self._settings.settings["http"])
            self.textAppMailServer.setText(self._settings.settings["smtp"])
            self.textAppMailServerPort.setText(
                str(self._settings.settings["port"]))
            self.textAppMailOrderTo.setText(self._settings.settings["mailto"])
            self.checkServerData.setChecked(
                utils.int2bool(self._settings.settings["sc"]))
            self.textExtMailServer.setText(
                self._settings.settings["mailserver"])
            self.textExtMailServerPort.setText(
                str(self._settings.settings["mailport"]))
            self.textExtMailServerUser.setText(
                self._settings.settings["mailuser"])
            self.textExtMailServerPass.setText(
                self._settings.settings["mailpass"])
        except KeyError:
            pass

    def resizeEvent(self, event):
        """
        Slot for the resize event signal
        Args:
            event:
        intended use is resize content to window
        :param event:
        """
        # TODO handle resize event
        # w = event.size().width()
        # h = event.size().height()
        # dpival = self.labelAvailable.devicePixelRatio()
        # dpivalf = self.labelAvailable.devicePixelRatioF()
        # dpivalfs = self.labelAvailable.devicePixelRatioFScale()
        # dpilogx = self.labelAvailable.logicalDpiX()
        # dpilogy = self.labelAvailable.logicalDpiY()
        #
        # winch = w/dpival
        # hinch = h/dpival
        # print("width = {}\n"
        #       "height = {}\n"
        #       "dpi = {}\n"
        #       "dpi f = {}\n"
        #       "w inch = {}\n"
        #       "h inch = {}\n"
        #       "dpi fs = {}\n"
        #       "dpi log x = {}\n"
        #       "dpi log y = {}".format(w, h, dpival, dpivalf, winch, hinch, dpivalfs, dpilogx, dpilogy))
        pass

    def run(self):
        """
        Setup database and basic configuration
        """
        # basic settings must be done
        is_set = check_settings(self._settings.settings)
        if is_set:
            try:
                _ = self._employees.employee["fullname"]
            except KeyError:
                msgbox = QMessageBox()
                msgbox.about(
                    self, __appname__,
                    "Der er en fejl i dine indstillinger.\nKontroller dem venligst.\nTak."
                )
        else:
            msgbox = QMessageBox()
            msgbox.about(
                self, __appname__,
                "App'en skal bruge nogle oplysninger.\nRing kontoret hvis du er i tvivl.\nTak."
            )

            self.show_page_settings()

        # if requested check server data
        try:
            if utils.int2bool(self._settings.settings["sc"]):
                # update sync status
                status = utils.refresh_sync_status(self._settings)
                self._settings.settings["sac"] = status[0][1].split()[0]
                self._settings.settings["sap"] = status[1][1].split()[0]
                self._settings.update()
        except KeyError:
            pass

        # display known sync data
        self.display_sync_status()

    def set_indexes(self):
        """
        Save page index to settings
        :return:
        """
        try:
            self._settings.settings["cust_idx"] = self._customers.customer[
                "customer_id"]
        except KeyError:
            self._settings.settings["cust_idx"] = 0

        try:
            _ = self._settings.settings["page_idx"]
        except KeyError:
            self._settings.settings[
                "page_idx"] = self.widgetAppPages.currentIndex()
        self._settings.update()

    def set_input_enabled(self, arg: bool) -> None:
        """Enable inputs"""
        self.checkVisitSas.setEnabled(arg)
        self.comboOrderItem.setEnabled(arg)
        self.comboOrderSku.setEnabled(arg)
        self.textVisitPcs.setEnabled(arg)
        self.textVisitLinePrice.setEnabled(arg)
        self.textVisitLineDiscount.setEnabled(arg)

    @pyqtSlot(name="app_exit")
    def app_exit(self):
        """
        Exit - save current customer
        """
        # customer id
        try:
            self._settings.settings["cust_idx"] = self._customers.customer[
                "customer_id"]
        except KeyError:
            self._settings.settings["cust_idx"] = 0
        self._settings.update()
        app.quit()

    @pyqtSlot(name="archive_contacts")
    def archive_contacts(self):
        """
        Save changes made to contacts
        """
        # TODO save changes made to contacts
        msgbox = QMessageBox()
        msgbox.information(self, __appname__,
                           "# TODO save changes made to contacts",
                           QMessageBox.Ok)

    @pyqtSlot(name="archive_customer")
    def archive_customer(self):
        """
        Slot for updateCustomer triggered signal
        """
        if not self._customers.customer:
            # msgbox triggered if no current is selected
            msgbox = QMessageBox()
            msgbox.information(self, __appname__,
                               "Det kan jeg ikke på nuværende tidspunkt!",
                               QMessageBox.Ok)
            return False
        # assign input field values to current object
        self._customers.customer["company"] = self.textCompany.text()
        self._customers.customer["address1"] = self.textAddress1.text()
        self._customers.customer["address2"] = self.textAddress2.text()
        self._customers.customer["zipcode"] = self.textZipCode.text()
        self._customers.customer["city"] = self.textCityName.text()
        self._customers.customer["phone1"] = self.textPhone1.text()
        self._customers.customer["phone2"] = self.textPhone2.text()
        self._customers.customer["email"] = self.textEmail.text()
        self._customers.customer["factor"] = self.textFactor.text()
        self._customers.customer[
            "infotext"] = self.textArchivedVisitNote.toPlainText()
        self._customers.customer["modified"] = 1
        self._customers.update()

    @pyqtSlot(name="archive_settings")
    def archive_settings(self):
        """
        Archive settings
        :return:
        """
        checkok = True
        items = []
        if self.textAppUserMail.text() == "":
            items.append("Gruppe 'Sælger' -> 'Email'")
            checkok = False
        if self.textAppUserPass.text() == "":
            items.append("Gruppe 'Sælger' -> 'Adgangsfrase'")
            checkok = False
        if self.textAppUserCountry.text() == "":
            items.append("Gruppe: Sælger -> landekode")
            checkok = False
        if self.textAppMailServer.text() == "":
            items.append("Gruppe: Intern -> Mailserver")
            checkok = False
        if self.textAppMailServerPort.text() == "":
            items.append("Gruppe: Intern -> Port")
            checkok = False
        if self.textAppMailOrderTo == "":
            items.append("Gruppe: Intern -> Mail til")
            checkok = False
        if self.textAppDataServer == "":
            items.append("Gruppe: Intern -> Dataserver")
            checkok = False
        # inform user about settings validity
        msgbox = QMessageBox()
        if not checkok:
            msgbox.warning(
                self, __appname__,
                "Der er mangler i dine indstillinger!\n{}".format(
                    "\n".join(items)), QMessageBox.Ok)
            return False
        # update password in settings
        if len(self.textAppUserPass.text()) < 97:
            self._settings.settings["userpass"] = passwdFn.hash_password(
                self.textAppUserPass.text())
        if len(self.textExtMailServerPass.text()) < 97:
            self._settings.settings["mailpass"] = passwdFn.hash_password(
                self.textExtMailServerPass.text())
        self._settings.settings["usermail"] = self.textAppUserMail.text(
        ).lower()
        self._settings.settings["usercountry"] = self.textAppUserCountry.text()
        self._settings.settings["http"] = self.textAppDataServer.text()
        self._settings.settings["smtp"] = self.textAppMailServer.text()
        self._settings.settings["port"] = self.textAppMailServerPort.text()
        self._settings.settings["mailto"] = self.textAppMailOrderTo.text()
        self._settings.settings["sc"] = utils.bool2int(
            self.checkServerData.isChecked())
        self._settings.settings["mailserver"] = self.textExtMailServer.text(
        ).lower()
        self._settings.settings["mailport"] = self.textExtMailServerPort.text()
        self._settings.settings["mailuser"] = self.textExtMailServerUser.text()
        self._settings.update()
        self._employees.load(self._settings.settings["usermail"])
        msgbox.information(self, __appname__, "Indstillinger opdateret.",
                           QMessageBox.Ok)

    @pyqtSlot(name="archive_visit")
    def archive_visit(self):
        """
        Slot for saving the visit
        """
        self.toolButtonCustomerVisit.setEnabled(False)
        # save visit head contents
        self._visits.visit["po_buyer"] = self.textVisitBuyer.text()
        self._visits.visit["po_number"] = self.textVisitPoNumber.text()
        self._visits.visit["po_company"] = self.textVisitDelCompany.text()
        self._visits.visit["po_address1"] = self.textVisitDelAddress1.text()
        self._visits.visit["po_address2"] = self.textVisitDelAddress2.text()
        self._visits.visit["po_postcode"] = self.textVisitDelZip.text()
        self._visits.visit["po_postofffice"] = self.textVisitDelCity.text()
        self._visits.visit["po_country"] = self._employees.employee["country"]
        self._visits.visit["po_note"] = self.textVisitOrderNote.text()
        self._visits.visit["prod_demo"] = self.textVisitProductDemo.text()
        self._visits.visit["prod_sale"] = self.textVisitProductSale.text()
        self._visits.visit["po_sas"] = self.textVisitSas.text()
        self._visits.visit["po_sale"] = self.textVisitSale.text()
        self._visits.visit["po_total"] = self.textVisitTotal.text()
        self._visits.visit["visit_note"] = self.textVisitInfo.toPlainText()

        # TODO: save visitdetails

    @pyqtSlot(name="create_contact")
    def create_contact(self):
        """
        Save changes made to contacts
        """
        # TODO add new contact
        msgbox = QMessageBox()
        msgbox.information(self, __appname__, "# TODO add new contact",
                           QMessageBox.Ok)

    @pyqtSlot(name="create_customer")
    def create_customer(self):
        """
        Slot for createCustomer triggered signal
        """
        if not self.textNewCompany.text() or not self.textNewPhone1.text():
            msgbox = QMessageBox()
            msgbox.information(
                self, __appname__,
                "Snap - Jeg mangler:\n Firma navn \n Telefon nummer",
                QMessageBox.Ok)
        else:
            msgbox = QMessageBox()
            msgbox.information(
                self, __appname__, "Gem kunde til database\n\n" +
                self.textNewCompany.text() + "\n" + self.textNewPhone1.text(),
                QMessageBox.Ok)

    @pyqtSlot(name="create_report")
    def create_report(self):
        """
        Slot for Report triggered signal
        """
        try:
            # check the report date
            # no report triggers KeyError which in turn launches the CreateReportDialog
            repdate = self._reports.report["rep_date"]
            if not repdate == self.textWorkdate.text():
                # if active report is not the same replace it with workdate
                self._reports.load(self.textWorkdate.text())
                # trigger a KeyError if no report is current which launches the CreateReportDialog
                repdate = self._reports.report["rep_date"]
                # check if the report is sent
                if self._reports.report["sent"] == 1:
                    # we do not allow visits to be created on a report which is closed
                    self.buttonCreateVisit.setEnabled(False)
                else:
                    self.buttonCreateVisit.setEnabled(True)
            infotext = "Rapport aktiv for: {}".format(repdate)
            msgbox = QMessageBox()
            msgbox.information(self, __appname__, infotext, QMessageBox.Ok)
            return True

        except KeyError:
            # Show report dialog
            create_report_dialog = ReportDialogCreate(self.textWorkdate.text())
            if create_report_dialog.exec_():
                # user chosed to create a report
                self.textWorkdate.setText(create_report_dialog.workdate)
                # try load a report for that date
                self._reports.load(self.textWorkdate.text())
                try:
                    # did the user choose an existing report
                    _ = self._reports.report["rep_date"]
                    infotext = "Eksisterende rapport hentet: {}".format(
                        self.textWorkdate.text())
                except KeyError:
                    # create the report
                    self._reports.create(self._employees.employee,
                                         self.textWorkdate.text())
                    infotext = "Rapport Createtet for: {}".format(
                        self.textWorkdate.text())
                msgbox = QMessageBox()
                msgbox.information(self, __appname__, infotext, QMessageBox.Ok)
                return True
            else:
                msgbox = QMessageBox()
                msgbox.information(
                    self, __appname__,
                    "Den aktive rapport er <strong>IKKE</strong> ændret!",
                    QMessageBox.Ok)
                return False

    @pyqtSlot(name="load_visit")
    def load_visit(self):
        """
        Slot for loading the visit dialog
        """

        try:
            # do we have a report
            _ = self._reports.report["rep_date"]
            active_report = True
        except KeyError:
            active_report = self.create_report()

        if active_report:
            self._reports.load(workdate=self.textWorkdate.text())
            try:
                # do we have a customer
                _ = self._customers.customer["company"]
            except KeyError:
                msgbox = QMessageBox()
                msgbox.information(
                    self, __appname__,
                    "Ingen valgt kunde! Besøg kan ikke oprettes.",
                    QMessageBox.Ok)
                return

        if self.textCustId.text() is not "" and \
                self.textCustId.text() is not self._customers.customer["customer_id"]:
            confirm = QMessageBox()
            val = confirm.question(
                self, __appname__,
                f"Du har et uafsluttet besøg på {self.textVisitCompany.text()}."
                f"<br/>Vil du slette det?", confirm.Yes | confirm.No)
            if val == confirm.No:
                self._customers.lookup_by_id(self.textCustId.text())
            else:
                self._archivedVisits.delete(self.textVisitId.text())

        self.toolButtonCustomerVisit.setEnabled(True)
        # self.widgetAppPages.setCurrentIndex(PAGE_VISIT)

        customer_pricelist = self._products
        workdate = self.textWorkdate.text()
        customerid = self._customers.customer["customer_id"]
        reportid = self._reports.report["report_id"]
        employeeid = self._employees.employee["employee_id"]

        self.textCustId.setText(str(customerid))
        self.textVisitDate.setText(self.textWorkdate.text())
        self.textVisitCompany.setText(self._customers.customer["company"])

        try:
            """
            load visits for workdate
            """
            self._visits.list_by_date(workdate)
            self.textVisitId.setText(str(self._visits.visit["visit_id"]))
        except (KeyError, ):
            self.textVisitId.setText(
                str(
                    self._visits.add(reportid, employeeid, customerid,
                                     workdate)))
            self._visits.visit["visit_type"] = "R"
            if self._customers.customer["account"] == "NY":
                self._visits.visit["visit_type"] = "N"

        visit_id = self.textVisitId.text()
        self._orderLines = OrderLine()
        self._orderLines.load_visit(visit_id)

        self.widgetTableSale.setColumnWidth(0, 43)  # line_type D/N/S
        self.widgetTableSale.setColumnWidth(1, 44)  # pcs
        self.widgetTableSale.setColumnWidth(2, 44)  # item
        self.widgetTableSale.setColumnWidth(3, 123)  # sku
        self.widgetTableSale.setColumnWidth(4, 153)  # text
        self.widgetTableSale.setColumnWidth(5, 60)  # price
        self.widgetTableSale.setColumnWidth(6, 50)  # discount
        self.widgetTableSale.setColumnWidth(6, 60)  # amount
        self.widgetTableSale.setColumnWidth(7, 30)  # SAS

        lines = self._orderLines.list_
        visit_sale = 0.0
        visit_sas = 0.0
        visit_total = 0.0
        line_demo = 0
        line_sale = 0
        row_number = 0
        self.widgetTableSale.setRowCount(len(lines) - 1)
        for line in lines:
            # "line_id", "visit_id",
            # "pcs", "sku", "text", "price", "sas", "discount",
            # "linetype", "linenote", "item"
            amount = float(
                line["pcs"]) * line["price"] * line["discount"] / 100
            if line["sas"] == 1:
                visit_sas += amount
            else:
                visit_sale += amount
            visit_total += amount

            # self.widgetTableSale.setRowHeight(row_number, 12)
            if line["linetype"].lower() == "d":
                line_demo += 1
                row_number = line_demo
                self.widgetTableDemo.setRowCount(row_number)

                c1 = QTableWidgetItem()
                c1.setText(line["linetype"])
                self.widgetTableDemo.setItem(row_number, 0, c1)
                c2 = QTableWidgetItem()
                c2.setText(str(line["pcs"]))
                self.widgetTableDemo.setItem(row_number, 1, c2)
                c3 = QTableWidgetItem()
                c3.setText(str(line["item"]))
                self.widgetTableDemo.setItem(row_number, 2, c3)
            else:
                line_sale += 1
                row_number = line_sale
                self.widgetTableSale.setRowCount(row_number)

                c1 = QTableWidgetItem()
                c1.setText(line["linetype"])
                self.widgetTableSale.setItem(row_number, 0, c1)
                c2 = QTableWidgetItem()
                c2.setText(str(line["pcs"]))
                self.widgetTableSale.setItem(row_number, 1, c2)
                c3 = QTableWidgetItem()
                c3.setText(str(line["item"]))
                self.widgetTableSale.setItem(row_number, 2, c3)
                c4 = QTableWidgetItem()
                c4.setText(line["sku"])
                self.widgetTableSale.setItem(row_number, 3, c4)
                c5 = QTableWidgetItem()
                c5.setText(line["text"])
                self.widgetTableSale.setItem(row_number, 4, c5)
                c6 = QTableWidgetItem()
                c6.setText(str(line["price"]))
                self.widgetTableSale.setItem(row_number, 5, c6)
                c7 = QTableWidgetItem()
                c6.setText(str(line["discount"]))
                self.widgetTableSale.setItem(row_number, 6, c7)
                c9 = QTableWidgetItem()
                c9.setText(utils.int2strdk(line["sas"]))
                self.widgetTableSale.setItem(row_number, 7, c9)
                c10 = QTableWidgetItem()
                c10.setText(line["linenote"])
                self.widgetTableSale.setItem(row_number, 8, c10)

        # Setup pricelist and selection combos
        factor = self._customers.customer["factor"]
        if not factor:
            factor = 0.0

        for item in customer_pricelist.products:
            if factor is not 0.0:
                item["price"] = item["price"] * factor
                item["d2"] = item["d2"] * factor
                item["d3"] = item["d3"] * factor
                item["d4"] = item["d4"] * factor
                item["d6"] = item["d6"] * factor
                item["d8"] = item["d8"] * factor
                item["d12"] = item["d12"] * factor
                item["d24"] = item["d24"] * factor
                item["d48"] = item["d48"] * factor
                item["d96"] = item["d96"] * factor
                item["min"] = item["min"] * factor
                item["net"] = item["net"] * factor
            self.comboLineItem.addItem(item["item"],
                                       [item["sku"], item["name1"], item])
            self.comboLineSku.addItem(item["sku"],
                                      [item["item"], item["name1"], item])

        # connect to signals
        self.buttonArchiveVisit.clicked.connect(self.archive_visit)
        self.comboOrderItem.currentIndexChanged.connect(
            self.on_order_item_changed)
        self.comboOrderSku.currentIndexChanged.connect(
            self.on_order_sku_changed)
        self.comboOrderSku.editTextChanged.connect(self.on_order_sku_changed)

    @pyqtSlot(name="data_export")
    def data_export(self):
        """
        Export Database backup file
        """
        # TODO: Create CSV data backup
        msgbox = QMessageBox()
        msgbox.information(self, __appname__,
                           "TODO: Create Database Backup File", QMessageBox.Ok)

    @pyqtSlot(name="data_import")
    def data_import(self):
        """
        Import Database backup file
        """
        # TODO: Restore from CSV data backup
        msgbox = QMessageBox()
        msgbox.information(self, __appname__,
                           "TODO: Import Database Backup File", QMessageBox.Ok)

    @pyqtSlot(name="get_customers")
    def get_customers(self):
        """
        Slot for getCustomers triggered signal
        """
        import_customers = GetCustomersDialog(app,
                                              customers=self._customers,
                                              employees=self._employees,
                                              settings=self._settings)
        import_customers.sig_done.connect(self.on_get_customers_done)
        import_customers.exec_()

    @pyqtSlot(name="get_pricelist")
    def get_pricelist(self):
        """
        Slot for getProducts triggered signal
        """
        import_product = GetPricelistDialog(app,
                                            products=self._products,
                                            settings=self._settings)
        import_product.sig_done.connect(self.on_get_products_done)
        import_product.exec_()

    @pyqtSlot(name="on_add_demo")
    def on_add_demo(self):
        """
        Add line to product demo table
        :return:
        """
        row_count = self.widgetTableDemo.rowCount()
        self.widgetTableDemo.setRowCount(row_count + 1)

    @pyqtSlot(name="on_add_sale")
    def on_add_sale(self):
        """
        Add line to product sale table
        :return:
        """
        row_count = self.widgetTableSale.rowCount()
        self.widgetTableSale.setRowCount(row_count + 1)

    @pyqtSlot(name="on_remove_demo")
    def on_remove_demo(self):
        """
        Remove line from product demo table
        :return:
        """
        if self.widgetTableDemo.currentIndex():
            self.widgetTableDemo.removeRow(self.widgetTableDemo.currentIndex())

    @pyqtSlot(name="on_remove_sale")
    def on_remove_sale(self):
        """
        Remove line from product sale table
        :return:
        """
        if self.widgetTableSale.currentIndex():
            self.widgetTableSale.removeRow(self.widgetTableSale.currentIndex())

    @pyqtSlot(QTreeWidgetItem, QTreeWidgetItem, name="on_customer_changed")
    def on_customer_changed(self, current, previous):
        """
        Slot for treewidget current item changed signal
        Used to respond to changes in the customer list
        and update the related customer info

        Args:
            current: currently selected item
            previous: previous selected item
        """
        try:
            # account = current.text(0)
            phone = current.text(2)
            company = current.text(4)
            # load customer
            self._customers.lookup(phone, company)
            # fill out fields
            self.textAccount.setText(self._customers.customer["account"])
            self.textCompany.setText(self._customers.customer["company"])
            self.textAddress1.setText(self._customers.customer["address1"])
            self.textAddress2.setText(self._customers.customer["address2"])
            self.textZipCode.setText(self._customers.customer["zipcode"])
            self.textCityName.setText(self._customers.customer["city"])
            self.textPhone1.setText(self._customers.customer["phone1"])
            self.textPhone2.setText(self._customers.customer["phone2"])
            self.textEmail.setText(self._customers.customer["email"])
            self.textFactor.setText(str(self._customers.customer["factor"]))
            self.textCustomerNotes.setText(
                self._customers.customer["infotext"])
            self.textCustomerNameCreateVisit.setText(
                self._customers.customer["company"])
        except AttributeError:
            pass
        except KeyError:
            pass
        # load customer infos
        self.populate_contact_list()
        self.populate_archived_visits()
        self.populate_archived_visit_details()
        self.load_visit()

    @pyqtSlot(name="on_csv_import_done")
    def on_csv_import_done(self):
        """
        Slog for csv import done signal
        """
        self.populate_customer_list()

    @pyqtSlot(QTreeWidgetItem, name="on_customer_clicked")
    def on_customer_double_clicked(self, current):
        """
        Customer selected in
        :param current:
        :return:
        """
        print("current: {}".format(current))
        self.toolButtonCustomer.click()

    @pyqtSlot(name="on_get_customers_done")
    def on_get_customers_done(self):
        """
        Slot for getCustomers finished signal
        """
        self.populate_customer_list()
        lsc = datetime.date.today().isoformat()
        self.textCustomerLocalDate.setText(lsc)
        self._settings.settings["lsc"] = lsc
        self._settings.update()

    @pyqtSlot(name="on_get_products_done")
    def on_get_products_done(self):
        """
        Slot for getProducts finished signal
        """
        _ = self._products.products
        lsp = datetime.date.today().isoformat()
        self.textPricelistLocalDate.setText(lsp)
        self._settings.settings["lsp"] = lsp
        self._settings.update()

    @pyqtSlot(QTreeWidgetItem, QTreeWidgetItem, name="on_visit_changed")
    def on_visit_changed(self, current, previous):
        """
        Response to current visit changed
        Args:
            current:
            previous:
        """
        try:
            self._archivedVisits.load_visit(current.text(0))
        except AttributeError:
            pass
        except KeyError:
            pass
        self.populate_archived_visit_details()

    @pyqtSlot(name="on_order_item_changed")
    def on_order_item_changed(self):
        """Update SKU combo when item changes"""
        self.comboOrderSku.setCurrentText(
            self.comboOrderItem.itemData(
                self.comboOrderItem.currentIndex())[0])
        self.update_orderline_text(
            self.comboOrderItem.itemData(
                self.comboOrderItem.currentIndex())[1])
        utils.item_price(
            self.comboOrderItem.itemData(
                self.comboOrderItem.currentIndex())[3],
            self.textVisitPcs.text())

    @pyqtSlot(name="on_order_sku_changed")
    def on_order_sku_changed(self):
        """Update ITEM combo when sku changes"""
        self.comboOrderItem.setCurrentText(
            self.comboOrderSku.itemData(self.comboOrderSku.currentIndex())[0])
        self.update_orderline_text(
            self.comboOrderSku.itemData(self.comboOrderSku.currentIndex())[1])
        utils.item_price(
            self.comboOrderSku.itemData(self.comboOrderSku.currentIndex()[3]),
            self.textVisitPcs.text())

    def update_orderline_text(self, text):
        self.textVisitLineText.setText(text)

    @pyqtSlot(name="show_csv_import_dialog")
    def show_csv_import_dialog(self):
        """
        Slot for fileImport triggered signal
        """
        if self._customers.customers:
            msgbox = QMessageBox()
            msgbox.warning(
                self, __appname__,
                "<strong>Ved import slettes alle eksisterende data</strong>!<br/><br/>"
                "Det er alt eller intet af hensyn til datas sammenhæng.<br/>"
                "Du <strong>SKAL</strong> importere <strong>ALLE<strong> tabeller fra listen!<br/><br/>"
                "<strong>Gør du ikke det giver det uløselige problemer</strong>!",
                QMessageBox.Ok)
        # app, contact, customer, detail, employee, report, visit, tables
        import_dialog = CsvFileImportDialog(
            app,
            contacts=self._contacts,
            customers=self._customers,
            employees=self._employees,
            orderlines=self._archivedOrderlines,
            reports=self._reports,
            tables=config.CSV_TABLES,
            visits=self._archivedVisits)
        import_dialog.sig_done.connect(self.on_csv_import_done)
        import_dialog.exec_()

    @pyqtSlot(name="show_page_customer")
    def show_page_customer(self):
        """
        Show page with customer
        """
        self.set_indexes()
        self.widgetAppPages.setCurrentIndex(PAGE_CUSTOMER)

    @pyqtSlot(name="show_page_customer_visits")
    def show_page_customer_visits(self):
        """
        Show page with customer visits and orders
        """
        self.set_indexes()
        self.widgetAppPages.setCurrentIndex(PAGE_CUSTOMER_VISITS)

    @pyqtSlot(name="show_page_customers")
    def show_page_customers(self):
        """
        Show page with customer list
        """
        self.set_indexes()
        self.widgetAppPages.setCurrentIndex(PAGE_CUSTOMERS)

    @pyqtSlot(name="show_page_info")
    def show_page_info(self):
        """
        Show page with about Qt and Eordre
        """
        self.set_indexes()
        self.widgetAppPages.setCurrentIndex(PAGE_INFO)

    @pyqtSlot(name="show_page_pricelist")
    def show_page_pricelist(self):
        """
        Show page with pricelist
        """
        self.set_indexes()
        self.widgetAppPages.setCurrentIndex(PAGE_PRICELIST)

    @pyqtSlot(name="show_page_report")
    def show_page_report(self):
        """
        Slot for masterData triggered signal
        """
        self.set_indexes()
        self.widgetAppPages.setCurrentIndex(PAGE_REPORT)

    @pyqtSlot(name="show_page_reports")
    def show_page_reports(self):
        """
        Show page with a report list
        """
        self.set_indexes()
        self.widgetAppPages.setCurrentIndex(PAGE_REPORTS)

    @pyqtSlot(name="show_page_settings")
    def show_page_settings(self):
        """
        Show page with settings
        """
        self.set_indexes()
        self.populate_settings_page()
        self.widgetAppPages.setCurrentIndex(PAGE_SETTINGS)

    @pyqtSlot(name="show_page_visit")
    def show_page_visit(self):
        """
        Show page with visit
        """
        self.set_indexes()
        self.load_visit()
        self.widgetAppPages.setCurrentIndex(PAGE_VISIT)

    @pyqtSlot(name="zero_database")
    def zero_database(self):
        """
        Slot for zeroDatabase triggered signal
        """
        confirm = QMessageBox()
        val = confirm.question(self, __appname__,
                               "Alle salgsdata slettes<br/>Vil du fortsætte?",
                               confirm.Yes | confirm.No)

        if val == confirm.Yes:
            self._contacts.recreate_table()
            self._customers.recreate_table()
            self._archivedOrderlines.recreate_table()
            self._archivedVisits.recreate_table()
            self._reports.recreate_table()

            self.populate_contact_list()
            self.populate_archived_visit_details()
            self.populate_archived_visits()
            self.populate_customer_list()

            self._settings.settings["lsc"] = ""
            self._settings.settings["sac"] = ""
            self._settings.settings["lsp"] = ""
            self._settings.settings["sap"] = ""
            self._settings.update()
            self.display_sync_status()

            msgbox = QMessageBox()
            msgbox.information(self, __appname__, "Salgsdata er nulstillet!",
                               QMessageBox.Ok)