Пример #1
0
def format_ref_number(bill):
    if not bill.ref_number:
        return ''
    num = bill.ref_number
    if bill.ref_type == "QRR":
        return esr.format(num)
    elif bill.ref_type == "SCOR":
        return iso11649.format(num)
    else:
        return num
Пример #2
0
    def __init__(self,
                 account=None,
                 creditor=None,
                 final_creditor=None,
                 amount=None,
                 currency='CHF',
                 due_date=None,
                 debtor=None,
                 ref_number=None,
                 extra_infos='',
                 alt_procs=(),
                 language='en',
                 top_line=True,
                 payment_line=True):
        """
        Arguments
        ---------
        account: str
            IBAN of the creditor (must start with 'CH' or 'LI')
        creditor: Address
            Address (combined or structured) of the creditor
        final_creditor: Address
            (for future use)
        amount: str
        currency: str
            two values allowed: 'CHF' and 'EUR'
        due_date: str (YYYY-MM-DD)
        debtor: Address
            Address (combined or structured) of the debtor
        extra_infos: str
            Extra information aimed for the bill recipient
        alt_procs: list of str (max 2)
            two additional fields for alternative payment schemes
        language: str
            language of the output (ISO, 2 letters): 'en', 'de', 'fr' or 'it'
        top_line: bool
            print a horizontal line at the top of the bill
        payment_line: bool
            print a vertical line between the receipt and the bill itself
        """
        # Account (IBAN) validation
        if not account:
            raise ValueError("The account parameter is mandatory")
        if not iban.is_valid(account):
            raise ValueError("Sorry, the IBAN is not valid")
        self.account = iban.validate(account)
        if self.account[:2] not in IBAN_ALLOWED_COUNTRIES:
            raise ValueError("IBAN must start with: %s" %
                             ", ".join(IBAN_ALLOWED_COUNTRIES))
        iban_iid = int(self.account[4:9])
        if QR_IID["start"] <= iban_iid <= QR_IID["end"]:
            self.account_is_qriban = True
        else:
            self.account_is_qriban = False

        if amount is not None:
            if isinstance(amount, Decimal):
                amount = str(amount)
            elif not isinstance(amount, str):
                raise ValueError(
                    "Amount can only be specified as str or Decimal.")
            # remove commonly used thousands separators
            amount = amount.replace("'", "").strip()
            # people often don't add .00 for amounts without cents/rappen
            if "." not in amount:
                amount = amount + ".00"
            # support lazy people who write 12.1 instead of 12.10
            if amount[-2] == '.':
                amount = amount + '0'
            # strip leading zeros
            amount = amount.lstrip("0")
            # some people tend to strip the leading zero on amounts below 1 CHF/EUR
            # and with removing leading zeros, we would have removed the zero before
            # the decimal delimiter anyway
            if amount[0] == ".":
                amount = "0" + amount
            m = re.match(AMOUNT_REGEX, amount)
            if not m:
                raise ValueError(
                    "If provided, the amount must match the pattern '###.##'"
                    " and cannot be larger than 999'999'999.99")
        self.amount = amount
        if currency not in self.allowed_currencies:
            raise ValueError("Currency can only contain: %s" %
                             ", ".join(self.allowed_currencies))
        self.currency = currency
        if due_date:
            m = re.match(DATE_REGEX, due_date)
            if not m:
                raise ValueError(
                    "The date must match the pattern 'YYYY-MM-DD'")
            due_date = date(*[int(g) for g in m.groups()])
        self.due_date = due_date
        if not creditor:
            raise ValueError("Creditor information is mandatory")
        try:
            self.creditor = Address.create(**creditor)
        except ValueError as err:
            raise ValueError("The creditor address is invalid: %s" % err)
        if final_creditor is not None:
            # The standard says ultimate creditor is reserved for future use.
            # The online validator does not properly validate QR-codes where
            # this is set, saying it must not (yet) be used.
            raise ValueError(
                "final creditor is reserved for future use, must not be used")
        else:
            self.final_creditor = final_creditor
        if debtor is not None:
            try:
                self.debtor = Address.create(**debtor)
            except ValueError as err:
                raise ValueError("The debtor address is invalid: %s" % err)
        else:
            self.debtor = debtor

        if not ref_number:
            self.ref_type = 'NON'
            self.ref_number = None
        elif ref_number.strip()[:2].upper() == "RF":
            if iso11649.is_valid(ref_number):
                self.ref_type = 'SCOR'
                self.ref_number = iso11649.validate(ref_number)
            else:
                raise ValueError("The reference number is invalid")
        elif esr.is_valid(ref_number):
            self.ref_type = 'QRR'
            self.ref_number = esr.format(ref_number).replace(" ", "")
        else:
            raise ValueError("The reference number is invalid")

        # A QRR reference number must only be used with a QR-IBAN and
        # with a QR-IBAN, a QRR reference number must be used
        if self.account_is_qriban:
            if self.ref_type != 'QRR':
                raise ValueError("A QR-IBAN requires a QRR reference number")
        else:
            if self.ref_type == 'QRR':
                raise ValueError(
                    "A QRR reference number is only allowed for a QR-IBAN")

        if extra_infos and len(extra_infos) > 140:
            raise ValueError(
                "Additional information cannot contain more than 140 characters"
            )
        self.extra_infos = extra_infos

        if len(alt_procs) > 2:
            raise ValueError(
                "Only two lines allowed in alternative procedure parameters")
        if any(len(el) > 100 for el in alt_procs):
            raise ValueError(
                "An alternative procedure line cannot be longer than 100 characters"
            )
        self.alt_procs = list(alt_procs)

        # Meta-information
        if language not in ['en', 'de', 'fr', 'it']:
            raise ValueError("Language should be 'en', 'de', 'fr', or 'it'")
        self.language = language
        self.top_line = top_line
        self.payment_line = payment_line