Ejemplo n.º 1
0
class EmployeeInfoGUI(Gtk.Builder):
    def __init__(self):

        Gtk.Builder.__init__(self)
        self.add_from_file(UI_FILE)
        self.connect_signals(self)
        self.cursor = DB.cursor()

        self.employee_store = self.get_object('employee_store')
        self.s_s_medicare_store = self.get_object('s_s_medicare_store')
        self.federal_withholding_store = self.get_object(
            'federal_withholding_store')
        self.state_withholding_store = self.get_object(
            'state_withholding_store')

        self.populate_employee_store()
        self.born_calendar = DateTimeCalendar(override=True)
        self.on_payroll_since_calendar = DateTimeCalendar(override=True)
        self.born_calendar.connect("day-selected",
                                   self.born_calendar_date_selected)
        self.on_payroll_since_calendar.connect(
            "day-selected", self.on_payroll_since_calendar_date_selected)

        self.window = self.get_object('window1')
        self.window.show_all()
        broadcaster.connect("shutdown", self.main_shutdown)

        self.get_object("button5").set_label("No scanner selected")
        self.get_object("button5").set_sensitive(False)

        self.data_queue = Queue()
        self.scanner_store = self.get_object("scanner_store")
        thread = Process(target=self.get_scanners)
        thread.start()
        GLib.timeout_add(100, self.populate_scanners)

    def populate_scanners(self):
        try:
            devices = self.data_queue.get_nowait()
            for scanner in devices:
                device_id = scanner[0]
                device_manufacturer = scanner[1]
                name = scanner[2]
                given_name = scanner[3]
                self.scanner_store.append(
                    [str(device_id), device_manufacturer, name, given_name])
        except Empty:
            return True

    def get_scanners(self):
        sane.init()
        devices = sane.get_devices()
        self.data_queue.put(devices)

    def main_shutdown(self):
        # commit all changes before shutdown,
        # because committing changes releases the row lock
        DB.commit()

    def populate_employee_store(self):
        self.populating = True
        self.employee_store.clear()
        self.cursor.execute("SELECT id, name FROM contacts "
                            "WHERE employee = True")
        for row in self.cursor.fetchall():
            self.employee_store.append(row)
        self.populating = False
        DB.rollback()

    def employee_treeview_cursor_changed(self, treeview):
        if self.populating == True:
            return
        selection = self.get_object('treeview-selection1')
        model, path = selection.get_selected_rows()
        self.employee_id = model[path][0]
        self.select_employee()

    def select_employee(self):
        self.populating = True
        DB.commit()  # save and unlock the active employee
        cursor = DB.cursor()
        try:
            cursor.execute(
                "SELECT "
                "born, "
                "social_security, "
                "social_security_exempt, "
                "on_payroll_since, "
                "wage, "
                "payments_per_year, "
                "married, "
                "format_date(last_updated), "
                "state_withholding_exempt, "
                "state_credits, "
                "state_extra_withholding, "
                "fed_withholding_exempt, "
                "fed_credits, "
                "fed_extra_withholding "
                "FROM payroll.employee_info "
                "WHERE employee_id = %s "
                "ORDER BY active DESC, id DESC "
                "LIMIT 1 FOR UPDATE NOWAIT", (self.employee_id, ))
        except psycopg2.OperationalError as e:
            DB.rollback()
            cursor.close()
            self.get_object('box1').set_sensitive(False)
            error = str(
                e) + "Hint: somebody else is editing this employee info"
            self.show_message(error)
            self.populating = False
            return False
        for row in cursor.fetchall():
            self.born_calendar.set_date(row[0])
            self.get_object('entry2').set_text(row[1])
            self.get_object('checkbutton3').set_active(row[2])
            self.on_payroll_since_calendar.set_date(row[3])
            self.get_object('spinbutton6').set_value(row[4])
            self.get_object('spinbutton5').set_value(row[5])
            self.get_object('checkbutton4').set_active(row[6])
            self.get_object('label6').set_text(row[7])
            self.get_object('checkbutton2').set_active(row[8])
            self.get_object('spinbutton3').set_value(row[9])
            self.get_object('spinbutton2').set_value(row[10])
            self.get_object('checkbutton1').set_active(row[11])
            self.get_object('spinbutton4').set_value(row[12])
            self.get_object('spinbutton1').set_value(row[13])
            break
        else:
            cursor.execute(
                "INSERT INTO payroll.employee_info (employee_id) "
                "VALUES (%s)", (self.employee_id, ))
            DB.commit()
            GLib.timeout_add(50, self.select_employee)
        self.populating = False
        self.populate_exemption_forms()
        cursor.close()
        self.get_object('box1').set_sensitive(True)

    def populate_exemption_forms(self):
        self.s_s_medicare_store.clear()
        self.state_withholding_store.clear()
        self.federal_withholding_store.clear()
        self.cursor.execute(
            "SELECT id, format_date(date_inserted) "
            "FROM payroll.emp_pdf_archive "
            "WHERE employee_id = %s "
            "AND s_s_medicare_exemption_pdf IS NOT NULL "
            "ORDER BY id", (self.employee_id, ))
        for row in self.cursor.fetchall():
            self.s_s_medicare_store.append(row)
        self.cursor.execute(
            "SELECT id, format_date(date_inserted) "
            "FROM payroll.emp_pdf_archive "
            "WHERE employee_id = %s "
            "AND state_withholding_pdf IS NOT NULL "
            "ORDER BY id", (self.employee_id, ))
        for row in self.cursor.fetchall():
            self.state_withholding_store.append(row)
        self.cursor.execute(
            "SELECT id, format_date(date_inserted) "
            "FROM payroll.emp_pdf_archive "
            "WHERE employee_id = %s "
            "AND fed_withholding_pdf IS NOT NULL "
            "ORDER BY id", (self.employee_id, ))
        for row in self.cursor.fetchall():
            self.federal_withholding_store.append(row)

    def s_s_m_row_activated(self, treeview, path, column):
        model = treeview.get_model()
        id = model[path][0]
        self.cursor.execute(
            "SELECT s_s_medicare_exemption_pdf "
            "FROM payroll.emp_pdf_archive "
            "WHERE id = %s", (id, ))
        for row in self.cursor.fetchall():
            file_data = row[0]
            file_name = "/tmp/Social_security_medicare_exemption.pdf"
            f = open(file_name, 'wb')
            f.write(file_data)
            subprocess.Popen("xdg-open %s" % file_name, shell=True)
            f.close()

    def federal_withholding_row_activated(self, treeview, path, column):
        model = treeview.get_model()
        id = model[path][0]
        self.cursor.execute(
            "SELECT fed_withholding_pdf "
            "FROM payroll.emp_pdf_archive "
            "WHERE id = %s", (id, ))
        for row in self.cursor.fetchall():
            file_data = row[0]
            file_name = "/tmp/Federal_withholding_exemption.pdf"
            f = open(file_name, 'wb')
            f.write(file_data)
            subprocess.Popen("xdg-open %s" % file_name, shell=True)
            f.close()

    def state_withholding_row_activated(self, treeview, path, column):
        model = treeview.get_model()
        id = model[path][0]
        self.cursor.execute(
            "SELECT state_withholding_pdf "
            "FROM payroll.emp_pdf_archive "
            "WHERE id = %s", (id, ))
        for row in self.cursor.fetchall():
            file_data = row[0]
            file_name = "/tmp/State_withholding_exemption.pdf"
            f = open(file_name, 'wb')
            f.write(file_data)
            subprocess.Popen("xdg-open %s" % file_name, shell=True)
            f.close()

    def payments_per_year_value_changed(self, spinbutton):
        if self.populating == True:
            return
        self.auto_save_employee_info()

    def state_income_status_toggled(self, checkbutton):
        if self.populating == True:
            return
        self.auto_save_employee_info()

    def state_credits_value_changed(self, spinbutton):
        if self.populating == True:
            return
        self.auto_save_employee_info()

    def state_extra_withholding_value_changed(self, spinbutton):
        if self.populating == True:
            return
        self.auto_save_employee_info()

    def federal_income_status_toggled(self, checkbutton):
        if self.populating == True:
            return
        self.auto_save_employee_info()

    def federal_credits_value_changed(self, spinbutton):
        if self.populating == True:
            return
        self.auto_save_employee_info()

    def federal_extra_withholding_value_changed(self, spinbutton):
        if self.populating == True:
            return
        self.auto_save_employee_info()

    def married_checkbutton_toggled(self, checkbutton):
        if self.populating == True:
            return
        self.auto_save_employee_info()

    def social_security_entry_changed(self, entry):
        if self.populating == True:
            return
        self.auto_save_employee_info()

    def wage_spinbutton_value_changed(self, spinbutton):
        if self.populating == True:
            return
        self.auto_save_employee_info()

    def social_security_exemption_changed(self, checkbutton):
        if self.populating == True:
            return
        self.auto_save_employee_info()

    def scanner_combo_changed(self, combo):
        if combo.get_active() > -1:
            self.get_object("button5").set_label("Scan")
            self.get_object("button5").set_sensitive(True)

    def show_scan_pdf_dialog(self, column):
        global device
        dialog = self.get_object("dialog1")
        result = dialog.run()
        dialog.hide()
        if result != Gtk.ResponseType.ACCEPT:
            return
        if device == None:
            device_address = self.get_object("combobox1").get_active_id()
            device = sane.open(device_address)
        document = device.scan()
        path = "/tmp/posting_pdf.pdf"
        document.save(path)
        f = open(path, 'rb')
        file_data = f.read()
        binary = psycopg2.Binary(file_data)
        f.close()
        self.cursor.execute(
            "UPDATE payroll.emp_pdf_archive "
            "SET archived = True "
            "WHERE employee_id = %s "
            "AND " + column + " IS NOT NULL", (self.employee_id, ))
        self.cursor.execute(
            "INSERT INTO payroll.emp_pdf_archive "
            "( " + column + ", employee_id, date_inserted) "
            "VALUES (%s, %s, %s)",
            (binary, self.employee_id, datetime.today()))
        DB.commit()
        self.populate_exemption_forms()

    def state_button_release_event(self, button, event):
        if event.button == 1:
            self.cursor.execute(
                "SELECT state_withholding_pdf "
                "FROM payroll.emp_pdf_archive "
                "WHERE (employee_id, archived) = (%s, False) "
                "AND state_withholding_pdf IS NOT NULL", (self.employee_id, ))
            for row in self.cursor.fetchall():
                file_data = row[0]
                file_name = "/tmp/State_withholding_status.pdf"
                f = open(file_name, 'wb')
                f.write(file_data)
                subprocess.Popen("xdg-open %s" % file_name, shell=True)
                f.close()
                break
            else:
                label = 'Do you want to add a file from the scanner?'
                self.get_object('label9').set_label(label)
                self.show_scan_pdf_dialog("state_withholding_pdf")
        elif event.button == 3:
            label = 'Do you want to update the file from the scanner?'
            self.get_object('label9').set_label(label)
            self.show_scan_pdf_dialog("state_withholding_pdf")

    def s_s_m_button_release_event(self, button, event):
        if event.button == 1:
            self.cursor.execute(
                "SELECT s_s_medicare_exemption_pdf "
                "FROM payroll.emp_pdf_archive "
                "WHERE (employee_id, archived) = (%s, False) "
                "AND s_s_medicare_exemption_pdf IS NOT NULL",
                (self.employee_id, ))
            for row in self.cursor.fetchall():
                file_data = row[0]
                file_name = "/tmp/Social_security_and_medicare_exemption.pdf"
                f = open(file_name, 'wb')
                f.write(file_data)
                subprocess.Popen("xdg-open %s" % file_name, shell=True)
                f.close()
                break
            else:
                label = 'Do you want to add a file from the scanner?'
                self.get_object('label9').set_label(label)
                self.show_scan_pdf_dialog("s_s_medicare_exemption_pdf")
        elif event.button == 3:
            label = 'Do you want to update the file from the scanner?'
            self.get_object('label9').set_label(label)
            self.show_scan_pdf_dialog("s_s_medicare_exemption_pdf")

    def fed_button_release_event(self, button, event):
        if event.button == 1:
            self.cursor.execute(
                "SELECT fed_withholding_pdf "
                "FROM payroll.emp_pdf_archive "
                "WHERE (employee_id, archived) = (%s, False) "
                "AND fed_withholding_pdf IS NOT NULL", (self.employee_id, ))
            for row in self.cursor.fetchall():
                file_data = row[0]
                file_name = "/tmp/Federal_withholding_exemption.pdf"
                f = open(file_name, 'wb')
                f.write(file_data)
                subprocess.Popen("xdg-open %s" % file_name, shell=True)
                f.close()
                break
            else:  # table
                label = 'Do you want to add a file from the scanner?'
                self.get_object('label9').set_label(label)
                self.show_scan_pdf_dialog("fed_withholding_pdf")
        elif event.button == 3:
            label = 'Do you want to update the file from the scanner?'
            self.get_object('label9').set_label(label)
            self.show_scan_pdf_dialog("fed_withholding_pdf")

    def born_calendar_date_selected(self, calendar):
        date_text = calendar.get_text()
        self.get_object('entry1').set_text(date_text)
        if self.populating == True:
            return
        self.auto_save_employee_info()

    def born_entry_icon_released(self, entry, icon, event):
        self.born_calendar.set_relative_to(entry)
        self.born_calendar.show()

    def on_payroll_since_calendar_date_selected(self, calendar):
        date_text = calendar.get_text()
        self.get_object('entry3').set_text(date_text)
        if self.populating == True:
            return
        self.auto_save_employee_info()

    def on_payroll_since_entry_icon_released(self, entry, icon, event):
        self.on_payroll_since_calendar.set_relative_to(entry)
        self.on_payroll_since_calendar.show()

    def save_clicked(self, button):
        born = self.born_calendar.get_date()
        social_security = self.get_object('entry2').get_text()
        social_security_exempt = self.get_object('checkbutton3').get_active()
        on_payroll_since = self.on_payroll_since_calendar.get_date()
        wage = self.get_object('spinbutton6').get_value()
        payments_per_year = self.get_object('spinbutton5').get_value()
        married = self.get_object('checkbutton4').get_active()
        state_withholding_exempt = self.get_object('checkbutton2').get_active()
        state_credits = self.get_object('spinbutton3').get_value()
        state_extra_withholding = self.get_object('spinbutton2').get_value()
        fed_withholding_exempt = self.get_object('checkbutton1').get_active()
        fed_credits = self.get_object('spinbutton4').get_value()
        fed_extra_withholding = self.get_object('spinbutton1').get_value()
        c = DB.cursor()
        c.execute(
            "INSERT INTO payroll.employee_info "
            "(born, "
            "social_security, "
            "social_security_exempt, "
            "on_payroll_since, "
            "wage, "
            "payments_per_year, "
            "married, "
            "state_withholding_exempt, "
            "state_credits, "
            "state_extra_withholding, "
            "fed_withholding_exempt, "
            "fed_credits, "
            "fed_extra_withholding, "
            "employee_id) "
            "VALUES (%s, %s, %s, %s, %s, %s, %s, "
            "%s, %s, %s, %s, %s, %s, %s) "
            "ON CONFLICT (active, employee_id) "
            "WHERE active = True "
            "DO UPDATE SET "
            "(born, "
            "social_security, "
            "social_security_exempt, "
            "on_payroll_since, "
            "wage, "
            "payments_per_year, "
            "married, "
            "state_withholding_exempt, "
            "state_credits, "
            "state_extra_withholding, "
            "fed_withholding_exempt, "
            "fed_credits, "
            "fed_extra_withholding, "
            "last_updated) "
            "= "
            "(EXCLUDED.born, "
            "EXCLUDED.social_security, "
            "EXCLUDED.social_security_exempt, "
            "EXCLUDED.on_payroll_since, "
            "EXCLUDED.wage, "
            "EXCLUDED.payments_per_year, "
            "EXCLUDED.married, "
            "EXCLUDED.state_withholding_exempt, "
            "EXCLUDED.state_credits, "
            "EXCLUDED.state_extra_withholding, "
            "EXCLUDED.fed_withholding_exempt, "
            "EXCLUDED.fed_credits, "
            "EXCLUDED.fed_extra_withholding, "
            "now()) "
            "WHERE (employee_info.employee_id, employee_info.active) = "
            "(EXCLUDED.employee_id, True) ",
            (born, social_security, social_security_exempt, on_payroll_since,
             wage, payments_per_year, married, state_withholding_exempt,
             state_credits, state_extra_withholding, fed_withholding_exempt,
             fed_credits, fed_extra_withholding, self.employee_id))
        c.close()
        self.get_object('treeview1').set_sensitive(True)

    def cancel_clicked(self, button):
        self.select_employee()
        self.get_object('treeview1').set_sensitive(True)

    def auto_save_employee_info(self):
        # if we ever decide to implement autosave again, the caveats are :
        # 1 locking the row
        # 2 upserts increment the id
        self.get_object('treeview1').set_sensitive(False)

    def show_message(self, message):
        dialog = Gtk.MessageDialog(message_type=Gtk.MessageType.ERROR,
                                   buttons=Gtk.ButtonsType.CLOSE)
        dialog.set_transient_for(self.window)
        dialog.set_markup(message)
        dialog.run()
        dialog.destroy()

    def window_delete_event(self, window, event):
        # save any uncommitted changes and unlock the selected row
        DB.commit()
Ejemplo n.º 2
0
class CreditMemoGUI:
    credit_memo_template = None

    def __init__(self):
        self.builder = Gtk.Builder()
        self.builder.add_from_file(UI_FILE)
        self.builder.connect_signals(self)
        self.cursor = DB.cursor()

        self.customer_store = self.builder.get_object('customer_store')
        self.product_store = self.builder.get_object('credit_products_store')
        self.credit_items_store = self.builder.get_object('credit_items_store')
        self.handler_ids = list()
        for connection in (("contacts_changed",
                            self.populate_customer_store), ):
            handler = broadcaster.connect(connection[0], connection[1])
            self.handler_ids.append(handler)
        self.populate_customer_store()

        self.date_returned_calendar = DateTimeCalendar()
        self.date_returned_calendar.connect('day-selected',
                                            self.return_day_selected)
        date_column = self.builder.get_object('label3')
        self.date_returned_calendar.set_relative_to(date_column)

        self.date_calendar = DateTimeCalendar()
        self.date_calendar.connect('day-selected', self.day_selected)

        product_completion = self.builder.get_object('product_completion')
        product_completion.set_match_func(self.product_match_func)
        customer_completion = self.builder.get_object('customer_completion')
        customer_completion.set_match_func(self.customer_match_func)

        self.window = self.builder.get_object('window1')
        self.window.show_all()

    def window_destroy(self, window):
        for handler in self.handler_ids:
            broadcaster.disconnect(handler)
        self.cursor.close()

    def customer_match_func(self, completion, key, iter):
        split_search_text = key.split()
        for text in split_search_text:
            if text not in self.customer_store[iter][1].lower():
                return False
        return True

    def product_match_selected(self, completion, model, _iter_):
        invoice_item_id = model[_iter_][0]
        selection = self.builder.get_object('treeview-selection1')
        model, path = selection.get_selected_rows()
        if path == []:
            return
        self.update_product_row(path, invoice_item_id)

    def product_renderer_changed(self, combo, path, tree_iter):
        invoice_item_id = self.product_store[tree_iter][0]
        self.update_product_row(path, invoice_item_id)

    def update_product_row(self, path, invoice_item_id):
        c = DB.cursor()
        iter_ = self.credit_items_store.get_iter(path)
        self.check_row_id(iter_)
        row_id = self.credit_items_store[iter_][0]
        c.execute(
            "WITH tax_cte AS "
            "(SELECT tr.rate / 100 AS rate, price "
            "FROM invoice_items AS ii "
            "JOIN tax_rates AS tr ON tr.id = ii.tax_rate_id "
            "WHERE ii.id = %s"
            ") "
            "UPDATE credit_memo_items AS cmi "
            "SET (invoice_item_id, "
            "price, "
            "ext_price, "
            "tax"
            ") "
            "= "
            "(%s, "
            "(SELECT price FROM tax_cte), "
            "qty * (SELECT price FROM tax_cte), "
            "qty * (SELECT price FROM tax_cte) * (SELECT rate FROM tax_cte)"
            ") "
            "WHERE id = %s; "  #new sql; this updates values
            "SELECT "
            "p.id, "
            "p.name, "
            "p.ext_name, "
            "ii.price::text, "
            "cmi.ext_price::text, "
            "cmi.tax::text, "
            "cmi.invoice_item_id, "
            "ii.invoice_id "
            "FROM credit_memo_items AS cmi "
            "JOIN invoice_items AS ii ON ii.id = cmi.invoice_item_id "
            "JOIN products AS p ON p.id = ii.product_id "
            "WHERE cmi.id = %s",
            (invoice_item_id, invoice_item_id, row_id, row_id))
        for row in c.fetchall():
            self.credit_items_store[iter_][2] = row[0]
            self.credit_items_store[iter_][3] = row[1]
            self.credit_items_store[iter_][4] = row[2]
            self.credit_items_store[iter_][5] = row[3]
            self.credit_items_store[iter_][6] = row[4]
            self.credit_items_store[iter_][7] = row[5]
            self.credit_items_store[iter_][8] = row[6]
            self.credit_items_store[iter_][9] = row[7]
        self.calculate_totals()

    def product_editing_started(self, renderer, combo, path):
        renderer_invoice = Gtk.CellRendererText()
        combo.pack_start(renderer_invoice, True)
        combo.add_attribute(renderer_invoice, "text", 2)
        renderer_date = Gtk.CellRendererText()
        combo.pack_start(renderer_date, True)
        combo.add_attribute(renderer_date, "text", 3)
        entry = combo.get_child()
        entry.set_completion(self.builder.get_object('product_completion'))

    def price_edited(self, cellrenderer, path, text):
        c = DB.cursor()
        iter_ = self.credit_items_store.get_iter(path)
        self.check_row_id(iter_)
        row_id = self.credit_items_store[iter_][0]
        invoice_item_id = self.credit_items_store[iter_][8]
        try:
            c.execute(
                "WITH tax_cte AS "
                "(SELECT tr.rate / 100 AS rate "
                "FROM invoice_items AS ii "
                "JOIN tax_rates AS tr ON tr.id = ii.tax_rate_id "
                "WHERE ii.id = %s"
                ") "
                "UPDATE credit_memo_items "
                "SET "
                "(price, "
                "ext_price, "
                "tax) "
                "= "
                "(%s, "
                "qty*%s, "
                "qty*%s*(SELECT rate FROM tax_cte)) "
                "WHERE id = %s "
                "RETURNING price::text, ext_price::text, tax::text",
                (invoice_item_id, text, text, text, row_id))
        except psycopg2.DataError as e:
            self.show_message(str(e))
            DB.rollback()
            return
        for row in c.fetchall():
            price = row[0]
            ext_price = row[1]
            tax = row[2]
        self.credit_items_store[iter_][5] = price
        self.credit_items_store[iter_][6] = ext_price
        self.credit_items_store[iter_][7] = tax
        c.close()
        self.calculate_totals()

    def qty_edited(self, cellrenderertext, path, text):
        c = DB.cursor()
        iter_ = self.credit_items_store.get_iter(path)
        self.check_row_id(iter_)
        row_id = self.credit_items_store[iter_][0]
        invoice_item_id = self.credit_items_store[iter_][8]
        try:
            c.execute(
                "WITH tax_cte AS "
                "(SELECT tr.rate / 100 AS rate "
                "FROM invoice_items AS ii "
                "JOIN tax_rates AS tr ON tr.id = ii.tax_rate_id "
                "WHERE ii.id = %s"
                ") "
                "UPDATE credit_memo_items "
                "SET "
                "(qty, "
                "ext_price, "
                "tax) "
                "= "
                "(%s, "
                "%s*price, "
                "%s*price*(SELECT rate FROM tax_cte)) "
                "WHERE id = %s "
                "RETURNING qty::text, ext_price::text",
                (invoice_item_id, text, text, text, row_id))
        except psycopg2.DataError as e:
            self.show_message(str(e))
            DB.rollback()
            return
        for row in c.fetchall():
            qty = row[0]
            ext_price = row[1]
        self.credit_items_store[iter_][1] = qty
        self.credit_items_store[iter_][6] = ext_price
        c.close()
        self.calculate_totals()

    def tax_edited(self, cellrendererspin, path, text):
        iter_ = self.credit_items_store.get_iter(path)
        self.check_row_id(iter_)
        row_id = self.credit_items_store[iter_][0]
        try:
            self.cursor.execute(
                "UPDATE credit_memo_items "
                "SET tax = %s "
                "WHERE id = %s "
                "RETURNING tax::text", (text, row_id))
        except psycopg2.DataError as e:
            self.show_message(str(e))
            DB.rollback()
            return
        for row in self.cursor.fetchall():
            tax = row[0]
        self.credit_items_store[iter_][7] = tax
        self.calculate_totals()

    def product_match_func(self, completion, key, tree_iter):
        split_search_text = key.split()
        for text in split_search_text:
            if text not in self.product_store[tree_iter][1].lower():
                return False
        return True

    def calculate_totals(self):
        c = DB.cursor()
        c.execute(
            "WITH cte AS "
            "(SELECT "
            "SUM(ext_price) AS subtotal, "
            "SUM(tax) AS tax, "
            "SUM(tax + ext_price) AS total "
            "FROM credit_memo_items WHERE "
            "(credit_memo_id, deleted) = (%s, False) "
            ")"
            "UPDATE credit_memos "
            "SET "
            "(total, "
            "tax, "
            "amount_owed) "
            "= "
            "((SELECT subtotal FROM cte),"
            "(SELECT tax FROM cte),"
            "(SELECT total FROM cte)"
            ")"
            "WHERE id = %s "
            "RETURNING "
            "total::money, "
            "tax::money, "
            "amount_owed::money", (self.credit_memo_id, self.credit_memo_id))
        for row in c.fetchall():
            subtotal = row[0]
            tax = row[1]
            total = row[2]
            self.builder.get_object('subtotal_entry').set_text(subtotal)
            self.builder.get_object('tax_entry').set_text(tax)
            self.builder.get_object('total_entry').set_text(total)
        c.close()
        DB.commit()
        self.credit_memo_template = None  # credit memo changed, force regenerate

    def populate_customer_store(self, m=None, i=None):
        self.customer_store.clear()
        self.cursor.execute("SELECT c.id::text, c.name, c.ext_name "
                            "FROM contacts AS c "
                            "JOIN invoices AS i ON c.id = i.customer_id "
                            "WHERE (c.deleted, c.customer, i.paid) = "
                            "(False, True, True) "
                            "GROUP BY c.id, c.name, c.ext_name "
                            "ORDER BY name")
        for row in self.cursor.fetchall():
            self.customer_store.append(row)

    def customer_combo_changed(self, combo):
        customer_id = combo.get_active_id()
        if customer_id != None:
            self.select_customer(customer_id)

    def customer_match_selected(self, completion, model, _iter):
        customer_id = model[_iter][0]
        self.select_customer(customer_id)

    def select_customer(self, customer_id):
        self.customer_id = customer_id
        self.cursor.execute(
            "SELECT "
            "address, "
            "COALESCE(cm.id, NULL), "
            "COALESCE(-total, -0.00)::money, "
            "COALESCE(-tax, -0.00)::money, "
            "COALESCE(-amount_owed, -0.00)::money, "
            "COALESCE(dated_for, now()), "
            "COALESCE(comments, '') "
            "FROM contacts AS c "
            "LEFT JOIN credit_memos AS cm "
            "ON cm.customer_id = c.id AND cm.posted = False "
            "WHERE c.id = %s", (customer_id, ))
        for row in self.cursor.fetchall():
            address = row[0]
            self.credit_memo_id = row[1]
            subtotal = row[2]
            tax = row[3]
            total = row[4]
            self.date = row[5]
            comments = row[6]
            self.builder.get_object('address_entry').set_text(address)
            self.builder.get_object('subtotal_entry').set_text(subtotal)
            self.builder.get_object('tax_entry').set_text(tax)
            self.builder.get_object('total_entry').set_text(total)
            self.date_calendar.set_date(self.date)
            self.builder.get_object('comments_buffer').set_text(comments)
        self.populate_credit_memo()
        self.populate_product_store()
        self.builder.get_object('menuitem2').set_sensitive(True)
        self.builder.get_object('button1').set_sensitive(True)
        self.builder.get_object('button2').set_sensitive(True)
        self.builder.get_object('comments_textview').set_sensitive(True)

    def populate_credit_memo(self):
        c = DB.cursor()
        self.credit_items_store.clear()
        c.execute(
            "SELECT "
            "cmi.id, "
            "cmi.qty::text, "
            "p.id, "
            "p.name, "
            "p.ext_name, "
            "cmi.price::text, "
            "cmi.ext_price::text, "
            "cmi.tax::text, "
            "cmi.invoice_item_id, "
            "ili.invoice_id, "
            "date_returned::text, "
            "format_date(date_returned) "
            "FROM credit_memo_items AS cmi "
            "JOIN invoice_items AS ili ON ili.id = cmi.invoice_item_id "
            "JOIN products AS p ON p.id = ili.product_id "
            "WHERE (credit_memo_id, cmi.deleted) = (%s, False) "
            "ORDER BY cmi.id", (self.credit_memo_id, ))
        for row in c.fetchall():
            self.credit_items_store.append(row)
        c.close()

    def populate_product_store(self, m=None, i=None):
        self.product_store.clear()
        c = DB.cursor()
        c.execute(
            "SELECT ili.id::text, p.name || '  {' || ext_name || '}', "
            "i.id::text, format_date(i.dated_for) "
            "FROM products AS p "
            "JOIN invoice_items AS ili ON ili.product_id = p.id "
            "JOIN invoices AS i ON ili.invoice_id = i.id "
            "WHERE (customer_id, posted) = (%s, True) "
            "ORDER BY p.name", (self.customer_id, ))
        for row in c.fetchall():
            self.product_store.append(row)
        c.close()

    def treeview_cursor_changed(self, treeview):
        selection = treeview.get_selection()
        model, path = selection.get_selected_rows()
        if path == []:
            return
        product_id = model[path][2]
        store = self.builder.get_object('serial_number_store')
        store.clear()
        self.cursor.execute(
            "SELECT ii.id, sn.serial_number "
            "FROM serial_numbers AS sn "
            "JOIN invoice_items AS ii ON ii.id = sn.invoice_item_id "
            "JOIN invoices AS i ON i.id = ii.invoice_id "
            "WHERE (i.customer_id, ii.product_id) = (%s, %s)",
            (self.customer_id, product_id))
        for row in self.cursor.fetchall():
            store.append(row)

    def serial_number_changed(self, combo, path, tree_iter):
        model = self.builder.get_object('serial_number_store')
        invoice_item_id = model[tree_iter][0]
        serial_number = model[tree_iter][1]
        self.credit_items_store[path][6] = invoice_item_id
        self.credit_items_store[path][11] = serial_number

    def return_day_selected(self, calendar):
        date = calendar.get_date()
        _iter = self.credit_items_store.get_iter(self.path)
        row_id = self.credit_items_store[_iter][0]
        self.cursor.execute(
            "UPDATE credit_memo_items "
            "SET date_returned = %s "
            "WHERE id = %s "
            "RETURNING date_returned::text, "
            "format_date (date_returned)", (date, row_id))
        for row in self.cursor.fetchall():
            date = row[0]
            date_formatted = row[1]
            self.credit_items_store[_iter][10] = str(date)
            self.credit_items_store[_iter][11] = date_formatted

    def date_entry_icon_released(self, entry, icon, position):
        self.date_calendar.set_relative_to(entry)
        self.date_calendar.show_all()

    def day_selected(self, calendar):
        self.date = calendar.get_date()
        text = calendar.get_text()
        self.builder.get_object('entry1').set_text(text)
        if self.credit_memo_id:
            self.cursor.execute(
                "UPDATE credit_memos "
                "SET dated_for = %s "
                "WHERE id = %s", (self.date, self.credit_memo_id))
            DB.commit()

    def date_returned_editing_started(self, renderer, entry, path):
        self.path = path
        current_date = self.credit_items_store[path][10]
        self.date_returned_calendar.set_date(current_date)
        GLib.idle_add(self.date_returned_calendar.show_all)
        entry.destroy()

    def check_row_id(self, _iter):
        c = DB.cursor()
        row_id = self.credit_items_store[_iter][0]
        qty = self.credit_items_store[_iter][1]
        price = self.credit_items_store[_iter][5]
        tax = self.credit_items_store[_iter][7]
        invoice_item_id = self.credit_items_store[_iter][8]
        if row_id == 0:
            c.execute(
                "INSERT INTO credit_memo_items "
                "(qty, "
                "invoice_item_id, "
                "price, "
                "tax, "
                "date_returned, "
                "credit_memo_id) "
                "VALUES "
                "(%s, %s, %s, %s, %s, %s) RETURNING id",
                (qty, invoice_item_id, price, tax, self.date,
                 self.credit_memo_id))
            row_id = c.fetchone()[0]
            self.credit_items_store[_iter][0] = row_id
        DB.commit()
        c.close()

    def new_item_clicked(self, button):
        c = DB.cursor()
        self.check_credit_memo_id()
        invoice_item_id = self.product_store[0][0]
        c.execute(
            "SELECT "
            "0, "
            "1.0::text, "
            "p.id, "
            "p.name, "
            "p.ext_name, "
            "price::text, "
            "price::text, "
            "ROUND(1.0 * price * tr.rate/100, 2)::text, "
            "ii.id, "
            "ii.invoice_id, "
            "CURRENT_DATE::text, "
            "format_date(CURRENT_DATE) "
            "FROM invoice_items AS ii "
            "JOIN products AS p ON p.id = ii.product_id "
            "JOIN tax_rates AS tr ON tr.id = ii.tax_rate_id "
            "WHERE ii.id = %s LIMIT 1", (invoice_item_id, ))
        for row in c.fetchall():
            iter_ = self.credit_items_store.append(row)
            treeview = self.builder.get_object('treeview1')
            column = treeview.get_column(0)
            path = self.credit_items_store.get_path(iter_)
            treeview.set_cursor(path, column, True)

    def delete_item_clicked(self, menuitem):
        selection = self.builder.get_object('treeview-selection1')
        model, path = selection.get_selected_rows()
        if path == []:
            return
        row_id = model[path][0]
        self.cursor.execute(
            "UPDATE credit_memo_items "
            "SET deleted = True "
            "WHERE id = %s", (row_id, ))
        DB.commit()
        self.populate_credit_memo()

    def treeview_key_release_event(self, treeview, event):
        keyname = Gdk.keyval_name(event.keyval)
        path, col = treeview.get_cursor()
        # only visible columns!!
        columns = [c for c in treeview.get_columns() if c.get_visible()]
        colnum = columns.index(col)
        if keyname == "Tab" or keyname == "Esc":
            if colnum + 1 < len(columns):
                next_column = columns[colnum + 1]
            else:
                tmodel = treeview.get_model()
                titer = tmodel.iter_next(tmodel.get_iter(path))
                if titer is None:
                    titer = tmodel.get_iter_first()
                    path = tmodel.get_path(titer)
                    next_column = columns[0]
            if keyname == 'Tab':
                GLib.idle_add(treeview.set_cursor, path, next_column, True)
            elif keyname == 'Escape':
                pass

    def check_credit_memo_id(self):
        if self.credit_memo_id == None:
            self.cursor.execute(
                "INSERT INTO credit_memos "
                "(name, customer_id, date_created, total) "
                "VALUES ('Credit Memo', %s, now(), 0.00) "
                "RETURNING id", (self.customer_id, ))
            self.credit_memo_id = self.cursor.fetchone()[0]
            DB.commit()

    def post_credit_memo_clicked(self, button):
        import credit_memo_template as cmt
        self.credit_memo_template = cmt.Setup(self.credit_items_store,
                                              self.credit_memo_id,
                                              self.customer_id)
        self.credit_memo_template.print_pdf(self.window)
        self.credit_memo_template.post()
        DB.commit()
        self.window.destroy()

    def view_document_activated(self, button):
        if not self.credit_memo_template:
            import credit_memo_template as cmt
            self.credit_memo_template = cmt.Setup(self.credit_items_store,
                                                  self.credit_memo_id,
                                                  self.customer_id)
        self.credit_memo_template.view_odt()

    def comments_buffer_changed(self, textbuffer):
        start = textbuffer.get_start_iter()
        end = textbuffer.get_end_iter()
        notes = textbuffer.get_text(start, end, True)
        self.cursor.execute(
            "UPDATE credit_memos SET comments = %s "
            "WHERE id = %s", (notes, self.credit_memo_id))
        DB.commit()

    def show_message(self, message):
        dialog = Gtk.MessageDialog(message_type=Gtk.MessageType.ERROR,
                                   buttons=Gtk.ButtonsType.CLOSE)
        dialog.set_transient_for(self.window)
        dialog.set_markup(message)
        dialog.run()
        dialog.destroy()
Ejemplo n.º 3
0
class FiscalYearGUI:
    def __init__(self):

        self.builder = Gtk.Builder()
        self.builder.add_from_file(UI_FILE)
        self.builder.connect_signals(self)
        self.cursor = DB.cursor()

        self.start_calendar = DateTimeCalendar(True)
        self.start_calendar.connect('day-selected', self.start_day_selected)
        self.start_calendar.set_today()

        self.end_calendar = DateTimeCalendar(True)
        self.end_calendar.connect('day-selected', self.end_day_selected)
        self.end_calendar.set_date(datetime.today() + timedelta(days=365))

        self.fiscal_year_store = self.builder.get_object('fiscal_year_store')
        self.window = self.builder.get_object('window')
        self.window.show_all()
        self.populate_fiscal_years()

    def destroy(self, widget):
        self.cursor.close()

    def populate_fiscal_years(self):
        self.fiscal_year_store.clear()
        self.cursor.execute("SELECT "
                            "id, "
                            "name, "
                            "start_date::text, "
                            "format_date(start_date), "
                            "end_date::text, "
                            "format_date(end_date), "
                            "active "
                            "FROM fiscal_years ORDER BY start_date")
        for row in self.cursor.fetchall():
            self.fiscal_year_store.append(row)
        DB.rollback()

    def active_toggled(self, toggle_renderer, path):
        active = not toggle_renderer.get_active()
        id_ = self.fiscal_year_store[path][0]
        self.cursor.execute(
            "UPDATE fiscal_years SET active = %s "
            "WHERE id = %s", (active, id_))
        DB.commit()
        self.populate_fiscal_years()

    def fiscal_years_name_edited(self, textrenderer, path, text):
        id_ = self.fiscal_year_store[path][0]
        self.cursor.execute(
            "UPDATE fiscal_years SET name = %s "
            "WHERE id = %s", (text, id_))
        DB.commit()
        self.populate_fiscal_years()

    def create_fiscal_year_clicked(self, button):
        dialog = self.builder.get_object('dialog1')
        response = dialog.run()
        dialog.hide()
        if response == Gtk.ResponseType.ACCEPT:
            fiscal_name = self.builder.get_object('entry1').get_text()
            self.cursor.execute(
                "INSERT INTO fiscal_years "
                "(name, start_date, end_date, active) "
                "VALUES (%s, %s, %s, True)",
                (fiscal_name, self.start_date, self.end_date))
            DB.commit()
            self.builder.get_object('entry1').set_text('')
            self.populate_fiscal_years()

    def start_day_selected(self, calendar):
        self.start_date = calendar.get_datetime()
        day_text = calendar.get_text()
        self.builder.get_object('entry2').set_text(day_text)

    def end_day_selected(self, calendar):
        self.end_date = calendar.get_datetime()
        day_text = calendar.get_text()
        self.builder.get_object('entry3').set_text(day_text)

    def start_date_icon_released(self, entry, position, event):
        self.start_calendar.set_relative_to(entry)
        #self.start_calendar.set_position (Gtk.PositionType.TOP)
        self.start_calendar.show()

    def end_date_icon_released(self, entry, position, event):
        self.end_calendar.set_relative_to(entry)
        self.end_calendar.show()

    def fiscal_year_name_entry_changed(self, entry):
        if entry.get_text() != '':
            self.builder.get_object('button1').set_sensitive(True)
        else:
            self.builder.get_object('button1').set_sensitive(False)
Ejemplo n.º 4
0
class ResourceDiaryGUI:
    def __init__(self, db):

        self.builder = Gtk.Builder()
        self.builder.add_from_file(UI_FILE)
        self.builder.connect_signals(self)

        self.db = db
        self.cursor = self.db.cursor()
        self.populating = False

        textview = self.builder.get_object('textview1')
        spell_check.add_checker_to_widget(textview)

        self.calendar = DateTimeCalendar(self.db)
        self.calendar.connect('day-selected', self.calendar_day_selected)
        self.calendar.set_today()

        self.window = self.builder.get_object('window1')
        self.window.show_all()

    def add_day_info(self):
        self.populating = True
        cursor = self.db.cursor()
        cursor.execute(
            "WITH date_range AS "
            "(SELECT generate_series "
            "(%s - INTERVAL '4 year', "
            "%s,  '1 year' "
            ") AS diary_date "
            ") "
            "SELECT "
            "COALESCE(subject, ''), "
            "to_char(date_range.diary_date, 'Dy FMMonth DD YYYY') "
            "FROM date_range "
            "LEFT JOIN resources "
            "ON date_range.diary_date = resources.dated_for "
            "AND diary = True "
            "ORDER BY date_range.diary_date DESC", (self.day, self.day))
        tupl = cursor.fetchall()

        subject0 = tupl[0][0]
        date0 = tupl[0][1]

        self.builder.get_object('label1').set_label(date0)
        self.builder.get_object('entry1').set_text(date0)
        self.builder.get_object('textbuffer1').set_text(subject0)

        subject1 = tupl[1][0]
        date1 = tupl[1][1]

        self.builder.get_object('label2').set_label(date1)
        self.builder.get_object('textbuffer2').set_text(subject1)

        subject2 = tupl[2][0]
        date2 = tupl[2][1]

        self.builder.get_object('label3').set_label(date2)
        self.builder.get_object('textbuffer3').set_text(subject2)

        subject3 = tupl[3][0]
        date3 = tupl[3][1]

        self.builder.get_object('label4').set_label(date3)
        self.builder.get_object('textbuffer4').set_text(subject3)

        subject4 = tupl[4][0]
        date4 = tupl[4][1]

        self.builder.get_object('label5').set_label(date4)
        self.builder.get_object('textbuffer5').set_text(subject4)
        cursor.close()
        self.populating = False

    def next_day_clicked(self, button):
        self.day = (self.day + timedelta(days=1))
        self.calendar.set_date(
            self.day)  # this will fire signal and update views

    def previous_day_clicked(self, button):
        self.day = (self.day - timedelta(days=1))
        self.calendar.set_date(
            self.day)  # this will fire signal and update views

    def diary_textbuffer_changed(self, textbuffer):
        if self.populating == True:
            return
        end = textbuffer.get_end_iter()
        start = textbuffer.get_start_iter()
        text = textbuffer.get_text(start, end, True)
        self.cursor.execute(
            "INSERT INTO resources "
            "(subject, dated_for, diary) "
            "VALUES (%s, %s, True) "
            "ON CONFLICT (dated_for, diary) "
            "DO UPDATE SET subject = %s "
            "WHERE (resources.diary, resources.dated_for) = "
            "(True, %s)", (text, self.day, text, self.day))
        self.db.commit()

    def entry_icon_release(self, entry, position, button):
        self.calendar.set_relative_to(entry)
        self.calendar.show()

    def calendar_day_selected(self, calendar):
        self.day = calendar.get_date()
        text = calendar.get_user_text()
        self.add_day_info()
Ejemplo n.º 5
0
class IncomingInvoiceGUI(Gtk.Builder):
	__gsignals__ = { 
	'invoice_applied': (GObject.SignalFlags.RUN_FIRST, GObject.TYPE_NONE, ())
	}
	"""the invoice_applied signal is used to send a message to the parent 
		window that the incoming invoice is now finished"""
	def __init__(self):

		GObject.GObject.__init__(self)
		Gtk.Builder.__init__(self)
		self.add_from_file(UI_FILE)
		self.connect_signals(self)
		self.cursor = DB.cursor()

		self.handler_ids = list()
		for connection in (("contacts_changed", self.populate_service_providers ),):
			handler = broadcaster.connect(connection[0], connection[1])
			self.handler_ids.append(handler)
		self.expense_account_store = expense_tree
		self.get_object('cellrenderercombo1').set_property('model', expense_tree)
		self.get_object('account_completion').set_model(expense_list)
		
		self.calendar = DateTimeCalendar()
		self.calendar.connect('day-selected', self.calendar_day_selected)
		self.date = None

		price_column = self.get_object ('treeviewcolumn2')
		price_renderer = self.get_object ('cellrenderertext1')
		price_column.set_cell_data_func(price_renderer, self.price_cell_func)
		provider_completion = self.get_object('provider_completion')
		provider_completion.set_match_func(self.provider_match_func)
		
		self.populating = False
		self.service_provider_store = self.get_object(
													'service_provider_store')
		self.expense_percentage_store = self.get_object(
													'expense_percentage_store')
		self.bank_account_store = self.get_object('bank_account_store')
		self.cash_account_store = self.get_object('cash_account_store')
		self.credit_card_store = self.get_object('credit_card_store')
		self.populate_stores ()
		self.populate_service_providers ()
		self.expense_percentage_store.append([0, Decimal('1.00'), 0, "", "", ""])
	
		self.window = self.get_object('window1')
		self.window.show_all()
		self.file_data = None

	def destroy (self, widget):
		for handler in self.handler_ids:
			broadcaster.disconnect(handler)
		self.cursor.close()

	def provider_match_func(self, completion, key, iter_):
		split_search_text = key.split()
		for text in split_search_text:
			if text not in self.service_provider_store[iter_][1].lower():
				return False
		return True

	def amount_focus_in_event (self, spinbutton, event):
		GLib.idle_add(spinbutton.select_region, 0, -1)

	def focus (self, window, event):
		pass
		self.populating = False

	def populate_service_providers (self, m=None, i=None):
		self.populating = True
		combo = self.get_object('combobox1')
		active_sp = combo.get_active_id()
		self.service_provider_store.clear()
		self.cursor.execute("SELECT id::text, name, ext_name FROM contacts "
							"WHERE service_provider = True "
							"ORDER BY name")
		for row in self.cursor.fetchall():
			self.service_provider_store.append(row)
		combo.set_active_id(active_sp)
		self.populating = False
		DB.rollback()

	def populate_stores (self):
		self.cursor.execute("SELECT number::text, name FROM gl_accounts "
							"WHERE check_writing = True ORDER BY name ")
		for row in self.cursor.fetchall():
			self.bank_account_store.append(row)
		self.cursor.execute("SELECT number::text, name FROM gl_accounts "
							"WHERE cash_account = True ORDER BY name ")
		for row in self.cursor.fetchall():
			self.cash_account_store.append(row)
		self.cursor.execute("SELECT number::text, name FROM gl_accounts "
							"WHERE credit_card_account = True ORDER BY name ")
		for row in self.cursor.fetchall():
			self.credit_card_store.append(row)
		DB.rollback()

	def set_shipping_description (self, text):
		self.get_object('entry1').set_text(text)

	def set_date (self, date):
		self.calendar.set_date(date)

	def service_provider_clicked (self, button):
		import contacts_overview
		contacts_overview.ContactsOverviewGUI()
		
	def provider_match_selected(self, completion, model, iter_):
		self.provider_id = model[iter_][0]
		self.get_object('combobox1').set_active_id(self.provider_id)

	def service_provider_combo_changed (self, combo):
		if self.populating == True:
			return
		a_iter = combo.get_active_iter()
		if a_iter == None:
			return
		self.check_if_all_entries_valid ()
		contact_name = self.service_provider_store[a_iter][1]
		self.get_object('label14').set_label(contact_name)

	def add_percentage_row_clicked (self, button):
		self.expense_percentage_store.append([0, Decimal('1.00'), 0, "", "", ""])
		self.add_expense_totals ()

	def delete_percentage_row_clicked (self, button):
		selection = self.get_object('treeview-selection1')
		model, path = selection.get_selected_rows()
		if path != []:
			tree_iter = model.get_iter(path)
			self.expense_percentage_store.remove(tree_iter)
		self.add_expense_totals ()

	def equalize_amounts_clicked (self, button):
		lines = self.expense_percentage_store.iter_n_children()
		if lines == 0:
			return
		percentage = Decimal('100') / lines
		invoice_amount = self.get_object('spinbutton1').get_text()
		percent = Decimal(percentage) / Decimal('100')
		split_amount = Decimal(invoice_amount) * percent
		for row in self.expense_percentage_store:
			row[0] = percentage
			row[1] = split_amount
		self.add_expense_totals ()

	def invoice_spinbutton_changed (self, spinbutton):
		self.add_expense_totals ()

	def expense_amount_edited (self, renderer, path, text):
		value = Decimal(text).quantize(Decimal('0.01'), rounding = ROUND_HALF_UP)
		self.expense_percentage_store[path][1] = value
		self.add_expense_totals ()

	def price_cell_func(self, column, cellrenderer, model, iter1, data):
		price = model.get_value(iter1, 1)
		cellrenderer.set_property("text" , str(price))

	def percent_render_edited (self, renderer, path, text):
		self.expense_percentage_store[path][0] = int(text)
		invoice_amount = self.get_object('spinbutton1').get_text()
		percent = Decimal(text) / Decimal('100')
		split_amount = Decimal(invoice_amount) * percent
		self.expense_percentage_store[path][1] = split_amount
		self.add_expense_totals ()

	def add_expense_totals (self):
		total = Decimal()
		for row in self.expense_percentage_store:
			total += row[1]
		money_text = get_written_check_amount_text (total)
		self.get_object('label10').set_label(money_text)
		self.get_object('entry4').set_text('${:,.2f}'.format(total))
		self.get_object('entry5').set_text('${:,.2f}'.format(total))
		self.get_object('entry6').set_text('${:,.2f}'.format(total))
		self.get_object('entry8').set_text('${:,.2f}'.format(total))
		self.check_if_all_entries_valid ()

	def expense_account_render_changed (self, renderer, path, tree_iter):
		account_number = self.expense_account_store[tree_iter][0]
		account_name = self.expense_account_store[tree_iter][1]
		account_path = self.expense_account_store[tree_iter][2]
		self.expense_percentage_store[path][2] = int(account_number)
		self.expense_percentage_store[path][3] = account_name
		self.expense_percentage_store[path][4] = account_path
		self.check_if_all_entries_valid ()

	def expense_combo_editing_started (self, cellrenderer, celleditable, path):
		entry = celleditable.get_child()
		entry.set_completion(self.get_object('account_completion'))

	def account_match_selected (self, entrycompletion, model, treeiter):
		selection = self.get_object('treeview-selection1')
		treeview_model, path = selection.get_selected_rows()
		if path == []:
			return
		account_number = model[treeiter][0]
		account_name = model[treeiter][1]
		account_path = model[treeiter][2]
		treeview_model[path][2] = int(account_number)
		treeview_model[path][3] = account_name
		treeview_model[path][4] = account_path
		self.check_if_all_entries_valid()

	def remark_edited (self, cellrenderertext, path, text):
		self.expense_percentage_store[path][5] = text

	def bank_credit_card_combo_changed (self, combo):
		if combo.get_active() == None:
			self.get_object('entry3').set_sensitive(False)
			self.get_object('entry5').set_sensitive(False)
		else:
			self.get_object('entry3').set_sensitive(True)
			self.get_object('entry5').set_sensitive(True)
			bank_account = combo.get_active_id()
			check_number = get_check_number(bank_account)
			self.get_object('entry7').set_text(str(check_number))
		self.check_if_all_entries_valid ()

	def cash_combo_changed (self, combo):
		self.check_if_all_entries_valid ()

	def transaction_entry_changed (self, entry):
		self.check_if_all_entries_valid ()

	def credit_card_changed (self, combo):
		self.check_if_all_entries_valid ()

	def check_if_all_entries_valid (self):
		check_button = self.get_object('button3')
		transfer_button = self.get_object('button4')
		cash_button = self.get_object('button5')
		credit_card_button = self.get_object('button7')
		check_button.set_sensitive(False)
		#transfer_button.set_sensitive(False)
		cash_button.set_sensitive(False)
		credit_card_button.set_sensitive(False)
		if self.get_object('combobox1').get_active() == -1:
			self.set_button_message('No service provider')
			return # no service provider selected
		if self.date == None:
			self.set_button_message('No date selected')
			return
		invoice_amount = Decimal(self.get_object('spinbutton1').get_text())
		if invoice_amount == 0.00:
			self.set_button_message('No invoice amount')
			return
		text = self.get_object('entry4').get_text()
		payment_amount = Decimal(re.sub("[^0-9.]", "", text))
		if invoice_amount != payment_amount:
			self.set_button_message('Invoice amount does not match payment')
			return
		for row in self.expense_percentage_store:
			if row[2] == 0:
				self.set_button_message('Missing expense accounts')
				return
		if self.get_object('combobox3').get_active() > -1:
			#cash account selected
			cash_button.set_label('Cash payment')
			cash_button.set_sensitive(True)
		else:
			cash_button.set_label('No cash account selected')
		if self.get_object('combobox4').get_active() > -1:
			#cash account selected
			credit_card_button.set_label('Credit card payment')
			credit_card_button.set_sensitive(True)
		else:
			credit_card_button.set_label('No credit card selected')
		if self.get_object('combobox2').get_active() > -1:
			# bank / credit card selected
			check_button.set_label('Check payment')
			check_button.set_sensitive(True)
			transfer_button.set_label('Transfer payment')
			transfer_button.set_sensitive(True)
		else:
			check_button.set_label('No bank account selected')
			transfer_button.set_label('No bank account selected')

	def set_button_message (self, message):
		self.get_object('button3').set_label(message)
		self.get_object('button4').set_label(message)
		self.get_object('button5').set_label(message)
		self.get_object('button7').set_label(message)

	def cash_payment_clicked (self, button):
		total = self.save_incoming_invoice ()
		cash_account = self.get_object('combobox3').get_active_id()
		self.invoice.cash_payment (total, cash_account)
		DB.commit()
		button.set_sensitive(False)
		self.emit('invoice_applied')

	def credit_card_payment_clicked (self, button):
		total = self.save_incoming_invoice ()
		credit_card = self.get_object('combobox4').get_active_id()
		transfer_number = self.get_object('entry3').get_text()
		active = self.get_object('combobox1').get_active()
		service_provider = self.service_provider_store[active][1]
		description = "%s : %s" % (service_provider, transfer_number)
		self.invoice.credit_card_payment (total, description, credit_card)
		DB.commit()
		button.set_sensitive(False)
		self.emit('invoice_applied')

	def transfer_clicked (self, button):
		total = self.save_incoming_invoice ()
		checking_account = self.get_object('combobox2').get_active_id()
		transfer_number = self.get_object('entry3').get_text()
		active = self.get_object('combobox1').get_active()
		service_provider = self.service_provider_store[active][1]
		description = "%s : %s" % (service_provider, transfer_number)
		self.invoice.transfer (total, description, checking_account)
		DB.commit()
		button.set_sensitive(False)
		self.emit('invoice_applied')

	def post_only_clicked (self,button):
		self.perform_payment()
		button.set_sensitive(False)

	def perform_payment(self):
		total = self.save_incoming_invoice ()
		checking_account = self.get_object('combobox2').get_active_id()
		check_number = self.get_object('entry7').get_text()
		active = self.get_object('combobox1').get_active()
		description = self.service_provider_store[active][1]
		self.invoice.check_payment(total, check_number, checking_account, description)
		DB.commit()
		self.emit('invoice_applied')
		check_number = get_check_number(checking_account)
		self.get_object('entry7').set_text(str(check_number))
		self.file_data = None

	def save_incoming_invoice (self):
		c = DB.cursor()
		contact_id = self.get_object('combobox1').get_active_id()
		description = self.get_object('entry1').get_text()
		total = Decimal(self.get_object('spinbutton1').get_text())
		self.invoice = transactor.ServiceProviderPayment (
															self.date, 
															total)
		c.execute(	"INSERT INTO incoming_invoices "
						"(contact_id, "
						"date_created, "
						"amount, "
						"description, "
						"gl_transaction_id, "
						"attached_pdf) "
					"VALUES (%s, %s, %s, %s, %s, %s) RETURNING id", 
					(contact_id, self.date, total, description, 
					self.invoice.transaction_id, self.file_data))
		self.invoice_id = c.fetchone()[0] # self.invoice_id is a public variable
		self.invoice.incoming_invoice_id = self.invoice_id
		for row in self.expense_percentage_store:
			amount = row[1]
			account = row[2]
			remark = row[5]
			self.invoice.expense(amount, account, remark)
		c.close()
		return total

	def balance_this_row_activated (self, menuitem):
		selection = self.get_object('treeview-selection1')
		model, path = selection.get_selected_rows()
		if path == []:
			return
		tree_sum = Decimal()
		for row in self.expense_percentage_store:
			if row.path != path[0]:
				tree_sum += row[1]
		total = Decimal(self.get_object('spinbutton1').get_text())
		model[path][1] = (total - tree_sum)
		self.add_expense_totals ()

	def treeview_button_release_event (self, treeview, event):
		if event.button == 3:
			menu = self.get_object('menu1')
			menu.popup_at_pointer()

	def calendar_day_selected (self, calendar):
		self.date = calendar.get_date()
		day_text = calendar.get_text()
		self.get_object('entry2').set_text(day_text)
		self.check_if_all_entries_valid ()

	def calendar_entry_icon_released (self, widget, icon, event):
		self.calendar.set_relative_to(widget)
		self.calendar.show()

	def attach_button_clicked (self, button):
		import pdf_attachment
		paw = pdf_attachment.PdfAttachmentWindow(self.window)
		paw.connect("pdf_optimized", self.optimized_callback)

	def optimized_callback (self, pdf_attachment_window):
		self.file_data = pdf_attachment_window.get_pdf ()

	def print_and_post_clicked (self, button):
		total = Decimal(self.get_object('spinbutton1').get_text())
		check_number = self.get_object('entry7').get_text()
		bank_account = self.get_object('combobox2').get_active_id()
		self.cursor.execute("SELECT "
								"name, "
								"checks_payable_to, "
								"address, "
								"city, "
								"state, "
								"zip, "
								"phone "
							"FROM contacts WHERE id = %s",(self.provider_id,))
		provider = Item()
		for line in self.cursor.fetchall():
			provider.name = line[0]
			provider.pay_to = line[1]
			provider.street = line[2]
			provider.city = line[3]
			provider.state = line[4]
			provider.zip = line[5]
			provider.phone = line[6]
			pay_to = line[1].split()[0]
		items = list()
		'''for row in self.provider_invoice_store:
			if row[3] == True:'''
				
		item = Item()
		item.po_number = ''#row[0] 
		item.amount = ''#row[2]
		item.date = ''#row[4]
		items.append(item)
		check = Item()
		check.check_number = check_number
		check.checking_account = bank_account
		check.date = self.date
		check.amount = total 
		check.amount_text = get_written_check_amount_text (total)
		from py3o.template import Template
		data = dict(contact = provider, check = check, items = items )#- kept this
		#in case we ever wish to list the accountbreakdown on the check stubs
		self.tmp_file = "/tmp/check" + pay_to +".odt"
		self.tmp_file_pdf = "/tmp/check" + pay_to + ".pdf"
		t = Template(template_dir+"/vendor_check_template.odt", self.tmp_file, True)
		t.render(data)
		subprocess.call(["odt2pdf", self.tmp_file])
		p = printing.Operation(settings_file = 'Vendor_check')
		p.set_file_to_print(self.tmp_file_pdf)
		p.set_parent(self.window)
		result = p.print_dialog()
		if result != "user canceled":
			self.perform_payment()
Ejemplo n.º 6
0
class EmployeeInfoGUI:
    def __init__(self, db):

        self.builder = Gtk.Builder()
        self.builder.add_from_file(UI_FILE)
        self.builder.connect_signals(self)

        self.employee_store = self.builder.get_object('employee_store')
        self.s_s_medicare_store = self.builder.get_object('s_s_medicare_store')
        self.federal_withholding_store = self.builder.get_object(
            'federal_withholding_store')
        self.state_withholding_store = self.builder.get_object(
            'state_withholding_store')

        self.db = db
        self.cursor = db.cursor()

        self.populate_employee_store()
        self.born_calendar = DateTimeCalendar(self.db)
        self.on_payroll_since_calendar = DateTimeCalendar(self.db)
        self.born_calendar.connect("day-selected",
                                   self.born_calendar_date_selected)
        self.on_payroll_since_calendar.connect(
            "day-selected", self.on_payroll_since_calendar_date_selected)

        self.window = self.builder.get_object('window1')
        self.window.show_all()

        self.builder.get_object("button5").set_label("No scanner selected")
        self.builder.get_object("button5").set_sensitive(False)

        #self.data_queue = Queue()
        #self.scanner_store = self.builder.get_object("scanner_store")
        #thread = Process(target=self.get_scanners)
        #thread.start()

        #GLib.timeout_add(100, self.populate_scanners)

    def populate_scanners(self):
        try:
            devices = self.data_queue.get_nowait()
            for scanner in devices:
                device_id = scanner[0]
                device_manufacturer = scanner[1]
                name = scanner[2]
                given_name = scanner[3]
                self.scanner_store.append(
                    [str(device_id), device_manufacturer, name, given_name])
        except Empty:
            return True

    def get_scanners(self):
        sane.init()
        devices = sane.get_devices()
        self.data_queue.put(devices)

    def populate_employee_store(self):
        self.populating = True
        self.employee_store.clear()
        self.cursor.execute("SELECT id, name FROM contacts "
                            "WHERE employee = True")
        for row in self.cursor.fetchall():
            employee_id = row[0]
            employee_name = row[1]
            self.employee_store.append([employee_id, employee_name])
        self.populating = False

    def employee_treeview_cursor_changed(self, treeview):
        if self.populating == True:
            return
        selection = self.builder.get_object('treeview-selection1')
        model, path = selection.get_selected_rows()
        self.employee_id = model[path][0]
        self.employee_selected()

    def employee_selected(self):
        self.populating = True
        self.cursor.execute(
            "SELECT COALESCE(born, '1970-1-1'), "
            "COALESCE (social_security, ''), "
            "COALESCE (social_security_exempt, False), "
            "COALESCE (on_payroll_since, '1970-1-1'), "
            "COALESCE (wage, 10.00), "
            "COALESCE (payment_frequency, 10), "
            "COALESCE (married, False), "
            "COALESCE (last_updated, '1970-1-1'), "
            "COALESCE (state_withholding_exempt, False), "
            "COALESCE (state_credits, 0), "
            "COALESCE (state_extra_withholding, 0.00), "
            "COALESCE (fed_withholding_exempt, False), "
            "COALESCE (fed_credits, 0), "
            "COALESCE (fed_extra_withholding, 0.00) "
            "FROM payroll.employee_info WHERE employee_id = %s",
            (self.employee_id, ))
        for row in self.cursor.fetchall():
            self.born_calendar.set_date(row[0])
            self.builder.get_object('entry2').set_text(row[1])
            self.builder.get_object('checkbutton3').set_active(row[2])
            self.on_payroll_since_calendar.set_date(row[3])
            self.builder.get_object('spinbutton6').set_value(row[4])
            self.builder.get_object('spinbutton5').set_value(row[5])
            self.builder.get_object('checkbutton4').set_active(row[6])
            self.builder.get_object('label6').set_text(row[7])
            self.builder.get_object('checkbutton2').set_active(row[8])
            self.builder.get_object('spinbutton3').set_value(row[9])
            self.builder.get_object('spinbutton2').set_value(row[10])
            self.builder.get_object('checkbutton1').set_active(row[11])
            self.builder.get_object('spinbutton4').set_value(row[12])
            self.builder.get_object('spinbutton1').set_value(row[13])
            break
        else:
            self.cursor.execute(
                "INSERT INTO payroll.employee_info (employee_id) "
                "VALUES (%s)", (self.employee_id, ))
            self.db.commit()
            GLib.timeout_add(50, self.employee_selected)
        self.populating = False
        self.populate_exemption_forms()

    def populate_exemption_forms(self):
        self.s_s_medicare_store.clear()
        self.state_withholding_store.clear()
        self.federal_withholding_store.clear()
        self.cursor.execute(
            "SELECT id, date_inserted "
            "FROM payroll.emp_pdf_archive "
            "WHERE employee_id = %s "
            "AND s_s_medicare_exemption_pdf IS NOT NULL "
            "ORDER BY id", (self.employee_id, ))
        for row in self.cursor.fetchall():
            id = row[0]
            date_formatted = date_to_user_format(row[1])
            self.s_s_medicare_store.append([id, date_formatted])
        self.cursor.execute(
            "SELECT id, date_inserted "
            "FROM payroll.emp_pdf_archive "
            "WHERE employee_id = %s "
            "AND state_withholding_pdf IS NOT NULL "
            "ORDER BY id", (self.employee_id, ))
        for row in self.cursor.fetchall():
            id = row[0]
            date_formatted = date_to_user_format(row[1])
            self.state_withholding_store.append([id, date_formatted])
        self.cursor.execute(
            "SELECT id, date_inserted "
            "FROM payroll.emp_pdf_archive "
            "WHERE employee_id = %s "
            "AND fed_withholding_pdf IS NOT NULL "
            "ORDER BY id", (self.employee_id, ))
        for row in self.cursor.fetchall():
            id = row[0]
            date_formatted = date_to_user_format(row[1])
            self.federal_withholding_store.append([id, date_formatted])

    def s_s_m_row_activated(self, treeview, path, column):
        model = treeview.get_model()
        id = model[path][0]
        self.cursor.execute(
            "SELECT s_s_medicare_exemption_pdf "
            "FROM payroll.emp_pdf_archive "
            "WHERE id = %s", (id, ))
        for row in self.cursor.fetchall():
            file_data = row[0]
            file_name = "/tmp/Social_security_medicare_exemption.pdf"
            f = open(file_name, 'wb')
            f.write(file_data)
            subprocess.Popen("xdg-open %s" % file_name, shell=True)
            f.close()

    def federal_withholding_row_activated(self, treeview, path, column):
        model = treeview.get_model()
        id = model[path][0]
        self.cursor.execute(
            "SELECT fed_withholding_pdf "
            "FROM payroll.emp_pdf_archive "
            "WHERE id = %s", (id, ))
        for row in self.cursor.fetchall():
            file_data = row[0]
            file_name = "/tmp/Federal_withholding_exemption.pdf"
            f = open(file_name, 'wb')
            f.write(file_data)
            subprocess.Popen("xdg-open %s" % file_name, shell=True)
            f.close()

    def state_withholding_row_activated(self, treeview, path, column):
        model = treeview.get_model()
        id = model[path][0]
        self.cursor.execute(
            "SELECT state_withholding_pdf "
            "FROM payroll.emp_pdf_archive "
            "WHERE id = %s", (id, ))
        for row in self.cursor.fetchall():
            file_data = row[0]
            file_name = "/tmp/State_withholding_exemption.pdf"
            f = open(file_name, 'wb')
            f.write(file_data)
            subprocess.Popen("xdg-open %s" % file_name, shell=True)
            f.close()

    def payment_frequency_value_changed(self, spinbutton):
        if self.populating == True:
            return
        payment_frequency = spinbutton.get_value()
        self.cursor.execute(
            "UPDATE payroll.employee_info "
            "SET (payment_frequency, last_updated) = (%s, %s) "
            "WHERE employee_id = %s",
            (payment_frequency, datetime.today(), self.employee_id))
        self.db.commit()

    def state_income_status_toggled(self, checkbutton):
        if self.populating == True:
            return
        status = checkbutton.get_active()
        self.cursor.execute(
            "UPDATE payroll.employee_info "
            "SET (state_withholding_exempt, last_updated) = (%s, %s) "
            "WHERE employee_id = %s",
            (status, datetime.today(), self.employee_id))
        self.db.commit()

    def state_credits_value_changed(self, spinbutton):
        if self.populating == True:
            return
        state_credits = spinbutton.get_value()
        self.cursor.execute(
            "UPDATE payroll.employee_info "
            "SET (state_credits, last_updated) = (%s, %s) "
            "WHERE employee_id = %s",
            (state_credits, datetime.today(), self.employee_id))
        self.db.commit()

    def state_extra_withholding_value_changed(self, spinbutton):
        if self.populating == True:
            return
        state_withholding = spinbutton.get_value()
        self.cursor.execute(
            "UPDATE payroll.employee_info "
            "SET (state_extra_withholding, last_updated) = "
            "(%s, %s) "
            "WHERE employee_id = %s",
            (state_withholding, datetime.today(), self.employee_id))
        self.db.commit()

    def federal_income_status_toggled(self, checkbutton):
        if self.populating == True:
            return
        status = checkbutton.get_active()
        self.cursor.execute(
            "UPDATE payroll.employee_info "
            "SET (fed_withholding_exempt, last_updated) = (%s, %s) "
            "WHERE employee_id = %s",
            (status, datetime.today(), self.employee_id))
        self.db.commit()

    def federal_credits_value_changed(self, spinbutton):
        if self.populating == True:
            return
        federal_credits = spinbutton.get_value()
        self.cursor.execute(
            "UPDATE payroll.employee_info "
            "SET (fed_credits, last_updated) = (%s, %s) "
            "WHERE employee_id = %s",
            (federal_credits, datetime.today(), self.employee_id))
        self.db.commit()

    def federal_extra_withholding_value_changed(self, spinbutton):
        if self.populating == True:
            return
        fed_withholding = spinbutton.get_value()
        self.cursor.execute(
            "UPDATE payroll.employee_info "
            "SET (fed_extra_withholding, last_updated) = "
            "(%s, %s) "
            "WHERE employee_id = %s",
            (fed_withholding, datetime.today(), self.employee_id))
        self.db.commit()

    def married_checkbutton_toggled(self, checkbutton):
        if self.populating == True:
            return
        married = checkbutton.get_active()
        self.cursor.execute(
            "UPDATE payroll.employee_info "
            "SET (married, last_updated) = (%s, %s) "
            "WHERE employee_id = %s",
            (married, datetime.today(), self.employee_id))
        self.db.commit()

    def social_security_entry_changed(self, entry):
        if self.populating == True:
            return
        s_s = entry.get_text()
        self.cursor.execute(
            "UPDATE payroll.employee_info "
            "SET (social_security, last_updated) = (%s, %s) "
            "WHERE employee_id = %s",
            (s_s, datetime.today(), self.employee_id))
        self.db.commit()

    def wage_spinbutton_value_changed(self, spinbutton):
        if self.populating == True:
            return
        wage = spinbutton.get_value()
        self.cursor.execute(
            "UPDATE payroll.employee_info "
            "SET (wage, last_updated) = (%s, %s) "
            "WHERE employee_id = %s",
            (wage, datetime.today(), self.employee_id))
        self.db.commit()

    def social_security_exemption_changed(self, checkbutton):
        if self.populating == True:
            return
        exemption = checkbutton.get_active()
        self.cursor.execute(
            "UPDATE payroll.employee_info "
            "SET (social_security_exempt, last_updated) = (%s, %s) "
            "WHERE employee_id = %s",
            (exemption, datetime.today(), self.employee_id))
        self.db.commit()

    def scanner_combo_changed(self, combo):
        if combo.get_active() > -1:
            self.builder.get_object("button5").set_label("Scan")
            self.builder.get_object("button5").set_sensitive(True)

    def show_scan_pdf_dialog(self, column):
        global device
        dialog = self.builder.get_object("dialog1")
        result = dialog.run()
        dialog.hide()
        if result != Gtk.ResponseType.ACCEPT:
            return
        if device == None:
            device_address = self.builder.get_object(
                "combobox1").get_active_id()
            device = sane.open(device_address)
        document = device.scan()
        path = "/tmp/posting_pdf.pdf"
        document.save(path)
        f = open(path, 'rb')
        file_data = f.read()
        binary = psycopg2.Binary(file_data)
        f.close()
        self.cursor.execute(
            "UPDATE payroll.emp_pdf_archive "
            "SET archived = True "
            "WHERE employee_id = %s "
            "AND " + column + " IS NOT NULL", (self.employee_id, ))
        self.cursor.execute(
            "INSERT INTO payroll.emp_pdf_archive "
            "( " + column + ", employee_id, date_inserted) "
            "VALUES (%s, %s, %s)",
            (binary, self.employee_id, datetime.today()))
        self.db.commit()
        self.populate_exemption_forms()

    def state_button_release_event(self, button, event):
        if event.button == 1:
            self.cursor.execute(
                "SELECT state_withholding_pdf "
                "FROM payroll.emp_pdf_archive "
                "WHERE (employee_id, archived) = (%s, False) "
                "AND state_withholding_pdf IS NOT NULL", (self.employee_id, ))
            for row in self.cursor.fetchall():
                file_data = row[0]
                file_name = "/tmp/State_withholding_status.pdf"
                f = open(file_name, 'wb')
                f.write(file_data)
                subprocess.Popen("xdg-open %s" % file_name, shell=True)
                f.close()
                break
            else:
                label = 'Do you want to add a file from the scanner?'
                self.builder.get_object('label9').set_label(label)
                self.show_scan_pdf_dialog("state_withholding_pdf")
        elif event.button == 3:
            label = 'Do you want to update the file from the scanner?'
            self.builder.get_object('label9').set_label(label)
            self.show_scan_pdf_dialog("state_withholding_pdf")

    def s_s_m_button_release_event(self, button, event):
        if event.button == 1:
            self.cursor.execute(
                "SELECT s_s_medicare_exemption_pdf "
                "FROM payroll.emp_pdf_archive "
                "WHERE (employee_id, archived) = (%s, False) "
                "AND s_s_medicare_exemption_pdf IS NOT NULL",
                (self.employee_id, ))
            for row in self.cursor.fetchall():
                file_data = row[0]
                file_name = "/tmp/Social_security_and_medicare_exemption.pdf"
                f = open(file_name, 'wb')
                f.write(file_data)
                subprocess.Popen("xdg-open %s" % file_name, shell=True)
                f.close()
                break
            else:
                label = 'Do you want to add a file from the scanner?'
                self.builder.get_object('label9').set_label(label)
                self.show_scan_pdf_dialog("s_s_medicare_exemption_pdf")
        elif event.button == 3:
            label = 'Do you want to update the file from the scanner?'
            self.builder.get_object('label9').set_label(label)
            self.show_scan_pdf_dialog("s_s_medicare_exemption_pdf")

    def fed_button_release_event(self, button, event):
        if event.button == 1:
            self.cursor.execute(
                "SELECT fed_withholding_pdf "
                "FROM payroll.emp_pdf_archive "
                "WHERE (employee_id, archived) = (%s, False) "
                "AND fed_withholding_pdf IS NOT NULL", (self.employee_id, ))
            for row in self.cursor.fetchall():
                file_data = row[0]
                file_name = "/tmp/Federal_withholding_exemption.pdf"
                f = open(file_name, 'wb')
                f.write(file_data)
                subprocess.Popen("xdg-open %s" % file_name, shell=True)
                f.close()
                break
            else:  # table
                label = 'Do you want to add a file from the scanner?'
                self.builder.get_object('label9').set_label(label)
                self.show_scan_pdf_dialog("fed_withholding_pdf")
        elif event.button == 3:
            label = 'Do you want to update the file from the scanner?'
            self.builder.get_object('label9').set_label(label)
            self.show_scan_pdf_dialog("fed_withholding_pdf")

    def born_calendar_date_selected(self, calendar):
        date_text = calendar.get_text()
        self.builder.get_object('entry1').set_text(date_text)
        if self.populating == True:
            return
        date = calendar.get_date()
        self.cursor.execute(
            "UPDATE payroll.employee_info "
            "SET (born, last_updated) = (%s, %s) "
            "WHERE employee_id = %s",
            (date, datetime.today(), self.employee_id))
        self.db.commit()

    def born_entry_icon_released(self, entry, icon, event):
        self.born_calendar.set_relative_to(entry)
        self.born_calendar.show()

    def on_payroll_since_calendar_date_selected(self, calendar):
        date_text = calendar.get_text()
        self.builder.get_object('entry3').set_text(date_text)
        if self.populating == True:
            return
        date = calendar.get_date()
        self.cursor.execute(
            "UPDATE payroll.employee_info "
            "SET (on_payroll_since, last_updated) = (%s, %s) "
            "WHERE employee_id = %s",
            (date, datetime.today(), self.employee_id))
        self.db.commit()

    def on_payroll_since_entry_icon_released(self, entry, icon, event):
        self.on_payroll_since_calendar.set_relative_to(entry)
        self.on_payroll_since_calendar.show()
Ejemplo n.º 7
0
class InvoiceGUI:
	
	def __init__(self, main, invoice_id = None):
		
		self.invoice_id = invoice_id
		self.builder = Gtk.Builder()
		self.builder.add_from_file(UI_FILE)
		self.builder.connect_signals(self)
		self.window = self.builder.get_object('window')
		self.edited_renderer_text = 1
		self.qty_renderer_value = 1
		self.invoice = None

		self.main = main
		self.db = main.db
		
		self.populating = False
		self.invoice_store = self.builder.get_object('invoice_store')
		self.location_store = self.builder.get_object('location_store')
		self.document_list_store = self.builder.get_object('document_list_store')
		
		enforce_target = Gtk.TargetEntry.new('text/plain', Gtk.TargetFlags(1), 129)
		self.treeview = self.builder.get_object('treeview2')
		self.treeview.drag_dest_set(Gtk.DestDefaults.ALL, [enforce_target], Gdk.DragAction.COPY)
		self.treeview.connect("drag-data-received", self.on_drag_data_received)
		self.treeview.drag_dest_set_target_list([enforce_target])
		self.cursor = self.db.cursor()
		self.handler_c_id = main.connect ("contacts_changed", self.populate_customer_store )
		self.handler_p_id = main.connect ("products_changed", self.populate_product_store )
		self.customer_id = 0
		self.menu_visible = False
		
		textview = self.builder.get_object('comment_textview')
		spell_check.add_checker_to_widget (textview)
			
		self.customer_store = self.builder.get_object('customer_store')
		self.product_store = self.builder.get_object('product_store')
		self.barcodes_not_found_store = self.builder.get_object('barcodes_not_found_store')
		product_completion = self.builder.get_object('product_completion')
		product_completion.set_match_func(self.product_match_func)
		customer_completion = self.builder.get_object('customer_completion')
		customer_completion.set_match_func(self.customer_match_func)

		qty_column = self.builder.get_object ('treeviewcolumn1')
		qty_renderer = self.builder.get_object ('cellrenderertext2')
		qty_column.set_cell_data_func(qty_renderer, self.qty_cell_func)

		price_column = self.builder.get_object ('treeviewcolumn4')
		price_renderer = self.builder.get_object ('cellrenderertext5')
		price_column.set_cell_data_func(price_renderer, self.price_cell_func)

		tax_column = self.builder.get_object ('treeviewcolumn5')
		tax_renderer = self.builder.get_object ('cellrenderertext6')
		tax_column.set_cell_data_func(tax_renderer, self.tax_cell_func)

		ext_price_column = self.builder.get_object ('treeviewcolumn6')
		ext_price_renderer = self.builder.get_object ('cellrenderertext7')
		ext_price_column.set_cell_data_func(ext_price_renderer, self.ext_price_cell_func)

		self.document_type = "Invoice"
		self.populate_location_store ()
		self.populate_customer_store ()
		self.populate_product_store ()
		self.builder.get_object('combobox2').set_active(0)
		
		self.calendar = DateTimeCalendar(self.db)
		self.calendar.connect('day-selected', self.calendar_day_selected)
		self.calendar.set_relative_to(self.builder.get_object('entry1'))
		self.calendar.set_today()

		if invoice_id != None:  # edit an existing invoice; put all the existing items in the liststore
			self.populate_customer_store ()
			self.set_widgets_sensitive ()
			self.populate_invoice_items()
			self.cursor.execute("SELECT customer_id, COALESCE(dated_for, now())"
								"FROM invoices "
								"WHERE id = %s", (self.invoice_id,))
			for row in self.cursor.fetchall():
				customer_id = row[0]
				date = row[1]
				self.calendar.set_date(date)
			self.builder.get_object('combobox1').set_active_id(str(customer_id))

		self.tax = 0
		self.window.show_all()
		self.calculate_totals ()
		
		GLib.idle_add(self.load_settings)

	def load_settings (self):
		self.cursor.execute("SELECT column_id, visible FROM settings.invoice_columns")
		for row in self.cursor.fetchall():
			column_id = row[0]
			visible = row[1]
			self.builder.get_object(column_id).set_visible(visible)
		self.cursor.execute("SELECT print_direct, email_when_possible FROM settings")
		print_direct, email = self.cursor.fetchone()
		self.builder.get_object('menuitem1').set_active(print_direct) #set the direct print checkbox
		self.builder.get_object('menuitem4').set_active(email) #set the email checkbox

	def populate_location_store (self):
		location_combo = self.builder.get_object('combobox2')
		active_location = location_combo.get_active_id()
		self.location_store.clear()
		self.cursor.execute("SELECT id, name FROM locations ORDER BY name")
		for row in self.cursor.fetchall():
			location_id = row[0]
			location_name = row[1]
			self.location_store.append([str(location_id), location_name])
		location_combo.set_active_id(active_location)

	def transfer_invoice_activated (self, menuitem):
		dialog = self.builder.get_object('transfer_invoice_dialog')
		result = dialog.run()
		dialog.hide()
		if result == Gtk.ResponseType.ACCEPT:
			combo = self.builder.get_object('combobox3')
			transfer_customer_id = combo.get_active_id()
			self.cursor.execute("UPDATE invoices SET customer_id = %s "
								"WHERE id = %s", 
								(transfer_customer_id, self.invoice_id))
			self.db.commit()
			combo = self.builder.get_object('combobox1')
			combo.set_active_id(transfer_customer_id)
			self.update_invoice_name ("Inv")

	def invoice_transfer_match_selected (self, completion, model, iter):
		transfer_customer_id = model[iter][0]
		combo = self.builder.get_object('combobox3')
		combo.set_active_id(transfer_customer_id)

	def barcode_entry_key_pressed (self, entry, event):
		if event.get_state() & Gdk.ModifierType.SHIFT_MASK: #shift held down
			barcode = entry.get_text()
			if barcode == "":
				return # blank barcode
			self.cursor.execute("SELECT id FROM products "
								"WHERE (barcode, deleted, sellable, stock) = "
								"(%s, False, True, True)", (barcode,))
			for row in self.cursor.fetchall():
				product_id = row[0]
				break
			else:
				return
			keyname = Gdk.keyval_name(event.keyval)
			if keyname == 'Return' or keyname == "KP_Enter": # enter key(s)
				for row in self.invoice_store:
					if row[2] == product_id:
						row[1] -= 1
						break

	def barcode_entry_activate (self, entry):
		self.check_invoice_id()
		barcode = entry.get_text()
		entry.select_region(0,-1)
		if barcode == "":
			return # blank barcode
		self.cursor.execute("SELECT process_invoice_barcode(%s, %s)", 
							(barcode, self.invoice_id))
		for row in self.cursor.fetchall():
			if row[0] != 0:
				self.populate_invoice_items()
				row_id = row[0]
			else:            #barcode not found
				for row in self.barcodes_not_found_store:
					if row[2] == barcode:
						row[1] += 1
						break
					continue
				else:
					self.barcodes_not_found_store.append([0, 1, barcode])
				self.builder.get_object('entry10').grab_focus()
				barcode_error_dialog = self.builder.get_object('barcode_error_dialog')
				barcode_error_dialog.run()
				barcode_error_dialog.hide()
				return
		for row in self.invoice_store:   #select the item we scanned
			if row[0] == row_id:
				treeview = self.builder.get_object('treeview2')
				c = treeview.get_column(0)
				#path = self.invoice_store.get_path(row.path)
				treeview.set_cursor(row.path, c, False)

	def import_time_clock_window(self, widget):
		self.check_invoice_id ()
		from invoice import import_time_clock_entries as itce
		self.time_clock_import = itce.ImportGUI(self.db, self.customer_id, self.invoice_id)		

	def on_drag_data_received(self, widget, drag_context, x,y, data,info, time):
		list_ = data.get_text().split(' ')
		if len(list_) != 2:
			raise Exception("invalid drag data received")
			return
		if self.customer_id == 0:
			return
		qty, product_id = list_[0], list_[1]
		self.check_invoice_id()
		iter_ = self.invoice_store.append([0, qty, int(product_id), '',
											'', '', '1', '1', '1', '', 
											True, '', False])
		self.check_invoice_item_id (iter_)
		treeview = self.builder.get_object('treeview2')
		c = treeview.get_column(0)
		path = self.invoice_store.get_path(iter_)
		treeview.set_cursor(path, c, True)
		self.product_selected (product_id, path)

	def destroy(self, window):
		self.main.disconnect(self.handler_c_id)
		self.main.disconnect(self.handler_p_id)
		self.cursor.close()

	def focus (self, window, event):
		self.populate_location_store ()
		if self.invoice_id != None:
			self.populate_invoice_items ()

	def treeview_button_release_event (self, treeview, event):
		if event.button == 3 and self.menu_visible == False:
			selection = self.builder.get_object("treeview-selection")
			model, path = selection.get_selected_rows ()
			cancel_time_import_menuitem = self.builder.get_object("menuitem13")
			cancel_time_import_menuitem.set_visible(False)
			if path != []:
				line_id = model[path][0]
				self.cursor.execute("SELECT id FROM time_clock_entries "
									"WHERE invoice_line_id = %s LIMIT 1", 
									(line_id,))
				self.time_clock_entries_ids = self.cursor.fetchall()
				for row in self.time_clock_entries_ids:
					cancel_time_import_menuitem.set_visible(True)
			menu = self.builder.get_object('invoice_line_item_menu')
			menu.popup(None, None, None, None, event.button, event.time)
			menu.show_all()
			self.menu_visible = True
		else:
			self.menu_visible = False

	def cancel_time_clock_import_activated (self, menuitem):
		for row in self.time_clock_entries_ids:
			self.cursor.execute("UPDATE time_clock_entries "
								"SET (invoiced, invoice_line_id) = "
								"(False, NULL) WHERE id = %s", (row[0],))
		self.db.commit()

	def refresh_price_activated (self, menuitem):
		selection = self.builder.get_object("treeview-selection")
		model, path = selection.get_selected_rows ()
		if path == []:
			return
		self.set_product_price (path)

	def customer_combo_populate_popup (self, entry, menu):
		separator = Gtk.SeparatorMenuItem ()
		separator.show ()
		menu.prepend(separator)
		edit_customer_menu = Gtk.MenuItem.new_with_label("Edit customer")
		edit_customer_menu.connect("activate", self.edit_customer_clicked)
		edit_customer_menu.show()
		menu.prepend(edit_customer_menu)

	def edit_customer_clicked (self, menuitem):
		if self.customer_id != None:
			import contacts
			contacts.GUI(self.main, self.customer_id)

	def product_hub_activated (self, menuitem):
		selection = self.builder.get_object("treeview-selection")
		model, path = selection.get_selected_rows ()
		if path == []:
			return
		product_id = model[path][2]
		import product_hub
		product_hub.ProductHubGUI(self.main, product_id)

	def tax_exemption_window (self, widget):
		import customer_tax_exemptions as cte
		cte.CustomerTaxExemptionsGUI(self.window, self.db, self.customer_id)
		self.populate_tax_exemption_combo ()

	def product_clicked (self, menuitem):
		import products
		products.ProductsGUI(self.main)

	def document_list_clicked (self, menuitem):
		self.show_document_list_window ()

	def show_document_list_window (self):
		self.populate_document_list ()
		pos = self.window.get_position()
		x, y = pos[0], pos[1]
		x_size = self.window.get_size()[0]
		x = int(x) + int(x_size)
		window = self.builder.get_object('document_list_window')
		window.move(x , int(y))
		window.show_all()

	def populate_document_list (self):
		selection = self.builder.get_object('treeview-selection4')
		self.document_list_store.clear()
		self.cursor.execute("SELECT id, name, doc_type, active "
							"FROM invoices "
							"WHERE (customer_id, posted, canceled) = "
							"(%s, False, False)", (self.customer_id,))
		for row in self.cursor.fetchall():
			_id_ = row[0]
			name = row[1]
			doc_type = row[2]
			active = row[3]
			self.document_list_store.append ([_id_, name, doc_type, active])
		for row in self.document_list_store:
			if row[0] == self.invoice_id:
				selection.select_path(row.path)

	def active_cell_renderer_toggled (self, renderer, path):
		active = self.document_list_store[path][3]
		invoice_id = self.document_list_store[path][0]
		self.document_list_store[path][3] = not active
		self.cursor.execute("UPDATE invoices SET active = %s WHERE id = %s",
							(not active, invoice_id))
		self.db.commit()

	def document_window_delete (self, window, event):
		window.hide()
		return True

	def document_list_row_activated (self, treeview, path, column):
		self.invoice_id = self.document_list_store[path][0]
		self.cursor.execute("SELECT comments FROM invoices WHERE id = %s",
														(self.invoice_id,))
		comments = self.cursor.fetchone()[0]
		self.builder.get_object("comment_buffer").set_text(comments)
		self.document_type = self.document_list_store[path][2]
		self.populate_invoice_items()
		self.cursor.execute("SELECT dated_for FROM invoices WHERE id = %s", (self.invoice_id,))
		date = self.cursor.fetchone()[0]
		self.calendar.set_date(date)

	def update_invoice_name (self, document_prefix):
		self.cursor.execute("SELECT name FROM contacts WHERE id = %s", (self.customer_id,))
		name = self.cursor.fetchone()[0]
		split_name = name.split(' ')
		name_str = ""
		for i in split_name:
			name_str += i[0:3]
		name = name_str.lower()
		invoice_date = str(self.datetime)[0:10]
		doc_prefix = document_prefix[0:3]
		doc_name = doc_prefix + "_" + str(self.invoice_id) + "_"  + name + "_" + invoice_date
		self.cursor.execute("UPDATE invoices SET name = %s WHERE id = %s", (doc_name, self.invoice_id))
		self.db.commit()

	def document_type_edited(self, cell_renderer, path, text):
		self.document_type = text
		self.update_invoice_name (text)
		self.cursor.execute("UPDATE invoices SET doc_type = %s WHERE id = %s", (text, self.invoice_id))
		self.populate_document_list()
		
	def contacts_window(self, widget):
		import contacts
		contacts.GUI(self.main)

	def delete_invoice_clicked (self, button):
		self.cursor.execute("UPDATE invoices SET canceled = True "
							"WHERE id = %s", (self.invoice_id,))
		self.db.commit()
		self.populate_document_list ()
		self.invoice_store.clear()

	def new_invoice_clicked (self, button):
		self.invoice_id = 0
		self.invoice_store.clear()

	def comment_textbuffer_changed (self, buf):
		start = buf.get_start_iter()
		end = buf.get_end_iter()
		comment = buf.get_text(start, end, True)
		self.cursor.execute("UPDATE invoices SET comments = %s WHERE id = %s", 
													(comment, self.invoice_id))
		self.db.commit()
		self.invoice = None  #comments changed, recreate odt file

	def view_invoice(self, widget):
		buf = self.builder.get_object('comment_buffer')
		start = buf.get_start_iter()
		end = buf.get_end_iter()
		comment = buf.get_text(start, end, True)
		if not self.invoice:
			self.invoice = invoice_create.Setup(self.db, self.invoice_store, 
												self.customer_id, comment, 
												self.datetime, self.invoice_id, 
												self, self.document_type)
		self.invoice.view()

	def post_invoice(self, widget):
		buf = self.builder.get_object('comment_buffer')
		start = buf.get_start_iter()
		end = buf.get_end_iter()
		comment = buf.get_text(start, end, True)
		if not self.invoice:
			self.invoice = invoice_create.Setup(self.db, self.invoice_store, 
												self.customer_id, comment, 
												self.datetime, self.invoice_id,
												self, self.document_type)
		else:
			self.invoice.save()
		if os.path.exists(self.invoice.lock_file):
			dialog = self.builder.get_object('dialog1')
			response = dialog.run()
			dialog.hide()
			if response != Gtk.ResponseType.ACCEPT:
				return
		if self.builder.get_object('menuitem1').get_active() == True:
			self.invoice.print_directly(self.window)
		else:
			self.invoice.print_dialog(self.window)
		self.invoice.post()
		if self.builder.get_object('menuitem4').get_active() == True:
			self.cursor.execute("SELECT * FROM contacts WHERE id = %s", 
														(self.customer_id, ))
			for row in self.cursor.fetchall():
				name = row[1]
				email = row[9]
				if email != "":
					email = "%s '< %s >'" % (name, email)
					self.invoice.email(email)
		location_id = self.builder.get_object('combobox2').get_active_id()
		from inventory import inventorying
		inventorying.sell(self.db, self.invoice_store, location_id, self.customer_id, self.datetime)
		self.db.commit()
		self.window.destroy()

	def populate_invoice_items (self):
		self.invoice_store.clear()
		self.cursor.execute("SELECT ili.id, qty, product_id, products.name, "
							"ext_name, remark, price::text, tax::text, ext_price::text, "
							"ili.tax_rate_id, COALESCE(tax_letter, ''), "
							"products.invoice_serial_numbers "
							"FROM invoice_items AS ili "
							"JOIN products ON products.id = ili.product_id "
							"LEFT JOIN tax_rates "
							"ON tax_rates.id = ili.tax_rate_id "
							"WHERE (invoice_id, canceled) = (%s, False) "
							"ORDER BY ili.id", (self.invoice_id,))
		for row in self.cursor.fetchall():
			id = row[0]
			qty = row[1]
			product_id = row[2]
			product_name = row[3]
			ext_name = row[4]
			remark = row[5]
			price = row[6]
			tax = row[7]
			ext_price = row[8]
			tax_rate_id = str(row[9])
			tax_letter = row[10]
			serial_number = row[11]
			if serial_number == True:
				self.builder.get_object('treeviewcolumn13').set_visible(True)
				qty = int(qty)
			self.invoice_store.append([id, str(qty), product_id, product_name, 
										ext_name, remark, price, tax, 
										ext_price, tax_rate_id, False, 
										tax_letter, serial_number])
		self.check_serial_numbers()
			
	def tax_exemption_combo_changed(self, combo):
		'''if tax_rate_id is NULL, trigger will use default tax rate'''
		if self.populating == True:
			return
		tax_rate_id = combo.get_active_id()
		self.cursor.execute("UPDATE invoice_items SET tax_rate_id = %s "
							"WHERE invoice_id = %s", 
							(tax_rate_id, self.invoice_id))
		self.db.commit()
		self.populate_invoice_items ()
		self.calculate_totals ()

	################## start customer

	def populate_customer_store (self, m=None, i=None):
		self.customer_store.clear()
		self.cursor.execute("SELECT "
								"id::text, "
								"name || '   Unpaid : ' || "
								"(( SELECT COALESCE(SUM(amount_due), 0.00) "
								"FROM invoices "
								"WHERE canceled = False "
								"AND customer_id = c_outer.id) - "
								"(SELECT COALESCE(SUM(amount), 0.00) "
								"FROM payments_incoming "
								"WHERE (customer_id, misc_income) = "
								"(c_outer.id, False) ))::money, " 
								"ext_name "
							"FROM contacts AS c_outer "
							"WHERE (deleted, customer) = "
							"(False, True) ORDER BY name")
		for row in self.cursor.fetchall():
			self.customer_store.append(row)
		
	def customer_match_selected(self, completion, model, iter):
		self.customer_id = model[iter][0]
		self.customer_selected (self.customer_id)

	def customer_match_func(self, completion, key, iter_):
		split_search_text = key.split()
		for text in split_search_text:
			if text not in self.customer_store[iter_][1].lower():
				return False
		return True

	def customer_combobox_changed(self, widget, toggle_button=None): #updates the customer
		customer_id = widget.get_active_id()
		if customer_id != None:
			self.customer_id = customer_id
			self.customer_selected (self.customer_id)
			self.calculate_totals ()

	def populate_tax_exemption_combo (self):
		self.populating = True
		exemption_combo = self.builder.get_object('comboboxtext1')
		active = exemption_combo.get_active_id()
		exemption_combo.remove_all()
		exemption_combo.append(None, "No exemption")
		final_id = '0'
		self.cursor.execute("SELECT tax_rates.id, tax_rates.name FROM "
							"customer_tax_exemptions "
							"JOIN tax_rates "
							"ON customer_tax_exemptions.tax_rate_id = "
							"tax_rates.id "
							"WHERE customer_tax_exemptions.customer_id = (%s)",
							(self.customer_id,))
		for row in self.cursor.fetchall():
			exemption_combo.append(str(row[0]), row[1])
			final_id = str(row[0])
		if active == None:
			self.populating = False
			exemption_combo.set_active_id(final_id)
			return
		exemption_combo.set_active_id(active)
		self.populating = False

	def customer_selected(self, name_id):
		self.cursor.execute("SELECT address, phone, city, state, zip FROM contacts "
							"WHERE id = (%s)",(name_id,))
		for row in self.cursor.fetchall() :
			self.builder.get_object('entry6').set_text(row[0])
			self.builder.get_object('entry8').set_text(row[1])
			self.builder.get_object('entry15').set_text(row[2])
			self.builder.get_object('entry16').set_text(row[3])
			self.builder.get_object('entry17').set_text(row[4])
		self.populate_tax_exemption_combo ()
		self.set_widgets_sensitive ()
		self.cursor.execute("SELECT id, comments FROM invoices "
							"WHERE (customer_id, posted) = (%s, False) ", 
							(name_id,))
		tupl = self.cursor.fetchall()
		if len(tupl) > 1:
			self.invoice_id = 0
			self.show_document_list_window ()
			self.builder.get_object("comment_buffer").set_text('')
		elif len(tupl) == 1:
			self.invoice_id = tupl[0][0]
			comments = tupl[0][1]
			self.builder.get_object("comment_buffer").set_text(comments)
		else:
			self.invoice_id = 0
			self.builder.get_object("comment_buffer").set_text('')
		self.populate_invoice_items()
		self.cursor.execute("SELECT dated_for FROM invoices WHERE id = %s "
							"AND dated_for IS NOT NULL", (self.invoice_id,))
		for row in self.cursor.fetchall():
			date = row[0]
			self.calendar.set_date(date)
			break
		else:
			self.calendar.set_today()

	################## start qty
	
	def qty_cell_func(self, column, cellrenderer, model, iter_, data):
		return
		if model.get_value(iter_, 12) == True:
			qty = int(model.get_value(iter_, 1))
			cellrenderer.set_property("text" , str(qty))

	def qty_edited(self, widget, path, text):
		if self.invoice_store[path][12] == True:
			text = int(text) # only allow whole numbers for inventory
		iter_ = self.invoice_store.get_iter (path)
		self.check_invoice_item_id (iter_)
		line_id = self.invoice_store[iter_][0]
		try:
			self.cursor.execute("UPDATE invoice_items SET qty = %s "
								"WHERE id = %s;"
								"SELECT qty::text, price::text, "
									"ext_price::text, tax::text "
								"FROM invoice_items WHERE id = %s", 
								(text, line_id, line_id))
			self.db.commit()
		except psycopg2.DataError as e:
			self.show_error_dialog (str(e))
			self.db.rollback()
			return
		for row in self.cursor.fetchall():
			qty = row[0]
			price = row[1]
			ext_price = row[2]
			tax = row[3]
			self.invoice_store[iter_][1] = qty
			self.invoice_store[iter_][6] = price
			self.invoice_store[iter_][7] = tax
			self.invoice_store[iter_][8] = ext_price
		self.check_serial_numbers ()
		self.calculate_totals ()

	################## start remark

	def remark_edited(self, widget, path, text):
		iter_ = self.invoice_store.get_iter(path)
		self.invoice_store[iter_][5] = text
		line_id = self.invoice_store[iter_][0]
		self.cursor.execute("UPDATE invoice_items SET remark = %s "
							"WHERE id = %s", (text, line_id))
		self.db.commit()

	################## start price

	def price_cell_func(self, column, cellrenderer, model, iter_, data):
		return
		price = '{:,.2f}'.format(model.get_value(iter_, 6))
		cellrenderer.set_property("text" , price)
		
	def price_edited(self, widget, path, text):
		iter_ = self.invoice_store.get_iter(path)
		line_id = self.invoice_store[iter_][0]
		try:
			self.cursor.execute("UPDATE invoice_items SET price = %s "
								"WHERE id = %s;"
								"SELECT price::text, ext_price::text, tax::text "
								"FROM invoice_items WHERE id = %s", 
								(text, line_id, line_id))
			self.db.commit()
		except psycopg2.DataError as e:
			self.show_error_dialog (str(e))
			self.db.rollback()
			return
		for row in self.cursor.fetchall():
			price = row[0]
			ext_price = row[1]
			tax = row[2]
			self.invoice_store[iter_][6] = price
			self.invoice_store[iter_][7] = tax
			self.invoice_store[iter_][8] = ext_price
		self.calculate_totals()

	################## end price

	def tax_cell_func(self, column, cellrenderer, model, iter_, data):
		return
		tax = '{:,.2f}'.format(model.get_value(iter_, 7))
		cellrenderer.set_property("text" , tax)

	def ext_price_cell_func(self, column, cellrenderer, model, iter_, data):
		return
		ext_price = '{:,.2f}'.format(model.get_value(iter_, 8))
		cellrenderer.set_property("text" , ext_price)
		
	################## start product
	
	def product_match_func(self, completion, key, tree_iter):
		split_search_text = key.split()
		for text in split_search_text:
			if text not in self.product_store[tree_iter][1].lower():
				return False
		return True

	def product_match_selected(self, completion, model, iter_):
		product_id = self.product_store[iter_][0]
		selection = self.builder.get_object('treeview-selection')
		model, path = selection.get_selected_rows()
		self.product_selected (product_id, path)

	def product_renderer_started (self, renderer, combo, path):
		completion = self.builder.get_object('product_completion')
		entry = combo.get_child()
		entry.set_completion(completion)
		
	def product_renderer_changed (self, widget, path, iter_):
		product_id = self.product_store[iter_][0]
		self.product_selected (product_id, path)

	def product_selected (self, product_id, path):
		invoice_line_id = self.invoice_store[path][0]
		self.cursor.execute("UPDATE serial_numbers "
							"SET invoice_item_id = NULL "
							"WHERE invoice_item_id = %s", 
							(invoice_line_id,))
		self.cursor.execute("SELECT products.name, ext_name, tax_letter, "
							"invoice_serial_numbers "
							"FROM products JOIN tax_rates "
							"ON tax_rates.id = products.tax_rate_id "  
							"WHERE products.id = %s", (product_id,))
		for row in self.cursor.fetchall ():
			product_name = row[0]
			ext_name = row[1]
			tax_letter = row[2]
			serial_number = row[3]
			iter_ = self.invoice_store.get_iter(path)
			if serial_number == True:
				self.builder.get_object('treeviewcolumn13').set_visible(True)
				#allow only whole numbers for inventory
				qty = self.invoice_store[iter_][1].split('.')[0] 
				self.invoice_store[iter_][1] = qty
			self.invoice_store[iter_][2] = int(product_id)
			self.invoice_store[iter_][3] = product_name
			self.invoice_store[iter_][4] = ext_name
			self.invoice_store[iter_][10] = False
			self.invoice_store[iter_][11] = tax_letter
			self.invoice_store[iter_][12] = serial_number
			self.set_product_price (iter_)
			line_id = self.invoice_store[iter_][0]
			self.cursor.execute("UPDATE invoice_items SET product_id = %s "
								"WHERE id = %s;"
								"SELECT price::text, tax::text, ext_price::text "
								"FROM invoice_items WHERE id = %s", 
								(product_id, line_id, line_id))
			for row in self.cursor.fetchall():
				price = row[0]
				tax = row[1]
				ext_price = row[2]
				self.invoice_store[iter_][6] = price
				self.invoice_store[iter_][7] = tax
				self.invoice_store[iter_][8] = ext_price
			self.db.commit()
			self.set_serial_number_box_state(serial_number)
		self.check_serial_numbers ()
		self.populate_serial_numbers ()
		self.calculate_totals()

	def populate_serial_numbers (self):
		serial_number_store = self.builder.get_object('serial_number_store')
		serial_number_store.clear()
		selection = self.builder.get_object('treeview-selection')
		model, path = selection.get_selected_rows()
		if path == []:
			return # no row selected
		invoice_line_id = model[path][0]
		product_id = model[path][2]
		product_name = model[path][3]
		self.cursor.execute("SELECT id, serial_number FROM serial_numbers "
							"WHERE invoice_item_id = %s", 
							(invoice_line_id,))
		for row in self.cursor.fetchall():
			id_ = row[0]
			serial_number = row[1]
			serial_number_store.append([product_id, invoice_line_id, product_name, serial_number, id_])

	def check_serial_numbers (self):
		mismatch = False
		box = self.builder.get_object('box4')
		for row in self.invoice_store:
			if row[12] == True:
				box.set_visible(True)
				invoice_line_id = row[0]
				qty = int(row[1])
				product_id = row[2]
				product_name = row[3]
				self.cursor.execute("SELECT COUNT(id) FROM serial_numbers "
									"WHERE invoice_item_id = %s", 
									(invoice_line_id,))
				ser_qty = self.cursor.fetchone()[0]
				if qty != ser_qty:
					mismatch = True
					break
		button = self.builder.get_object('button2')
		if mismatch == True:
			button.set_label('Qty/serial number mismatch')
			button.set_sensitive(False)
		else:
			button.set_label('Post invoice')
			button.set_sensitive(True)

	def invoice_item_row_activated (self, treeview, path, column):
		store = treeview.get_model()
		invoice_item_id = store[path][0]
		if invoice_item_id == 0:
			return # no valid invoice item yet
		enforce_serial_numbers = store[path][12]
		self.set_serial_number_box_state(enforce_serial_numbers)
		product_id = store[path][2]
		self.check_serial_numbers()
		self.populate_serial_numbers ()

	def set_serial_number_box_state (self, sensitive):
		box = self.builder.get_object('box4')
		box.set_sensitive(sensitive)

	def serial_number_entry_activated (self, entry):
		serial_number = entry.get_text()
		item_selection = self.builder.get_object('treeview-selection')
		model, path = item_selection.get_selected_rows()
		if path == []:
			self.show_error_dialog ("No invoice item selected!")
			return # no invoice item selected
		invoice_line_id = model[path][0]
		product_id = model[path][2]
		self.cursor.execute("SELECT c.name, i.id FROM serial_numbers AS sn "
							"JOIN invoice_items AS ili "
							"ON ili.id = sn.invoice_item_id "
							"JOIN invoices AS i ON i.id = ili.invoice_id "
							"JOIN contacts AS c ON c.id = i.customer_id "
							"WHERE (sn.product_id, sn.serial_number) = (%s, %s) ",
							(product_id, serial_number))
		for row in self.cursor.fetchall():
			customer_name = row[0]
			invoice_number = row[1]
			error = "Serial number %s is in use on invoice number %s, "\
			"customer name %s.\n Most likely you entered the serial number "\
			"twice or maybe the serial number\n got entered wrong now, or "\
			"sometime before today."\
			%(serial_number, invoice_number, customer_name)
			self.show_error_dialog(error)
			return  # serial number is in use
		self.cursor.execute("UPDATE serial_numbers "
							"SET invoice_item_id = %s "
							"WHERE (product_id, serial_number) = (%s, %s) "
							"AND invoice_item_id IS NULL RETURNING id", 
							(invoice_line_id, product_id, serial_number ))
		for row in self.cursor.fetchall():
			product_serial_number_id = row[0]
			break
		else:
			error = ("That serial number was not found in the system.\n "
			"This means it was not manufactured or received yet.\n "
			"If you want to add it manually, you can go to\n "
			"General>Serial Numbers on the main window.")
			self.show_error_dialog(error)
			return  # no serial number found in the system
		self.db.commit()
		self.check_serial_numbers ()
		self.populate_serial_numbers ()
		entry.select_region(0, -1)
		entry.grab_focus()

	def show_error_dialog (self, error):
		self.builder.get_object('label2').set_label(error)
		dialog = self.builder.get_object('error_dialog')
		dialog.run()
		dialog.hide()

	def serial_number_treeview_row_activated (self, treeview, path, column):
		entry = self.builder.get_object('entry11')
		entry.select_region(0, -1)
		entry.grab_focus()

	def remove_serial_number_clicked (self, button):
		selection = self.builder.get_object('treeview-selection5')
		model, path = selection.get_selected_rows()
		if path != []:
			product_serial_number_id = model[path][4]
			self.cursor.execute("UPDATE serial_numbers "
								"SET invoice_item_id = NULL "
								"WHERE id = %s", (product_serial_number_id,))
			self.db.commit()
		self.check_serial_numbers ()
		self.populate_serial_numbers ()
		
	def populate_product_store(self, m=None, i=None):
		self.product_store.clear()
		self.cursor.execute("SELECT id, name, ext_name FROM products "
							"WHERE (deleted, sellable) = (False, True) "
							"ORDER BY name")
		for i in self.cursor.fetchall():
			_id_ = i[0]
			name = i[1]
			ext_name = i[2]
			self.product_store.append([str(_id_), "%s {%s}" % (name, ext_name)])
			
	def set_product_price (self, iter_):
		product_id = self.invoice_store[iter_][2]
		price = get_customer_product_price (self.db, 
											self.customer_id, product_id)
		self.invoice_store[iter_][6] = str(price)
		line_id = self.invoice_store[iter_][0]
		self.cursor.execute("UPDATE invoice_items SET price = %s "
							"WHERE id = %s", (price, line_id))
		self.db.commit()

	################## end product

	def set_widgets_sensitive (self):
		self.builder.get_object('button1').set_sensitive(True)
		self.builder.get_object('button2').set_sensitive(True)
		self.builder.get_object('button3').set_sensitive(True)
		self.builder.get_object('menuitem14').set_sensitive(True)
		self.builder.get_object('entry9').set_sensitive(True)
		self.builder.get_object('menuitem2').set_sensitive(True)
		self.builder.get_object('menuitem6').set_sensitive(True)
		self.builder.get_object('menuitem7').set_sensitive(True)
		self.builder.get_object('menuitem8').set_sensitive(True)
		self.builder.get_object('comment_textview').set_sensitive(True)

	def refresh_all_prices_clicked (self, menuitem):
		for row in self.invoice_store:
			self.set_product_price (row.path)
	
	def calculate_totals (self, widget = None):
		c = self.db.cursor()
		c.execute("WITH totals AS "
					"(SELECT COALESCE(SUM(ext_price), 0.00) AS subtotal, "
					"COALESCE(SUM(tax), 0.00) AS tax, "
					"(COALESCE(SUM(ext_price) + SUM(tax), 0.00)) "
					"AS total FROM invoice_items "
					"WHERE invoice_id = %s"
					"),"
					"update AS "
					"(UPDATE invoices SET (subtotal, tax, total) = "
						"((SELECT subtotal FROM totals), "
						"(SELECT tax FROM totals), "
						"(SELECT total FROM totals)) "
					"WHERE id = %s"
					")"
					"SELECT * FROM totals",
					(self.invoice_id, self.invoice_id))
		for row in c.fetchall():
			self.subtotal = row[0]
			self.tax = row[1] 
			self.total = row[2]
		self.db.commit()
		subtotal = '${:,.2f}'.format(self.subtotal)
		tax = '${:,.2f}'.format(self.tax)
		total = '${:,.2f}'.format(self.total)
		self.builder.get_object('entry3').set_text(subtotal)
		self.builder.get_object('entry4').set_text(tax)
		self.builder.get_object('entry5').set_text(total)

	def check_invoice_item_id (self, iter_):
		id = self.invoice_store[iter_][0]
		qty = self.invoice_store[iter_][1]
		product_id = self.invoice_store[iter_][2]
		remark = self.invoice_store[iter_] [5]
		price = self.invoice_store[iter_][6]
		tax = self.invoice_store[iter_][7]
		ext_price = self.invoice_store[iter_][8]
		tax_id = self.builder.get_object('comboboxtext1').get_active_id()
		if id == 0:
			self.check_invoice_id()
			self.cursor.execute("INSERT INTO invoice_items "
								"(invoice_id, qty, product_id, remark, price, "
								"canceled, tax_rate_id) "
								"VALUES (%s, %s, %s, %s, %s, %s, %s) "
								"RETURNING id", 
								(self.invoice_id, qty, product_id, remark, 
								price, False, tax_id))
			self.invoice_store[iter_][0] = self.cursor.fetchone()[0]
			self.db.commit()
		self.invoice = None #the generated .odt is no longer valid

	def check_invoice_id (self):
		if self.invoice_id == 0:
			self.invoice_id = create_new_invoice(self.cursor, self.datetime, self.customer_id)
			self.db.commit()
			self.populate_document_list()

	def new_item_clicked (self, button):
		self.cursor.execute("SELECT id, name "
							"FROM products "
							"WHERE (deleted, sellable, stock) = "
									"(False, True, True) "
							"ORDER BY invoice_serial_numbers ASC, id ASC "
							"LIMIT 1")
		for i in self.cursor.fetchall():
			product_id = i[0]
			product_name = i[1]
			iter_ = self.invoice_store.append([0, '1', product_id, product_name,
												"", "", '1', '1', '1', "", 
												True, '', False])
			self.check_invoice_item_id (iter_)
			treeview = self.builder.get_object('treeview2')
			c = treeview.get_column(0)
			path = self.invoice_store.get_path(iter_)
			treeview.set_cursor(path, c, True)
		self.set_serial_number_box_state(False)

	def delete_line_item_activated (self, menuitem):
		selection = self.builder.get_object("treeview-selection")
		model, path = selection.get_selected_rows ()
		if path == []:
			return
		row_id = model[path][0]
		self.cursor.execute("WITH deleted AS "
							"(DELETE FROM invoice_items WHERE id = %s "
							"RETURNING gl_entries_id) "
							"DELETE FROM gl_entries WHERE id = "
							"(SELECT gl_entries_id FROM deleted)"
							, (row_id,))
		self.db.commit()
		self.populate_invoice_items ()

	def key_tree_tab(self, treeview, event):
		keyname = Gdk.keyval_name(event.keyval)
		path, col = treeview.get_cursor()
		# only visible columns!!
		columns = [c for c in treeview.get_columns() if c.get_visible()]
		colnum = columns.index(col)
		if keyname=="Tab" or keyname=="Esc":
			if colnum + 1 < len(columns):
				next_column = columns[colnum + 1]
			else:
				tmodel = treeview.get_model()
				titer = tmodel.iter_next(tmodel.get_iter(path))
				if titer is None:
					titer = tmodel.get_iter_first()
					path = tmodel.get_path(titer)
					next_column = columns[0]
			if keyname == 'Tab':
				GLib.timeout_add(10, treeview.set_cursor, path, next_column, True)
			elif keyname == 'Escape':
				pass

	def help_clicked (self, widget):
		import subprocess
		subprocess.Popen(["yelp", main.help_dir + "/invoice.page"])

	def window_key_event(self, window, event):
		keyname = Gdk.keyval_name(event.keyval)
		if keyname == 'F1':
			self.help_clicked (None)
		if keyname == 'F2':
			self.new_item_clicked (None)
		if keyname == 'F3':
			self.delete_entry(None)

	def calendar_day_selected (self, calendar):
		self.datetime = calendar.get_date()
		day_text = calendar.get_text()
		self.builder.get_object('entry1').set_text(day_text)

	def calendar(self, widget, icon, event):
		self.calendar.show()
Ejemplo n.º 8
0
class SalesTaxReportGUI:
	def __init__(self):

		self.builder = Gtk.Builder()
		self.builder.add_from_file(UI_FILE)
		self.builder.connect_signals(self)
		self.cursor = DB.cursor()
		self.tax_store = self.builder.get_object('tax_store')

		self.end_datetime = None

		start_entry = self.builder.get_object('entry1')
		end_entry = self.builder.get_object('entry2')

		self.start_calendar = DateTimeCalendar()
		self.start_calendar.set_relative_to(start_entry)
		self.end_calendar = DateTimeCalendar()
		self.end_calendar.set_relative_to(end_entry)

		self.start_calendar.connect('day-selected', self.start_date_selected)
		self.end_calendar.connect('day-selected', self.end_date_selected)

		self.start_calendar.set_date(datetime.today() - timedelta(days = 365))
		self.end_calendar.set_today ()
		
		self.window = self.builder.get_object('window1')
		self.window.show_all()

	def destroy (self, widget):
		self.cursor.close()

	def populate_tax_treeview(self):
		self.tax_store.clear()
		self.cursor.execute("SELECT tax_rates.name, "
							"SUM(i.tax)::money, "
							"SUM(i.ext_price)::money "
							"FROM invoice_items AS i "
							"JOIN tax_rates ON i.tax_rate_id = tax_rates.id "
							"JOIN invoices ON invoices.id = i.invoice_id "
							"WHERE (invoices.canceled, invoices.posted) "
							"= (False, True) "
							"AND date_created >= %s "
							"AND date_created <= %s "
							"GROUP BY tax_rates.name", 
							(self.start_datetime, self.end_datetime))
		for row in self.cursor.fetchall():
			self.tax_store.append(row)
		self.cursor.execute("SELECT "
								"COALESCE(SUM(i.ext_price), 0.00)::money, "
								"COALESCE(SUM(i.tax), 0.00)::money "
							"FROM invoice_items AS i "
							"JOIN invoices ON invoices.id = i.invoice_id "
							"WHERE (invoices.canceled, invoices.posted) "
							"= (False, True) "
							"AND date_created >= %s "
							"AND date_created <= %s", 
							(self.start_datetime, self.end_datetime))
		for row in self.cursor.fetchall():
			self.builder.get_object('label6').set_label(row[0])
			self.builder.get_object('label4').set_label(row[1])
		DB.rollback()

	def start_date_selected(self, calendar):
		self.start_datetime = calendar.get_datetime()
		day_text = calendar.get_text()
		self.builder.get_object('entry1').set_text(day_text)
		if self.end_datetime != None: #end date not available before start date
			self.populate_tax_treeview ()

	def end_date_selected (self, calendar):
		self.end_datetime = calendar.get_datetime()
		day_text = calendar.get_text()
		self.builder.get_object('entry2').set_text(day_text)
		self.populate_tax_treeview ()

	def start_icon_clicked (self, entry, icon, event):
		self.start_calendar.show()

	def end_icon_clicked (self, entry, icon, event):
		self.end_calendar.show()
Ejemplo n.º 9
0
class SalesTaxReportGUI:
    def __init__(self, db):

        self.builder = Gtk.Builder()
        self.builder.add_from_file(UI_FILE)
        self.builder.connect_signals(self)

        self.db = db
        self.cursor = self.db.cursor()
        self.tax_store = self.builder.get_object('tax_store')

        self.end_datetime = None

        start_entry = self.builder.get_object('entry1')
        end_entry = self.builder.get_object('entry2')

        self.start_calendar = DateTimeCalendar()
        self.start_calendar.set_relative_to(start_entry)
        self.end_calendar = DateTimeCalendar()
        self.end_calendar.set_relative_to(end_entry)

        self.start_calendar.connect('day-selected', self.start_date_selected)
        self.end_calendar.connect('day-selected', self.end_date_selected)

        self.start_calendar.set_date(datetime.today() - timedelta(days=365))
        self.end_calendar.set_today()

        tax_column = self.builder.get_object('treeviewcolumn2')
        tax_renderer = self.builder.get_object('cellrenderertext2')
        tax_column.set_cell_data_func(tax_renderer, self.tax_cell_func)

        total_column = self.builder.get_object('treeviewcolumn3')
        total_renderer = self.builder.get_object('cellrenderertext3')
        total_column.set_cell_data_func(total_renderer, self.total_cell_func)

        self.window = self.builder.get_object('window1')
        self.window.show_all()

    def populate_tax_treeview(self):
        self.tax_store.clear()
        self.cursor.execute(
            "SELECT SUM(i.ext_price), SUM(i.tax), "
            "tax_rates.name "
            "FROM invoice_items AS i "
            "JOIN tax_rates ON i.tax_rate_id = tax_rates.id "
            "JOIN invoices ON invoices.id = i.invoice_id "
            "WHERE (invoices.canceled, invoices.posted) "
            "= (False, True) "
            "AND date_created >= %s "
            "AND date_created <= %s "
            "GROUP BY tax_rates.name",
            (self.start_datetime, self.end_datetime))
        for row in self.cursor.fetchall():
            sale_amount = row[0]
            tax_amount = row[1]
            tax_rate_name = row[2]
            self.tax_store.append(
                [tax_rate_name,
                 float(tax_amount),
                 float(sale_amount)])
        self.cursor.execute(
            "SELECT "
            "COALESCE(SUM(i.ext_price), 0.00), "
            "COALESCE(SUM(i.tax), 0.00) "
            "FROM invoice_items AS i "
            "JOIN invoices ON invoices.id = i.invoice_id "
            "WHERE (invoices.canceled, invoices.posted) "
            "= (False, True) "
            "AND date_created >= %s "
            "AND date_created <= %s", (self.start_datetime, self.end_datetime))
        for row in self.cursor.fetchall():
            sale_total = '${:,.2f}'.format(row[0])
            tax_total = '${:,.2f}'.format(row[1])
            self.builder.get_object('label4').set_label(tax_total)
            self.builder.get_object('label6').set_label(sale_total)

    def tax_cell_func(self, column, cellrenderer, model, iter1, data):
        tax = '${:,.2f}'.format(model.get_value(iter1, 1))
        cellrenderer.set_property("text", tax)

    def total_cell_func(self, column, cellrenderer, model, iter1, data):
        total = '${:,.2f}'.format(model.get_value(iter1, 2))
        cellrenderer.set_property("text", total)

    def start_date_selected(self, calendar):
        self.start_datetime = calendar.get_datetime()
        day_text = calendar.get_text()
        self.builder.get_object('entry1').set_text(day_text)
        if self.end_datetime != None:  #end date not available before start date
            self.populate_tax_treeview()

    def end_date_selected(self, calendar):
        self.end_datetime = calendar.get_datetime()
        day_text = calendar.get_text()
        self.builder.get_object('entry2').set_text(day_text)
        self.populate_tax_treeview()

    def start_icon_clicked(self, entry, icon, event):
        self.start_calendar.show()

    def end_icon_clicked(self, entry, icon, event):
        self.end_calendar.show()