コード例 #1
0
class SintegraDialog(BasicDialog):
    title = _('Fiscal Printer History')

    def __init__(self, store):
        BasicDialog.__init__(self, title=self.title)
        self.main_label.set_justify(Gtk.Justification.CENTER)

        self.store = store
        self.ok_button.set_label(_("Generate"))

        self.date_filter = DateSearchFilter(_('Month:'))
        self.date_filter.set_use_date_entries(False)
        self.date_filter.clear_options()
        self._populate_date_filter(self.date_filter)
        self.date_filter.select()

        self.add(self.date_filter)
        self.date_filter.show()

    def confirm(self):
        start = self.date_filter.get_start_date()
        end = self.date_filter.get_end_date()
        filename = save(_("Save Sintegra file"), self.get_toplevel(),
                        "sintegra-%s.txt" % (start.strftime('%Y-%m'), ))
        if not filename:
            return

        try:
            generator = StoqlibSintegraGenerator(self.store, start, end)
            generator.write(filename)
        except SintegraError as e:
            warning(str(e))
            return

        self.close()

    #
    # Private
    #

    def _populate_date_filter(self, date_filter):
        # The options we want to show to the users are the following:
        #   'May 2007'
        #   'June 2007'
        #   ...
        #   'September 2008'

        initial_date = self.store.find(SystemTable).min(
            SystemTable.updated).date()

        # Start is the first day of the month
        # End is the last day of the month
        start = initial_date + relativedelta(day=1)
        end = localtoday().date() + relativedelta(day=31)
        intervals = []
        while start < end:
            intervals.append((start, start + relativedelta(day=31)))
            start = start + relativedelta(months=1)

        # When we have the list of intervals, add them to the list and
        # make sure that they are translated
        month_names = get_month_names()
        for start, end in intervals:
            # Translators: Do not translate 'month' and 'year'. You can
            #              change it's positions. In the way it is,
            #              it will product for example 'December 2012'
            name = _('{month} {year}').format(month=month_names[start.month -
                                                                1],
                                              year=start.year)
            date_filter.add_option_fixed_interval(name, start, end, position=0)

    def _date_filter_query(self, search_spec, column):
        executer = QueryExecuter(self.store)
        executer.set_filter_columns(self.date_filter, [column])
        executer.set_table(search_spec)
        return executer.search([self.date_filter.get_state()])
コード例 #2
0
class TransactionPage(object):
    # shows either a list of:
    #   - transactions
    #   - payments
    def __init__(self, model, app, parent):
        self.model = model
        self.app = app
        self.parent_window = parent
        self._block = False

        self._create_search()
        self._add_date_filter()

        self._setup_search()
        self.refresh()

    def get_toplevel(self):
        return self.parent_window

    def _create_search(self):
        self.search = SearchSlave(self._get_columns(self.model.kind),
                                  store=self.app.store)
        self.search.connect('result-item-activated',
                            self._on_search__item_activated)
        self.search.enable_advanced_search()
        self.search.set_result_view(FinancialSearchResults)
        self.result_view = self.search.result_view
        self.result_view.page = self
        self.result_view.set_cell_data_func(
            self._on_result_view__cell_data_func)
        tree_view = self.search.result_view.get_treeview()
        tree_view.set_rules_hint(True)
        tree_view.set_grid_lines(Gtk.TreeViewGridLines.BOTH)

    def _add_date_filter(self):
        self.date_filter = DateSearchFilter(_('Date:'))
        self.date_filter.clear_options()
        self.date_filter.add_option(Any, 0)
        year = datetime.datetime.today().year
        month_names = get_month_names()
        for i, month in enumerate(month_names):
            name = month_names[i]
            option = type(name + 'Option', (MonthOption, ), {
                'name': _(name),
                'month': i + 1,
                'year': year
            })
            self.date_filter.add_option(option, i + 1)
        self.date_filter.add_custom_options()
        self.date_filter.select(Any)
        self.search.add_filter(self.date_filter)

    def _append_date_query(self, field):
        date = self.date_filter.get_state()
        queries = []
        if isinstance(date, DateQueryState) and date.date is not None:
            queries.append(Date(field) == date.date)
        elif isinstance(date, DateIntervalQueryState):
            queries.append(Date(field) >= date.start)
            queries.append(Date(field) <= date.end)
        return queries

    def _payment_query(self, store):
        executer = self.search.get_query_executer()
        search_spec = executer.search_spec
        queries = self._append_date_query(search_spec.due_date)
        if queries:
            return store.find(search_spec, And(*queries))

        return store.find(search_spec)

    def _transaction_query(self, store):
        queries = [
            Or(self.model.id == AccountTransaction.account_id,
               self.model.id == AccountTransaction.source_account_id)
        ]

        queries.extend(self._append_date_query(AccountTransaction.date))
        return store.find(AccountTransactionView, And(*queries))

    def show(self):
        self.search.show()

    def _setup_search(self):
        if self.model.kind == 'account':
            self.search.set_search_spec(AccountTransactionView)
            self.search.set_text_field_columns(['description'])
            self.search.set_query(self._transaction_query)
        elif self.model.kind == 'payable':
            self.search.set_text_field_columns(
                ['description', 'supplier_name'])
            self.search.set_search_spec(OutPaymentView)
            self.search.set_query(self._payment_query)
        elif self.model.kind == 'receivable':
            self.search.set_text_field_columns(['description', 'drawee'])
            self.search.set_search_spec(InPaymentView)
            self.search.set_query(self._payment_query)
        else:
            raise TypeError("unknown model kind: %r" % (self.model.kind, ))

    def refresh(self):
        self.search.refresh()

    def _get_columns(self, kind):
        if kind in ['payable', 'receivable']:
            return self._get_payment_columns()
        else:
            return self._get_account_columns()

    def _on_result_view__cell_data_func(self, column, renderer, account_view,
                                        text):
        if not isinstance(renderer, Gtk.CellRendererText):
            return text

        if self.model.kind != 'account':
            return text

        trans = account_view.transaction
        is_imbalance = self.app._imbalance_account_id in [
            trans.dest_account_id, trans.source_account_id
        ]

        renderer.set_property('weight-set', is_imbalance)
        if is_imbalance:
            renderer.set_property('weight', Pango.Weight.BOLD)

        return text

    def _get_account_columns(self):
        def format_withdrawal(value):
            if value < 0:
                return currency(abs(value)).format(symbol=True, precision=2)

        def format_deposit(value):
            if value > 0:
                return currency(value).format(symbol=True, precision=2)

        if self.model.account_type == Account.TYPE_INCOME:
            color_func = lambda x: False
        else:
            color_func = lambda x: x < 0
        return [
            Column('date',
                   title=_("Date"),
                   data_type=datetime.date,
                   sorted=True),
            Column('code', title=_("Code"), data_type=str),
            Column('description',
                   title=_("Description"),
                   data_type=str,
                   expand=True),
            Column('account', title=_("Account"), data_type=str),
            Column('value',
                   title=self.model.account.get_type_label(out=False),
                   data_type=currency,
                   format_func=format_deposit),
            Column('value',
                   title=self.model.account.get_type_label(out=True),
                   data_type=currency,
                   format_func=format_withdrawal),
            ColoredColumn('total',
                          title=_("Total"),
                          data_type=currency,
                          color='red',
                          data_func=color_func)
        ]

    def _get_payment_columns(self):
        return [
            SearchColumn('due_date',
                         title=_("Due date"),
                         data_type=datetime.date,
                         sorted=True),
            IdentifierColumn('identifier', title=_("Payment #")),
            SearchColumn('description',
                         title=_("Description"),
                         data_type=str,
                         expand=True),
            SearchColumn('value', title=_("Value"), data_type=currency)
        ]

    def append_transactions(self, transactions):
        for transaction in transactions:
            description = transaction.get_account_description(self.model)
            value = transaction.get_value(self.model)
            # If a transaction has the source equals to the destination account.
            # Show the same transaction, but with reversed value.
            if transaction.source_account_id == transaction.dest_account_id:
                self._add_transaction(transaction, description, -value)
            self._add_transaction(transaction, description, value)
        self.update_totals()

    def _add_transaction(self, transaction, description, value):
        item = Settable(transaction=transaction)
        self._update_transaction(item, transaction, description, value)
        self.search.result_view.append(item)
        return item

    def _update_transaction(self, item, transaction, description, value):
        item.account = description
        item.date = transaction.date
        item.description = transaction.description
        item.value = value
        item.code = transaction.code

    def update_totals(self):
        total = decimal.Decimal('0')
        for item in self.search.result_view:
            total += item.value
            item.total = total

    def _edit_transaction_dialog(self, item):
        store = api.new_store()
        if isinstance(item.transaction, AccountTransactionView):
            account_transaction = store.fetch(item.transaction.transaction)
        else:
            account_transaction = store.fetch(item.transaction)
        model = getattr(self.model, 'account', self.model)

        transaction = run_dialog(AccountTransactionEditor, self.app, store,
                                 account_transaction, model)

        store.confirm(transaction)
        if transaction:
            self.app.refresh_pages()
            self.update_totals()
            self.app.accounts.refresh_accounts(self.app.store)
        store.close()

    def on_dialog__opened(self, dialog):
        dialog.connect('account-added', self.on_dialog__account_added)

    def on_dialog__account_added(self, dialog):
        self.app.accounts.refresh_accounts(self.app.store)

    def add_transaction_dialog(self):
        store = api.new_store()
        model = getattr(self.model, 'account', self.model)
        model = store.fetch(model)

        transaction = run_dialog(AccountTransactionEditor, self.app, store,
                                 None, model)
        store.confirm(transaction)
        if transaction:
            self.app.refresh_pages()
            self.update_totals()
            self.app.accounts.refresh_accounts(self.app.store)
        store.close()

    def _on_search__item_activated(self, objectlist, item):
        if self.model.kind == 'account':
            self._edit_transaction_dialog(item)
コード例 #3
0
class FinancialReportDialog(BasicDialog):
    title = _('Financial Report Dialog')

    def __init__(self, store):
        self.store = store

        self.date_filter = DateSearchFilter(_('Year:'))
        self.date_filter.clear_options()
        self._populate_date_filter(self.date_filter)
        self.date_filter.select()
        self.date_filter.set_use_date_entries(False)

        BasicDialog.__init__(self, title=self.title)
        self.main_label.set_justify(Gtk.Justification.CENTER)

        self.ok_button.set_label(_("Generate"))
        self.add(self.date_filter)
        self.date_filter.show()

    def confirm(self):
        start = self.date_filter.get_start_date()
        if start is None:
            warning(_("There are no transactions yet"))
            return

        f = FinancialIntervalReport(self.store, start.year)
        if not f.run():
            return
        temporary = tempfile.NamedTemporaryFile(
            # Translators: This will be part of a filename
            prefix=_('stoq-yearly-report'),
            suffix='.xls', delete=False)
        f.write(temporary)
        sse = SpreadSheetExporter()
        sse.export_temporary(temporary)

        self.close()
        self.temporary = temporary

    #
    # Private
    #

    def _populate_date_filter(self, date_filter):
        transaction = self.store.find(AccountTransaction).order_by(
            AccountTransaction.date).first()
        if transaction is None:
            return

        for i in range(transaction.date.year,
                       localtoday().year + 1):
            year = datetime.datetime(i, 1, 1)
            date_filter.add_option_fixed_interval(
                _('Year %d') % (i, ),
                year, year.replace(month=12, day=31),
                position=0)

    def _date_filter_query(self, search_spec, column):
        executer = QueryExecuter(self.store)
        executer.set_filter_columns(self.date_filter, [column])
        executer.set_search_spec(search_spec)
        return executer.search([self.date_filter.get_state()])