def _setup_widgets(self): self._test_button = gtk.Button(_("Print a test bill")) self._test_button.connect('clicked', self._on_test_button__clicked) self.parent_accounts = AccountTree(with_code=False, create_mode=True) self.parent_accounts.connect( 'selection-changed', self._on_parent_accounts__selection_changed) self.tree_box.pack_start(self.parent_accounts) self.tree_box.reorder_child(self.parent_accounts, 0) if self.model == sysparam(self.store).IMBALANCE_ACCOUNT: self.account_type.set_sensitive(False) self.account_type.prefill(Account.account_type_descriptions) account_type = self.model.account_type self.parent_accounts.insert_initial(self.store, edited_account=self.model) if self.parent_account: account = self.parent_accounts.get_account_by_id( self.parent_account.id) self.parent_accounts.select(account) if not self.existing: account_type = account.account_type self.account_type.select(account_type) self.parent_accounts.show()
def __init__(self, window, store=None): # Account id -> TransactionPage self._pages = {} self.accounts = AccountTree() ShellApp.__init__(self, window, store=store) self._tills_account = api.sysparam(self.store).TILLS_ACCOUNT self._imbalance_account = api.sysparam(self.store).IMBALANCE_ACCOUNT self._banks_account = api.sysparam(self.store).BANKS_ACCOUNT
def _setup_widgets(self): self._test_button = gtk.Button(_("Print a test bill")) self._test_button.connect('clicked', self._on_test_button__clicked) self.parent_accounts = AccountTree(with_code=False, create_mode=True) self.parent_accounts.connect('selection-changed', self._on_parent_accounts__selection_changed) self.tree_box.pack_start(self.parent_accounts) self.tree_box.reorder_child(self.parent_accounts, 0) if self.model == sysparam(self.store).IMBALANCE_ACCOUNT: self.account_type.set_sensitive(False) self.account_type.prefill(Account.account_type_descriptions) account_type = self.model.account_type self.parent_accounts.insert_initial(self.store, edited_account=self.model) if self.parent_account: account = self.parent_accounts.get_account_by_id( self.parent_account.id) self.parent_accounts.select(account) if not self.existing: account_type = account.account_type self.account_type.select(account_type) self.parent_accounts.show()
def __init__(self, app, store=None): self._pages = {} self.accounts = AccountTree() AppWindow.__init__(self, app, store=store) self._tills_account = api.sysparam(self.store).TILLS_ACCOUNT self._imbalance_account = api.sysparam(self.store).IMBALANCE_ACCOUNT self._banks_account = api.sysparam(self.store).BANKS_ACCOUNT
class FinancialApp(ShellApp): app_title = _('Financial') gladefile = 'financial' def __init__(self, window, store=None): # Account id -> TransactionPage self._pages = {} self.accounts = AccountTree() ShellApp.__init__(self, window, store=store) self._tills_account = api.sysparam(self.store).TILLS_ACCOUNT self._imbalance_account = api.sysparam(self.store).IMBALANCE_ACCOUNT self._banks_account = api.sysparam(self.store).BANKS_ACCOUNT # # ShellApp overrides # def create_actions(self): group = get_accels('app.financial') actions = [ ('TransactionMenu', None, _('Transaction')), ('AccountMenu', None, _('Account')), ('Import', gtk.STOCK_ADD, _('Import...'), group.get('import'), _('Import a GnuCash or OFX file')), ('ConfigurePaymentMethods', None, _('Payment methods'), group.get('configure_payment_methods'), _('Select accounts for the payment methods on the system')), ('DeleteAccount', gtk.STOCK_DELETE, _('Delete...'), group.get('delete_account'), _('Delete the selected account')), ('DeleteTransaction', gtk.STOCK_DELETE, _('Delete...'), group.get('delete_transaction'), _('Delete the selected transaction')), ("NewAccount", gtk.STOCK_NEW, _("Account..."), group.get('new_account'), _("Add a new account")), ("NewTransaction", gtk.STOCK_NEW, _("Transaction..."), group.get('new_store'), _("Add a new transaction")), ("Edit", gtk.STOCK_EDIT, _("Edit..."), group.get('edit')), ] self.financial_ui = self.add_ui_actions('', actions, filename='financial.xml') self.set_help_section(_("Financial help"), 'app-financial') self.Edit.set_short_label(_('Edit')) self.DeleteAccount.set_short_label(_('Delete')) self.DeleteTransaction.set_short_label(_('Delete')) user = api.get_current_user(self.store) if not user.profile.check_app_permission(u'admin'): self.ConfigurePaymentMethods.set_sensitive(False) def create_ui(self): self.trans_popup = self.uimanager.get_widget('/TransactionSelection') self.acc_popup = self.uimanager.get_widget('/AccountSelection') self.window.add_new_items([self.NewAccount, self.NewTransaction]) self.search_holder.add(self.accounts) self.accounts.show() self._create_initial_page() self._refresh_accounts() def activate(self, params): for page in self._pages.values(): page.refresh() self._update_actions() self._update_tooltips() self.window.SearchToolItem.set_sensitive(False) def deactivate(self): self.uimanager.remove_ui(self.financial_ui) self.window.SearchToolItem.set_sensitive(True) def print_activate(self): self._print_transaction_report() def export_spreadsheet_activate(self): self._export_spreadsheet() def get_current_page(self): widget = self._get_current_page_widget() if hasattr(widget, 'page'): return widget.page # # Private # def _update_actions(self): is_accounts_tab = self._is_accounts_tab() self.AccountMenu.set_visible(is_accounts_tab) self.TransactionMenu.set_visible(not is_accounts_tab) self.DeleteAccount.set_visible(is_accounts_tab) self.DeleteTransaction.set_visible(not is_accounts_tab) self.window.ExportSpreadSheet.set_sensitive(True) self.window.Print.set_sensitive(not is_accounts_tab) self.NewAccount.set_sensitive(self._can_add_account()) self.DeleteAccount.set_sensitive(self._can_delete_account()) self.NewTransaction.set_sensitive(self._can_add_transaction()) self.DeleteTransaction.set_sensitive(self._can_delete_transaction()) self.Edit.set_sensitive(self._can_edit_account() or self._can_edit_transaction()) def _update_tooltips(self): if self._is_accounts_tab(): self.Edit.set_tooltip(_("Edit the selected account")) self.window.Print.set_tooltip("") else: self.Edit.set_tooltip(_("Edit the selected transaction")) self.window.Print.set_tooltip( _("Print a report of these transactions")) def _create_initial_page(self): pixbuf = self.accounts.render_icon('stoq-money', gtk.ICON_SIZE_MENU) page = self.notebook.get_nth_page(0) hbox = self._create_tab_label(_('Accounts'), pixbuf) self.notebook.set_tab_label(page, hbox) def _create_new_account(self): parent_view = None if self._is_accounts_tab(): parent_view = self.accounts.get_selected() else: page_id = self.notebook.get_current_page() widget = self.notebook.get_nth_page(page_id) page = widget.page if page.account_view.kind == 'account': parent_view = page.account_view retval = self._run_account_editor(None, parent_view) if retval: self.accounts.refresh_accounts(self.store) def _refresh_accounts(self): self.accounts.clear() self.accounts.insert_initial(self.store) def _edit_existing_account(self, account_view): assert account_view.kind == 'account' retval = self._run_account_editor(account_view, self.accounts.get_parent(account_view)) if not retval: return self.accounts.refresh_accounts(self.store) def _run_account_editor(self, model, parent_account): store = api.new_store() if model: model = store.fetch(model.account) if parent_account: if parent_account.kind in ['payable', 'receivable']: parent_account = None if parent_account == api.sysparam(self.store).IMBALANCE_ACCOUNT: parent_account = None retval = self.run_dialog(AccountEditor, store, model=model, parent_account=parent_account) if store.confirm(retval): self.accounts.refresh_accounts(self.store) store.close() return retval def _close_current_page(self): assert self._can_close_tab() page = self.get_current_page() self._close_page(page) def _get_current_page_widget(self): page_id = self.notebook.get_current_page() widget = self.notebook.get_children()[page_id] return widget def _close_page(self, page): for page_id, child in enumerate(self.notebook.get_children()): if getattr(child, 'page', None) == page: break else: raise AssertionError(page) self.notebook.remove_page(page_id) del self._pages[page.account_view.id] def _is_accounts_tab(self): page_id = self.notebook.get_current_page() return page_id == 0 def _is_transaction_tab(self): page = self.get_current_page() if not isinstance(page, TransactionPage): return False if page.model.kind != 'account': return False if (page.model == self._tills_account or page.model.parent_id == self._tills_account.id): return False return True def _can_close_tab(self): # The first tab is not closable return not self._is_accounts_tab() def _create_tab_label(self, title, pixbuf, page=None): hbox = gtk.HBox() image = gtk.image_new_from_pixbuf(pixbuf) hbox.pack_start(image, False, False) label = gtk.Label(title) hbox.pack_start(label, True, False) if title != _("Accounts"): button = NotebookCloseButton() if page: button.connect('clicked', lambda button: self._close_page(page)) hbox.pack_end(button, False, False) hbox.show_all() return hbox def _new_page(self, account_view): if account_view.id in self._pages: page = self._pages[account_view.id] page_id = self.notebook.page_num(page.search) else: pixbuf = self.accounts.get_pixbuf(account_view) page = TransactionPage(account_view, self, self.get_toplevel()) page.search.connect('result-selection-changed', self._on_search__result_selection_changed) page.search.connect('result-item-popup-menu', self._on_search__result_item_popup_menu) hbox = self._create_tab_label(account_view.description, pixbuf, page) widget = page.search.vbox widget.page = page page_id = self.notebook.append_page(widget, hbox) page.show() page.account_view = account_view self._pages[account_view.id] = page self.notebook.set_current_page(page_id) self._update_actions() def _import(self): ffilters = [] all_filter = gtk.FileFilter() all_filter.set_name(_('All supported formats')) all_filter.add_pattern('*.ofx') all_filter.add_mime_type('application/xml') all_filter.add_mime_type('application/x-gzip') ffilters.append(all_filter) ofx_filter = gtk.FileFilter() ofx_filter.set_name(_('Open Financial Exchange (OFX)')) ofx_filter.add_pattern('*.ofx') ffilters.append(ofx_filter) gnucash_filter = gtk.FileFilter() gnucash_filter.set_name(_('GNUCash xml format')) gnucash_filter.add_mime_type('application/xml') gnucash_filter.add_mime_type('application/x-gzip') ffilters.append(gnucash_filter) with selectfile("Import", parent=self.get_toplevel(), filters=ffilters) as file_chooser: file_chooser.run() filename = file_chooser.get_filename() if not filename: return ffilter = file_chooser.get_filter() if ffilter == gnucash_filter: format = 'gnucash.xml' elif ffilter == ofx_filter: format = 'account.ofx' else: # Guess if filename.endswith('.ofx'): format = 'account.ofx' else: format = 'gnucash.xml' run_dialog(ImporterDialog, self, format, filename) # Refresh everthing after an import self.accounts.refresh_accounts(self.store) for page in self._pages.values(): page.refresh() def _export_spreadsheet(self): """Runs a dialog to export the current search results to a CSV file. """ if self._is_accounts_tab(): run_dialog(FinancialReportDialog, self, self.store) else: page = self.get_current_page() sse = SpreadSheetExporter() sse.export(object_list=page.result_view, name=self.app_title, filename_prefix=self.app_name) def _can_add_account(self): if self._is_accounts_tab(): return True return False def _can_edit_account(self): if not self._is_accounts_tab(): return False account_view = self.accounts.get_selected() if account_view is None: return False # Can only remove real accounts if account_view.kind != 'account': return False if account_view.id in [self._banks_account.id, self._imbalance_account.id, self._tills_account.id]: return False return True def _can_delete_account(self): if not self._is_accounts_tab(): return False account_view = self.accounts.get_selected() if account_view is None: return False # Can only remove real accounts if account_view.kind != 'account': return False return account_view.account.can_remove() def _can_add_transaction(self): if self._is_transaction_tab(): return True return False def _can_delete_transaction(self): if not self._is_transaction_tab(): return False page = self.get_current_page() transaction = page.result_view.get_selected() if transaction is None: return False return True def _can_edit_transaction(self): if not self._is_transaction_tab(): return False page = self.get_current_page() transaction = page.result_view.get_selected() if transaction is None: return False return True def _add_transaction(self): page = self.get_current_page() page.add_transaction_dialog() self._refresh_accounts() def _delete_account(self, account_view): store = api.new_store() account = store.fetch(account_view.account) methods = PaymentMethod.get_by_account(store, account) if methods.count() > 0: if not yesno( _('This account is used in at least one payment method.\n' 'To be able to delete it the payment methods needs to be' 're-configured first'), gtk.RESPONSE_NO, _("Configure payment methods"), _("Keep account")): store.close() return elif not yesno( _('Are you sure you want to remove account "%s" ?') % ( (account_view.description, )), gtk.RESPONSE_NO, _("Remove account"), _("Keep account")): store.close() return if account_view.id in self._pages: account_page = self._pages[account_view.id] self._close_page(account_page) self.accounts.remove(account_view) self.accounts.flush() imbalance = api.sysparam(store).IMBALANCE_ACCOUNT for method in methods: method.destination_account = imbalance account.remove(store) store.commit(close=True) def _delete_transaction(self, item): msg = _('Are you sure you want to remove transaction "%s" ?') % ( (item.description)) if not yesno(msg, gtk.RESPONSE_YES, _(u"Remove transaction"), _(u"Keep transaction")): return account_transactions = self.get_current_page() account_transactions.result_view.remove(item) store = api.new_store() if isinstance(item.transaction, AccountTransactionView): account_transaction = store.fetch(item.transaction.transaction) else: account_transaction = store.fetch(item.transaction) account_transaction.delete(account_transaction.id, store=store) store.commit(close=True) account_transactions.update_totals() def _print_transaction_report(self): assert not self._is_accounts_tab() page = self.get_current_page() print_report(AccountTransactionReport, page.result_view, list(page.result_view), account=page.model, filters=page.search.get_search_filters()) # # Kiwi callbacks # def key_escape(self): if self._can_close_tab(): self._close_current_page() return True def key_control_w(self): if self._can_close_tab(): self._close_current_page() return True def on_accounts__row_activated(self, ktree, account_view): self._new_page(account_view) def on_accounts__selection_changed(self, ktree, account_view): self._update_actions() def on_accounts__right_click(self, results, result, event): self.acc_popup.popup(None, None, None, event.button, event.time) def on_Edit__activate(self, button): if self._is_accounts_tab(): account_view = self.accounts.get_selected() self._edit_existing_account(account_view) elif self._is_transaction_tab(): page = self.get_current_page() transaction = page.result_view.get_selected() page._edit_transaction_dialog(transaction) def after_notebook__switch_page(self, notebook, page, page_id): self._update_actions() self._update_tooltips() def _on_search__result_selection_changed(self, search): self._update_actions() def _on_search__result_item_popup_menu(self, search, result, event): self.trans_popup.popup(None, None, None, event.button, event.time) # Toolbar def new_activate(self): if self._is_accounts_tab() and self._can_add_account(): self._create_new_account() elif self._is_transaction_tab() and self._can_add_transaction(): self._add_transaction() def on_NewAccount__activate(self, action): self._create_new_account() def on_NewTransaction__activate(self, action): self._add_transaction() def on_DeleteAccount__activate(self, action): account_view = self.accounts.get_selected() self._delete_account(account_view) def on_DeleteTransaction__activate(self, action): transactions = self.get_current_page() transaction = transactions.result_view.get_selected() self._delete_transaction(transaction) self._refresh_accounts() # Financial def on_Import__activate(self, action): self._import() # Edit def on_ConfigurePaymentMethods__activate(self, action): from stoqlib.gui.dialogs.paymentmethod import PaymentMethodsDialog store = api.new_store() model = self.run_dialog(PaymentMethodsDialog, store) store.confirm(model) store.close()
class AccountEditor(BaseEditor): """ Account Editor """ gladefile = "AccountEditor" proxy_widgets = ['description', 'code'] model_type = Account model_name = _('Account') def __init__(self, store, model=None, parent_account=None): self._last_account_type = None self._bank_number = -1 self._bank_widgets = [] self._bank_option_widgets = [] self._option_fields = {} self._test_button = None self.existing = model is not None self.parent_account = parent_account self.bank_model = _TemporaryBankAccount() BaseEditor.__init__(self, store, model) action_area = self.main_dialog.action_area action_area.set_layout(gtk.BUTTONBOX_END) action_area.pack_start(self._test_button, expand=False, fill=False) action_area.set_child_secondary(self._test_button, True) self._test_button.show() # # BaseEditor hooks # def create_model(self, store): return Account(description=u"", account_type=Account.TYPE_CASH, store=store) def _setup_widgets(self): self._test_button = gtk.Button(_("Print a test bill")) self._test_button.connect('clicked', self._on_test_button__clicked) self.parent_accounts = AccountTree(with_code=False, create_mode=True) self.parent_accounts.connect('selection-changed', self._on_parent_accounts__selection_changed) self.tree_box.pack_start(self.parent_accounts) self.tree_box.reorder_child(self.parent_accounts, 0) if self.model == sysparam(self.store).IMBALANCE_ACCOUNT: self.account_type.set_sensitive(False) self.account_type.prefill(Account.account_type_descriptions) account_type = self.model.account_type self.parent_accounts.insert_initial(self.store, edited_account=self.model) if self.parent_account: account = self.parent_accounts.get_account_by_id( self.parent_account.id) self.parent_accounts.select(account) if not self.existing: account_type = account.account_type self.account_type.select(account_type) self.parent_accounts.show() def setup_proxies(self): self._setup_widgets() self.add_proxy(self.model, AccountEditor.proxy_widgets) def validate_confirm(self): if not self.model.description: return False account = self.parent_accounts.get_selected() if not account: return True return account.selectable def on_confirm(self): new_parent = self.parent_accounts.get_selected() if new_parent: new_parent = new_parent.account if new_parent != self.model: self.model.parent = new_parent self.model.account_type = self.account_type.get_selected() self._save_bank() def refresh_ok(self, value): BaseEditor.refresh_ok(self, value) account_type = self.account_type.get_selected() if account_type != Account.TYPE_BANK: value = False self._test_button.set_sensitive(value) # Private def _save_bank(self): bank_account = self.model.bank if not bank_account: bank_account = BankAccount(account=self.model, store=self.store) # FIXME: Who sets this to a str? bank_account.bank_account = unicode(self.bank_model.bank_account) bank_account.bank_branch = unicode(self.bank_model.bank_branch) if self._bank_number is not None: bank_account.bank_number = self.bank_model.bank_number self._save_bank_bill_options(bank_account) def _save_bank_bill_options(self, bank_account): for option, entry in self._option_fields.items(): value = unicode(entry.get_text()) bill_option = self.store.find(BillOption, bank_account=bank_account, option=option).one() if bill_option is None: bill_option = BillOption(store=self.store, bank_account=bank_account, option=option, value=value) bill_option.value = value def _add_widget(self, label, widget, options=False): n_rows = self.table.props.n_rows l = gtk.Label() l.set_markup(label) l.props.xalign = 1.0 self.table.resize(n_rows + 1, 2) self.table.attach( l, 0, 1, n_rows, n_rows + 1, gtk.FILL, 0, 0, 0) self.table.attach( widget, 1, 2, n_rows, n_rows + 1, gtk.EXPAND | gtk.FILL, 0, 0, 0) if options: self._bank_option_widgets.extend([l, widget]) else: self._bank_widgets.extend([l, widget]) l.show() return l def _update_bank_type(self): self._remove_bank_option_widgets() bank_number = self.bank_type.get_selected() bank_info = None if bank_number: bank_info = get_bank_info_by_number(bank_number) self.bank_number = ProxyEntry() self.bank_number.props.data_type = int self.bank_number.set_sensitive(False) bank_number_lbl = self._add_widget(api.escape(_("Number:")), self.bank_number, options=True) self.bank_branch = ProxyEntry() self.bank_branch.connect('validate', self._on_bank_branch__validate, bank_info) self.bank_branch.props.data_type = 'str' self.bank_branch.props.mandatory = True self.bank_branch.model_attribute = "bank_branch" bank_branch_lbl = self._add_widget(api.escape(_("Agency:")), self.bank_branch, options=True) if bank_number is not None: bank_branch_lbl.show() self.bank_branch.show() else: bank_branch_lbl.hide() self.bank_account = ProxyEntry() self.bank_account.connect('validate', self._on_bank_account__validate, bank_info) self._add_widget(api.escape(_("Account:")), self.bank_account, options=True) self.bank_account.model_attribute = "bank_account" self.bank_account.props.data_type = 'str' if bank_number is not None: self.bank_account.props.mandatory = True self.bank_account.show() attributes = ['bank_account', 'bank_branch', 'bank_number'] if bank_number is not None: bank_number_lbl.show() self.bank_number.show() self.bank_model.bank_number = bank_number for i, option in enumerate(bank_info.get_extra_options()): name = 'option' + str(i) entry = ProxyEntry() entry.model_attribute = name setattr(self, name, entry) # Set the model attr too so it can be validated setattr(self.bank_model, name, u'') entry.props.data_type = 'str' entry.connect('validate', self._on_bank_option__validate, bank_info, option) self._add_widget("<i>%s</i>:" % (api.escape(option.capitalize()), ), entry, options=True) entry.show() self._option_fields[option] = entry attributes.append(entry.model_attribute) else: bank_number_lbl.hide() self.bank_proxy = self.add_proxy( self.bank_model, attributes) self._fill_bank_account() def _fill_bank_account(self): if not self.model.bank: return self.bank_model.bank_branch = self.model.bank.bank_branch.encode('utf-8') self.bank_model.bank_account = self.model.bank.bank_account.encode('utf-8') self.bank_proxy.update('bank_branch') self.bank_proxy.update('bank_account') bill_options = list(self.store.find(BillOption, bank_account=self.model.bank)) for bill_option in bill_options: if bill_option.option is None: continue field_entry = self._option_fields.get(bill_option.option) if field_entry: field_entry.set_text(bill_option.value) def _update_account_type(self, account_type): if not self.account_type.get_sensitive(): return if account_type != Account.TYPE_BANK: self._remove_bank_widgets() self._remove_bank_option_widgets() self.code.set_sensitive(True) return self.code.set_sensitive(False) self.bank_type = ProxyComboBox() self._add_widget(api.escape(_("Bank:")), self.bank_type) self.bank_type.connect('content-changed', self._on_bank_type__content_changed) self.bank_type.show() banks = [(_('Generic'), None)] banks.extend([(b.description, b.bank_number) for b in get_all_banks()]) self.bank_type.prefill(banks) if self.model.bank: try: self.bank_type.select(self.model.bank.bank_number) except KeyError: self.bank_type.select(None) self._update_bank_type() def _remove_bank_widgets(self): for widget in self._bank_widgets: widget.get_parent().remove(widget) widget.destroy() self.table.resize(5, 2) self._bank_widgets = [] def _remove_bank_option_widgets(self): for widget in self._bank_option_widgets: widget.get_parent().remove(widget) widget.destroy() self.table.resize(5 + len(self._bank_widgets) / 2, 2) self._bank_option_widgets = [] self._option_fields = {} def _print_test_bill(self): try: bank_info = get_bank_info_by_number(self.bank_model.bank_number) except NotImplementedError: info(_("This bank does not support printing of bills")) return kwargs = dict( valor_documento=12345.67, data_vencimento=datetime.date.today(), data_documento=datetime.date.today(), data_processamento=datetime.date.today(), nosso_numero=u'624533', numero_documento=u'1138', sacado=[_(u"Drawee"), _(u"Address"), _(u"Details")], cedente=_(u"Supplier"), demonstrativo=[_(u"Demonstration")], instrucoes=[_(u"Instructions")], agencia=self.bank_model.bank_branch, conta=self.bank_model.bank_account, ) for opt in self.bank_model.options: kwargs[opt.option] = opt.value data = bank_info(**kwargs) print_report(BillTestReport, data) # Callbacks def _on_parent_accounts__selection_changed(self, objectlist, account): self.force_validation() def on_description__activate(self, entry): if self.validate_confirm(): self.confirm() def on_description__validate(self, entry, text): if not text: return ValidationError(_("Account description cannot be empty")) def on_account_type__content_changed(self, account_type): account_type = account_type.get_selected() if self._last_account_type == account_type: return self._update_account_type(account_type) self._last_account_type = account_type def _on_bank_type__content_changed(self, bank_type): bank_number = bank_type.get_selected() if self._bank_number == bank_number: return self._update_bank_type() self._bank_number = bank_number def _on_bank_branch__validate(self, entry, value, bank_info): if bank_info: try: bank_info.validate_field(value) except BoletoException, e: return ValidationError(str(e))
class AccountEditor(BaseEditor): """ Account Editor """ gladefile = "AccountEditor" proxy_widgets = ['description', 'code'] model_type = Account model_name = _('Account') def __init__(self, store, model=None, parent_account=None): self._last_account_type = None self._bank_number = -1 self._bank_widgets = [] self._bank_option_widgets = [] self._option_fields = {} self._test_button = None self.existing = model is not None self.parent_account = parent_account self.bank_model = _TemporaryBankAccount() BaseEditor.__init__(self, store, model) action_area = self.main_dialog.action_area action_area.set_layout(gtk.BUTTONBOX_END) action_area.pack_start(self._test_button, expand=False, fill=False) action_area.set_child_secondary(self._test_button, True) self._test_button.show() # # BaseEditor hooks # def create_model(self, store): return Account(description=u"", account_type=Account.TYPE_CASH, store=store) def _setup_widgets(self): self._test_button = gtk.Button(_("Print a test bill")) self._test_button.connect('clicked', self._on_test_button__clicked) self.parent_accounts = AccountTree(with_code=False, create_mode=True) self.parent_accounts.connect( 'selection-changed', self._on_parent_accounts__selection_changed) self.tree_box.pack_start(self.parent_accounts) self.tree_box.reorder_child(self.parent_accounts, 0) if self.model == sysparam(self.store).IMBALANCE_ACCOUNT: self.account_type.set_sensitive(False) self.account_type.prefill(Account.account_type_descriptions) account_type = self.model.account_type self.parent_accounts.insert_initial(self.store, edited_account=self.model) if self.parent_account: account = self.parent_accounts.get_account_by_id( self.parent_account.id) self.parent_accounts.select(account) if not self.existing: account_type = account.account_type self.account_type.select(account_type) self.parent_accounts.show() def setup_proxies(self): self._setup_widgets() self.add_proxy(self.model, AccountEditor.proxy_widgets) def validate_confirm(self): if not self.model.description: return False account = self.parent_accounts.get_selected() if not account: return True return account.selectable def on_confirm(self): new_parent = self.parent_accounts.get_selected() if new_parent: new_parent = new_parent.account if new_parent != self.model: self.model.parent = new_parent self.model.account_type = self.account_type.get_selected() self._save_bank() def refresh_ok(self, value): BaseEditor.refresh_ok(self, value) account_type = self.account_type.get_selected() if account_type != Account.TYPE_BANK: value = False self._test_button.set_sensitive(value) # Private def _save_bank(self): bank_account = self.model.bank if not bank_account: bank_account = BankAccount(account=self.model, store=self.store) # FIXME: Who sets this to a str? bank_account.bank_account = unicode(self.bank_model.bank_account) bank_account.bank_branch = unicode(self.bank_model.bank_branch) if self._bank_number is not None: bank_account.bank_number = self.bank_model.bank_number self._save_bank_bill_options(bank_account) def _save_bank_bill_options(self, bank_account): for option, entry in self._option_fields.items(): value = unicode(entry.get_text()) bill_option = self.store.find(BillOption, bank_account=bank_account, option=option).one() if bill_option is None: bill_option = BillOption(store=self.store, bank_account=bank_account, option=option, value=value) bill_option.value = value def _add_widget(self, label, widget, options=False): n_rows = self.table.props.n_rows l = gtk.Label() l.set_markup(label) l.props.xalign = 1.0 self.table.resize(n_rows + 1, 2) self.table.attach(l, 0, 1, n_rows, n_rows + 1, gtk.FILL, 0, 0, 0) self.table.attach(widget, 1, 2, n_rows, n_rows + 1, gtk.EXPAND | gtk.FILL, 0, 0, 0) if options: self._bank_option_widgets.extend([l, widget]) else: self._bank_widgets.extend([l, widget]) l.show() return l def _update_bank_type(self): self._remove_bank_option_widgets() bank_number = self.bank_type.get_selected() bank_info = None if bank_number: bank_info = get_bank_info_by_number(bank_number) self.bank_number = ProxyEntry() self.bank_number.props.data_type = int self.bank_number.set_sensitive(False) bank_number_lbl = self._add_widget(api.escape(_("Number:")), self.bank_number, options=True) self.bank_branch = ProxyEntry() self.bank_branch.connect('validate', self._on_bank_branch__validate, bank_info) self.bank_branch.props.data_type = 'str' self.bank_branch.props.mandatory = True self.bank_branch.model_attribute = "bank_branch" bank_branch_lbl = self._add_widget(api.escape(_("Agency:")), self.bank_branch, options=True) if bank_number is not None: bank_branch_lbl.show() self.bank_branch.show() else: bank_branch_lbl.hide() self.bank_account = ProxyEntry() self.bank_account.connect('validate', self._on_bank_account__validate, bank_info) self._add_widget(api.escape(_("Account:")), self.bank_account, options=True) self.bank_account.model_attribute = "bank_account" self.bank_account.props.data_type = 'str' if bank_number is not None: self.bank_account.props.mandatory = True self.bank_account.show() attributes = ['bank_account', 'bank_branch', 'bank_number'] if bank_number is not None: bank_number_lbl.show() self.bank_number.show() self.bank_model.bank_number = bank_number for i, option in enumerate(bank_info.get_extra_options()): name = 'option' + str(i) entry = ProxyEntry() entry.model_attribute = name setattr(self, name, entry) # Set the model attr too so it can be validated setattr(self.bank_model, name, u'') entry.props.data_type = 'str' entry.connect('validate', self._on_bank_option__validate, bank_info, option) self._add_widget("<i>%s</i>:" % (api.escape(option.capitalize()), ), entry, options=True) entry.show() self._option_fields[option] = entry attributes.append(entry.model_attribute) else: bank_number_lbl.hide() self.bank_proxy = self.add_proxy(self.bank_model, attributes) self._fill_bank_account() def _fill_bank_account(self): if not self.model.bank: return self.bank_model.bank_branch = self.model.bank.bank_branch.encode( 'utf-8') self.bank_model.bank_account = self.model.bank.bank_account.encode( 'utf-8') self.bank_proxy.update('bank_branch') self.bank_proxy.update('bank_account') bill_options = list( self.store.find(BillOption, bank_account=self.model.bank)) for bill_option in bill_options: if bill_option.option is None: continue field_entry = self._option_fields.get(bill_option.option) if field_entry: field_entry.set_text(bill_option.value) def _update_account_type(self, account_type): if not self.account_type.get_sensitive(): return if account_type != Account.TYPE_BANK: self._remove_bank_widgets() self._remove_bank_option_widgets() self.code.set_sensitive(True) return self.code.set_sensitive(False) self.bank_type = ProxyComboBox() self._add_widget(api.escape(_("Bank:")), self.bank_type) self.bank_type.connect('content-changed', self._on_bank_type__content_changed) self.bank_type.show() banks = [(_('Generic'), None)] banks.extend([(b.description, b.bank_number) for b in get_all_banks()]) self.bank_type.prefill(banks) if self.model.bank: try: self.bank_type.select(self.model.bank.bank_number) except KeyError: self.bank_type.select(None) self._update_bank_type() def _remove_bank_widgets(self): for widget in self._bank_widgets: widget.get_parent().remove(widget) widget.destroy() self.table.resize(5, 2) self._bank_widgets = [] def _remove_bank_option_widgets(self): for widget in self._bank_option_widgets: widget.get_parent().remove(widget) widget.destroy() self.table.resize(5 + len(self._bank_widgets) / 2, 2) self._bank_option_widgets = [] self._option_fields = {} def _print_test_bill(self): try: bank_info = get_bank_info_by_number(self.bank_model.bank_number) except NotImplementedError: info(_("This bank does not support printing of bills")) return kwargs = dict( valor_documento=12345.67, data_vencimento=datetime.date.today(), data_documento=datetime.date.today(), data_processamento=datetime.date.today(), nosso_numero=u'624533', numero_documento=u'1138', sacado=[_(u"Drawee"), _(u"Address"), _(u"Details")], cedente=_(u"Supplier"), demonstrativo=[_(u"Demonstration")], instrucoes=[_(u"Instructions")], agencia=self.bank_model.bank_branch, conta=self.bank_model.bank_account, ) for opt in self.bank_model.options: kwargs[opt.option] = opt.value data = bank_info(**kwargs) print_report(BillTestReport, data) # Callbacks def _on_parent_accounts__selection_changed(self, objectlist, account): self.force_validation() def on_description__activate(self, entry): if self.validate_confirm(): self.confirm() def on_description__validate(self, entry, text): if not text: return ValidationError(_("Account description cannot be empty")) def on_account_type__content_changed(self, account_type): account_type = account_type.get_selected() if self._last_account_type == account_type: return self._update_account_type(account_type) self._last_account_type = account_type def _on_bank_type__content_changed(self, bank_type): bank_number = bank_type.get_selected() if self._bank_number == bank_number: return self._update_bank_type() self._bank_number = bank_number def _on_bank_branch__validate(self, entry, value, bank_info): if bank_info: try: bank_info.validate_field(value) except BoletoException as e: return ValidationError(str(e)) def _on_bank_account__validate(self, entry, value, bank_info): if bank_info: try: bank_info.validate_field(value) except BoletoException as e: return ValidationError(str(e)) def _on_bank_option__validate(self, entry, value, bank_info, option): try: bank_info.validate_option(option, value) except BoletoException as e: return ValidationError(str(e)) self.bank_model.set_option(option, value) def _on_test_button__clicked(self, button): self._print_test_bill()