Exemplo n.º 1
0
    def _compute_l10n_ch_isr_optical_line(self):
        """ The optical reading line of the ISR looks like this :
                left>isr_ref+ bank_ref>

           Where:
           - left is composed of two ciphers indicating the currency (01 for CHF,
           03 for EUR), followed by ten characters containing the total of the
           invoice (with the dot between units and cents removed, everything being
           right-aligned and empty places filled with zeros). After the total,
           left contains a last cipher, which is the result of a recursive modulo
           10 function ran over the rest of it.

            - isr_ref is the ISR reference number

            - bank_ref is the full postal bank code (aka clearing number) of the
            bank supporting the ISR (including the zeros).
        """
        for record in self:
            if record.l10n_ch_isr_number and record.l10n_ch_isr_postal and record.currency_id.name:
                #Left part
                currency_code = None
                if record.currency_id.name == 'CHF':
                    currency_code = '01'
                elif record.currency_id.name == 'EUR':
                    currency_code = '03'
                units, cents = float_split_str(record.amount_total, 2)
                amount_to_display = units + cents
                amount_ref = amount_to_display.zfill(10)
                left = currency_code + amount_ref
                left = mod10r(left)
                #Final assembly (the space after the '+' is no typo, it stands in the specs.)
                record.l10n_ch_isr_optical_line = left + '>' + record.l10n_ch_isr_number + '+ ' + record.l10n_ch_isr_postal + '>'
Exemplo n.º 2
0
    def _compute_l10n_ch_isr_number(self):
        """ The ISR reference number is 27 characters long. The first 12 of them
        contain the postal account number of this ISR's issuer, removing the zeros
        at the beginning and filling the empty places with zeros on the right if it is
        too short. The next 14 characters contain an internal reference identifying
        the invoice. For this, we use the invoice sequence number, removing each
        of its non-digit characters, and pad the unused spaces on the left of
        this number with zeros. The last character of the ISR number is the result
        of a recursive modulo 10 on its first 26 characters.
        """
        def _space_isr_number(isr_number):
            to_treat = isr_number
            res = ''
            while to_treat:
                res = to_treat[-5:] + res
                to_treat = to_treat[:-5]
                if to_treat:
                    res = ' ' + res
            return res

        for record in self:
            if record.number and record.partner_bank_id and record.partner_bank_id.l10n_ch_postal:
                invoice_issuer_ref = re.sub('^0*', '', record.partner_bank_id.l10n_ch_postal)
                invoice_issuer_ref = invoice_issuer_ref.ljust(l10n_ch_ISR_NUMBER_ISSUER_LENGTH, '0')
                invoice_ref = re.sub('[^\d]', '', record.number)
                #We only keep the last digits of the sequence number if it is too long
                invoice_ref = invoice_ref[-l10n_ch_ISR_NUMBER_ISSUER_LENGTH:]
                internal_ref = invoice_ref.zfill(l10n_ch_ISR_NUMBER_LENGTH - l10n_ch_ISR_NUMBER_ISSUER_LENGTH - 1) # -1 for mod10r check character

                record.l10n_ch_isr_number = mod10r(invoice_issuer_ref + internal_ref)
                record.l10n_ch_isr_number_spaced = _space_isr_number(record.l10n_ch_isr_number)
Exemplo n.º 3
0
 def _is_qr_reference(self, reference):
     """ Checks whether the given reference is a QR-reference, i.e. it is
     made of 27 digits, the 27th being a mod10r check on the 26 previous ones.
     """
     return reference \
            and len(reference) == 27 \
            and re.match('\d+$', reference) \
            and reference == mod10r(reference[:-1])
Exemplo n.º 4
0
def _is_l10n_ch_postal(account_ref):
    """ Returns True iff the string account_ref is a valid postal account number,
    i.e. it only contains ciphers and is last cipher is the result of a recursive
    modulo 10 operation ran over the rest of it.
    """
    if re.match('\d+$', account_ref or ''):
        account_ref_without_check = account_ref[:-1]
        return mod10r(account_ref_without_check) == account_ref
    return False
Exemplo n.º 5
0
def _is_l10n_ch_postal(account_ref):
    """ Returns True if the string account_ref is a valid postal account number,
    i.e. it only contains ciphers and is last cipher is the result of a recursive
    modulo 10 operation ran over the rest of it. Shorten form with - is also accepted.
    """
    if _re_postal.match(account_ref or ''):
        ref_subparts = account_ref.split('-')
        account_ref = ref_subparts[0] + ref_subparts[1].rjust(6, '0') + ref_subparts[2]

    if re.match('\d+$', account_ref or ''):
        account_ref_without_check = account_ref[:-1]
        return mod10r(account_ref_without_check) == account_ref
    return False
Exemplo n.º 6
0
 def _get_l10n_ch_isr_optical_amount(self):
     """Prepare amount string for ISR optical line"""
     self.ensure_one()
     currency_code = None
     if self.currency_id.name == 'CHF':
         currency_code = '01'
     elif self.currency_id.name == 'EUR':
         currency_code = '03'
     units, cents = float_split_str(self.amount_residual, 2)
     amount_to_display = units + cents
     amount_ref = amount_to_display.zfill(10)
     optical_amount = currency_code + amount_ref
     optical_amount = mod10r(optical_amount)
     return optical_amount
Exemplo n.º 7
0
 def _has_isr_ref(self):
     """Check if this invoice has a valid ISR reference (for Switzerland)
     e.g.
     12371
     000000000000000000000012371
     210000000003139471430009017
     21 00000 00003 13947 14300 09017
     """
     self.ensure_one()
     ref = self.payment_reference or self.ref
     if not ref:
         return False
     ref = ref.replace(' ', '')
     if re.match(r'^(\d{2,27})$', ref):
         return ref == mod10r(ref[:-1])
     return False
Exemplo n.º 8
0
    def _compute_l10n_ch_isr_number(self):
        """Generates the ISR or QRR reference

        An ISR references are 27 characters long.
        QRR is a recycling of ISR for QR-bills. Thus works the same.

        The invoice sequence number is used, removing each of its non-digit characters,
        and pad the unused spaces on the left of this number with zeros.
        The last digit is a checksum (mod10r).

        There are 2 types of references:

        * ISR (Postfinance)

            The reference is free but for the last
            digit which is a checksum.
            If shorter than 27 digits, it is filled with zeros on the left.

            e.g.

                120000000000234478943216899
                \________________________/|
                         1                2
                (1) 12000000000023447894321689 | reference
                (2) 9: control digit for identification number and reference

        * ISR-B (Indirect through a bank, requires a customer ID)

            In case of ISR-B The firsts digits (usually 6), contain the customer ID
            at the Bank of this ISR's issuer.
            The rest (usually 20 digits) is reserved for the reference plus the
            control digit.
            If the [customer ID] + [the reference] + [the control digit] is shorter
            than 27 digits, it is filled with zeros between the customer ID till
            the start of the reference.

            e.g.

                150001123456789012345678901
                \____/\__________________/|
                   1           2          3
                (1) 150001 | id number of the customer (size may vary)
                (2) 12345678901234567890 | reference
                (3) 1: control digit for identification number and reference
        """
        for record in self:
            has_qriban = record.partner_bank_id and record.partner_bank_id._is_qr_iban(
            ) or False
            isr_subscription = record.l10n_ch_isr_subscription
            if (has_qriban or isr_subscription) and record.name:
                id_number = record._get_isrb_id_number()
                if id_number:
                    id_number = id_number.zfill(l10n_ch_ISR_ID_NUM_LENGTH)
                invoice_ref = re.sub('[^\d]', '', record.name)
                # keep only the last digits if it exceed boundaries
                full_len = len(id_number) + len(invoice_ref)
                ref_payload_len = l10n_ch_ISR_NUMBER_LENGTH - 1
                extra = full_len - ref_payload_len
                if extra > 0:
                    invoice_ref = invoice_ref[extra:]
                internal_ref = invoice_ref.zfill(ref_payload_len -
                                                 len(id_number))
                record.l10n_ch_isr_number = mod10r(id_number + internal_ref)
            else:
                record.l10n_ch_isr_number = False