def setup_slaves(self): marker('Setting up slaves') BaseMethodSelectionStep.setup_slaves(self) marker('Finished parent') self.pm_slave.set_client(self.model.client, total_amount=self.wizard.get_total_to_pay()) marker('Setting discount') self.discount_slave = SaleDiscountSlave(self.store, self.model, self.model_type) if sysparam.get_bool('USE_TRADE_AS_DISCOUNT'): self.subtotal_expander.set_expanded(True) self.discount_slave.discount_value_ck.set_active(True) self.discount_slave.update_sale_discount() marker('Finshed setting up discount') self.discount_slave.connect('discount-changed', self.on_discount_slave_changed) slave_holder = 'discount_surcharge_slave' if self.get_slave(slave_holder): self.detach_slave(slave_holder) self.attach_slave(slave_holder, self.discount_slave) marker('Finished setting up slaves')
def setup_slaves(self): marker('Setting up slaves') BaseMethodSelectionStep.setup_slaves(self) marker('Finished parent') self.pm_slave.method_set_sensitive(u'store_credit', bool(self.model.client)) self.pm_slave.method_set_sensitive(u'bill', bool(self.model.client)) self.pm_slave.method_set_sensitive(u'credit', bool(self.model.client)) marker('Setting discount') self.discount_slave = SaleDiscountSlave(self.store, self.model, self.model_type) marker('Finshed setting up discount') self.discount_slave.connect('discount-changed', self.on_discount_slave_changed) slave_holder = 'discount_surcharge_slave' if self.get_slave(slave_holder): self.detach_slave(slave_holder) self.attach_slave(slave_holder, self.discount_slave) marker('Finished setting up slaves')
def setup_slaves(self): marker('Setting up slaves') BaseMethodSelectionStep.setup_slaves(self) marker('Finished parent') self.pm_slave.set_client(self.model.client, total_amount=self.wizard.get_total_to_pay()) marker('Setting discount') self.discount_slave = SaleDiscountSlave(self.store, self.model, self.model_type) marker('Finshed setting up discount') self.discount_slave.connect('discount-changed', self.on_discount_slave_changed) slave_holder = 'discount_surcharge_slave' if self.get_slave(slave_holder): self.detach_slave(slave_holder) self.attach_slave(slave_holder, self.discount_slave) marker('Finished setting up slaves')
def setup_slaves(self): marker('Setting up slaves') BaseMethodSelectionStep.setup_slaves(self) marker('Finished parent') self.pm_slave.method_set_sensitive(u'store_credit', bool(self.model.client)) self.pm_slave.method_set_sensitive(u'bill', bool(self.model.client)) marker('Setting discount') self.discount_slave = SaleDiscountSlave(self.store, self.model, self.model_type) marker('Finshed setting up discount') self.discount_slave.connect('discount-changed', self.on_discount_slave_changed) slave_holder = 'discount_surcharge_slave' if self.get_slave(slave_holder): self.detach_slave(slave_holder) self.attach_slave(slave_holder, self.discount_slave) marker('Finished setting up slaves')
class SalesPersonStep(BaseMethodSelectionStep, WizardEditorStep): """ An abstract step which allows to define a salesperson, the sale's discount and surcharge, when it is needed. """ gladefile = 'SalesPersonStep' model_type = Sale proxy_widgets = ('salesperson', 'client', 'transporter', 'cost_center') invoice_widgets = ('invoice_number', ) cfop_widgets = ('cfop', ) def __init__(self, wizard, store, model, payment_group, invoice_model): self.invoice_model = invoice_model self.payment_group = payment_group BaseMethodSelectionStep.__init__(self) marker("WizardEditorStep.__init__") WizardEditorStep.__init__(self, store, wizard, model) self._update_totals() self.update_discount_and_surcharge() # # Private API # def _update_totals(self): subtotal = self.wizard.get_subtotal() self.subtotal_lbl.update(subtotal) total_paid = self.wizard.get_total_paid() self.total_paid_lbl.update(total_paid) to_pay = self.model.get_total_sale_amount(subtotal=subtotal) - total_paid self.cash_change_slave.update_total_sale_amount(to_pay) self.total_lbl.update(to_pay) def _update_widgets(self): has_client = bool(self.client.get_selected()) self.pm_slave.method_set_sensitive(u'store_credit', has_client) self.pm_slave.method_set_sensitive(u'bill', has_client) def _fill_clients_combo(self): marker('Filling clients') # FIXME: This should not be using a normal ProxyComboEntry, # we need a specialized widget that does the searching # on demand. clients = Client.get_active_clients(self.store) self.client.prefill(api.for_person_combo(clients)) self.client.set_sensitive(len(self.client.get_model())) marker('Filled clients') def _fill_transporter_combo(self): marker('Filling transporters') transporters = Transporter.get_active_transporters(self.store) items = api.for_person_combo(transporters) self.transporter.prefill(items) self.transporter.set_sensitive(len(items)) marker('Filled transporters') def _fill_cost_center_combo(self): marker('Filling cost centers') cost_centers = CostCenter.get_active(self.store) # we keep this value because each call to is_empty() is a new sql query # to the database cost_centers_exists = not cost_centers.is_empty() if cost_centers_exists: self.cost_center.prefill(api.for_combo(cost_centers, attr='name', empty=_('No cost center.'))) self.cost_center.set_visible(cost_centers_exists) self.cost_center_lbl.set_visible(cost_centers_exists) marker('Filled cost centers') def _fill_cfop_combo(self): marker('Filling CFOPs') cfops = self.store.find(CfopData) self.cfop.prefill(api.for_combo(cfops)) marker('Filled CFOPs') def _create_client(self): store = api.new_store() client = run_person_role_dialog(ClientEditor, self.wizard, store, None) store.confirm(client) client = self.store.fetch(client) store.close() if not client: return if len(self.client) == 0: self._fill_clients_combo() return clients = self.client.get_model_items().values() if client in clients: if client.is_active: self.client.select(client) else: # remove client from combo self.client.select_item_by_data(client) iter = self.client.get_active_iter() model = self.client.get_model() model.remove(iter) # just in case the inactive client was selected before. self.client.select_item_by_position(0) elif client.is_active: self.client.append_item(client.person.name, client) self.client.select(client) self._update_widgets() # # Public API # def update_discount_and_surcharge(self): marker("update_discount_and_surcharge") # Here we need avoid to reset sale data defined when creating the # Sale in the POS application, i.e, we should not reset the # discount and surcharge if they are already set (this is the # case when CONFIRM_SALES_ON_TILL parameter is enabled). if not sysparam(self.store).CONFIRM_SALES_ON_TILL: self.model.discount_value = currency(0) self.model.surcharge_value = currency(0) def setup_widgets(self): marker('Setting up widgets') # Only quotes have expire date. self.expire_date.hide() self.expire_label.hide() # Hide operation nature widgets self.operation_nature.hide() self.nature_lbl.hide() # Hide client category widgets self.client_category_lbl.hide() self.client_category.hide() # if the NF-e plugin is active, the client is mandantory in this # wizard (in this situation, we have only quote sales). if self.model.status == Sale.STATUS_QUOTE: manager = get_plugin_manager() mandatory_client = manager.is_active('nfe') self.client.set_property('mandatory', mandatory_client) marker('Filling sales persons') salespersons = self.store.find(SalesPerson) self.salesperson.prefill(api.for_person_combo(salespersons)) marker('Finished filling sales persons') marker('Read parameter') if not sysparam(self.store).ACCEPT_CHANGE_SALESPERSON: self.salesperson.set_sensitive(False) else: self.salesperson.grab_focus() marker('Finished reading parameter') self._fill_clients_combo() self._fill_transporter_combo() self._fill_cost_center_combo() if sysparam(self.store).ASK_SALES_CFOP: self._fill_cfop_combo() else: self.cfop_lbl.hide() self.cfop.hide() self.create_cfop.hide() # the maximum number allowed for an invoice is 999999999. self.invoice_number.set_adjustment( gtk.Adjustment(lower=1, upper=999999999, step_incr=1)) if not self.model.invoice_number: new_invoice_number = Sale.get_last_invoice_number(self.store) + 1 self.invoice_model.invoice_number = new_invoice_number else: new_invoice_number = self.model.invoice_number self.invoice_model.invoice_number = new_invoice_number self.invoice_number.set_sensitive(False) self.invoice_model.original_invoice = new_invoice_number marker('Finished setting up widgets') def _refresh_next(self, validation_value): self.client.validate(force=True) client_valid = self.client.is_valid() self.wizard.refresh_next(validation_value and client_valid) # # WizardStep hooks # def post_init(self): BaseMethodSelectionStep.post_init(self) marker('Entering post_init') self.toogle_client_details() if self.wizard.need_create_payment(): self.wizard.payment_group.clear_unused() self.register_validate_function(self._refresh_next) self._update_next_step(self.get_selected_method()) if hasattr(self, 'cash_change_slave'): self.cash_change_slave.received_value.grab_focus() self.force_validation() marker('Leaving post_init') def setup_slaves(self): marker('Setting up slaves') BaseMethodSelectionStep.setup_slaves(self) marker('Finished parent') self.pm_slave.method_set_sensitive(u'store_credit', bool(self.model.client)) self.pm_slave.method_set_sensitive(u'bill', bool(self.model.client)) marker('Setting discount') self.discount_slave = SaleDiscountSlave(self.store, self.model, self.model_type) marker('Finshed setting up discount') self.discount_slave.connect('discount-changed', self.on_discount_slave_changed) slave_holder = 'discount_surcharge_slave' if self.get_slave(slave_holder): self.detach_slave(slave_holder) self.attach_slave(slave_holder, self.discount_slave) marker('Finished setting up slaves') def setup_proxies(self): marker('Setting up proxies') self.setup_widgets() self.proxy = self.add_proxy(self.model, SalesPersonStep.proxy_widgets) self.invoice_proxy = self.add_proxy(self.invoice_model, self.invoice_widgets) if self.model.client: self.client.set_sensitive(False) self.create_client.set_sensitive(False) if sysparam(self.store).ASK_SALES_CFOP: self.add_proxy(self.model, SalesPersonStep.cfop_widgets) marker('Finished setting up proxies') def toogle_client_details(self): client = self.client.read() self.client_details.set_sensitive(bool(client)) # # Callbacks # def on_client__changed(self, entry): self.toogle_client_details() self._update_widgets() self.discount_slave.update_max_discount() def on_payment_method_changed(self, slave, method_name): self.client.validate(force=True) self._update_next_step(method_name) def on_client__validate(self, widget, client): if not client: return # this is used to avoid some tests from crashing if not hasattr(self, 'pm_slave'): return method = self.pm_slave.get_selected_method() try: client.can_purchase(method, self.model.get_total_sale_amount()) self.wizard.refresh_next(True) except SellError as e: self.wizard.refresh_next(False) return ValidationError(e) def on_create_client__clicked(self, button): self._create_client() def on_create_transporter__clicked(self, button): store = api.new_store() transporter = store.fetch(self.model.transporter) model = run_person_role_dialog(TransporterEditor, self.wizard, store, transporter) rv = store.confirm(model) store.close() if rv: self._fill_transporter_combo() model = self.store.fetch(model) self.transporter.select(model) def on_discount_slave_changed(self, slave): self._update_totals() self.client.validate() def on_notes_button__clicked(self, *args): run_dialog(NoteEditor, self.wizard, self.store, self.model, 'notes', title=_("Additional Information")) def on_create_cfop__clicked(self, widget): self.store.savepoint('before_run_editor_cfop') cfop = run_dialog(CfopEditor, self.wizard, self.store, None) if cfop: self.cfop.append_item(cfop.get_description(), cfop) self.cfop.select_item_by_data(cfop) else: self.store.rollback_to_savepoint('before_run_editor_cfop') def on_invoice_number__validate(self, widget, value): if not 0 < value <= 999999999: return ValidationError( _("Invoice number must be between 1 and 999999999")) exists = self.store.find( Sale, And(Sale.invoice_number == value, Sale.id != self.model.id)) if not exists.is_empty(): return ValidationError(_(u'Invoice number already used.')) def on_client_details__clicked(self, button): client = self.model.client run_dialog(ClientDetailsDialog, self.wizard, self.store, client)
class SalesPersonStep(BaseMethodSelectionStep, WizardEditorStep): """ An abstract step which allows to define a salesperson, the sale's discount and surcharge, when it is needed. """ gladefile = 'SalesPersonStep' model_type = Sale proxy_widgets = ('salesperson', 'client', 'transporter', 'cost_center') invoice_widgets = ('invoice_number', ) cfop_widgets = ('cfop', ) def __init__(self, wizard, store, model, payment_group, invoice_model, previous=None): self.invoice_model = invoice_model self.pm_slave = None self.payment_group = payment_group BaseMethodSelectionStep.__init__(self) marker("WizardEditorStep.__init__") WizardEditorStep.__init__(self, store, wizard, model, previous=previous) self._update_totals() self.update_discount_and_surcharge() # # Private API # def _get_client(self): client_id = self.client.read() if not client_id: return None return self.store.get(Client, client_id) def _update_totals(self): subtotal = self.wizard.get_subtotal() self.subtotal_lbl.update(subtotal) total_paid = self.wizard.get_total_paid() self.total_paid_lbl.update(total_paid) to_pay = self.model.get_total_sale_amount(subtotal=subtotal) - total_paid self.cash_change_slave.update_total_sale_amount(to_pay) self.total_lbl.update(to_pay) def _setup_clients_widget(self): marker('Filling clients') self.client_gadget = ClientSearchEntryGadget( entry=self.client, store=self.store, model=self.model, parent=self.wizard) marker('Filled clients') def _fill_transporter_combo(self): marker('Filling transporters') transporters = Transporter.get_active_transporters(self.store) items = api.for_person_combo(transporters) self.transporter.prefill(items) self.transporter.set_sensitive(len(items)) marker('Filled transporters') def _fill_cost_center_combo(self): marker('Filling cost centers') cost_centers = CostCenter.get_active(self.store) # we keep this value because each call to is_empty() is a new sql query # to the database cost_centers_exists = not cost_centers.is_empty() if cost_centers_exists: self.cost_center.prefill(api.for_combo(cost_centers, attr='name', empty=_('No cost center.'))) self.cost_center.set_visible(cost_centers_exists) self.cost_center_lbl.set_visible(cost_centers_exists) marker('Filled cost centers') def _fill_cfop_combo(self): marker('Filling CFOPs') cfops = CfopData.get_for_sale(self.store) self.cfop.prefill(api.for_combo(cfops)) marker('Filled CFOPs') def _create_client(self): store = api.new_store() client = run_person_role_dialog(ClientEditor, self.wizard, store, None) store.confirm(client) if not client: return if len(self.client) == 0: self._setup_clients_widget() return clients = self.client.get_model_items().values() if client.id in clients: if client.is_active: self.client.select(client.id) else: # remove client from combo self.client.select_item_by_data(client.id) iter = self.client.get_active_iter() model = self.client.get_model() model.remove(iter) # just in case the inactive client was selected before. self.client.select_item_by_position(0) elif client.is_active: self.client.append_item(client.person.name, client.id) self.client.select(client.id) store.close() # # Public API # def update_discount_and_surcharge(self): marker("update_discount_and_surcharge") # Here we need avoid to reset sale data defined when creating the # Sale in the POS application, i.e, we should not reset the # discount and surcharge if they are already set (this is the # case when one of the parameters, CONFIRM_SALES_ON_TILL or # USE_TRADE_AS_DISCOUNT is enabled). if (not sysparam.get_bool('CONFIRM_SALES_ON_TILL') and not sysparam.get_bool('USE_TRADE_AS_DISCOUNT')): self.model.discount_value = currency(0) self.model.surcharge_value = currency(0) def setup_widgets(self): marker('Setting up widgets') # Only quotes have expire date. self.expire_date.hide() self.expire_label.hide() # Hide client category widgets self.client_category_lbl.hide() self.client_category.hide() # if the NF-e plugin is active, the client is mandantory in this # wizard (in this situation, we have only quote sales). if self.model.status == Sale.STATUS_QUOTE: manager = get_plugin_manager() mandatory_client = manager.is_active('nfe') self.client.set_property('mandatory', mandatory_client) marker('Filling sales persons') salespersons = self.store.find(SalesPerson) self.salesperson.prefill(api.for_person_combo(salespersons)) marker('Finished filling sales persons') marker('Read parameter') change_salesperson = sysparam.get_int('ACCEPT_CHANGE_SALESPERSON') if change_salesperson == ChangeSalespersonPolicy.ALLOW: self.salesperson.grab_focus() elif change_salesperson == ChangeSalespersonPolicy.DISALLOW: self.salesperson.set_sensitive(False) elif change_salesperson == ChangeSalespersonPolicy.FORCE_CHOOSE: self.model.salesperson = None self.salesperson.grab_focus() else: raise AssertionError marker('Finished reading parameter') self._setup_clients_widget() self._fill_transporter_combo() self._fill_cost_center_combo() if sysparam.get_bool('ASK_SALES_CFOP'): self._fill_cfop_combo() else: self.cfop_lbl.hide() self.cfop.hide() self.create_cfop.hide() # the maximum number allowed for an invoice is 999999999. self.invoice_number.set_adjustment( gtk.Adjustment(lower=1, upper=999999999, step_incr=1)) if not self.model.invoice_number: new_invoice_number = Invoice.get_next_invoice_number(self.store) self.invoice_model.invoice_number = new_invoice_number else: new_invoice_number = self.model.invoice_number self.invoice_model.invoice_number = new_invoice_number self.invoice_number.set_sensitive(False) self.invoice_model.original_invoice = new_invoice_number marker('Finished setting up widgets') def _refresh_next(self, validation_value): self.client.validate(force=True) client_valid = self.client.is_valid() self.wizard.refresh_next(validation_value and client_valid) # # WizardStep hooks # def post_init(self): BaseMethodSelectionStep.post_init(self) marker('Entering post_init') if self.wizard.need_create_payment(): self.wizard.payment_group.clear_unused() self.register_validate_function(self._refresh_next) self._update_next_step(self.get_selected_method()) # If there's no salesperson, keep the focus there as it should be # selected first to have a nice flow if (hasattr(self, 'cash_change_slave') and self.model.salesperson is not None): self.cash_change_slave.received_value.grab_focus() self.force_validation() marker('Leaving post_init') def setup_slaves(self): marker('Setting up slaves') BaseMethodSelectionStep.setup_slaves(self) marker('Finished parent') self.pm_slave.set_client(self.model.client, total_amount=self.wizard.get_total_to_pay()) marker('Setting discount') self.discount_slave = SaleDiscountSlave(self.store, self.model, self.model_type) if sysparam.get_bool('USE_TRADE_AS_DISCOUNT'): self.subtotal_expander.set_expanded(True) self.discount_slave.discount_value_ck.set_active(True) self.discount_slave.update_sale_discount() marker('Finshed setting up discount') self.discount_slave.connect('discount-changed', self.on_discount_slave_changed) slave_holder = 'discount_surcharge_slave' if self.get_slave(slave_holder): self.detach_slave(slave_holder) self.attach_slave(slave_holder, self.discount_slave) marker('Finished setting up slaves') def setup_proxies(self): marker('Setting up proxies') self.setup_widgets() self.proxy = self.add_proxy(self.model, SalesPersonStep.proxy_widgets) self.invoice_proxy = self.add_proxy(self.invoice_model, self.invoice_widgets) if self.model.client: self.client_gadget.set_editable(False) if sysparam.get_bool('ASK_SALES_CFOP'): self.add_proxy(self.model, SalesPersonStep.cfop_widgets) marker('Finished setting up proxies') # # Callbacks # def on_client__content_changed(self, entry): # This gets called before setup_slaves, but we must wait until slaves # are setup correctly if not self.pm_slave: return self.discount_slave.update_max_discount() self.pm_slave.set_client( client=self._get_client(), total_amount=self.wizard.get_total_to_pay()) def on_payment_method_changed(self, slave, method): self.force_validation() self._update_next_step(method) def on_client__validate(self, widget, client_id): if not client_id: return # this is used to avoid some tests from crashing if self.pm_slave is None: return client = self.store.get(Client, client_id) method = self.pm_slave.get_selected_method() try: client.can_purchase(method, self.get_remaining_value()) except SellError as e: return ValidationError(e) def on_create_client__clicked(self, button): self._create_client() def on_create_transporter__clicked(self, button): store = api.new_store() transporter = store.fetch(self.model.transporter) model = run_person_role_dialog(TransporterEditor, self.wizard, store, transporter) rv = store.confirm(model) store.close() if rv: self._fill_transporter_combo() model = self.store.fetch(model) self.transporter.select(model) def on_discount_slave_changed(self, slave): self._update_totals() self.client.validate() def on_observations_button__clicked(self, *args): self.store.savepoint('before_run_notes_editor') model = self.model.comments.first() if not model: model = SaleComment(store=self.store, sale=self.model, author=api.get_current_user(self.store)) rv = run_dialog(NoteEditor, self.wizard, self.store, model, 'comment', title=_('Sale observations')) if not rv: self.store.rollback_to_savepoint('before_run_notes_editor') def on_create_cfop__clicked(self, widget): self.store.savepoint('before_run_editor_cfop') cfop = run_dialog(CfopEditor, self.wizard, self.store, None) if cfop: self.cfop.append_item(cfop.get_description(), cfop) self.cfop.select_item_by_data(cfop) else: self.store.rollback_to_savepoint('before_run_editor_cfop') def on_invoice_number__validate(self, widget, value): if not 0 < value <= 999999999: return ValidationError( _("Invoice number must be between 1 and 999999999")) invoice = self.model.invoice branch = self.model.branch if invoice.check_unique_invoice_number_by_branch(value, branch): return ValidationError(_(u'Invoice number already used.'))
class SalesPersonStep(BaseMethodSelectionStep, WizardEditorStep): """ An abstract step which allows to define a salesperson, the sale's discount and surcharge, when it is needed. """ gladefile = 'SalesPersonStep' model_type = Sale proxy_widgets = ['salesperson', 'client', 'transporter', 'cost_center'] cfop_widgets = ('cfop', ) def __init__(self, wizard, store, model, payment_group, previous=None): self.pm_slave = None self.payment_group = payment_group BaseMethodSelectionStep.__init__(self) marker("WizardEditorStep.__init__") WizardEditorStep.__init__(self, store, wizard, model, previous=previous) self._update_totals() self.update_discount_and_surcharge() # # Private API # def _update_totals(self): subtotal = self.wizard.get_subtotal() self.subtotal_lbl.update(subtotal) total_paid = self.wizard.get_total_paid() self.total_paid_lbl.update(total_paid) to_pay = self.model.get_total_sale_amount( subtotal=subtotal) - total_paid self.cash_change_slave.update_total_sale_amount(to_pay) self.total_lbl.update(to_pay) def _setup_clients_widget(self): marker('Filling clients') self.client_gadget = ClientEntryGadget( entry=self.client, store=self.store, initial_value=self.model.client, parent=self.wizard, run_editor=self._run_client_editor) marker('Filled clients') def _run_client_editor(self, store, model, description=None, visual_mode=False): return run_person_role_dialog(ClientEditor, self.wizard, store, model, document=self.wizard._current_document, description=description, visual_mode=visual_mode) def _fill_transporter_combo(self): marker('Filling transporters') transporters = Transporter.get_active_transporters(self.store) items = api.for_person_combo(transporters) self.transporter.prefill(items) self.transporter.set_sensitive(len(items)) marker('Filled transporters') def _fill_cost_center_combo(self): marker('Filling cost centers') cost_centers = CostCenter.get_active(self.store) # we keep this value because each call to is_empty() is a new sql query # to the database cost_centers_exists = not cost_centers.is_empty() if cost_centers_exists: self.cost_center.prefill( api.for_combo(cost_centers, attr='name', empty=_('No cost center.'))) self.cost_center.set_visible(cost_centers_exists) self.cost_center_lbl.set_visible(cost_centers_exists) marker('Filled cost centers') def _fill_cfop_combo(self): marker('Filling CFOPs') cfops = CfopData.get_for_sale(self.store) self.cfop.prefill(api.for_combo(cfops)) marker('Filled CFOPs') # # Public API # def update_discount_and_surcharge(self): marker("update_discount_and_surcharge") # Here we need avoid to reset sale data defined when creating the # Sale in the POS application, i.e, we should not reset the # discount and surcharge if they are already set (this is the # case when one of the parameters, CONFIRM_SALES_ON_TILL or # USE_TRADE_AS_DISCOUNT is enabled). if (not sysparam.get_bool('CONFIRM_SALES_ON_TILL') and not sysparam.get_bool('USE_TRADE_AS_DISCOUNT')): self.model.discount_value = currency(0) self.model.surcharge_value = currency(0) def setup_widgets(self): marker('Setting up widgets') # Only quotes have expire date. self.expire_date.hide() self.expire_label.hide() # Hide client category widgets self.client_category_lbl.hide() self.client_category.hide() # if the NF-e plugin is active, the client is mandantory in this # wizard (in this situation, we have only quote sales). if self.model.status == Sale.STATUS_QUOTE: manager = get_plugin_manager() mandatory_client = manager.is_active('nfe') self.client.set_property('mandatory', mandatory_client) marker('Filling sales persons') salespersons = SalesPerson.get_active_salespersons(self.store) self.salesperson.prefill(salespersons) marker('Finished filling sales persons') marker('Read parameter') change_salesperson = sysparam.get_int('ACCEPT_CHANGE_SALESPERSON') if change_salesperson == ChangeSalespersonPolicy.ALLOW: self.salesperson.grab_focus() elif change_salesperson == ChangeSalespersonPolicy.DISALLOW: self.salesperson.set_sensitive(False) elif change_salesperson == ChangeSalespersonPolicy.FORCE_CHOOSE: self.model.salesperson = None self.salesperson.grab_focus() else: raise AssertionError marker('Finished reading parameter') self._setup_clients_widget() self._fill_transporter_combo() self._fill_cost_center_combo() if sysparam.get_bool('ASK_SALES_CFOP'): self._fill_cfop_combo() else: self.cfop_lbl.hide() self.cfop.hide() self.create_cfop.hide() marker('Finished setting up widgets') def _refresh_next(self, validation_value): self.client.validate(force=True) client_valid = self.client.is_valid() self.wizard.refresh_next(validation_value and client_valid) # # WizardStep hooks # def post_init(self): BaseMethodSelectionStep.post_init(self) marker('Entering post_init') if self.wizard.need_create_payment(): self.wizard.payment_group.clear_unused() self.register_validate_function(self._refresh_next) self._update_next_step(self.get_selected_method()) # If there's no salesperson, keep the focus there as it should be # selected first to have a nice flow if (hasattr(self, 'cash_change_slave') and self.model.salesperson is not None): self.cash_change_slave.received_value.grab_focus() self.force_validation() marker('Leaving post_init') def setup_slaves(self): marker('Setting up slaves') BaseMethodSelectionStep.setup_slaves(self) marker('Finished parent') self.pm_slave.set_client(self.model.client, total_amount=self.wizard.get_total_to_pay()) marker('Setting discount') self.discount_slave = SaleDiscountSlave(self.store, self.model, self.model_type) if sysparam.get_bool('USE_TRADE_AS_DISCOUNT'): self.subtotal_expander.set_expanded(True) self.discount_slave.discount_value_ck.set_active(True) self.discount_slave.update_sale_discount() marker('Finshed setting up discount') self.discount_slave.connect('discount-changed', self.on_discount_slave_changed) slave_holder = 'discount_surcharge_slave' if self.get_slave(slave_holder): self.detach_slave(slave_holder) self.attach_slave(slave_holder, self.discount_slave) marker('Finished setting up slaves') def setup_proxies(self): marker('Setting up proxies') self.setup_widgets() self.proxy = self.add_proxy(self.model, self.proxy_widgets) if self.model.client: self.client_gadget.set_editable(False) if sysparam.get_bool('ASK_SALES_CFOP'): self.add_proxy(self.model, SalesPersonStep.cfop_widgets) marker('Finished setting up proxies') # # Callbacks # def on_client__content_changed(self, entry): # This gets called before setup_slaves, but we must wait until slaves # are setup correctly if not self.pm_slave: return self.discount_slave.update_max_discount() self.pm_slave.set_client(client=self.model.client, total_amount=self.wizard.get_total_to_pay()) def on_payment_method_changed(self, slave, method): self.force_validation() self._update_next_step(method) def on_client__validate(self, widget, client): if not client: return # this is used to avoid some tests from crashing if self.pm_slave is None: return method = self.pm_slave.get_selected_method() try: client.can_purchase(method, self.get_remaining_value()) except SellError as e: return ValidationError(e) return StockOperationPersonValidationEvent.emit( client.person, type(client)) def on_create_transporter__clicked(self, button): store = api.new_store() transporter = store.fetch(self.model.transporter) model = run_person_role_dialog(TransporterEditor, self.wizard, store, transporter) rv = store.confirm(model) store.close() if rv: self._fill_transporter_combo() model = self.store.fetch(model) self.transporter.select(model) def on_discount_slave_changed(self, slave): self._update_totals() self.client.validate() def on_observations_button__clicked(self, *args): self.store.savepoint('before_run_notes_editor') model = self.model.comments.first() if not model: model = SaleComment(store=self.store, sale=self.model, author=api.get_current_user(self.store)) rv = run_dialog(NoteEditor, self.wizard, self.store, model, 'comment', title=_('Sale observations')) if not rv: self.store.rollback_to_savepoint('before_run_notes_editor') def on_create_cfop__clicked(self, widget): self.store.savepoint('before_run_editor_cfop') cfop = run_dialog(CfopEditor, self.wizard, self.store, None) if cfop: self.cfop.append_item(cfop.get_description(), cfop) self.cfop.select_item_by_data(cfop) else: self.store.rollback_to_savepoint('before_run_editor_cfop') def on_invoice_number__validate(self, widget, value): if not 0 < value <= 999999999: return ValidationError( _("Invoice number must be between 1 and 999999999")) invoice = self.model.invoice branch = self.model.branch if invoice.check_unique_invoice_number_by_branch(value, branch): return ValidationError(_(u'Invoice number already used.')) def on_transporter__validate(self, widget, transporter): return StockOperationPersonValidationEvent.emit( transporter.person, type(transporter))
class SalesPersonStep(BaseMethodSelectionStep, WizardEditorStep): """ An abstract step which allows to define a salesperson, the sale's discount and surcharge, when it is needed. """ gladefile = 'SalesPersonStep' model_type = Sale proxy_widgets = ('salesperson', 'client', 'transporter', 'cost_center') invoice_widgets = ('invoice_number', ) cfop_widgets = ('cfop', ) def __init__(self, wizard, store, model, payment_group, invoice_model, previous=None): self.invoice_model = invoice_model self.payment_group = payment_group BaseMethodSelectionStep.__init__(self) marker("WizardEditorStep.__init__") WizardEditorStep.__init__(self, store, wizard, model, previous=previous) self._update_totals() self.update_discount_and_surcharge() # # Private API # def _update_totals(self): subtotal = self.wizard.get_subtotal() self.subtotal_lbl.update(subtotal) total_paid = self.wizard.get_total_paid() self.total_paid_lbl.update(total_paid) to_pay = self.model.get_total_sale_amount( subtotal=subtotal) - total_paid self.cash_change_slave.update_total_sale_amount(to_pay) self.total_lbl.update(to_pay) def _update_widgets(self): has_client = bool(self.client.get_selected()) self.pm_slave.method_set_sensitive(u'store_credit', has_client) self.pm_slave.method_set_sensitive(u'bill', has_client) self.pm_slave.method_set_sensitive(u'credit', has_client) def _fill_clients_combo(self): marker('Filling clients') # FIXME: This should not be using a normal ProxyComboEntry, # we need a specialized widget that does the searching # on demand. clients = Client.get_active_clients(self.store) self.client.prefill(api.for_person_combo(clients)) self.client.set_sensitive(len(self.client.get_model())) marker('Filled clients') def _fill_transporter_combo(self): marker('Filling transporters') transporters = Transporter.get_active_transporters(self.store) items = api.for_person_combo(transporters) self.transporter.prefill(items) self.transporter.set_sensitive(len(items)) marker('Filled transporters') def _fill_cost_center_combo(self): marker('Filling cost centers') cost_centers = CostCenter.get_active(self.store) # we keep this value because each call to is_empty() is a new sql query # to the database cost_centers_exists = not cost_centers.is_empty() if cost_centers_exists: self.cost_center.prefill( api.for_combo(cost_centers, attr='name', empty=_('No cost center.'))) self.cost_center.set_visible(cost_centers_exists) self.cost_center_lbl.set_visible(cost_centers_exists) marker('Filled cost centers') def _fill_cfop_combo(self): marker('Filling CFOPs') cfops = self.store.find(CfopData) self.cfop.prefill(api.for_combo(cfops)) marker('Filled CFOPs') def _create_client(self): store = api.new_store() client = run_person_role_dialog(ClientEditor, self.wizard, store, None) store.confirm(client) client = self.store.fetch(client) store.close() if not client: return if len(self.client) == 0: self._fill_clients_combo() return clients = self.client.get_model_items().values() if client in clients: if client.is_active: self.client.select(client) else: # remove client from combo self.client.select_item_by_data(client) iter = self.client.get_active_iter() model = self.client.get_model() model.remove(iter) # just in case the inactive client was selected before. self.client.select_item_by_position(0) elif client.is_active: self.client.append_item(client.person.name, client) self.client.select(client) self._update_widgets() # # Public API # def update_discount_and_surcharge(self): marker("update_discount_and_surcharge") # Here we need avoid to reset sale data defined when creating the # Sale in the POS application, i.e, we should not reset the # discount and surcharge if they are already set (this is the # case when CONFIRM_SALES_ON_TILL parameter is enabled). if not sysparam(self.store).CONFIRM_SALES_ON_TILL: self.model.discount_value = currency(0) self.model.surcharge_value = currency(0) def setup_widgets(self): marker('Setting up widgets') # Only quotes have expire date. self.expire_date.hide() self.expire_label.hide() # Hide operation nature widgets self.operation_nature.hide() self.nature_lbl.hide() # Hide client category widgets self.client_category_lbl.hide() self.client_category.hide() # if the NF-e plugin is active, the client is mandantory in this # wizard (in this situation, we have only quote sales). if self.model.status == Sale.STATUS_QUOTE: manager = get_plugin_manager() mandatory_client = manager.is_active('nfe') self.client.set_property('mandatory', mandatory_client) marker('Filling sales persons') salespersons = self.store.find(SalesPerson) self.salesperson.prefill(api.for_person_combo(salespersons)) marker('Finished filling sales persons') marker('Read parameter') if not sysparam(self.store).ACCEPT_CHANGE_SALESPERSON: self.salesperson.set_sensitive(False) else: self.salesperson.grab_focus() marker('Finished reading parameter') self._fill_clients_combo() self._fill_transporter_combo() self._fill_cost_center_combo() if sysparam(self.store).ASK_SALES_CFOP: self._fill_cfop_combo() else: self.cfop_lbl.hide() self.cfop.hide() self.create_cfop.hide() # the maximum number allowed for an invoice is 999999999. self.invoice_number.set_adjustment( gtk.Adjustment(lower=1, upper=999999999, step_incr=1)) if not self.model.invoice_number: new_invoice_number = Sale.get_last_invoice_number(self.store) + 1 self.invoice_model.invoice_number = new_invoice_number else: new_invoice_number = self.model.invoice_number self.invoice_model.invoice_number = new_invoice_number self.invoice_number.set_sensitive(False) self.invoice_model.original_invoice = new_invoice_number marker('Finished setting up widgets') def _refresh_next(self, validation_value): self.client.validate(force=True) client_valid = self.client.is_valid() self.wizard.refresh_next(validation_value and client_valid) # # WizardStep hooks # def post_init(self): BaseMethodSelectionStep.post_init(self) marker('Entering post_init') self.toogle_client_details() if self.wizard.need_create_payment(): self.wizard.payment_group.clear_unused() self.register_validate_function(self._refresh_next) self._update_next_step(self.get_selected_method()) if hasattr(self, 'cash_change_slave'): self.cash_change_slave.received_value.grab_focus() self.force_validation() marker('Leaving post_init') def setup_slaves(self): marker('Setting up slaves') BaseMethodSelectionStep.setup_slaves(self) marker('Finished parent') self.pm_slave.method_set_sensitive(u'store_credit', bool(self.model.client)) self.pm_slave.method_set_sensitive(u'bill', bool(self.model.client)) self.pm_slave.method_set_sensitive(u'credit', bool(self.model.client)) marker('Setting discount') self.discount_slave = SaleDiscountSlave(self.store, self.model, self.model_type) marker('Finshed setting up discount') self.discount_slave.connect('discount-changed', self.on_discount_slave_changed) slave_holder = 'discount_surcharge_slave' if self.get_slave(slave_holder): self.detach_slave(slave_holder) self.attach_slave(slave_holder, self.discount_slave) marker('Finished setting up slaves') def setup_proxies(self): marker('Setting up proxies') self.setup_widgets() self.proxy = self.add_proxy(self.model, SalesPersonStep.proxy_widgets) self.invoice_proxy = self.add_proxy(self.invoice_model, self.invoice_widgets) if self.model.client: self.client.set_sensitive(False) self.create_client.set_sensitive(False) if sysparam(self.store).ASK_SALES_CFOP: self.add_proxy(self.model, SalesPersonStep.cfop_widgets) marker('Finished setting up proxies') def toogle_client_details(self): client = self.client.read() self.client_details.set_sensitive(bool(client)) # # Callbacks # def on_client__changed(self, entry): self.toogle_client_details() self._update_widgets() self.discount_slave.update_max_discount() def on_payment_method_changed(self, slave, method_name): self.client.validate(force=True) self._update_next_step(method_name) def on_client__validate(self, widget, client): if not client: return # this is used to avoid some tests from crashing if not hasattr(self, 'pm_slave'): return method = self.pm_slave.get_selected_method() try: client.can_purchase(method, self.model.get_total_sale_amount()) self.wizard.refresh_next(True) except SellError as e: self.wizard.refresh_next(False) return ValidationError(e) def on_create_client__clicked(self, button): self._create_client() def on_create_transporter__clicked(self, button): store = api.new_store() transporter = store.fetch(self.model.transporter) model = run_person_role_dialog(TransporterEditor, self.wizard, store, transporter) rv = store.confirm(model) store.close() if rv: self._fill_transporter_combo() model = self.store.fetch(model) self.transporter.select(model) def on_discount_slave_changed(self, slave): self._update_totals() self.client.validate() def on_observations_button__clicked(self, *args): run_dialog(NoteEditor, self.wizard, self.store, self.model, 'notes', title=_("Additional Information")) def on_create_cfop__clicked(self, widget): self.store.savepoint('before_run_editor_cfop') cfop = run_dialog(CfopEditor, self.wizard, self.store, None) if cfop: self.cfop.append_item(cfop.get_description(), cfop) self.cfop.select_item_by_data(cfop) else: self.store.rollback_to_savepoint('before_run_editor_cfop') def on_invoice_number__validate(self, widget, value): if not 0 < value <= 999999999: return ValidationError( _("Invoice number must be between 1 and 999999999")) exists = self.store.find( Sale, And(Sale.invoice_number == value, Sale.id != self.model.id)) if not exists.is_empty(): return ValidationError(_(u'Invoice number already used.')) def on_client_details__clicked(self, button): client = self.model.client run_dialog(ClientDetailsDialog, self.wizard, self.store, client)