コード例 #1
0
    def _read_reply(self):
        reply = ''
        timeouts = 0

        while True:
            if timeouts > RETRIES_BEFORE_TIMEOUT:
                raise DriverError(
                    _("Timeout communicating with fiscal "
                      "printer"))

            c = self.read(1)
            if len(c) != 1:
                timeouts += 1
                continue

            # STX is always the first char in the reply. Ignore garbage
            # until STX is received.
            if len(reply) == 0 and c != STX:
                log.info('ignoring garbage in reply: %r' % c)
                continue

            reply += c

            if c == ETX and reply[-2] != ESC:
                break

        reply += self.read(4)
        log.debug("<<< %s" % repr(reply))

        return Reply(reply, self._command_id)
コード例 #2
0
 def set_coupon_footers(self, footers):
     if len(footers) < HEADER_LINE_NUMBER:
         for i in range(0, len(footers)):
             footer = footers[i]
             if len(footer) < HEADER_LINE_SIZE:
                 self._send_command(CMD_SET_FOOTER,
                                    "%02d" % (i + 91),
                                    str(footer),
                                    response='c')
             else:
                 raise DriverError(
                     _("This printer supports a"
                       "maximum of 40 characters per line"))
     else:
         raise DriverError(
             _("This printer supports up to 8 lines"
               "of header"))
コード例 #3
0
ファイル: fiscal.py プロジェクト: vintec-ca/addons-cluster
 def set_tax_rates(self, tax_rates):
     log.info('set_tax_rates()')
     if hasattr(self._driver, 'set_tax_rates'):
         self._driver.set_tax_rates(tax_rates)
     else:
         raise DriverError(
             _("This method is not supported from "
               "the current printer"))
コード例 #4
0
ファイル: fiscal.py プロジェクト: vintec-ca/addons-cluster
 def set_coupon_headers(self, headers):
     log.info('set_coupon_headers()')
     if hasattr(self._driver, 'set_coupon_headers'):
         self._driver.set_coupon_headers(headers)
     else:
         raise DriverError(
             _("This method is not supported from "
               "the current printer"))
コード例 #5
0
 def set_payment_methods(self, payment_methods):
     for pm in payment_methods:
         if (int(pm.get('code')) <= 16):
             if (len(pm.get('description')) <= 14):
                 data = "%02d%-14s" % (int(
                     pm.get('code')), str(pm.get('description')))
                 self._send_command(CMD_SET_PAYMENT_METHOD,
                                    data,
                                    response='c')
             else:
                 raise DriverError(
                     _("The 'description'"
                       "field has a maximum length of 14 characters"))
         else:
             raise DriverError(
                 _("Invalid code: " + pm.get('code') + ""
                   "Try a value between 01-16"))
コード例 #6
0
ファイル: fiscal.py プロジェクト: vintec-ca/addons-cluster
 def set_payment_methods(self, payment_methods):
     log.info('set_payment_methods()')
     if hasattr(self._driver, 'set_payment_methods'):
         self._driver.set_payment_methods(payment_methods)
     else:
         raise DriverError(
             _("This method is not supported from "
               "the current printer"))
コード例 #7
0
    def set_tax_rates(self, tax_rates):

        if len(tax_rates) == 4:
            taxes = {tax.get('code'): tax.get('value') for tax in tax_rates}
            vcodes = set(['!', '#', '"', ' '])
            if vcodes.difference(set(taxes.keys())) == set():
                data = ("2%05.2f2%05.2f2%05.2f") % (
                    taxes.get('!'), taxes.get('"'), taxes.get('#'))
                data = data.replace(".", "")
                self._send_command(CMD_SET_TAXES, data, response='c')
            else:
                raise DriverError(
                    _("This tax codes is not supported from "
                      "the current printer"))
        else:
            raise DriverError(_("this printer just can set 4 fixed taxes"))
        return True
コード例 #8
0
ファイル: FS345.py プロジェクト: echeverrifm/stoqdrivers
 def handle_error(self, error_value, raw):
     error = int(error_value[2:])
     # Page 61-62
     if error == 39:
         raise DriverError('Bad parameters: %r' % raw, error)
     elif error == 10:
         raise CouponOpenError(_("Document is already open"), error)
     elif error == 11:
         raise CouponNotOpenError(_("Coupon is not open"), error)
     elif error == 12:
         raise CouponNotOpenError(_("There's no open document to cancel"),
                                  error)
     elif error == 15:
         raise CancelItemError(_("There is no such item in "
                                 "the coupon"), error)
     elif error == 16:
         raise DriverError("Bad discount/markup parameter", error)
     elif error == 21:
         log.warning(_('Printer error %s: No paper'), error)
     elif error == 22:
         raise DriverError(
             "Reduce Z was already sent today, try again tomorrow", error)
     elif error == 23:
         raise PendingReduceZ
     elif error == 24:
         raise DriverError("Bad unit specified: %r" % raw, error)
     elif error == 42:
         raise DriverError("Read X has not been sent yet", error)
     elif error == 45:
         raise DriverError(_("Required field is blank"), error)
     else:
         raise DriverError("Unhandled error: %d" % error, error)
コード例 #9
0
 def close_till(self, previous_day=False):
     self._check()
     if self.till_closed:
         raise DriverError(
             "Reduce Z was already sent today, try again tomorrow")
     self.till_closed = True
     self._save_state()
     self.output.feed("REDUÇÃO Z\n")
     self.output.feed_line()
コード例 #10
0
    def payment_receipt_open(self, identifier, coo, method_id, value):
        method = self._get_payment_description(method_id)
        if not method:
            raise DriverError('Looks like this payment method '
                              'is not configured in the printer')

        value = int(value * 100)
        self._send_command(CMD_PAYMENT_RECEIPT_OPEN,
                           '%-16s%014d%06d' % (method, value, coo))
コード例 #11
0
ファイル: fiscal.py プロジェクト: vintec-ca/addons-cluster
 def get_coupon_footers(self):
     log.info('get_coupon_footers()')
     footers = []
     if hasattr(self._driver, 'get_coupon_footers'):
         footers = self._driver.get_coupon_footers()
     else:
         raise DriverError(
             _("This method is not supported from "
               "the current printer"))
     return footers
コード例 #12
0
 def handle_error(self, reply):
     # Page 4-2
     # format: |.-NNNNERROR_MESSAGE}|
     if reply[1] != '-':
         return reply[2:]
     errmsg = reply[6:]
     try:
         exception, reason = self.errors_dict[errmsg]
         raise exception(reason)
     except KeyError:
         raise DriverError(errmsg)
コード例 #13
0
ファイル: FBII.py プロジェクト: tiagocapelli/stoqdrivers
 def cancel_last_coupon(self):
     # Informações sobre último documento.
     reply = self._send_command('0908')
     last_coupon = reply.fields[0]
     if last_coupon == FISCAL_COUPON:
         self._cancel_fiscal_coupon()
     elif last_coupon == NON_FISCAL_COUPON:
         self._cancel_non_fiscal_coupon()
     else:
         raise DriverError(_("Attempt to cancel after emission of another "
                             "DOC"))
コード例 #14
0
ファイル: EP375.py プロジェクト: leandrodax/stoqdrivers
    def parse_error(self):
        status = ord(self.statuses)

        # There is no error to parse.
        if status == EP375Status.PRINTER_IS_OK:
            return
        try:
            exception, reason = self.errors_dict[status]
            raise exception(reason)
        except KeyError:
            raise DriverError("Unhandled error: %d" % status)
コード例 #15
0
ファイル: FS345.py プロジェクト: vintec-ca/addons-cluster
    def get_payment_receipt_identifier(self, method_name):
        """Returns the receipt identifier corresponding to the payment method.

        @param method_name: this is the payment method name. A receipt with
                            the same name should be configured at the printer.
        """
        constants = self._get_bound_receipt_constants()
        for id, name in constants:
            if str(name) == str(method_name):
                return id

        raise DriverError(_("Receipt for method %s is not configured") % method_name)
コード例 #16
0
    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))
コード例 #17
0
    def _send_command(self, command, **params):
        # Page 38-39
        parameters = []
        for param, value in sorted(params.items()):
            if isinstance(value, Decimal):
                value = ('%.03f' % value).replace('.', ',')
            elif isinstance(value, bytes):
                value = '"%s"' % bytes2str(value)
            elif isinstance(value, str):
                value = '"%s"' % value
            elif isinstance(value, bool):
                if value is False:
                    value = 'f'
                elif value is True:
                    value = 't'
            elif isinstance(value, datetime.date):
                value = value.strftime('#%d/%m/%y#')

            parameters.append('%s=%s' % (param, value))

        reply = self.writeline("%d;%s;%s;" % (self._command_id,
                                              command,
                                              ' '.join(parameters)))
        if reply[0] != '{':
            # This happened once after the first command issued after
            # the power returned, it should probably be handled gracefully
            raise AssertionError(repr(reply))

        # Page 39
        sections = reply[1:].split(';')
        if len(sections) != 4:
            raise AssertionError

        retdict = self._parse_return_value(sections[2])
        errorcode = int(sections[1])
        if errorcode != 0:
            errordesc = retdict['Circunstancia']
            try:
                exception = self.errors_dict[errorcode]
            except KeyError:
                raise DriverError(errordesc, errorcode)
            raise exception(errordesc, errorcode)

        return retdict
コード例 #18
0
    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)
コード例 #19
0
ファイル: FS345.py プロジェクト: vintec-ca/addons-cluster
    def _read_reply(self):
        rep = ''
        timeouts = 0

        while True:
            if timeouts > RETRIES_BEFORE_TIMEOUT:
                raise DriverError(_("Timeout communicating with fiscal "
                                    "printer"))

            c = self.read(1)
            if len(c) != 1:
                timeouts += 1
                continue

            if c == self.EOL_DELIMIT:
                log.debug("<<< %r" % rep)
                return rep

            rep += c
コード例 #20
0
    def _read_reply(self, size):
        a = 0
        data = ''
        while True:
            if a > RETRIES_BEFORE_TIMEOUT:
                raise DriverError(_("Timeout communicating with fiscal "
                                    "printer"))

            a += 1
            reply = self.read(size)
            if reply is None:
                continue

            data += reply
            if len(data) < size:
                continue

            log.debug("<<< %r (%d bytes)" % (data, len(data)))
            return data
コード例 #21
0
    def readline(self):
        out = ''
        a = 0
        retries = 10
        while True:
            if a > retries:
                raise DriverError(
                    _("Timeout communicating with fiscal "
                      "printer"))

            c = self._port.read(1)
            if not c:
                a += 1
                print 'take %s' % a
                continue
            a = 0
            if c == self.EOL_DELIMIT:
                log.debug('<<< %r' % out)
                return out
            out += c
コード例 #22
0
    def _define_tax_name(self, code, name, entrada=False):
        try:
            retdict = self._send_command(
                'LeNaoFiscal', CodNaoFiscal=code)
        except DriverError as e:
            if e.code != 8057:  # Not configured
                raise
        else:
            for retname in ['NomeNaoFiscal', 'DescricaoNaoFiscal']:
                configured_name = retdict[retname]
                if configured_name != name:
                    raise DriverError(
                        "The name of the tax code %d is set to %r, "
                        "but it needs to be configured as %r" % (
                            code, configured_name, name))

        try:
            self._send_command(
                'DefineNaoFiscal', CodNaoFiscal=code, DescricaoNaoFiscal=name,
                NomeNaoFiscal=name, TipoNaoFiscal=entrada)
        except DriverError as e:
            if e.code != 8036:
                raise
コード例 #23
0
    def _send_command(self, command, extension='0000', *args):
        cmd = self._get_package(command, extension, args)
        self.write(cmd)

        # Printer should reply with an ACK imediataly
        ack = self.read(1)
        if not ack:
            raise DriverError(_("Timeout communicating with fiscal "
                                "printer"))
        assert ack == ACK, repr(ack)

        reply = self._read_reply()

        # Keep reading while printer sends intermediate replies.
        while reply.intermediate:
            log.debug("intermediate")
            reply = self._read_reply()

        # send our ACK
        self.write(ACK)

        reply.check_error()
        return reply
コード例 #24
0
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]
コード例 #25
0
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
コード例 #26
0
 def get_payment_constants(self):
     raise DriverError(
         _("This command is not supported "
           "for the current printer"))
コード例 #27
0
            result = 0.0
        return result

    # This how the printer needs to be configured.
    def _define_tax_name(self, code, name, entrada=False):
        try:
            retdict = self._send_command('LeNaoFiscal', CodNaoFiscal=code)
        except DriverError, e:
            if e.code != 8057:  # Not configured
                raise
        else:
            for retname in ['NomeNaoFiscal', 'DescricaoNaoFiscal']:
                configured_name = retdict[retname]
                if configured_name != name:
                    raise DriverError(
                        "The name of the tax code %d is set to %r, "
                        "but it needs to be configured as %r" %
                        (code, configured_name, name))

        try:
            self._send_command('DefineNaoFiscal',
                               CodNaoFiscal=code,
                               DescricaoNaoFiscal=name,
                               NomeNaoFiscal=name,
                               TipoNaoFiscal=entrada)
        except DriverError, e:
            if e.code != 8036:
                raise

    def _delete_tax_name(self, code):
        try:
            self._send_command('ExcluiNaoFiscal', CodNaoFiscal=code)