def _check_status(self, verbose=False): status = self._get_status() if status[0] != ':': raise HardwareFailure('Broken status reply') if verbose: print '== STATUS ==' # Codes found on page 57-59 print 'Raw status code:', status print 'Cashier drawer is', ifset(status[1], 3, 'closed', 'open') if self.has_pending_reduce(): raise PendingReduceZ(_('Pending Reduce Z')) if self.status_check(status, 1, 2): raise HardwareFailure(_('Mechanical failure')) if not self.status_check(status, 1, 1): raise AuthenticationFailure(_('Not properly authenticated')) if self.status_check(status, 1, 0): raise OutofPaperError(_('No paper')) if self.status_check(status, 2, 3): raise PrinterOfflineError(_("Offline")) #if not self.status_check(status, 2, 2): # raise CommError(_("Peripheral is not connected to AUX")) if self.status_check(status, 2, 0): log.info('Almost out of paper') if verbose: S3 = status[3] print ifset(S3, 3, 'Maintenance', 'Operational'), 'mode' print 'Authentication', ifset(S3, 2, 'disabled', 'enabled') print 'Guillotine', ifset(S3, 1, 'disabled', 'enabled') print 'Auto close CF?', ifset(S3, 0, 'no', 'yes') if self.status_check(status, 6, 1): raise ReduceZError(_("readZ is already emitted")) # FIXME: I am not sure we should be doing this here. This method # should only check the status, and not emit any other command. #if self.needs_read_x(status): # self.send_command(CMD_GET_X) return status
class SRP350Status(object): st1_codes = { 0x40: _("Test mode and standby"), 0x41: _("Test mode and in the middle of a fiscal transaction"), 0x42: _("Test mode and in the middle of a non fiscal transaction"), 0x60: _("Fiscal mode and standby"), 0x68: _("Fiscal mode, out of fiscal memory and waiting"), 0x61: _("Fiscal mode and in the middle of a fiscal transaction"), 0x69: _("Fiscal mode, out of fiscal memory and in the middle of" "a fiscal transaction"), 0x62: _("Fiscal mode and in the middle of a non fiscal transaction"), 0x6A: _("Fiscal mode, out of fiscal memory and in the middle of" "a non fiscal transaction"), } st2_codes = { 0x08: (HardwareFailure(_("Till Error"))), 0x41: (OutofPaperError(_("Out of paper"))), 0x42: (HardwareFailure(_("Printer cover is open / Low paper"))), 0x43: (HardwareFailure(_("Mechanical printer error / Out of paper"))), 0x60: (PrinterError(_("Fiscal Error"))), 0x64: (HardwareFailure(_("Fiscal Memory Error"))), 0x6C: (HardwareFailure(_("Out of fiscal memory error"))), 0x48: (HardwareFailure(_("Out of fiscal memory"))), } def __init__(self, value): for key in self.st2_codes: if (key & value) == key: print chr(key) raise self.st2_codes[key]
def _check_status(self, verbose=False): status = self._get_status() if status[0] != ':': raise HardwareFailure('Broken status reply') if verbose: print('== STATUS ==') # Codes found on page 57-59 print('Raw status code:', status) print('Cashier drawer is', ifset(status[1], 3, 'closed', 'open')) if self.has_pending_reduce(): raise PendingReduceZ(_('Pending Reduce Z')) if self.status_check(status, 1, 2): raise HardwareFailure(_('Mechanical failure')) if not self.status_check(status, 1, 1): raise AuthenticationFailure(_('Not properly authenticated')) if self.status_check(status, 1, 0): raise OutofPaperError(_('No paper')) if self.status_check(status, 2, 3): raise PrinterOfflineError(_("Offline")) if self.status_check(status, 2, 0): log.info('Almost out of paper') if verbose: S3 = status[3] print(ifset(S3, 3, 'Maintenance', 'Operational'), 'mode') print('Authentication', ifset(S3, 2, 'disabled', 'enabled')) print('Guillotine', ifset(S3, 1, 'disabled', 'enabled')) print('Auto close CF?', ifset(S3, 0, 'no', 'yes')) if self.status_check(status, 6, 1): raise ReduceZError(_("readZ is already emitted")) return status
class MP25Status(object): PENDING_REDUCE_Z = 66 st1_codes = { 128: (OutofPaperError(_("Printer is out of paper"))), # 64: (AlmostOutofPaper(_("Printer almost out of paper"))), 32: (PrinterError(_("Printer clock error"))), 16: (PrinterError(_("Printer in error state"))), 8: (CommandError(_("First data value in CMD is not ESC (1BH)"))), 4: (CommandError(_("Nonexistent command"))), # 2: (CouponOpenError(_("Printer has a coupon currently open"))), 1: (CommandError(_("Invalid number of parameters")))} st2_codes = { 128: (CommandError(_("Invalid CMD parameter"))), 64: (HardwareFailure(_("Fiscal memory is full"))), 32: (HardwareFailure(_("Error in CMOS memory"))), 16: (PrinterError(_("Given tax is not programmed on the printer"))), 8: (DriverError(_("No available tax slot"))), 4: (CancelItemError(_("The item wasn't added in the coupon or can't " "be cancelled"))), # 2: (PrinterError(_("Owner data (CGC/IE) not programmed on the printer"))), # FIXME: This shouldn't be commented. But it will break the tests. # Need to update the tests for all bematech printers #1: (CommandError(_("Command not executed"))) } st3_codes = { # 7: (CouponOpenError(_("Coupon already Open"))), # 8: (CouponNotOpenError(_("Coupon is closed"))), 13: (PrinterOfflineError(_("Printer is offline"))), 16: (DriverError(_("Surcharge or discount greater than coupon total" "value"))), 17: (DriverError(_("Coupon with no items"))), 20: (PaymentAdditionError(_("Payment method not recognized"))), 22: (PaymentAdditionError(_("Isn't possible add more payments since" "the coupon total value already was " "reached"))), 23: (DriverError(_("Coupon isn't totalized yet"))), 43: (CouponNotOpenError(_("Printer not initialized"))), 45: (PrinterError(_("Printer without serial number"))), 52: (DriverError(_("Invalid start date"))), 53: (DriverError(_("Invalid final date"))), 85: (DriverError(_("Sale with null value"))), 91: (ItemAdditionError(_("Surcharge or discount greater than item" "value"))), 100: (DriverError(_("Invalid date"))), 115: (CancelItemError(_("Item doesn't exists or already was cancelled"))), 118: (DriverError(_("Surcharge greater than item value"))), 119: (DriverError(_("Discount greater than item value"))), 129: (CouponOpenError(_("Invalid month"))), 169: (CouponTotalizeError(_("Coupon already totalized"))), 170: (PaymentAdditionError(_("Coupon not totalized yet"))), 171: (DriverError(_("Surcharge on subtotal already effected"))), 172: (DriverError(_("Discount on subtotal already effected"))), 176: (DriverError(_("Invalid date")))} def __init__(self, reply): self.st1, self.st2, self.st3 = reply[-3:] @property def open(self): return self.st1 & 2 def _check_error_in_dict(self, error_codes, value): for key in error_codes: if key & value: raise error_codes[key] def check_error(self): log.debug("status: st1=%s st2=%s st3=%s" % (self.st1, self.st2, self.st3)) if self.st1 != 0: self._check_error_in_dict(self.st1_codes, self.st1) if self.st2 != 0: self._check_error_in_dict(self.st2_codes, self.st2) # first bit means not executed, look in st3 for more if self.st2 & 1 and self.st3: if self.st3 in self.st3_codes: raise self.st3_codes[self.st3]
class Reply(object): # # Printer flags # error_codes = { '0101': (CommandError(_("Invalid command for current state."))), '0102': (CommandError(_("Invalid command for current document."))), '0203': (CommandError(_("Excess fields"))), '0204': (CommandError(_("Missing fields"))), '0205': (CommandParametersError(_("Field not optional."))), '0206': (CommandParametersError(_("Invalid alphanumeric field."))), '0207': (CommandParametersError(_("Invalid alphabetic field."))), '0208': (CommandParametersError(_("Invalid numeric field."))), '020E': (CommandParametersError(_("Fields with print invalid " "attributes."))), '0304': (OutofPaperError(_("Out of paper."))), '0305': (AlmostOutofPaper(_("Almost out of paper."))), '0801': (CommandError(_("Invalid command with closed " "fiscal journey."))), '090C': (DriverError(_("Payment method not defined."))), '090F': (ItemAdditionError(_("Tax not found."))), '0910': (ItemAdditionError(_("Invalid tax."))), '0A12': (CancelItemError( _("It was not possible cancel the last " "fiscal coupon."))), '0A15': (PrinterError(_("Requires CDC cancellation."))), '0A16': (CancelItemError(_("Invalid item number in fiscal coupon"))), '0E0A': (PrinterError(_("Last non-fiscal coupon not found."))), '0E0B': (PrinterError(_("Payment method not found."))), } def __init__(self, string, command_id): checksum = string[-4:] self.string = string[:-4] log.debug('reply %s' % repr(string)) cs = '%04X' % sum([ord(i) for i in self.string]) if cs != checksum: raise DriverError('Erro de checksum') self.string = unescape(self.string) # Verifica header & tail assert self.pop() == STX, 'STX' frame_id = self.pop() if frame_id == '\x80': self.intermediate = True return self.intermediate = False assert frame_id == chr(command_id), ('command_id', command_id) assert self.string[-1] == ETX, 'ETX' # Retira statuses self.printer_status = struct.unpack('>H', str2bytes(self.pop(2)))[0] assert self.pop() == FLD, 'FLD 1' self.fiscal_status = struct.unpack('>H', str2bytes(self.pop(2)))[0] assert self.pop() == FLD, 'FLD 2' # reserved self.pop() r = self.pop(2) self.reply_status = '%02X%02X' % (ord(r[0]), ord(r[1])) assert self.pop() == FLD, 'FLD 3' # reserved self.pop() # Pega dados de retorno fields = self.string[:-1] # FIXME: Maybe we need to de-escape the string self.fields = fields.split(FLD) def check_error(self): log.debug("reply_status %s" % self.reply_status) error_code = self.reply_status # Success, do nothing if error_code == '0000': return if error_code in self.error_codes: error = self.error_codes[error_code] error.code = int(error_code, 16) raise error raise DriverError(error="unhandled driver error", code=int(error_code, 16)) def pop(self, size=1): """Remove size bites from the begining of self.string and returns it """ head = self.string[:size] self.string = self.string[size:] return head def check_printer_status(self): status = bin(self.printer_status) printer_status = status[2:] return printer_status def check_fiscal_status(self): status = bin(self.fiscal_status) fiscal_status = status[2:] return fiscal_status