def test_get_serial_devices(self, comports): class MockDevice: device = '/dev/ttyS0' comports.return_value = [MockDevice()] devices = DeviceManager.get_serial_devices() self.assertEqual(len(devices), 1) self.assertEqual(devices[0].device_name, '/dev/ttyS0')
def _populate_serial_ports(self): values = [] for device in DeviceManager.get_serial_devices(): values.append(device.device_name) if not self.model.device_name in values: values.append(self.model.device_name) if sysparam.get_bool('DEMO_MODE') or is_developer_mode(): values.append(u'/dev/null') self.device_name.prefill(values)
def setup_device_port_combo(self): items = [(_("Choose..."), None)] items.extend([(str(device.device_name), str(device.device_name)) for device in DeviceManager.get_serial_devices()]) items.extend(self._get_usb_devices()) if is_developer_mode(): # Include virtual port for virtual printer items.append(('Virtual device', u'/dev/null')) devices = [i[1] for i in items] if self.model.device_name not in devices: items.append(('Unkown device (%s)' % self.model.device_name, self.model.device_name)) self.device_combo.prefill(items)
class ECFEditor(BaseEditor): translation_domain = 'stoq' domain = 'ecf' gladefile = 'FiscalPrinterDialog' model_type = ECFPrinter model_name = _('Fiscal Printer') proxy_widgets = [ 'device_name', 'device_serial', 'is_active', 'baudrate', 'user_number', 'register_date', 'register_cro' ] def __init__(self, store, model=None): self._device_manager = DeviceManager() BaseEditor.__init__(self, store, model) self.progress_dialog = ProgressDialog() self.progress_dialog.connect('cancel', self._on_progress_dialog__cancel) self.progress_dialog.set_transient_for(self.main_dialog) if self.edit_mode: self.printer.set_sensitive(False) self.main_dialog.ok_button.grab_focus() else: self.edit_constants.hide() self.device_serial.hide() self.device_serial_label.hide() self.is_active.hide() # # BaseEditor # def create_model(self, store): model = ECFPrinter(brand=u'daruma', model=u'FS345', device_name=u'/dev/ttyS0', device_serial=u'', baudrate=9600, station=get_current_station(store), is_active=True, store=store) if platform.system() == 'Windows': model.device_name = u'COM1' return model def setup_proxies(self): self._populate_printers() self._populate_serial_ports() self._populate_baudrate() self.proxy = self.add_proxy(self.model, ECFEditor.proxy_widgets) self.printer.select_item_by_label(self.model.get_description()) def validate_confirm(self): if not self.can_activate_printer(): return False if self.edit_mode: return True try: self._status = ECFAsyncPrinterStatus(self.model.device_name, self.model.printer_class, self.model.baudrate) except SerialException as e: warning(_('Error opening serial port'), str(e)) return False self._status.connect('reply', self._printer_status__reply) self._status.connect('timeout', self._printer_status__timeout) self.progress_dialog.set_label( _("Probing for a %s printer on %s") % (self.model.model_name, self._status.get_device_name())) self.progress_dialog.start() return False def can_activate_printer(self): serial = self.model.device_serial printers = self.store.find(ECFPrinter, is_active=True, station=get_current_station(self.store)) till = self.store.find(Till, status=Till.STATUS_OPEN, station=get_current_station(self.store)).one() if till and printers: warning( _("You need to close the till opened at %s before " "changing this printer.") % till.opening_date.date()) return False for p in printers: if p.device_serial != serial and self.model.is_active: warning( _(u'The ECF %s is already active for this ' 'station. Deactivate that printer before ' 'activating this one.') % p.model) return False return True # # Callbacks # def _on_progress_dialog__cancel(self, progress): # FIXME: # status.stop() pass def on_printer__content_changed(self, combo): # Cannot change the model in edit mode! if self.edit_mode: return printer = combo.get_selected() self.model.model = printer.model self.model.brand = printer.brand # These are not persistent self.model.model_name = printer.model_name self.model.printer_class = printer.printer_class def on_edit_constants__clicked(self, button): run_dialog(DeviceConstantsDialog, self, self.store, self.model) def _printer_status__reply(self, status, reply): self.progress_dialog.stop() if not reply: return if not self._populate_ecf_printer(status): return if yesno( _("An ECF Printer was added. You need to restart Stoq " "before using it. Would you like to restart it now?"), gtk.RESPONSE_YES, _("Restart now"), _("Restart later")): self.store.commit() raise SystemExit # FIXME: move to base dialogs or base editor self.retval = self.model self.main_dialog.close() def _printer_status__timeout(self, status): self.progress_dialog.stop() info( _("Could not find a %s printer connected to %s") % (self.model.model_name, status.get_device_name())) # # Private # def _populate_baudrate(self): values = get_baudrate_values() self.baudrate.prefill(values) def _populate_printers(self): supported_ifaces = get_supported_printers_by_iface( ICouponPrinter).items() printers = [] for brand, printer_classes in supported_ifaces: for printer_class in printer_classes: printer = _PrinterModel(brand, printer_class) printers.append((printer.get_description(), printer)) # Allow to use virtual printer for both demo mode and developer mode # so it's easier for testers and developers to test ecf functionality if sysparam.get_bool('DEMO_MODE') or is_developer_mode(): from stoqdrivers.printers.virtual.Simple import Simple printer = _PrinterModel('virtual', Simple) printers.append((printer.get_description(), printer)) self.printer.prefill( locale_sorted(printers, key=operator.itemgetter(0))) def _populate_serial_ports(self): values = [] for device in self._device_manager.get_serial_devices(): values.append(device.device_name) if not self.model.device_name in values: values.append(self.model.device_name) self.device_name.prefill(values) def _populate_ecf_printer(self, status): serial = unicode(status.printer.get_serial()) if self.store.find(ECFPrinter, device_serial=serial): status.stop() status.get_port().close() info(_("This printer is already known to the system")) return False self.model.device_serial = serial self._populate_constants(self.model, status) return True def _populate_constants(self, model, status): driver = status.get_driver() for tax_enum, device_value, value in driver.get_tax_constants(): if tax_enum == TaxType.CUSTOM: constant = self.store.find(SellableTaxConstant, tax_value=value).one() # If the constant is not defined in the system, create it if not constant: constant = SellableTaxConstant( tax_value=value, tax_type=int(TaxType.CUSTOM), description=u'%0.2f %%' % value, store=self.store) elif tax_enum == TaxType.SERVICE: constant = self.store.find(DeviceConstant, constant_enum=int(tax_enum), printer=model).one() # Skip, If we have a service tax defined for this printer # This needs to be improved when we support more than one # service tax if constant is not None: continue else: constant = self.store.find(SellableTaxConstant, tax_type=int(tax_enum)).one() # Ignore if its unkown tax if not constant: continue if value: constant_name = u'%0.2f %%' % (value, ) elif constant: constant_name = constant.description else: constant_name = None DeviceConstant(constant_enum=int(tax_enum), constant_name=constant_name, constant_type=DeviceConstant.TYPE_TAX, constant_value=value, device_value=device_value, printer=model, store=self.store) # This is going to be ugly, most printers don't support # a real constant for the payment methods, so we have to look # at the description and guess payment_enums = { 'dinheiro': PaymentMethodType.MONEY, 'cheque': PaymentMethodType.CHECK, 'boleto': PaymentMethodType.BILL, 'cartao credito': PaymentMethodType.CREDIT_CARD, 'cartao debito': PaymentMethodType.DEBIT_CARD, 'financeira': PaymentMethodType.FINANCIAL, 'vale compra': PaymentMethodType.GIFT_CERTIFICATE } payment_methods = [] for device_value, constant_name in driver.get_payment_constants(): lower = constant_name.lower() lower = lower.replace('é', 'e') # Workaround method names with lower = lower.replace('ã', 'a') # accents payment_enum = payment_enums.get(lower) if payment_enum is None: continue # Avoid register the same method twice for the same device if payment_enum in payment_methods: continue DeviceConstant(constant_enum=int(payment_enum), constant_name=unicode(constant_name), constant_type=DeviceConstant.TYPE_PAYMENT, constant_value=None, device_value=device_value, printer=model, store=self.store) payment_methods.append(payment_enum)
class ECFEditor(BaseEditor): translation_domain = 'stoq' domain = 'ecf' gladefile = 'FiscalPrinterDialog' model_type = ECFPrinter model_name = _('Fiscal Printer') proxy_widgets = ['device_name', 'device_serial', 'is_active', 'baudrate', 'user_number', 'register_date', 'register_cro'] def __init__(self, store, model=None): self._device_manager = DeviceManager() BaseEditor.__init__(self, store, model) self.progress_dialog = ProgressDialog() self.progress_dialog.connect('cancel', self._on_progress_dialog__cancel) self.progress_dialog.set_transient_for(self.main_dialog) if self.edit_mode: self.printer.set_sensitive(False) self.main_dialog.ok_button.grab_focus() else: self.edit_constants.hide() self.device_serial.hide() self.device_serial_label.hide() self.is_active.hide() # # BaseEditor # def create_model(self, store): model = ECFPrinter(brand=u'daruma', model=u'FS345', device_name=u'/dev/ttyS0', device_serial=u'', baudrate=9600, station=get_current_station(store), is_active=True, store=store) if platform.system() == 'Windows': model.device_name = u'COM1' return model def setup_proxies(self): self._populate_printers() self._populate_serial_ports() self._populate_baudrate() self.proxy = self.add_proxy(self.model, ECFEditor.proxy_widgets) self.printer.select_item_by_label(self.model.get_description()) def validate_confirm(self): if not self.can_activate_printer(): return False if self.edit_mode: return True try: self._status = ECFAsyncPrinterStatus(self.model.device_name, self.model.printer_class, self.model.baudrate) except SerialException as e: warning(_('Error opening serial port'), str(e)) return False self._status.connect('reply', self._printer_status__reply) self._status.connect('timeout', self._printer_status__timeout) self.progress_dialog.set_label(_("Probing for a %s printer on %s") % ( self.model.model_name, self._status.get_device_name())) self.progress_dialog.start() return False def can_activate_printer(self): serial = self.model.device_serial printers = self.store.find(ECFPrinter, is_active=True, station=get_current_station(self.store)) till = self.store.find(Till, status=Till.STATUS_OPEN, station=get_current_station(self.store)).one() if till and printers: warning(_("You need to close the till opened at %s before " "changing this printer.") % till.opening_date.date()) return False for p in printers: if p.device_serial != serial and self.model.is_active: warning(_(u'The ECF %s is already active for this ' 'station. Deactivate that printer before ' 'activating this one.') % p.model) return False return True # # Callbacks # def _on_progress_dialog__cancel(self, progress): # FIXME: # status.stop() pass def on_printer__content_changed(self, combo): # Cannot change the model in edit mode! if self.edit_mode: return printer = combo.get_selected() self.model.model = printer.model self.model.brand = printer.brand # These are not persistent self.model.model_name = printer.model_name self.model.printer_class = printer.printer_class def on_edit_constants__clicked(self, button): run_dialog(DeviceConstantsDialog, self, self.store, self.model) def _printer_status__reply(self, status, reply): self.progress_dialog.stop() if not reply: return if not self._populate_ecf_printer(status): return if yesno(_("An ECF Printer was added. You need to restart Stoq " "before using it. Would you like to restart it now?"), gtk.RESPONSE_YES, _("Restart now"), _("Restart later")): self.store.commit() raise SystemExit # FIXME: move to base dialogs or base editor self.retval = self.model self.main_dialog.close() def _printer_status__timeout(self, status): self.progress_dialog.stop() info(_("Could not find a %s printer connected to %s") % ( self.model.model_name, status.get_device_name())) # # Private # def _populate_baudrate(self): values = get_baudrate_values() self.baudrate.prefill(values) def _populate_printers(self): supported_ifaces = get_supported_printers_by_iface(ICouponPrinter).items() printers = [] for brand, printer_classes in supported_ifaces: for printer_class in printer_classes: printer = _PrinterModel(brand, printer_class) printers.append((printer.get_description(), printer)) # Allow to use virtual printer for both demo mode and developer mode # so it's easier for testers and developers to test ecf functionality if sysparam.get_bool('DEMO_MODE') or is_developer_mode(): from stoqdrivers.printers.virtual.Simple import Simple printer = _PrinterModel('virtual', Simple) printers.append((printer.get_description(), printer)) self.printer.prefill(locale_sorted( printers, key=operator.itemgetter(0))) def _populate_serial_ports(self): values = [] for device in self._device_manager.get_serial_devices(): values.append(device.device_name) if not self.model.device_name in values: values.append(self.model.device_name) self.device_name.prefill(values) def _populate_ecf_printer(self, status): serial = unicode(status.printer.get_serial()) if self.store.find(ECFPrinter, device_serial=serial): status.stop() status.get_port().close() info(_("This printer is already known to the system")) return False self.model.device_serial = serial self._populate_constants(self.model, status) return True def _populate_constants(self, model, status): driver = status.get_driver() for tax_enum, device_value, value in driver.get_tax_constants(): if tax_enum == TaxType.CUSTOM: constant = self.store.find(SellableTaxConstant, tax_value=value).one() # If the constant is not defined in the system, create it if not constant: constant = SellableTaxConstant(tax_value=value, tax_type=int(TaxType.CUSTOM), description=u'%0.2f %%' % value, store=self.store) elif tax_enum == TaxType.SERVICE: constant = self.store.find(DeviceConstant, constant_enum=int(tax_enum), printer=model).one() # Skip, If we have a service tax defined for this printer # This needs to be improved when we support more than one # service tax if constant is not None: continue else: constant = self.store.find(SellableTaxConstant, tax_type=int(tax_enum)).one() # Ignore if its unkown tax if not constant: continue if value: constant_name = u'%0.2f %%' % (value, ) elif constant: constant_name = constant.description else: constant_name = None DeviceConstant(constant_enum=int(tax_enum), constant_name=constant_name, constant_type=DeviceConstant.TYPE_TAX, constant_value=value, device_value=device_value, printer=model, store=self.store) # This is going to be ugly, most printers don't support # a real constant for the payment methods, so we have to look # at the description and guess payment_enums = {'dinheiro': PaymentMethodType.MONEY, 'cheque': PaymentMethodType.CHECK, 'boleto': PaymentMethodType.BILL, 'cartao credito': PaymentMethodType.CREDIT_CARD, 'cartao debito': PaymentMethodType.DEBIT_CARD, 'financeira': PaymentMethodType.FINANCIAL, 'vale compra': PaymentMethodType.GIFT_CERTIFICATE } payment_methods = [] for device_value, constant_name in driver.get_payment_constants(): lower = constant_name.lower() lower = lower.replace('é', 'e') # Workaround method names with lower = lower.replace('ã', 'a') # accents payment_enum = payment_enums.get(lower) if payment_enum is None: continue # Avoid register the same method twice for the same device if payment_enum in payment_methods: continue DeviceConstant(constant_enum=int(payment_enum), constant_name=unicode(constant_name), constant_type=DeviceConstant.TYPE_PAYMENT, constant_value=None, device_value=device_value, printer=model, store=self.store) payment_methods.append(payment_enum)
class DeviceSettingsEditor(BaseEditor): gladefile = 'DeviceSettingsEditor' model_type = DeviceSettings proxy_widgets = ('type_combo', 'brand_combo', 'device_combo', 'model_combo', 'station', 'is_active_button') def __init__(self, store, model=None, station=None): if station is not None and not isinstance(station, BranchStation): raise TypeError("station should be a BranchStation") self._device_manager = DeviceManager() self.printers_dict = get_supported_printers() self._branch_station = station # This attribute is set to True when setup_proxies is finished self._is_initialized = False BaseEditor.__init__(self, store, model) self._original_brand = self.model.brand self._original_model = self.model.model def refresh_ok(self, *args): if self._is_initialized: BaseEditor.refresh_ok(self, self.model.is_valid()) def setup_station_combo(self): if self._branch_station: self.station.prefill([(self._branch_station.name, self._branch_station)]) self.model.station = self._branch_station self.station.set_sensitive(False) return self.station.prefill( [(station.name, station) for station in self.store.find(BranchStation)]) def setup_device_port_combo(self): items = [(_("Choose..."), None)] items.extend([(unicode(device.device_name), unicode(device.device_name)) for device in self._device_manager.get_serial_devices()]) self.device_combo.prefill(items) def setup_device_types_combo(self): items = [(_("Choose..."), None)] device_types = ( # TODO: Reenable when we have cheque printers working. # DeviceSettings.CHEQUE_PRINTER_DEVICE, DeviceSettings.SCALE_DEVICE, ) items.extend([(self.model.get_device_type_name(t), t) for t in device_types]) self.type_combo.prefill(items) def setup_widgets(self): self.setup_device_types_combo() self.setup_device_port_combo() self.setup_station_combo() if not self.edit_mode: self.is_active_button.set_sensitive(False) def _get_supported_types(self): if self.model.type == DeviceSettings.SCALE_DEVICE: supported_types = get_supported_scales() elif self.model.type == DeviceSettings.CHEQUE_PRINTER_DEVICE: supported_types = get_supported_printers_by_iface(IChequePrinter) else: raise TypeError("The selected device type isn't supported") return supported_types def _get_supported_brands(self): return list(self._get_supported_types().keys()) def _get_supported_models(self): return self._get_supported_types()[self.model.brand] def update_brand_combo(self): self.brand_combo.clear() self.brand_combo.set_sensitive(self.model.type is not None) if self.model.type is None: return items = [(_("Choose..."), None)] supported_brands = self._get_supported_brands() items.extend([(brand.capitalize(), unicode(brand)) for brand in supported_brands]) self.brand_combo.prefill(items) def update_model_combo(self): self.model_combo.clear() brand = self.model.brand self.model_combo.set_sensitive(brand is not None) if self.model.brand is None: return supported_models = self._get_supported_models() items = [(_("Choose..."), None)] items.extend([(obj.model_name, unicode(obj.__name__)) for obj in supported_models]) self.model_combo.prefill(items) # # BaseEditor hooks # def setup_proxies(self): self.setup_widgets() self.proxy = self.add_proxy(self.model, DeviceSettingsEditor.proxy_widgets) self._is_initialized = True def create_model(self, store): return DeviceSettings(device_name=None, station=api.get_current_station(store), brand=None, model=None, type=None, store=store) def get_title(self, *args): if self.edit_mode: return _("Edit Device for %s") % self.model.station.name else: return _("Add Device") def validate_confirm(self): if not self.edit_mode: settings = DeviceSettings.get_by_station_and_type( store=api.get_default_store(), station=self.model.station.id, type=self.model.type) if settings: self.station.set_invalid( _(u"A %s already exists for station \"%s\"") % ( self.model.get_device_type_name(), self.model.station.name)) return False return True # # Kiwi callbacks # def on_brand_combo__changed(self, *args): self.update_model_combo() self.refresh_ok() def on_type_combo__changed(self, *args): self.update_brand_combo() self.refresh_ok() def on_brand_combo__state_changed(self, *args): self.update_model_combo() self.refresh_ok() def on_model_combo__changed(self, *args): self.refresh_ok() def on_device_combo__changed(self, *args): self.refresh_ok()
class DeviceSettingsEditor(BaseEditor): gladefile = 'DeviceSettingsEditor' model_type = DeviceSettings proxy_widgets = ('type_combo', 'brand_combo', 'device_combo', 'model_combo', 'station', 'is_active_button') def __init__(self, store, model=None, station=None): if station is not None and not isinstance(station, BranchStation): raise TypeError("station should be a BranchStation") self._device_manager = DeviceManager() self.printers_dict = get_supported_printers() self._branch_station = station # This attribute is set to True when setup_proxies is finished self._is_initialized = False BaseEditor.__init__(self, store, model) self._original_brand = self.model.brand self._original_model = self.model.model def refresh_ok(self, *args): if self._is_initialized: BaseEditor.refresh_ok(self, self.model.is_valid()) def setup_station_combo(self): if self._branch_station: self.station.prefill([(self._branch_station.name, self._branch_station)]) self.model.station = self._branch_station self.station.set_sensitive(False) return self.station.prefill([(station.name, station) for station in self.store.find(BranchStation)]) def setup_device_port_combo(self): items = [(_("Choose..."), None)] items.extend([(unicode(device.device_name), unicode(device.device_name)) for device in self._device_manager.get_serial_devices()]) self.device_combo.prefill(items) def setup_device_types_combo(self): items = [(_("Choose..."), None)] device_types = ( # TODO: Reenable when we have cheque printers working. # DeviceSettings.CHEQUE_PRINTER_DEVICE, DeviceSettings.SCALE_DEVICE, ) items.extend([(self.model.get_device_type_name(t), t) for t in device_types]) self.type_combo.prefill(items) def setup_widgets(self): self.setup_device_types_combo() self.setup_device_port_combo() self.setup_station_combo() if not self.edit_mode: self.is_active_button.set_sensitive(False) def _get_supported_types(self): if self.model.type == DeviceSettings.SCALE_DEVICE: supported_types = get_supported_scales() elif self.model.type == DeviceSettings.CHEQUE_PRINTER_DEVICE: supported_types = get_supported_printers_by_iface(IChequePrinter) else: raise TypeError("The selected device type isn't supported") return supported_types def _get_supported_brands(self): return list(self._get_supported_types().keys()) def _get_supported_models(self): return self._get_supported_types()[self.model.brand] def update_brand_combo(self): self.brand_combo.clear() self.brand_combo.set_sensitive(self.model.type is not None) if self.model.type is None: return items = [(_("Choose..."), None)] supported_brands = self._get_supported_brands() items.extend([(brand.capitalize(), unicode(brand)) for brand in supported_brands]) self.brand_combo.prefill(items) def update_model_combo(self): self.model_combo.clear() brand = self.model.brand self.model_combo.set_sensitive(brand is not None) if self.model.brand is None: return supported_models = self._get_supported_models() items = [(_("Choose..."), None)] items.extend([(obj.model_name, unicode(obj.__name__)) for obj in supported_models]) self.model_combo.prefill(items) # # BaseEditor hooks # def setup_proxies(self): self.setup_widgets() self.proxy = self.add_proxy(self.model, DeviceSettingsEditor.proxy_widgets) self._is_initialized = True def create_model(self, store): return DeviceSettings(device_name=None, station=api.get_current_station(store), brand=None, model=None, type=None, store=store) def get_title(self, *args): if self.edit_mode: return _("Edit Device for %s") % self.model.station.name else: return _("Add Device") def validate_confirm(self): if not self.edit_mode: settings = DeviceSettings.get_by_station_and_type( store=api.get_default_store(), station=self.model.station.id, type=self.model.type) if settings: self.station.set_invalid( _(u"A %s already exists for station \"%s\"") % (self.model.get_device_type_name(), self.model.station.name)) return False return True # # Kiwi callbacks # def on_brand_combo__changed(self, *args): self.update_model_combo() self.refresh_ok() def on_type_combo__changed(self, *args): self.update_brand_combo() self.refresh_ok() def on_brand_combo__state_changed(self, *args): self.update_model_combo() self.refresh_ok() def on_model_combo__changed(self, *args): self.refresh_ok() def on_device_combo__changed(self, *args): self.refresh_ok()
class DeviceSettingsEditor(BaseEditor): gladefile = 'DeviceSettingsEditor' model_type = DeviceSettings proxy_widgets = ('type_combo', 'brand_combo', 'device_combo', 'model_combo', 'baudrate', 'station', 'is_active_button') def __init__(self, store, model=None, station=None): if station is not None and not isinstance(station, BranchStation): raise TypeError("station should be a BranchStation") self._device_manager = DeviceManager() self._branch_station = station # This attribute is set to True when setup_proxies is finished self._is_initialized = False BaseEditor.__init__(self, store, model) self._original_brand = self.model.brand self._original_model = self.model.model self.test_button = self.add_button(_('Test device')) def refresh_ok(self, *args): if not self._is_initialized: return if self.test_button: self.test_button.set_sensitive(self.model.is_valid()) BaseEditor.refresh_ok(self, self.model.is_valid()) def setup_station_combo(self): if self._branch_station: self.station.prefill([(self._branch_station.name, self._branch_station)]) self.model.station = self._branch_station return self.station.prefill([ (station.name, station) for station in BranchStation.get_active_stations(self.store) ]) def setup_device_port_combo(self): items = [(_("Choose..."), None)] items.extend([(str(device.device_name), str(device.device_name)) for device in self._device_manager.get_serial_devices()]) items.extend(self._get_usb_devices()) if is_developer_mode(): # Include virtual port for virtual printer items.append(('Virtual device', u'/dev/null')) devices = [i[1] for i in items] if self.model.device_name not in devices: items.append(('Unkown device (%s)' % self.model.device_name, self.model.device_name)) self.device_combo.prefill(items) def setup_device_types_combo(self): items = [(_("Choose..."), None)] device_types = ( # TODO: Reenable when we have cheque printers working. # DeviceSettings.CHEQUE_PRINTER_DEVICE, DeviceSettings.NON_FISCAL_PRINTER_DEVICE, DeviceSettings.SCALE_DEVICE, ) items.extend([(self.model.describe_device_type(t), t) for t in device_types]) self.type_combo.prefill(items) def setup_widgets(self): self.setup_device_types_combo() self.setup_device_port_combo() self.setup_station_combo() self.baudrate.prefill(get_baudrate_values()) if not self.edit_mode: self.is_active_button.set_sensitive(False) def _get_supported_types(self): if self.model.type == DeviceSettings.SCALE_DEVICE: supported_types = get_supported_scales() #elif self.model.type == DeviceSettings.CHEQUE_PRINTER_DEVICE: # supported_types = get_supported_printers_by_iface(IChequePrinter) elif self.model.type == DeviceSettings.NON_FISCAL_PRINTER_DEVICE: supported_types = get_supported_printers_by_iface( INonFiscalPrinter, include_virtual=is_developer_mode()) else: raise TypeError("The selected device type isn't supported") return supported_types def _get_usb_devices(self): try: import usb.core except ImportError: # pragma no cover return [] devices = [] for device in get_usb_printer_devices(): try: dev = 'usb:{}:{}'.format(hex(device.idVendor), hex(device.idProduct)) try: if device.manufacturer is not None: desc = '{} {}'.format(device.manufacturer, device.product) else: desc = dev except Exception: desc = dev devices.append((desc, dev)) except usb.core.USBError: # pragma no cover # The user might not have access to some devices continue return devices def _get_supported_brands(self): return list(self._get_supported_types().keys()) def _get_supported_models(self): return self._get_supported_types()[self.model.brand] def update_brand_combo(self): self.brand_combo.clear() self.brand_combo.set_sensitive(self.model.type is not None) if self.model.type is None: return items = [(_("Choose..."), None)] supported_brands = self._get_supported_brands() items.extend([(brand.capitalize(), str(brand)) for brand in supported_brands]) self.brand_combo.prefill(items) def update_model_combo(self): self.model_combo.clear() brand = self.model.brand self.model_combo.set_sensitive(brand is not None) if self.model.brand is None: return supported_models = self._get_supported_models() items = [(_("Choose..."), None)] items.extend([(obj.model_name, str(obj.__name__)) for obj in supported_models]) self.model_combo.prefill(items) # # BaseEditor hooks # def setup_proxies(self): self.setup_widgets() self.proxy = self.add_proxy(self.model, DeviceSettingsEditor.proxy_widgets) self._is_initialized = True def create_model(self, store): return DeviceSettings(device_name=None, station=api.get_current_station(store), baudrate=9600, brand=None, model=None, type=None, store=store) def get_title(self, *args): if self.edit_mode: return _("Edit Device for %s") % self.model.station.name else: return _("Add Device") def validate_confirm(self): settings = DeviceSettings.get_by_station_and_type( store=api.get_default_store(), station=self.model.station.id, type=self.model.type, exclude=self.model) if settings and self.is_active_button.get_active(): warning( _(u"An active %s already exists for station \"%s\"") % (self.model.device_type_name, self.model.station_name)) return False return True # # Kiwi callbacks # def on_brand_combo__changed(self, *args): self.update_model_combo() self.refresh_ok() def on_type_combo__changed(self, *args): self.update_brand_combo() self.refresh_ok() def on_model_combo__changed(self, *args): self.refresh_ok() def on_device_combo__changed(self, *args): self.refresh_ok() def on_test_button__clicked(self, button): driver = self.model.get_interface() if self.model.type == DeviceSettings.NON_FISCAL_PRINTER_DEVICE: with driver.open(): driver.print_line(TEST_MESSAGE) elif self.model.type == DeviceSettings.SCALE_DEVICE: data = read_scale_info(self.store, self.model) warning(str(data.weight))