Example #1
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)
Example #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)
Example #3
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 + '>'
Example #4
0
 def _compute_l10n_ch_isr_number(self):
     """ The QRR or 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.
     """
     for record in self:
         has_qriban = record.invoice_partner_bank_id and record.invoice_partner_bank_id._is_qr_iban(
         ) or False
         isr_subscription = (record.invoice_partner_bank_id.l10n_ch_postal
                             or '').replace(
                                 "-", "")  # In case the user put the -
         if (has_qriban or isr_subscription) and record.name:
             invoice_issuer_ref = (isr_subscription or '').ljust(
                 l10n_ch_ISR_NUMBER_ISSUER_LENGTH, '0')
             invoice_ref = re.sub('[^\d]', '', record.name)
             #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)
         else:
             record.l10n_ch_isr_number = False
Example #5
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:
            record.l10n_ch_isr_optical_line = ''
            if record.l10n_ch_isr_number and record.l10n_ch_isr_subscription 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_residual, 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_subscription + '>'
Example #6
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])
Example #7
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
Example #8
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
Example #9
0
 def _is_isr_supplier_invoice(self):
     """Check for payments that a supplier invoice has a bank account
     that can issue ISR and that the reference is an ISR reference number"""
     # We consider a structured ref can only be in `reference` whereas in v13
     # it can be in 2 different fields
     ref = self.invoice_payment_ref or self.ref
     if (ref and self.invoice_partner_bank_id.is_isr_issuer()
             and re.match(r"^(\d{2,27}|\d{2}( \d{5}){5})$", ref)):
         ref = ref.replace(" ", "")
         return ref == mod10r(ref[:-1])
     return False
Example #10
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
Example #11
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. Shorten form with - is also accepted.
    """
    if re.match('^[0-9]{2}-[0-9]{1,6}-[0-9]$', 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
Example #12
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
Example #13
0
 def _has_isr_ref(self, payment_comm):
     """Check if the communication is a valid ISR reference (for Switzerland)
     e.g.
     12371
     000000000000000000000012371
     210000000003139471430009017
     21 00000 00003 13947 14300 09017
     This is used to determine SEPA local instrument
     """
     if not payment_comm:
         return False
     if re.match(r'^(\d{2,27}|\d{2}( \d{5}){5})$', payment_comm):
         ref = payment_comm.replace(' ', '')
         return ref == mod10r(ref[:-1])
     return False
Example #14
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.invoice_payment_ref 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
    def _compute_ref(self):
        """Retrieve ISR reference from move line in order to print it

        Returns False when no ISR reference should be generated.  No
        reference is generated when a transaction reference already
        exists for the line (likely been generated by a payment service).
        """
        for rec in self:
            move_line = rec.move_line_id
            if not rec._can_generate(move_line):
                continue
            # We should not use technical id but will keep it for
            # historical reason
            move_number = str(move_line.id)
            ad_number = rec._get_adherent_number()
            if move_line.invoice_id.number:
                compound = move_line.invoice_id.number + str(move_line.id)
                move_number = rec._compile_get_ref.sub('', compound)
            reference = mod10r(ad_number +
                               move_number.rjust(26 - len(ad_number), '0'))
            rec.reference = rec._space(reference)
Example #16
0
    def _compute_scan_line_list(self):
        """Generate a list containing all element of scan line

        the element are grouped by char or symbol

        This will allows the free placment of each element
        and enable a fine tuning of spacing

        :return: a list of sting representing the scan bar

        :rtype: list
        """
        self.ensure_one()
        line = []
        if not self._can_generate(self.move_line_id):
            return []
        justified_amount = '01%s' % ('%.2f' % self.amount_total).replace(
            '.', '').rjust(10, '0')
        line += [char for char in mod10r(justified_amount)]
        line.append('>')
        line += [char for char in self.reference.replace(" ", "")]
        line.append('+')
        line.append(' ')
        partner_bank = self.move_line_id.invoice_id.partner_bank_id
        bank = partner_bank.get_account_number()
        account_components = bank.split('-')
        if len(account_components) != 3:
            raise exceptions.UserError(
                _('Please enter a correct postal number like: '
                  '01-23456-1'))
        bank_identifier = "%s%s%s" % (
            account_components[0],
            account_components[1].rjust(6, '0'),
            account_components[2]
        )
        line += [car for car in bank_identifier]
        line.append('>')
        return line
Example #17
0
    def _create_record(self, line):
        """Create a v11 record dict
        :param line: raw v11 line
        :type line: str

        :return: current line dict representation
        :rtype: dict

        """
        amount = self._get_line_amount(line)
        cost = self._get_line_cost(line)
        record = {
            'reference': line[12:39],
            'amount': amount,
            'date': time.strftime('%Y-%m-%d',
                                  time.strptime(line[65:71], '%y%m%d')),
            'cost': cost,
        }

        if record['reference'] != mod10r(record['reference'][:-1]):
            raise exceptions.UserError(
                _('Recursive mod10 is invalid for reference: %s') %
                record['reference'])
        return record
    def _compute_l10n_ch_isr_optical_line(self):
        """ Compute the optical line to print on the bottom of the ISR.

        This line is read by an OCR.
        It's format is:

            amount>reference+ creditor>

        Where:

           - amount: currency and invoice amount
           - reference: ISR structured reference number
                - in case of ISR-B contains the Customer ID number
                - it can also contains a partner reference (of the debitor)
           - creditor: Subscription number of the creditor

        An optical line can have the 2 following formats:

        * ISR (Postfinance)

            0100003949753>120000000000234478943216899+ 010001628>
            |/\________/| \________________________/|  \_______/
            1     2     3          4                5      6

            (1) 01 | currency
            (2) 0000394975 | amount 3949.75
            (3) 4 | control digit for amount
            (5) 12000000000023447894321689 | reference
            (6) 9: control digit for identification number and reference
            (7) 010001628: subscription number (01-162-8)

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

            0100000494004>150001123456789012345678901+ 010234567>
            |/\________/| \____/\__________________/|  \_______/
            1     2     3    4           5          6      7

            (1) 01 | currency
            (2) 0000049400 | amount 494.00
            (3) 4 | control digit for amount
            (4) 150001 | id number of the customer (size may vary, usually 6 chars)
            (5) 12345678901234567890 | reference
            (6) 1: control digit for identification number and reference
            (7) 010234567: subscription number (01-23456-7)
        """
        for record in self:
            record.l10n_ch_isr_optical_line = ''
            if record.l10n_ch_isr_number and record.l10n_ch_isr_subscription 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_residual, 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_subscription + '>'
Example #19
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.invoice_partner_bank_id and record.invoice_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
    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.invoice_partner_bank_id and record.invoice_partner_bank_id._is_qr_iban(
            ) or False
            isr_subscription = (record.invoice_partner_bank_id.l10n_ch_postal
                                or '').replace(
                                    "-", "")  # In case the user put the -
            if (has_qriban or isr_subscription) and record.name:
                invoice_issuer_ref = (isr_subscription or '').ljust(
                    l10n_ch_ISR_NUMBER_ISSUER_LENGTH, '0')
                invoice_ref = re.sub('[^\d]', '', record.name)
                #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)
            else:
                record.l10n_ch_isr_number = False
Example #21
0
        this number with zeros. The last character of the ISR number is the result
        of a recursive modulo 10 on its first 26 characters.
        """
        for record in self:
<<<<<<< HEAD
            if record.name and record.invoice_partner_bank_id and record.invoice_partner_bank_id.l10n_ch_postal:
                invoice_issuer_ref = record.invoice_partner_bank_id.l10n_ch_postal.ljust(l10n_ch_ISR_NUMBER_ISSUER_LENGTH, '0')
=======
            if record.name and record.partner_bank_id and record.partner_bank_id.l10n_ch_postal:
                invoice_issuer_ref = record.partner_bank_id.l10n_ch_postal.ljust(l10n_ch_ISR_NUMBER_ISSUER_LENGTH, '0')
>>>>>>> f0a66d05e70e432d35dc68c9fb1e1cc6e51b40b8
                invoice_ref = re.sub('[^\d]', '', record.name)
                #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)
            else:
                record.l10n_ch_isr_number = False

    @api.depends('l10n_ch_isr_number')
    def _compute_l10n_ch_isr_number_spaced(self):
        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