Exemple #1
0
def send_email(recipient_email,
               email_template,
               email_params,
               email_subject,
               non_html_message,
               sender_email=None):
    if not sender_email:
        if Settings.get_by_name("APP_EMAIL"):
            sender_email = Settings.get_by_name(
                "APP_EMAIL").value  # reads from settings
        else:
            sender_email = "*****@*****.**"

    # send web app URL data by default to email template
    email_params["app_root_url"] = request.url_root

    # render the email HTML body
    email_body = render_template(email_template, **email_params)

    # params sent to the background task
    payload = {
        "recipient_email": recipient_email,
        "email_subject": email_subject,
        "sender_email": sender_email,
        "email_body": email_body,
        "non_html_message": non_html_message
    }

    run_background_task(
        relative_path=url_for("tasks.send_email_task.send_email_via_sendgrid"),
        payload=payload,
        queue="email",
        project=os.environ.get("GOOGLE_CLOUD_PROJECT"),
        location="europe-west1")
Exemple #2
0
    def post(self, category, command):
        settings = Settings.get_instance()
        items = settings[category]

        if command == "add":
            value = self.must_get("value")
            new_id = items.add(value)
            self.response.write(str(new_id))

        elif command == "edit":
            id = int(self.must_get("id"))
            value = self.must_get("value")
            success = items.edit(id, value)
            if success:
                self.response.write("OK")
            else:
                self.abort(400, "ID %d doesn't exist." % id)

        elif command == "remove":
            id = int(self.must_get("id"))
            success = items.remove(id)
            if success:
                self.response.write("OK")
            else:
                self.abort(400, "ID %d doesn't exist." % id)

        else:
            self.abort(500, "Invalid command. Should not occur.")

        Settings.save()
Exemple #3
0
    def __init__(self, app):
        super().__init__()
        self.app = app
        self.showMaximized()
        self.image_service = ImageService()
        self.storage_service = StorageService()
        self.stacked_widget = QStackedWidget()
        self.stacked_widget.showMaximized()

        self.main_widget = MainWidget(self)
        self.settings_widget = SettingsWidget(self, Settings())
        self.pattern_widget = PatternWidget(self, Pattern())

        self.stacked_widget.addWidget(self.main_widget)
        self.stacked_widget.addWidget(self.pattern_widget)
        self.stacked_widget.addWidget(self.settings_widget)

        self.setCentralWidget(self.stacked_widget)

        self.selected_pattern_name = None
        self.selected_settings_name = None
        self.pattern = None
        self.settings = None
        self._create_actions()
        self._set_menu_bar()
        self._set_tool_bar()
        self.errors_color = QColor(255, 0, 0)
Exemple #4
0
    def get(self):
        settings = Settings.get()  #Force email address update...
        posts = Post.query().order(-Post.date).fetch(1)
        is_newest = True
        if posts:
            post = posts[0]
            is_oldest = post.date == Post.min_date()
        else:
            post = None
            is_oldest = True

        #See if this is the very first time we've been here. In that case
        #send an email immediately to get people started...
        first_time = False

        if not Slug.query().get() and not Post.query().get():
            first_time = True
            DailyMail().send(True)

        self.response.write(
            get_template('frontpage.html').render({
                "page":
                "frontpage",
                "post":
                post,
                "is_oldest":
                is_oldest,
                "is_newest":
                is_newest,
                "first_time":
                first_time,
                "email":
                settings.email_address
            }))
Exemple #5
0
	def get(self):
		settings = Settings.get() #Force email address update...
		posts = Post.query().order(-Post.date).fetch(1)
		is_newest = True
		if posts:
			post = posts[0]
			is_oldest = post.date == Post.min_date()
		else:
			post = None
			is_oldest = True


		#See if this is the very first time we've been here. In that case
		#send an email immediately to get people started...
		first_time = False
		
		if not Slug.query().get() and not Post.query().get():
			first_time = True
			DailyMail().send(True)

		self.response.write(get_template('frontpage.html').render(
			{
				"page":"frontpage", 
				"post":post, 
				"is_oldest" : is_oldest,
				"is_newest" : is_newest,
				"first_time" : first_time,
				"email" : settings.email_address
			}))
Exemple #6
0
class SerialManager:
    serial = None
    settings = Settings.singleton()

    def __init__(self):
        self.serial = Serial(port=self.settings.serial_dev,
                             baudrate=1200,
                             parity=PARITY_NONE,
                             stopbits=STOPBITS_ONE,
                             bytesize=SEVENBITS,
                             timeout=1)
        Logging.info("Teleinfo is reading on " + self.settings.serial_dev + "...")

        Logging.info("Search the beginning of the trame")
        self.search_beginning_trame()

    def search_beginning_trame(self):
        line = self.serial.readline()
        while b'\x02' not in line:  # search the beginning trame character
            line = self.serial.readline()

    def read_line(self):
        return self.serial.readline().decode("utf-8")

    def close(self):
        self.serial.close()
        self.serial = None
Exemple #7
0
 def func_wrapper(self, *args):
     user = users.get_current_user()
     if user and user.email() in Settings.get_instance(
     )["emails"].values.values():
         return func(self, *args)
     self.response.set_status(403)
     self.response.write(
         'Move along, nothing to do here! Move along...<br><a href="%s">Logout</a>'
         % users.create_logout_url("/"))
Exemple #8
0
	def post(self):
		settings = Settings.get()

		settings.email_address = self.request.get('email-address')
		settings.timezone = self.request.get('timezone')
		settings.email_hour = int(self.request.get('email-hour'))
		settings.dropbox_access_token = self.request.get('dropbox-access-token')
		settings.include_old_post_in_entry = self.request.get('include-old-entry') == 'yes'
		settings.put()
		self._render(settings, True)
Exemple #9
0
def is_local():
    setting = Settings.get_by_name("PROD_ENV")

    if not setting:
        return True

    if setting.value:
        return False
    else:
        return True
 def load_settings(self, settings_name):
     settings = None
     settings_path = os.path.join(SETTINGS_DIR, settings_name)
     if os.path.exists(settings_path):
         with open(settings_path, 'r') as f:
             json_dict = json.load(f)
             image_processes = [
                 ImageProcess.from_json(j)
                 for j in json_dict[IMAGE_PROCESSES]
             ]
             settings = Settings(settings_name, image_processes)
     return settings
Exemple #11
0
 def __init__(self):
     """
     Initialize Employee class
     """
     self.model = {
         "name":
         "employees",
         "id":
         "employee_id",
         "fields":
         ("employee_id", "salesrep", "fullname", "email", "country", "sas"),
         "types": ("INTEGER PRIMARY KEY NOT NULL", "TEXT", "TEXT", "TEXT",
                   "TEXT", "INTEGER DEFAULT 0")
     }
     self._employee = {}
     self.q = Query()
     if not self.q.exist_table(self.model["name"]):
         sql = self.q.build("create", self.model)
         self.q.execute(sql)
     self.s = Settings()
     if rules.check_settings(self.s.settings):
         self.load(self.s.settings["usermail"])
Exemple #12
0
def send_email_via_sendgrid():
    """A background task that sends an email via SendGrid."""
    data = json.loads(request.get_data(as_text=True))

    recipient_email = data.get("recipient_email")
    sender_email = data.get("sender_email")
    email_subject = data.get("email_subject")
    email_body = data.get("email_body")
    non_html_message = data.get("non_html_message")

    if is_local():
        # localhost (not really sending the email)

        logging.warning("***********************")
        logging.warning(
            "You are on localhost, so no e-mail will be sent. This is message:"
        )
        logging.warning("Recipient: " + recipient_email)
        logging.warning("Sender: " + sender_email)
        logging.warning("Subject: " + email_subject)
        logging.warning("Body: " + non_html_message)
        logging.warning("+++++++++++++++++++++++")

        return "{sender_email} {email_subject}".format(
            sender_email=sender_email, email_subject=email_subject)
    else:
        # production (sending the email via SendGrid)
        if request.headers.get("X-AppEngine-QueueName"):
            # If the request has this header (X-AppEngine-QueueName), then it really came from Google Cloud Tasks.
            # Third-party requests that contain headers started with X are stripped of these headers once they hit GAE
            # servers. That's why no one can fake these headers.

            # SendGrid setup
            sg_api_key = Settings.get_by_name("SendGrid-Mail")
            sg = SendGridAPIClient(api_key=sg_api_key.value)

            # Set up email message
            email_message = Mail(from_email=sender_email,
                                 to_emails=recipient_email,
                                 subject=email_subject,
                                 html_content=email_body)

            try:
                response = sg.send(email_message)
                logging.info(response.status_code)
                logging.info(response.body)
                logging.info(response.headers)
            except Exception as e:
                logging.error(str(e))

        return "true"
Exemple #13
0
 def _new_settings_action_handler(self):
     file_dialog = QFileDialog(self)
     file_dialog.setNameFilters(["All Files (*)", "Images (*.png *.jpg)"])
     file_dialog.selectNameFilter("Images (*.png *.jpg)")
     if file_dialog.exec_():
         filename = file_dialog.selectedFiles()[0]
         with wait_cursor():
             image_orig = cv2.imread(filename, cv2.IMREAD_COLOR)
             self.stacked_widget.removeWidget(self.settings_widget)
             self.settings_widget = SettingsWidget(self, Settings())
             self.stacked_widget.addWidget(self.settings_widget)
             self.stacked_widget.setCurrentWidget(self.settings_widget)
             self.settings_widget.setImage(image_orig)
             self.settings_widget.update()
Exemple #14
0
def log_error(subject, message, *args):
	if args:
		try:
			message = message % args
		except:
			pass

	logging.error(subject + ' : ' + message)

	subject = 'MyLife Error: ' + subject
	app_id = app_identity.get_application_id()
	sender = "MyLife Errors <errors@%s.appspotmail.com>" % app_id
	try:
		to = Settings.get().email_address
		mail.check_email_valid(to, 'To')
		mail.send_mail(sender, to, subject, message)
	except:
		mail.send_mail_to_admins(sender, subject, message)
Exemple #15
0
	def get(self):

		#Check whether the migration is done so we can see whether to show the Blobstore Migration
		#or not...
		settings = Settings.get()

		if not settings.blobstore_migration_done:
			migration_task_finished = bool(MigrateTask.query(MigrateTask.status == 'finished').get())
			if migration_task_finished:
				settings.blobstore_migration_done = True
				settings.put()
			else:
				#Try to figure out whether this is a new user that has nothing in the blobstore...
				if not UserImage.query().get():
					settings.blobstore_migration_done = True
					settings.put()

		self._render(settings)
class Teleinfo:
    serial_manager = None
    settings = Settings.singleton()
    database = settings.database

    def run(self):
        try:
            nb_error = 0
            self.serial_manager = SerialManager()

            # lecture de la première ligne de la première trame
            line = self.serial_manager.read_line()

            Logging.info("Reading data from teleinfo")
            consumption = None
            last_consumption = None
            while True:
                ar = line.split(" ")
                try:
                    key = Keyword.value_of(ar[0])
                    if key is None:
                        line = self.serial_manager.read_line()
                        continue

                    if key == Keyword.ADCO:  # Begining of block
                        if consumption is not None:
                            if last_consumption is None or not last_consumption.has_same_indexes(
                                    consumption) or (consumption.datetime -
                                                     last_consumption.datetime
                                                     ).seconds > 30:
                                self.database.commit_model(consumption)
                                self.settings.remove_error_file()
                                nb_error = 0

                            last_consumption = consumption

                        consumption = models.Consumption()
                    elif consumption is None:
                        Logging.warning(
                            "We search the beginning of first trame")
                        line = self.serial_manager.read_line()
                        continue

                    if key.is_int_value():
                        value = int(ar[1])
                    else:
                        value = ar[1]

                    if key == Keyword.HCHP:
                        consumption.index_hp = value
                    elif key == Keyword.HCHC:
                        consumption.index_hc = value
                    elif key == Keyword.IINST:
                        consumption.intensite_inst = value
                    elif key == Keyword.PAPP:
                        consumption.puissance_apparente = value
                    elif key == Keyword.PTEC:
                        if value == "HC..":
                            consumption.periode = 2

                except Exception as e:
                    nb_error = nb_error + 1
                    if nb_error > 20:
                        Logging.error("Too many error. Stop the service.")
                        sys.exit()

                    try:
                        Logging.error("Exception no " + str(nb_error) +
                                      ": %s" % e)
                        self.settings.create_error_file()
                        self.settings.init_db()

                    except Exception as e2:
                        Logging.error("Exception : %s" % e2)

                line = self.serial_manager.read_line()
        finally:
            if self.serial_manager is not None:
                self.serial_manager.close()
Exemple #17
0
    def get(self):
        images_total = 0
        images_backed_up = 0
        try:
            self.response.headers['Content-Type'] = 'text/plain'
            settings = Settings.get()

            if not settings.dropbox_access_token:
                self.log(
                    'No access token available, no backup will be performed.')
                return

            posts = [p for p in Post.query().order(Post.date).fetch()]

            self.log('Backing up %s posts to Dropbox' % len(posts))
            post_text = StringIO()
            for p in posts:
                post_text.write(p.date.strftime('%Y-%m-%d'))
                post_text.write('\r\n\r\n')
                post_text.write(
                    p.text.replace('\r\n', '\n').replace('\n',
                                                         '\r\n').rstrip())
                post_text.write('\r\n\r\n')

            result = self.put_file(settings.dropbox_access_token, 'MyLife.txt',
                                   post_text.getvalue().encode('utf-8'))
            post_text.close()
            self.log('Backed up posts. Revision: %s' % result['rev'])

            self.log('Fetching Dropbox file list')

            files_in_dropbox = self.get_dropbox_filelist(
                settings.dropbox_access_token)

            self.log('Got %s files from Dropbox' % len(files_in_dropbox))

            self.log('Fetching images...')
            images = [
                i for i in UserImage.query().order(UserImage.date).fetch()
            ]

            self.log('Total images in MyLife: %s' % len(images))

            not_backed_up = [i for i in images if not i.backed_up_in_dropbox]
            not_in_dropbox = [
                i for i in images if not i.filename in files_in_dropbox
            ]

            self.log('\nFiles not backed up: \n\n' +
                     '\n'.join([i.filename for i in not_backed_up]))
            self.log('\nFiles marked as backed up, but not in Dropbox: \n\n' +
                     '\n'.join([i.filename for i in not_in_dropbox]))

            images = not_backed_up + not_in_dropbox

            images_total = len(images)
            self.log('Found %s images that need to be backed up in Dropbox' %
                     images_total)
            for img in images:
                self.log('Backing up %s' % img.filename)
                bytes = filestore.read(img.original_size_key)
                result = self.put_file(settings.dropbox_access_token,
                                       img.filename, bytes)
                self.log('Backed up %s. Revision: %s' %
                         (img.filename, result['rev']))
                img.backed_up_in_dropbox = True
                img.put()
                images_backed_up += 1

            settings.dropbox_last_backup = datetime.datetime.now()
            settings.put()
            self.log('Finished backup successfully')
        except apiproxy_errors.OverQuotaError, ex:
            self.log(ex)
            log_error(
                'Error backing up to Dropbox, quota exceeded',
                'The backup operation did not complete because it ran out of quota. '
                +
                'The next time it runs it will continue backing up your posts and images.'
                + '%s images out of %s were backed up before failing' %
                (images_backed_up, images_total))
Exemple #18
0
class Employee:
    """
    Employee class
    """
    def __init__(self):
        """
        Initialize Employee class
        """
        self.model = {
            "name":
            "employees",
            "id":
            "employee_id",
            "fields":
            ("employee_id", "salesrep", "fullname", "email", "country", "sas"),
            "types": ("INTEGER PRIMARY KEY NOT NULL", "TEXT", "TEXT", "TEXT",
                      "TEXT", "INTEGER DEFAULT 0")
        }
        self._employee = {}
        self.q = Query()
        if not self.q.exist_table(self.model["name"]):
            sql = self.q.build("create", self.model)
            self.q.execute(sql)
        self.s = Settings()
        if rules.check_settings(self.s.settings):
            self.load(self.s.settings["usermail"])

    @property
    def employee(self):
        """
        Return current and only employeeid
        """
        return self._employee

    def insert(self, values):
        """
        Insert employee in database
        Args:
            values:
        """
        sql = self.q.build("insert", self.model)
        self.q.execute(sql, values=values)

    def load(self, email):
        """
        Load the employee
        """
        filters = [("email", "=")]
        values = (email, )
        sql = self.q.build("select", self.model, filters=filters)
        success, data = self.q.execute(sql, values)
        # first check if employee is loaded
        # second check is in exception handling
        try:
            _ = data[0]
            self._employee = dict(zip(self.model["fields"], data[0]))
        except IndexError:
            if httpFn.inet_conn_check():
                # load from http
                self.load_from_http()
                success, data = self.q.execute(sql, values)
                try:
                    # second check after load_from_http
                    _ = data[0]
                    self._employee = dict(zip(self.model["fields"], data[0]))
                except IndexError:
                    self._employee = {}

    def load_from_http(self):
        """
        Load employee from http
        """
        self.s.get()
        data = httpFn.get_employee_data(self.s)
        if data:
            data = list(data)
            data[0:0] = [None]
            self.insert(tuple(data))

    def update(self):
        """
        Update employee in database
        """
        fields = list(self.model["fields"])[1:]
        filters = [(self.model["id"], "=")]
        values = self.q.values_to_update(self._employee.values())

        sql = self.q.build("update",
                           self.model,
                           update=fields,
                           filters=filters)

        self.q.execute(sql, values=values)
Exemple #19
0
async def updateSettings(request):
    params = await request.json()
    settings = Settings(params['frameBufferSize'], params['videoPath'])
    db.update_settings(settings)
    return web.Response(status=201)
Exemple #20
0
	def get(self, year, month):
		Settings.get() #Force email address update...

		now = datetime.datetime.now()
		if not year:
			last_post = Post.query().order(-Post.date).get()
			if last_post:
				year, month = last_post.date.year, last_post.date.month
			else:
				year, month = now.year, now.month
		else:
			year, month = int(year), int(month)

		from_date = datetime.date(year, month, 1)
		
		to_month = month + 1
		to_year = year
		if to_month == 13:
			to_month = 1
			to_year += 1

		to_date = datetime.date(to_year, to_month, 1)
		posts = [p for p in Post.query(ndb.AND(Post.date >= from_date, Post.date < to_date)).order(-Post.date).fetch()]
		month_name = from_date.strftime('%B %Y')
		
		#Get month list
		months = PostCounter.get().months[:]
		def cmp_months(a,b):
			if a.year != b.year:
				return cmp(a.year, b.year)
			else:
				return cmp(a.month, b.month)

		months.sort(cmp_months)

		archive = []

		next_link, prev_link = None, None

		for i, m in enumerate(months):
			date = datetime.date(m.year, m.month,1)
			descr = '%s, %s posts' % (date.strftime('%B %Y'), m.count)
			value = date.strftime('%Y-%m')
			archive.append((value,descr, m.year == year and m.month == month))
			if m.year == year and m.month == month:
				if i != 0:
					prev_link = '/past/%s' % datetime.date(months[i-1].year, months[i-1].month, 1).strftime('%Y-%m')

				if i < len(months)-1:
					next_link = '/past/%s' % datetime.date(months[i+1].year, months[i+1].month, 1).strftime('%Y-%m')

		if not archive:
			archive.append(('', '%s, 0 posts' % now.strftime('%B %Y'), False))

		data = {
			"page" : "past", 
			"posts" : posts, 
			"month" : month_name,
			"archive" : archive,
			"next" : next_link,
			"prev" : prev_link
		}
		self.response.write(get_template('past.html').render(data))
Exemple #21
0
STATUS_REBALANCE = 'rebalance'
STATUS_RIDES = 'rides'
STATUS_NEXT_CYCLE = 'next-cycle'
STATUS_FINISH = 'finish'
STATUS_NONE = None

PREDICTION_MODE_7DMA = 'Past 7 Days Moving Average'
PREDICTION_MODE_LSTM = 'LSTM'
PREDICTION_MODE_GRU = 'GRU'
PREDICTION_MODE_BI_LSTM = 'Bi-LSTM'
PREDICTION_MODE_ACTUAL = 'ACTUAL'

START_TIME = datetime(year=2018, month=10, day=1, hour=0)
DEFAULT_SETTINGS = Settings(interval_hour=2,
                            peak_cost=2,
                            off_peak_cost=1,
                            budget_per_cycle=1500,
                            cost_coef=0.2,
                            prediction_mode=PREDICTION_MODE_7DMA)
MOVING_AVERAGE_DAYS = 7

RESULTS_PATH = 'results'
check_dir(RESULTS_PATH)
DATA_PATH = 'data'
JOURNEYS_DATA_PATH = os.path.join(
    DATA_PATH, 'london_journeys_count_with_2h_interval.csv')
STATIONS_DATA_PATH = os.path.join(DATA_PATH, 'london_stations.json')
PREDICTION_DATA_PATHS = {
    PREDICTION_MODE_7DMA:
    os.path.join(DATA_PATH,
                 'london_journeys_predict_with_2h_interval_7DMA.csv'),
    PREDICTION_MODE_LSTM:
Exemple #22
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)
Exemple #23
0
 def setUp(self):
     self.storage_service = StorageService()
     self.pattern_name = 'test_pattern'
     self.pattern = self.create_pattern(self.pattern_name)
     self.settings_name = 'test_settings'
     self.settings = Settings(self.settings_name)
Exemple #24
0
	def get(self):
		images_total = 0
		images_backed_up = 0
		try:
			self.response.headers['Content-Type'] = 'text/plain'
			settings = Settings.get()

			if not settings.dropbox_access_token:
				self.log('No access token available, no backup will be performed.')
				return


			posts = [p for p in Post.query().order(Post.date).fetch()]

			self.log('Backing up %s posts to Dropbox' % len(posts))
			post_text = StringIO()
			for p in posts:
				post_text.write(p.date.strftime('%Y-%m-%d'))
				post_text.write('\r\n\r\n')
				post_text.write(p.text.replace('\r\n', '\n').replace('\n', '\r\n').rstrip())
				post_text.write('\r\n\r\n')

			result = self.put_file(settings.dropbox_access_token, 'MyLife.txt', post_text.getvalue().encode('utf-8'))
			post_text.close()
			self.log('Backed up posts. Revision: %s' % result['rev'])

			self.log('Fetching Dropbox file list')
			
			files_in_dropbox = self.get_dropbox_filelist(settings.dropbox_access_token)
			
			self.log('Got %s files from Dropbox' % len(files_in_dropbox))

			self.log('Fetching images...')
			images = [i for i in UserImage.query().order(UserImage.date).fetch()]

			self.log('Total images in MyLife: %s' % len(images))

			not_backed_up = [i for i in images if not i.backed_up_in_dropbox]
			not_in_dropbox = [i for i in images if not i.filename in files_in_dropbox]

			self.log('\nFiles not backed up: \n\n' + '\n'.join([i.filename for i in not_backed_up]))
			self.log('\nFiles marked as backed up, but not in Dropbox: \n\n' + '\n'.join([i.filename for i in not_in_dropbox]))

			images = not_backed_up + not_in_dropbox

			images_total = len(images)
			self.log('Found %s images that need to be backed up in Dropbox' % images_total)
			for img in images:
				self.log('Backing up %s' % img.filename)
				bytes = filestore.read(img.original_size_key)
				result = self.put_file(settings.dropbox_access_token, img.filename, bytes)
				self.log('Backed up %s. Revision: %s' % (img.filename, result['rev']))
				img.backed_up_in_dropbox = True
				img.put()
				images_backed_up += 1


			settings.dropbox_last_backup = datetime.datetime.now()
			settings.put()
			self.log('Finished backup successfully')
		except apiproxy_errors.OverQuotaError, ex:
			self.log(ex)
			log_error('Error backing up to Dropbox, quota exceeded', 'The backup operation did not complete because it ran out of quota. ' +
				'The next time it runs it will continue backing up your posts and images.' +
				'%s images out of %s were backed up before failing' % (images_backed_up, images_total))
Exemple #25
0
def save_setting(key, value):
    Settings().update(key=key, value=value)
 def get_settings(self) -> Settings:
     data = self.__settings.get(doc_id=0)
     return Settings(data['frame_buffer_size'], data['video_path'])
Exemple #27
0
    def get(self, year, month):
        Settings.get()  #Force email address update...

        now = datetime.datetime.now()
        if not year:
            last_post = Post.query().order(-Post.date).get()
            if last_post:
                year, month = last_post.date.year, last_post.date.month
            else:
                year, month = now.year, now.month
        else:
            year, month = int(year), int(month)

        from_date = datetime.date(year, month, 1)

        to_month = month + 1
        to_year = year
        if to_month == 13:
            to_month = 1
            to_year += 1

        to_date = datetime.date(to_year, to_month, 1)
        posts = [
            p for p in Post.query(
                ndb.AND(Post.date >= from_date, Post.date < to_date)).order(
                    -Post.date).fetch()
        ]
        month_name = from_date.strftime('%B %Y')

        #Get month list
        months = PostCounter.get().months[:]

        def cmp_months(a, b):
            if a.year != b.year:
                return cmp(a.year, b.year)
            else:
                return cmp(a.month, b.month)

        months.sort(cmp_months)

        archive = []

        next_link, prev_link = None, None

        for i, m in enumerate(months):
            date = datetime.date(m.year, m.month, 1)
            descr = '%s, %s posts' % (date.strftime('%B %Y'), m.count)
            value = date.strftime('%Y-%m')
            archive.append((value, descr, m.year == year and m.month == month))
            if m.year == year and m.month == month:
                if i != 0:
                    prev_link = '/past/%s' % datetime.date(
                        months[i - 1].year, months[i - 1].month,
                        1).strftime('%Y-%m')

                if i < len(months) - 1:
                    next_link = '/past/%s' % datetime.date(
                        months[i + 1].year, months[i + 1].month,
                        1).strftime('%Y-%m')

        if not archive:
            archive.append(('', '%s, 0 posts' % now.strftime('%B %Y'), False))

        data = {
            "page": "past",
            "posts": posts,
            "month": month_name,
            "archive": archive,
            "next": next_link,
            "prev": prev_link
        }
        self.response.write(get_template('past.html').render(data))
Exemple #28
0
class Library():
    def __init__(self):
        self.films = []
        self.settings = Settings()
        global portable_paths
        portable_paths = self.settings.portable_paths
        self._load()

    def _load(self):
        content = json.read(_filename)
        if content:
            for dictionary in content:
                self.films.append(Film(**dictionary))

    def save(self):
        json.write(self.films, _filename)
        self.settings.save()

    def update(self):
        from os import walk

        found = []

        for directory in self.settings.directories():
            if path.exists(directory):
                for root, dirnames, filenames in walk(directory):
                    for filename in filenames:

                        # Get around the 256 character limit by prepending \\\\?\\
                        absolute = path.join("\\\?\\", root, filename)

                        if filename.lower().endswith(tuple(self.settings.file_extensions)):

                            mode, ino, dev, nlink, uid, gid, size, atime, mtime, ctime = stat(absolute)
                            if size > self.settings.minimum_size_byte:

                                found.append(Film(abspath=absolute, last_modification=get_datetime(mtime), size=size))
            else:
                self.settings.directories().remove(directory)

        # Film has been removed from disk - remove from library
        for film in self.films:
            if film not in found:
                #print('Removed: {}'.format(film.print()))
                self.films.remove(film)
                #del film

        # New film - add to library
        for film in found:
            if film not in self.films:
                #print('Found: {}'.format(film.print()))
                self.films.append(film)

    def random_movie(self):
        import random

        if self.films:
            found = []

            for film in self.films:
                if not film.watched:
                    found.append(film)

            if found:
                return random.choice(found)
            else:
                print("There are no unwatched films.")
                return None
        else:
            print("There are no films added.")
            return None
Exemple #29
0
 def __init__(self):
     self.films = []
     self.settings = Settings()
     global portable_paths
     portable_paths = self.settings.portable_paths
     self._load()
Exemple #30
0
from common.database.databasetype import DatabaseType
from models.settings import Settings, Logging

import sys

if __name__ == '__main__':
    settings = Settings.singleton()

    if settings.service_already_running():
        Logging.error("Service teleinfo is already running")
        sys.exit()

    open(settings.pidfile, 'w').write(settings.pid)

    try:
        Logging.info("Start Teleinfo application")
        settings.init_db(DatabaseType.SQLITE)

        # Creation of models
        import models
        from serial_teleinfo import teleinfo

        Logging.info("Check creation of tables")
        settings.database.init_tables()

        teleinfo.Teleinfo().run()
    finally:
        settings.dispose()

Exemple #31
0
	def send(self, is_intro_email=False):

		try:
			now = datetime.datetime.now()
			settings = Settings.get()

			if is_intro_email:
				current_time = now
				logging.info('Sending intro email to %s' % settings.email_address)
			else:
				current_time, id, name, offset = self.get_time_in_timezone(settings)

				if current_time.hour != settings.email_hour:
					logging.info('Current time for %s is %s, not sending email now, will send at %02d:00' % (name, current_time, settings.email_hour))
					return


			today = current_time.date()
			
			if self.check_if_intro_email_sent_today(today):
				logging.info('Already sent the intro email today, skipping this email for now')	
				return	

			self.check_if_mail_already_sent(today)	


			slug_id = self.get_slug()

			slug = Slug(slug=slug_id, date=today)

			slug.put()

			subject = "It's %s, %s %s - How did your day go?" % (today.strftime('%A'), today.strftime("%b"), today.day)
			app_id = app_identity.get_application_id()

			sender = "MyLife <post+%s@%s.appspotmail.com>" % (slug.slug, app_id)

			message = mail.EmailMessage(sender=sender, subject=subject)

			message.to = settings.email_address
			if not settings.email_address:
				log_error('Missing To in daily email', 'There is no configured email address in your settings. Please visit your settings page to configure it so we can send you your daily email.')
				return

			message.body = """
Just reply to this email with your entry.

OLD_POST
You can see your past entries here:
https://APP_ID.appspot.com/past

	""".replace('APP_ID', app_id)

			message.html = """
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.=
w3.org/TR/html4/loose.dtd">
<html>
	<head>
		<title></title>
	</head>
	<body>
	Just reply to this email with your entry.
	<br>
	<br>
OLD_POST
	<a href="https://APP_ID.appspot.com/past">Past entries</a>
	</body>
</html>
""".replace('APP_ID', app_id)

			if is_intro_email:
				intro_msg = "Welcome to MyLife. We've sent you this email immediately so you can try the system out. In the future we will email you once a day and include an old post in each email. You can configure when you get your email and which email address we should use on the settings page."
				message.html = message.html.replace('OLD_POST', intro_msg + '<br><br>')
				message.body = message.body.replace('OLD_POST', intro_msg + '\r\n\r\n')
			else:
				#Lets try to put in an old post...
				old_post, old_type = self.get_old_post(today)

				if old_post and settings.include_old_post_in_entry:
					old_post_text = 'Remember this? One %s ago you wrote:\r\n\r\n' % old_type
					old_post_text += old_post.text.rstrip() + '\r\n\r\n'

					message.body = re.sub(r'OLD_POST\r?\n', old_post_text, message.body)

					old_post_text = re.sub(r'\r?\n', '<br>', old_post_text)
					message.html = re.sub(r'OLD_POST\r?\n', old_post_text, message.html)
				else:
					message.body = re.sub('OLD_POST\r?\n', '', message.body)
					message.html = re.sub('OLD_POST\r?\n', '', message.html)

			message.send()
			
			if is_intro_email:
				logging.info('Sent intro email')
			else:
				if old_post:
					logging.info('Sent daily email to %s, using old post from %s' % (message.to, old_post.date))
				else:
					logging.info('Sent daily email to %s, could not find old post' % message.to)

			return 'Email sent'
		except:
			log_error('Failed to send daily email', traceback.format_exc(6))
			return 'Failed sending email: %s' % traceback.format_exc(6)
Exemple #32
0
	def send(self, is_intro_email=False, force_send=False, date=None):

		try:
			now = datetime.datetime.now()
			settings = Settings.get()

			if is_intro_email:
				current_time = now
				logging.info('Sending intro email to %s' % settings.email_address)
			else:
				current_time, id, name, offset = self.get_time_in_timezone(settings)

				if current_time.hour != settings.email_hour and not force_send:
					logging.info('Current time for %s is %s, not sending email now, will send at %02d:00' % (name, current_time, settings.email_hour))
					return


			if date and force_send:
				today = date #Allow overriding this stuff
			else:
				today = current_time.date()
			
			if self.check_if_intro_email_sent_today(today) and not force_send:
				logging.info('Already sent the intro email today, skipping this email for now')	
				return	


			#Check if we've already sent an email
			slug = Slug.query(Slug.date == today).get()

			if slug and not force_send:
				msg = 'Tried to send another email on %s, already sent %s' % (date, slug.slug)
				log_error('Tried to send email again', msg)
				raise Exception(msg)

			if not slug:
				slug_id = self.get_slug()

				slug = Slug(slug=slug_id, date=today)

				slug.put()

			subject = "It's %s, %s %s - How did your day go?" % (today.strftime('%A'), today.strftime("%b"), today.day)
			app_id = app_identity.get_application_id()

			sender = "MyLife <post+%s@%s.appspotmail.com>" % (slug.slug, app_id)

			message = mail.EmailMessage(sender=sender, subject=subject)

			message.to = settings.email_address
			if not settings.email_address:
				log_error('Missing To in daily email', 'There is no configured email address in your settings. Please visit your settings page to configure it so we can send you your daily email.')
				return

			message.body = """
Just reply to this email with your entry.

OLD_POST

	""".replace('APP_ID', app_id)

			message.html = """
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.=
w3.org/TR/html4/loose.dtd">
<html>
	<head>
		<title></title>
	</head>
	<body>
	Just reply to this email with your entry.
	<br>
	<br>
OLD_POST
	</body>
</html>
""".replace('APP_ID', app_id)

			if is_intro_email:
				intro_msg = "Welcome to MyLife. We've sent you this email immediately so you can try the system out. In the future we will email you once a day and include an old post in each email. You can configure when you get your email and which email address we should use on the settings page."
				message.html = message.html.replace('OLD_POST', intro_msg + '<br><br>')
				message.body = message.body.replace('OLD_POST', intro_msg + '\r\n\r\n')
			else:
				#Lets try to put in an old post...
				old_post, old_type = self.get_old_post(today)

				if old_post and settings.include_old_post_in_entry:
					logging.info('Going to use old post %s because %s' % (old_post, settings.include_old_post_in_entry))

					if (old_type == 'random'):
						old_post_text = 'Remember this? On <b>%s, %s %s, %s</b> you wrote:\r\n\r\n' % (old_post.date.strftime('%A'), old_post.date.strftime("%b"), old_post.date.day, old_post.date.strftime("%Y"))
					else:
						old_post_text = 'Remember this? One %s ago you wrote:\r\n\r\n' % old_type
					old_post_text += old_post.text.rstrip() + '\r\n\r\n'

					message.body = re.sub(r'OLD_POST\r?\n', old_post_text, message.body)

					old_post_text = re.sub(r'\r?\n', '<br>', old_post_text)
					message.html = re.sub(r'OLD_POST\r?\n', old_post_text, message.html)
				else:
					logging.info('Not using Old post %s because %s' % (old_post, settings.include_old_post_in_entry))
					message.body = re.sub('OLD_POST\r?\n', '', message.body)
					message.html = re.sub('OLD_POST\r?\n', '', message.html)

			message.send()
			
			if is_intro_email:
				logging.info('Sent intro email')
			else:
				if old_post:
					logging.info('Sent daily email to %s, using old post from %s' % (message.to, old_post.date))
				else:
					logging.info('Sent daily email to %s, could not find old post' % message.to)

			return 'Email sent'
		except:
			log_error('Failed to send daily email', traceback.format_exc(6))
			return 'Failed sending email: %s' % traceback.format_exc(6)
Exemple #33
0
 def get(self, values):
     settings = Settings.get_instance()
     for category in settings:
         values[category] = sorted(settings[category].values.items())
     self.response.write(render("templates/configuracoes.html", values))
Exemple #34
0
    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()
Exemple #35
0
            self.data = []


from models.settings import Settings

defaults = { 'nuts': ['pages', 'articles'],
             'admins': ['Nobody <nobody@localhost>',],
             'hosts': ['localhost', 'appspot.com'],
             'dp_highlighter': False,
             'google_analytics' : '',
             'google_adsense_client' : '',
             'google_adsense_slot' : '',
             'google_adsense_width': 0,
             'google_adsense_height': 0,
             'disqus_forum' : '' }
NutSettings = lambda : Settings.get_or_create('settings:hazel', **defaults)

class SettingsForm(Form):
    nuts = CSVField('Nuts', [], u'A list of your activated modules')
    # FIXME: create a custom validator that does the validation of the
    #        Name <Email>[, Name <Email>]* field.
    admins = CSVField('Admins', [], u'A list of people who will be notified in case of emergency')
    hosts = CSVField('Hosts', [], u'A comma seperated list of hosts on which to listen. In case of a unknown host, a redirect to the first item in the list will occour.')
    # FIXME: create validator
    google_analytics = TextField('Google Analytics ID', [], u'UA-xxxxxx-xx')
    google_adsense_client = TextField('Google AdSense Client', [], u'pub-...')
    google_adsense_slot   = TextField('Google AdSense Slot', [], u'the slot value')
    google_adsense_width  = IntegerField('Google AdSense Width', [], u'the width value')
    google_adsense_height = IntegerField('Google AdSense Height', [], u'the height value')
    disqus_forum          = TextField('Disqus Forum ID', [], u'The name of the disqus forum to use for comments')
    dp_highlighter        = BooleanField('Enable dp.SyntaxHighlighter')