Beispiel #1
0
class ResultTable(ResultTableBase):
    COLUMNS = [
        Column('marked', ''),
        Column('name', 'Filename'),
        Column('folder_path', 'Directory'),
        Column('size', 'Size (KB)'),
        Column('extension', 'Kind'),
    ]
    DELTA_COLUMNS = {'size', }
Beispiel #2
0
class ResultTable(ResultTableBase):
    COLUMNS = [
        Column("marked", ""),
        Column("name", "Filename"),
        Column("folder_path", "Directory"),
        Column("size", "Size (KB)"),
        Column("extension", "Kind"),
    ]
    DELTA_COLUMNS = {
        "size",
    }
Beispiel #3
0
class SplitTable(GUITable):
    COLUMNS = [
        Column('account', display=trcol("Account")),
        Column('memo', display=trcol("Memo")),
        Column('debit', display=trcol("Debit")),
        Column('credit', display=trcol("Credit")),
    ]

    def __init__(self, transaction_panel):
        GUITable.__init__(self, document=transaction_panel.mainwindow.document)
        self.panel = transaction_panel
        self.completable_edit = self.panel.completable_edit

    # --- Override
    def _do_add(self):
        split = self.panel.new_split()
        row = SplitTableRow(self, split)
        return row, len(self)

    def _do_delete(self):
        self.panel.delete_split(self.selected_row.split)
        self.refresh()

    def _is_edited_new(self):
        split = self.edited.split
        return split not in split.transaction.splits

    def _fill(self):
        transaction = self.panel.transaction
        splits = transaction.splits
        for split in splits:
            self.append(SplitTableRow(self, split))

    def _update_selection(self):
        self.panel.select_splits([row.split for row in self.selected_rows])

    # --- Public
    def move_split(self, from_index, to_index):
        row = self[from_index]
        row.split.move_to_index(to_index)
        self.refresh(refresh_view=False)
        self.select([to_index])
        self.view.refresh()

    def refresh_splits(self):
        self._item_changed()

    def refresh_initial(self):
        # the refresh just after a panel loading is a bit different
        self.refresh(refresh_view=False)
        self.select([0])
        self.view.refresh()
Beispiel #4
0
class PluginListTable(GUITable):
    SAVENAME = 'PluginListTable'
    COLUMNS = [
        Column('enabled', display=trcol("Enabled")),
        Column('name', display=trcol("Name")),
        Column('type', display=trcol("Type")),
        Column('author', display=trcol("Author")),
    ]

    # --- Override
    def _fill(self):
        for plugin in self.document.app.plugins:
            self.append(PluginListRow(self, plugin))
Beispiel #5
0
class ResultTable(ResultTableBase):
    COLUMNS = [
        Column('marked', ''),
        Column('name', coltr("Filename")),
        Column('folder_path', coltr("Folder"), optional=True),
        Column('size', coltr("Size (KB)"), optional=True),
        Column('extension', coltr("Kind"), visible=False, optional=True),
        Column('dimensions', coltr("Dimensions"), optional=True),
        Column('exif_timestamp', coltr("EXIF Timestamp"), visible=False, optional=True),
        Column('mtime', coltr("Modification"), visible=False, optional=True),
        Column('percentage', coltr("Match %"), optional=True),
        Column('dupe_count', coltr("Dupe Count"), visible=False, optional=True),
    ]
    DELTA_COLUMNS = {'size', 'dimensions', 'mtime'}
Beispiel #6
0
class ExportAccountTable(GUITable):
    COLUMNS = [
        Column('name', display=trcol("Account")),
        Column('export', display=trcol("Export")),
    ]

    def __init__(self, export_panel):
        self.panel = export_panel
        GUITable.__init__(self, document=export_panel.document)

    # --- Override
    def _fill(self):
        accounts = sorted(self.panel.accounts, key=ACCOUNT_SORT_KEY)
        for account in accounts:
            self.append(ExportAccountTableRow(self, account))
class GeneralLedgerTable(EntryTableBase):
    SAVENAME = 'GeneralLedgerTable'
    COLUMNS = [
        Column('status', display=''),
        Column('date', display=trcol("Date")),
        Column('reconciliation_date', display=trcol("Reconciliation Date"), visible=False, optional=True),
        Column('checkno', display=trcol("Check #"), visible=False, optional=True),
        Column('description', display=trcol("Description"), optional=True),
        Column('payee', display=trcol("Payee"), visible=False, optional=True),
        Column('transfer', display=trcol("Transfer")),
        Column('debit', display=trcol("Debit")),
        Column('credit', display=trcol("Credit")),
        Column('balance', display=trcol("Balance")),
    ]
    ENTRY_ROWCLASS = GeneralLedgerRow
    
    # --- Override
    def _fill(self):
        accounts = self.document.accounts
        sort_accounts(accounts)
        for account in accounts:
            rows = self._get_account_rows(account)
            if not rows:
                continue
            self.append(AccountRow(self, account))
            for row in rows:
                self.append(row)
    
    def _get_current_account(self):
        row = self.selected_row
        return row.account if row is not None else None
    
    def _get_totals_currency(self):
        return self.document.default_currency
    
    # --- Public
    def is_account_row(self, row):
        return isinstance(row, AccountRow)
    
    def is_bold_row(self, row):
        return isinstance(row, (TotalRow, PreviousBalanceRow))
    
    # --- Event Handlers
    def date_range_changed(self):
        self.refresh(refresh_view=False)
        self._update_selection()
        self.view.refresh()
        self.view.show_selected_row()
Beispiel #8
0
class ExcludeListTable(GUITable, DupeGuruGUIObject):
    COLUMNS = [
        Column("marked", ""),
        Column("regex", tr("Regular Expressions"))
    ]

    def __init__(self, exclude_list_dialog, app):
        GUITable.__init__(self)
        DupeGuruGUIObject.__init__(self, app)
        self.columns = Columns(self)
        self.dialog = exclude_list_dialog

    def rename_selected(self, newname):
        row = self.selected_row
        if row is None:
            return False
        row._data = None
        return self.dialog.rename_selected(newname)

    # --- Virtual
    def _do_add(self, regex):
        """(Virtual) Creates a new row, adds it in the table.
        Returns ``(row, insert_index)``."""
        # Return index 0 to insert at the top
        return ExcludeListRow(self, self.dialog.exclude_list.is_marked(regex),
                              regex), 0

    def _do_delete(self):
        self.dalog.exclude_list.remove(self.selected_row.regex)

    # --- Override
    def add(self, regex):
        row, insert_index = self._do_add(regex)
        self.insert(insert_index, row)
        self.view.refresh()

    def _fill(self):
        for enabled, regex in self.dialog.exclude_list:
            self.append(ExcludeListRow(self, enabled, regex))

    def refresh(self, refresh_view=True):
        """Override to avoid keeping previous selection in case of multiple rows
        selected previously."""
        self.cancel_edits()
        del self[:]
        self._fill()
        if refresh_view:
            self.view.refresh()
Beispiel #9
0
class ResultTable(ResultTableBase):
    COLUMNS = [
        Column("marked", ""),
        Column("name", coltr("Filename")),
        Column("folder_path", coltr("Folder"), optional=True),
        Column("size", coltr("Size (KB)"), optional=True),
        Column("extension", coltr("Kind"), visible=False, optional=True),
        Column("mtime", coltr("Modification"), visible=False, optional=True),
        Column("percentage", coltr("Match %"), optional=True),
        Column("words", coltr("Words Used"), visible=False, optional=True),
        Column("dupe_count", coltr("Dupe Count"), visible=False, optional=True),
    ]
    DELTA_COLUMNS = {"size", "mtime"}
Beispiel #10
0
class IgnoreListTable(GUITable):
    COLUMNS = [
        # the str concat below saves us needless localization.
        Column('path1', coltr("File Path") + " 1"),
        Column('path2', coltr("File Path") + " 2"),
    ]
    
    def __init__(self, ignore_list_dialog):
        GUITable.__init__(self)
        self.columns = Columns(self)
        self.view = None
        self.dialog = ignore_list_dialog
    
    #--- Override
    def _fill(self):
        for path1, path2 in self.dialog.ignore_list:
            self.append(IgnoreListRow(self, path1, path2))
Beispiel #11
0
class ScheduleTable(GUITable, TableWithAmountMixin):
    SAVENAME = 'ScheduleTable'
    COLUMNS = [
        Column('start_date', display=trcol('Start Date')),
        Column('stop_date', display=trcol('Stop Date')),
        Column('repeat_type', display=trcol('Repeat Type')),
        Column('interval', display=trcol('Interval')),
        Column('checkno',
               display=trcol('Check #'),
               visible=False,
               optional=True),
        Column('description', display=trcol('Description'), optional=True),
        Column('payee', display=trcol('Payee'), visible=False, optional=True),
        Column('from', display=trcol('From')),
        Column('to', display=trcol('To')),
        Column('amount', display=trcol('Amount')),
    ]

    def __init__(self, schedule_view):
        GUITable.__init__(self, document=schedule_view.document)
        self.mainwindow = schedule_view.mainwindow

    # --- Override
    def _update_selection(self):
        self.mainwindow.selected_schedules = self.selected_schedules

    def _fill(self):
        self._all_amounts_are_native = True
        for schedule in self.document.schedules:
            row = ScheduleTableRow(self, schedule)
            if not row.is_amount_native:
                self._all_amounts_are_native = False
            self.append(row)

    # --- Public
    def delete(self):
        self.document.delete_schedules(self.selected_schedules)

    def edit(self):
        self.mainwindow.edit_item()

    # --- Properties
    @property
    def selected_schedules(self):
        return [row.schedule for row in self.selected_rows]
Beispiel #12
0
class ElementTable(GUIObject, GUITable):
    #--- model -> view calls:
    # refresh()
    #

    COLUMNS = [
        Column('page', "Page"),
        Column('order', "Order"),
        Column('x', "X"),
        Column('y', "Y"),
        Column('fontsize', "Font Size"),
        Column('text_length', "Text Length"),
        Column('state', "State"),
        Column('text', "Text"),
    ]

    def __init__(self, app):
        GUIObject.__init__(self, app)
        GUITable.__init__(self)
        self.columns = Columns(self)

    #--- Override
    def _fill(self):
        elements = self.app.elements
        if self.app.hide_ignored:
            elements = [e for e in elements if e.state != ElementState.Ignored]
        for element in elements:
            self.append(ElementRow(self, element))

    def _update_selection(self):
        # Takes the table's selection and does appropriates updates on the Document's side.
        elements = {row.element for row in self.selected_rows}
        self.app.select_elements(elements)

    #--- Public
    def press_key(self, key):
        key = key.upper()
        if key not in SHORTCUTKEY2FLAG:
            return
        state = SHORTCUTKEY2FLAG[key]
        self.app.change_state_of_selected(state)

    #--- Event Handlers
    def elements_changed(self):
        self.refresh()

    def elements_selected(self):
        selected_elements = self.app.selected_elements
        selected_indexes = []
        for index, row in enumerate(self):
            if row.element in selected_elements:
                selected_indexes.append(index)
        if selected_indexes != self.selected_indexes:
            self.selected_indexes = selected_indexes
            self.view.refresh()
Beispiel #13
0
class ProblemTable(GUITable):
    COLUMNS = [
        Column('path', coltr("File Path")),
        Column('msg', coltr("Error Message")),
    ]

    def __init__(self, problem_dialog):
        GUITable.__init__(self)
        self.columns = Columns(self)
        self.dialog = problem_dialog

    #--- Override
    def _update_selection(self):
        row = self.selected_row
        dupe = row.dupe if row is not None else None
        self.dialog.select_dupe(dupe)

    def _fill(self):
        problems = self.dialog.app.results.problems
        for dupe, msg in problems:
            self.append(ProblemRow(self, dupe, msg))
Beispiel #14
0
class BudgetTable(GUITable, TableWithAmountMixin):
    SAVENAME = 'BudgetTable'
    COLUMNS = [
        Column('start_date', display=trcol("Start Date")),
        Column('stop_date', display=trcol("Stop Date")),
        Column('repeat_type', display=trcol("Repeat Type")),
        Column('interval', display=trcol("Interval")),
        Column('account', display=trcol("Account")),
        Column('target', display=trcol("Target")),
        Column('amount', display=trcol("Amount")),
    ]

    def __init__(self, budget_view):
        GUITable.__init__(self, document=budget_view.document)
        self.mainwindow = budget_view.mainwindow

    # --- Override
    def _update_selection(self):
        self.mainwindow.selected_budgets = self.selected_budgets

    def _fill(self):
        self._all_amounts_are_native = True
        for budget in self.document.budgets:
            if not self.mainwindow.document.is_amount_native(budget.amount):
                self._all_amounts_are_native = False
            self.append(BudgetTableRow(self, budget))

    # --- Public
    def delete(self):
        self.document.delete_budgets(self.selected_budgets)

    def edit(self):
        self.mainwindow.edit_item()

    # --- Properties
    @property
    def selected_budgets(self):
        return [row.budget for row in self.selected_rows]
Beispiel #15
0
class ResultTable(ResultTableBase):
    COLUMNS = [
        Column("marked", ""),
        Column("name", coltr("Filename")),
        Column("folder_path", coltr("Folder"), visible=False, optional=True),
        Column("size", coltr("Size (MB)"), optional=True),
        Column("duration", coltr("Time"), optional=True),
        Column("bitrate", coltr("Bitrate"), optional=True),
        Column("samplerate",
               coltr("Sample Rate"),
               visible=False,
               optional=True),
        Column("extension", coltr("Kind"), optional=True),
        Column("mtime", coltr("Modification"), visible=False, optional=True),
        Column("title", coltr("Title"), visible=False, optional=True),
        Column("artist", coltr("Artist"), visible=False, optional=True),
        Column("album", coltr("Album"), visible=False, optional=True),
        Column("genre", coltr("Genre"), visible=False, optional=True),
        Column("year", coltr("Year"), visible=False, optional=True),
        Column("track", coltr("Track Number"), visible=False, optional=True),
        Column("comment", coltr("Comment"), visible=False, optional=True),
        Column("percentage", coltr("Match %"), optional=True),
        Column("words", coltr("Words Used"), visible=False, optional=True),
        Column("dupe_count", coltr("Dupe Count"), visible=False,
               optional=True),
    ]
    DELTA_COLUMNS = {"size", "duration", "bitrate", "samplerate", "mtime"}
Beispiel #16
0
class ResultTable(ResultTableBase):
    COLUMNS = [
        Column('marked', ''),
        Column('name', coltr("Filename")),
        Column('folder_path', coltr("Folder"), visible=False, optional=True),
        Column('size', coltr("Size (MB)"), optional=True),
        Column('duration', coltr("Time"), optional=True),
        Column('bitrate', coltr("Bitrate"), optional=True),
        Column('samplerate',
               coltr("Sample Rate"),
               visible=False,
               optional=True),
        Column('extension', coltr("Kind"), optional=True),
        Column('mtime', coltr("Modification"), visible=False, optional=True),
        Column('title', coltr("Title"), visible=False, optional=True),
        Column('artist', coltr("Artist"), visible=False, optional=True),
        Column('album', coltr("Album"), visible=False, optional=True),
        Column('genre', coltr("Genre"), visible=False, optional=True),
        Column('year', coltr("Year"), visible=False, optional=True),
        Column('track', coltr("Track Number"), visible=False, optional=True),
        Column('comment', coltr("Comment"), visible=False, optional=True),
        Column('percentage', coltr("Match %"), optional=True),
        Column('words', coltr("Words Used"), visible=False, optional=True),
        Column('dupe_count', coltr("Dupe Count"), visible=False,
               optional=True),
    ]
    DELTA_COLUMNS = {'size', 'duration', 'bitrate', 'samplerate', 'mtime'}
Beispiel #17
0
class TransactionTable(TransactionTableBase):
    SAVENAME = 'TransactionTable'
    COLUMNS = [
        Column('status', display=''),
        Column('date', display=trcol('Date')),
        Column('checkno',
               display=trcol('Check #'),
               visible=False,
               optional=True),
        Column('description', display=trcol('Description'), optional=True),
        Column('payee', display=trcol('Payee'), visible=False, optional=True),
        Column('from', display=trcol('From')),
        Column('to', display=trcol('To')),
        Column('amount', display=trcol('Amount')),
        Column('mtime',
               display=trcol('Modification Time'),
               visible=False,
               optional=True),
    ]

    # --- Override
    def _do_add(self):
        transactions = self.mainwindow.selected_transactions
        date = transactions[0].date if transactions else datetime.date.today()
        transaction = Transaction(date, amount=0)
        rows = self[:-1]  # ignore total row
        for index, row in enumerate(rows):
            if row._date > transaction.date:
                insert_index = index
                break
        else:
            insert_index = len(rows)
        row = TransactionTableRow(self, transaction)
        return row, insert_index

    def _do_delete(self):
        transactions = self.selected_transactions
        if transactions:
            self.document.delete_transactions(transactions)

    def _fill(self):
        self._all_amounts_are_native = True
        total_amount = 0
        for transaction in self.parent_view.visible_transactions:
            self.append(TransactionTableRow(self, transaction))
            convert = lambda a: convert_amount(
                a, self.document.default_currency, transaction.date)
            total_amount += convert(transaction.amount)
            if not self.document.is_amount_native(transaction.amount):
                self._all_amounts_are_native = False
        self.footer = TotalRow(self, self.document.date_range.end,
                               total_amount)
        self._restore_from_explicit_selection(refresh_view=False)

    # --- Private
    def _show_account(self, row_index=None, use_to_column=False):
        # if `use_to_column` is True, use the To column, else, use the From column
        if row_index is None:
            if not self.selected_transactions:
                return
            row_index = self.selected_index
        txn = self[row_index].transaction
        froms, tos = txn.splitted_splits()
        splits = tos if use_to_column else froms
        account_to_show = splits[0].account
        self.mainwindow.open_account(account_to_show)

    # --- Public
    def select_transactions(self, transactions):
        TransactionTableBase.select_transactions(self, transactions)
        if self and not self.selected_indexes:
            self.selected_indexes = [len(self) - 1]

    def show_from_account(self, row_index=None):
        self._show_account(row_index, use_to_column=False)

    def show_to_account(self, row_index=None):
        self._show_account(row_index, use_to_column=True)

    # --- Properties
    @property
    def selected_transactions(self):
        return [
            row.transaction for row in self.selected_rows
            if hasattr(row, 'transaction')
        ]

    # --- Event handlers
    def date_range_changed(self):
        self.refresh(refresh_view=False)
        self._update_selection()
        self.view.refresh()
        self.view.show_selected_row()

    def transactions_imported(self):
        self.refresh(refresh_view=False)
        self._update_selection()
        self.view.refresh()
Beispiel #18
0
class EntryTable(EntryTableBase):
    SAVENAME = 'EntryTable'
    COLUMNS = [
        Column('status', display=''),
        Column('date', display=trcol("Date")),
        Column('reconciliation_date',
               display=trcol("Reconciliation Date"),
               visible=False,
               optional=True),
        Column('checkno',
               display=trcol("Check #"),
               visible=False,
               optional=True),
        Column('description', display=trcol("Description"), optional=True),
        Column('payee', display=trcol("Payee"), visible=False, optional=True),
        Column('transfer', display=trcol("Transfer")),
        Column('increase', display=trcol("Increase")),
        Column('decrease', display=trcol("Decrease")),
        Column('debit', display=trcol("Debit"), visible=False),
        Column('credit', display=trcol("Credit"), visible=False),
        Column('balance', display=trcol("Balance")),
    ]

    def __init__(self, account_view):
        EntryTableBase.__init__(self, account_view)
        self.columns = EntryTableColumns(self,
                                         prefaccess=account_view.document,
                                         savename=self.SAVENAME)
        self.account = account_view.account
        self.completable_edit.account = self.account
        self._reconciliation_mode = False

    # --- Override
    def _fill(self):
        account = self.account
        if account is None:
            return
        self.account = account
        rows = self._get_account_rows(account)
        is_native = lambda row: self.document.is_amount_native(row._debit)\
            and self.document.is_amount_native(row._credit)
        self._all_amounts_are_native = all(is_native(row) for row in rows)
        if not rows:
            # We still show a total row
            rows.append(
                TotalRow(self, account, self.document.date_range.end, 0, 0))
        if isinstance(rows[0], PreviousBalanceRow):
            self.header = rows[0]
            del rows[0]
        for row in rows[:-1]:
            self.append(row)
        self.footer = rows[-1]
        balance_visible = account.is_balance_sheet_account()
        self.columns.set_column_visible('balance', balance_visible)
        self._restore_from_explicit_selection(refresh_view=False)

    def _get_current_account(self):
        return self.account

    def _get_totals_currency(self):
        return self._get_current_account().currency

    # --- Public
    def show_transfer_account(self, row_index=None):
        if row_index is None:
            if not self.selected_entries:
                return
            row_index = self.selected_index
        entry = self[row_index].entry
        splits = entry.transaction.splits
        accounts = dedupe(split.account for split in splits
                          if split.account is not None)
        if len(accounts) < 2:
            return  # no transfer
        index = accounts.index(entry.account)
        if index < len(accounts) - 1:
            account_to_show = accounts[index + 1]
        else:
            account_to_show = accounts[0]
        self.mainwindow.open_account(account_to_show)

    def toggle_reconciled(self):
        """Toggle the reconcile flag of selected entries"""
        entries = [
            row.entry for row in self.selected_rows if row.can_reconcile()
        ]
        self.document.toggle_entries_reconciled(entries)

    # --- Properties
    @property
    def reconciliation_mode(self):
        return self._reconciliation_mode

    @reconciliation_mode.setter
    def reconciliation_mode(self, value):
        if value == self._reconciliation_mode:
            return
        self._reconciliation_mode = value
        self.refresh()

    # --- Event Handlers
    def date_range_changed(self):
        date_range = self.document.date_range
        self.refresh(refresh_view=False)
        self.select_transactions(self.mainwindow.selected_transactions)
        if not self.selected_indexes:
            self._select_nearest_date(date_range.start +
                                      self._delta_before_change)
        self.view.refresh()
        self.view.show_selected_row()
        self.mainwindow.selected_transactions = self.selected_transactions

    def date_range_will_change(self):
        date_range = self.document.date_range
        transactions = self.selected_transactions
        date = transactions[0].date if transactions else date_range.end
        delta = date - date_range.start
        self._delta_before_change = delta

    def transaction_changed(self):
        EntryTableBase.transaction_changed(self)
        # It's possible that because of the change, the selected txn has been removed, so we have
        # to update document selection.
        self._update_selection()

    def transactions_imported(self):
        self.refresh(refresh_view=False)
        self.mainwindow.selected_transactions = self.selected_transactions
        self.view.refresh()
        self.view.show_selected_row()
Beispiel #19
0
class ImportTable(GUITable, TransactionSelectionMixin):
    SAVENAME = 'ImportTable'
    COLUMNS = [
        Column('will_import', display=''),
        Column('date', display=trcol("Date")),
        Column('description', display=trcol("Description")),
        Column('amount', display=trcol("Amount")),
        Column('bound', display=''),
        Column('date_import', display=trcol("Date")),
        Column('description_import', display=trcol("Description")),
        Column('payee_import', display=trcol("Payee")),
        Column('checkno_import', display=trcol("Check #")),
        Column('transfer_import', display=trcol("Transfer")),
        Column('amount_import', display=trcol("Amount")),
    ]

    def __init__(self, import_window):
        GUITable.__init__(self, document=import_window.document)
        self.window = import_window
        self._is_two_sided = False
        self.__last_explicitly_selected = []

    # --- Override
    def select_transactions(self, transactions):
        selected_indexes = []
        for index, row in enumerate(self):
            indexed_row = row.imported.transaction if row.imported else row.entry.transaction
            if indexed_row in transactions:
                selected_indexes.append(index)
        self.selected_indexes = selected_indexes

    @property
    def selected_transactions(self):
        return [
            row.imported.transaction if row.imported else row.entry.transaction
            for row in self.selected_rows
        ]

    @property
    def _explicitly_selected_transactions(self):
        return self.__last_explicitly_selected

    def _update_selection(self):
        self.__last_explicitly_selected = self.selected_transactions

    def _fill(self):
        self._is_two_sided = False
        self.pane = self.window.selected_pane
        if not self.pane:
            return
        for existing, imported in self.pane.matches:
            if existing is not None:
                self._is_two_sided = True
            self.append(ImportTableRow(self, existing, imported))

    # --- Public
    def bind(self, source_index, dest_index):
        source = self[source_index]
        dest = self[dest_index]
        source.bind(dest)
        self.refresh()

    def can_bind(self, source_index, dest_index):
        source = self[source_index]
        dest = self[dest_index]
        return source.can_bind(dest)

    def delete(self):
        rows = self.selected_rows
        for row in rows:
            row.will_import = False
        self.view.refresh()

    def toggle_import_status(self):
        for row in self.selected_rows:
            row.will_import = not row.will_import
        self.view.refresh()

    def unbind(self, index):
        row = self[index]
        if not row.bound:
            return
        row.unbind()
        self.refresh()

    # --- Properties
    @property
    def is_two_sided(self):
        """Returns whether the table should show columns to display matches from the target account.
        """
        return self._is_two_sided
Beispiel #20
0
class IncomeStatement(Report):
    SAVENAME = 'IncomeStatement'
    COLUMNS = [
        Column('name', display=trcol("Account")),
        Column('account_number',
               display=trcol("Account #"),
               visible=False,
               optional=True),
        Column('cash_flow', display=trcol("Current")),
        Column('last_cash_flow', display=trcol("Last"), optional=True),
        Column('delta', display=trcol("Change"), visible=False, optional=True),
        Column('delta_perc',
               display=trcol("Change %"),
               visible=False,
               optional=True),
        Column('budgeted', display=trcol("Budgeted"), optional=True),
    ]

    # --- Override
    def _compute_account_node(self, node):
        account = node.account
        date_range = self.document.date_range
        currency = self.document.default_currency
        cash_flow = account.entries.normal_cash_flow(date_range)
        cash_flow_native = account.entries.normal_cash_flow(
            date_range, currency)
        last_cash_flow = account.entries.normal_cash_flow(date_range.prev())
        last_cash_flow_native = account.entries.normal_cash_flow(
            date_range.prev(), currency)
        remaining = self.document.budgets.normal_amount_for_account(
            account, date_range)
        remaining_native = self.document.budgets.normal_amount_for_account(
            account, date_range, currency)
        delta = cash_flow - last_cash_flow

        # Amounts for totals are converted in the document's currency
        node.cash_flow_amount = cash_flow_native
        node.last_cash_flow_amount = last_cash_flow_native
        node.budgeted_amount = remaining_native

        # Amounts for display are kept in the account's currency
        node.cash_flow = self.document.format_amount(cash_flow)
        node.last_cash_flow = self.document.format_amount(last_cash_flow)
        node.budgeted = self.document.format_amount(remaining)
        node.delta = self.document.format_amount(delta)
        node.delta_perc = get_delta_perc(delta, last_cash_flow)

    def _make_node(self, name):
        node = Report._make_node(self, name)
        node.cash_flow = ''
        node.last_cash_flow = ''
        node.budget = ''
        node.budgeted = ''
        node.delta = ''
        node.delta_perc = ''
        node.cash_flow_amount = 0
        node.last_cash_flow_amount = 0
        node.budgeted_amount = 0
        return node

    def _refresh(self):
        self.clear()
        self.has_multiple_currencies = self.document.accounts.has_multiple_currencies(
        )
        self.income = self.make_type_node(tr('INCOME'), AccountType.Income)
        self.expenses = self.make_type_node(tr('EXPENSES'),
                                            AccountType.Expense)
        self.net_income = self._make_node(tr('NET INCOME'))
        net_income = self.income.cash_flow_amount - self.expenses.cash_flow_amount
        last_net_income = self.income.last_cash_flow_amount - self.expenses.last_cash_flow_amount
        net_budgeted = self.income.budgeted_amount - self.expenses.budgeted_amount
        delta = net_income - last_net_income
        force_explicit_currency = self.has_multiple_currencies
        self.net_income.cash_flow = self.document.format_amount(
            net_income, force_explicit_currency=force_explicit_currency)
        self.net_income.last_cash_flow = self.document.format_amount(
            last_net_income, force_explicit_currency=force_explicit_currency)
        self.net_income.budgeted = self.document.format_amount(
            net_budgeted, force_explicit_currency=force_explicit_currency)
        self.net_income.delta = self.document.format_amount(
            delta, force_explicit_currency=force_explicit_currency)
        self.net_income.delta_perc = get_delta_perc(delta, last_net_income)
        self.net_income.is_total = True
        self.append(self.income)
        self.append(self.expenses)
        self.append(self.net_income)

    # --- Public
    def make_total_node(self, parent, name):
        node = Report.make_total_node(self, name)
        parent.cash_flow_amount = sum(child.cash_flow_amount
                                      for child in parent)
        parent.last_cash_flow_amount = sum(child.last_cash_flow_amount
                                           for child in parent)
        parent.budgeted_amount = sum(child.budgeted_amount for child in parent)
        delta = parent.cash_flow_amount - parent.last_cash_flow_amount
        force_explicit_currency = self.has_multiple_currencies
        node.cash_flow = parent.cash_flow = self.document.format_amount(
            parent.cash_flow_amount,
            force_explicit_currency=force_explicit_currency)
        node.last_cash_flow = parent.last_cash_flow = self.document.format_amount(
            parent.last_cash_flow_amount,
            force_explicit_currency=force_explicit_currency)
        node.budgeted = parent.budgeted = self.document.format_amount(
            parent.budgeted_amount,
            force_explicit_currency=force_explicit_currency)
        node.delta = parent.delta = self.document.format_amount(
            delta, force_explicit_currency=force_explicit_currency)
        node.delta_perc = parent.delta_perc = get_delta_perc(
            delta, parent.last_cash_flow_amount)
        return node
Beispiel #21
0
class BalanceSheet(Report):
    SAVENAME = 'BalanceSheet'
    COLUMNS = [
        Column('name', display=trcol("Account")),
        Column('account_number',
               display=trcol("Account #"),
               visible=False,
               optional=True),
        Column('end', display=trcol("End")),
        Column('start', display=trcol("Start"), optional=True),
        Column('delta', display=trcol("Change"), visible=False, optional=True),
        Column('delta_perc',
               display=trcol("Change %"),
               visible=False,
               optional=True),
        Column('budgeted', display=trcol("Budgeted"), optional=True),
    ]

    # --- Override
    def _compute_account_node(self, node):
        account = node.account
        date_range = self.document.date_range
        start_date = date_range.start
        end_date = date_range.end
        currency = self.document.default_currency
        start_amount = account.entries.normal_balance(start_date -
                                                      timedelta(1))
        start_amount_native = account.entries.normal_balance(start_date -
                                                             timedelta(1),
                                                             currency=currency)
        end_amount = account.entries.normal_balance(end_date)
        end_amount_native = account.entries.normal_balance(end_date,
                                                           currency=currency)
        budget_date_range = DateRange(date.today(), end_date)
        budgeted_amount = self.document.budgeted_amount_for_target(
            account, budget_date_range)
        budgeted_amount_native = convert_amount(budgeted_amount, currency,
                                                date_range.end)
        delta = end_amount - start_amount

        # Amounts for totals are converted in the document's currency
        node.start_amount = start_amount_native
        node.end_amount = end_amount_native
        node.budgeted_amount = budgeted_amount_native

        # Amounts for display are kept in the account's currency
        node.start = self.document.format_amount(start_amount)
        node.end = self.document.format_amount(end_amount)
        node.budgeted = self.document.format_amount(budgeted_amount)
        node.delta = self.document.format_amount(delta)
        node.delta_perc = get_delta_perc(delta, start_amount)

    def _make_node(self, name):
        node = Report._make_node(self, name)
        node.start = ''
        node.end = ''
        node.budgeted = ''
        node.delta = ''
        node.delta_perc = ''
        node.start_amount = 0
        node.end_amount = 0
        node.budgeted_amount = 0
        return node

    def _refresh(self):
        self.clear()
        self.has_multiple_currencies = self.document.accounts.has_multiple_currencies(
        )
        self.assets = self.make_type_node(tr('ASSETS'), AccountType.Asset)
        self.liabilities = self.make_type_node(tr('LIABILITIES'),
                                               AccountType.Liability)
        self.net_worth = self._make_node(tr('NET WORTH'))
        net_worth_start = self.assets.start_amount - self.liabilities.start_amount
        net_worth_end = self.assets.end_amount - self.liabilities.end_amount
        budget_date_range = DateRange(date.today(),
                                      self.document.date_range.end)
        # The net worth's budget is not a simple subtraction, it must count the target-less budgets
        net_worth_budgeted = self.document.budgeted_amount_for_target(
            None, budget_date_range)
        net_worth_delta = net_worth_end - net_worth_start
        force_explicit_currency = self.has_multiple_currencies
        self.net_worth.start = self.document.format_amount(
            net_worth_start, force_explicit_currency=force_explicit_currency)
        self.net_worth.end = self.document.format_amount(
            net_worth_end, force_explicit_currency=force_explicit_currency)
        self.net_worth.budgeted = self.document.format_amount(
            net_worth_budgeted,
            force_explicit_currency=force_explicit_currency)
        self.net_worth.delta = self.document.format_amount(
            net_worth_delta, force_explicit_currency=force_explicit_currency)
        self.net_worth.delta_perc = get_delta_perc(net_worth_delta,
                                                   net_worth_start)
        self.net_worth.is_total = True
        self.append(self.assets)
        self.append(self.liabilities)
        self.append(self.net_worth)

    # --- Public
    def make_total_node(self, parent, name):
        node = Report.make_total_node(self, name)
        parent.start_amount = sum(child.start_amount for child in parent)
        parent.end_amount = sum(child.end_amount for child in parent)
        parent.budgeted_amount = sum(child.budgeted_amount for child in parent)
        delta_amount = parent.end_amount - parent.start_amount
        force_explicit_currency = self.has_multiple_currencies
        node.start = parent.start = self.document.format_amount(
            parent.start_amount,
            force_explicit_currency=force_explicit_currency)
        node.end = parent.end = self.document.format_amount(
            parent.end_amount, force_explicit_currency=force_explicit_currency)
        node.budgeted = parent.budgeted = self.document.format_amount(
            parent.budgeted_amount,
            force_explicit_currency=force_explicit_currency)
        node.delta = parent.delta = self.document.format_amount(
            delta_amount, force_explicit_currency=force_explicit_currency)
        node.delta_perc = parent.delta_perc = get_delta_perc(
            delta_amount, parent.start_amount)
        return node