コード例 #1
0
def test_name_too_long():
    sdd = SepaDD({
        "name": "TestCreditor",
        "BIC": "BANKNL2A",
        "IBAN": "NL50BANK1234567890",
        "batch": True,
        "creditor_id": "000000",
        "currency": "EUR"
    })
    payment1 = {
        "name":
        "Test von Testenstein Test von Testenstein Test von Testenstein",
        "IBAN": "NL50BANK1234567890",
        "BIC": "BANKNL2A",
        "amount": 1012,
        "type": "FRST",
        "collection_date": datetime.date.today(),
        "mandate_id": "1234",
        "mandate_date": datetime.date.today(),
        "description": "Test transaction1"
    }
    sdd.add_payment(payment1)
    with pytest.raises(ValidationError):
        sdd.export()
    sdd.export(validate=False)
コード例 #2
0
    def generate_batch(self):
        sepa = SepaDD(settings.SEPA_CONFIG,schema="pain.008.001.02", clean=True)
        payments = []

        for batch_result in SepaBatchResult.objects.filter(batch=self):
            payment = batch_result.payment

            if payment.amount <= 0:
                batch_result.success = False
                batch_result.fail_reason = ZERO_AMOUNT

            if not payment.account or not payment.account.iban_code:
                batch_result.success = False
                batch_result.fail_reason = IBAN_MISSING

            else:
                batch_result.iban_code = payment.account.iban_code[4:8]
                bank = BankBICCode.objects.filter(bank_code=batch_result.iban_code).first()
                if not bank:
                    batch_result.success = False
                    batch_result.fail_reason = BIC_MISSING

            if batch_result.success:
                batch_result.bic_code = bank.bic_code
                batch_result.bank_name = bank.bank_name
                pay = {
                    "name": payment.account.display_name,
                    "IBAN": payment.account.iban_code,
                    "amount": int(payment.amount * 100),
                    "BIC":  batch_result.bic_code,
                    "type": "RCUR",
                    "collection_date": datetime.date.today(),
                    "mandate_id": payment.account.cif,
                    "execution_date": datetime.date.today(),
                    "mandate_date": datetime.date.today(),
                    "description": payment.concept,
                    "endtoend_id": str(payment.reference).replace('-',''),
                }
                sepa.add_payment(pay)
                payments.append(batch_result.payment)

            batch_result.save()

        if (len(payments) > 0):
            sepa_xml = sepa.export(validate=True)
            xml_temp = NamedTemporaryFile()
            xml_temp.write(sepa_xml)
            xml_temp.flush()

            self.sepa_file.save(f"sepa_batch_{self.pk}.xml", File(xml_temp))
            self.save()

            # We check the included payments as paid
            for payment in payments:
                payment.completed = True
                payment.timestamp = datetime.datetime.now()
                payment.type = DEBIT
                payment.save()
コード例 #3
0
    def generate_batch(self):
        sepa = SepaDD(settings.SEPA_CONFIG,
                      schema="pain.008.001.02",
                      clean=True)
        payments = []

        for batch_result in SepaBatchResult.objects.filter(batch=self):
            payment = batch_result.payment

            if batch_result.success:
                pay = {
                    "name": payment.account.display_name,
                    "IBAN": payment.account.iban_code,
                    "amount": int(payment.amount * 100),
                    "BIC": batch_result.bic_code,
                    "type": "RCUR",
                    "collection_date": datetime.date.today(),
                    "mandate_id": payment.account.cif,
                    "execution_date": datetime.date.today(),
                    "mandate_date": datetime.date.today(),
                    "description": payment.concept,
                    "endtoend_id": str(payment.reference).replace('-', ''),
                }
                sepa.add_payment(pay)
                payments.append(batch_result.payment)

                payment.invoice_prefix = self.invoice_prefix
                payment.invoice_number = batch_result.invoice_number
                payment.invoice_date = self.attempt
                payment.save()

        if (len(payments) > 0):
            sepa_xml = sepa.export(validate=True)
            xml_temp = NamedTemporaryFile()
            xml_temp.write(sepa_xml)
            xml_temp.flush()

            self.sepa_file.save(f"sepa_batch_{self.pk}.xml", File(xml_temp))
            self.save()

            # We update the payments date
            for payment in payments:
                #payment.added = datetime.datetime.now()
                payment.type = DEBIT
                payment.save()
コード例 #4
0
def create_sepa_xml(input_file: IO[str], output_path: str,
                    config: Dict[str, Any]) -> None:
    """Creates a XML file from CSV data.

    Parameters
    ----------
    input_file: IO[str]
        Path to the CSV data.
    output_path: str
        Path to the output data.
        Default is in the project-root/output.
    config: Dict[str, Any]
        Config.json for SEPA XML generation.
    """
    today_s = str(date.today())
    hit_credit = False
    hit_debit = False

    sepa_credit = SepaTransfer(config, clean=True)
    sepa_debit = SepaDD(config, schema='pain.008.002.02', clean=True)

    echo('Getting Data...')
    for i, payment in enumerate(single_csv_row(input_file)):
        p, p_type = _pack_data(payment)

        if p_type == 'credit':
            hit_credit = True
            sepa_credit.add_payment(p)
        if p_type == 'debit':
            hit_debit = True
            sepa_debit.add_payment(p)

    if hit_credit:
        _generate_output(today_s + '_ueberweisung', sepa_credit.export(),
                         output_path)
    if hit_debit:
        _generate_output(today_s + '_gutschrift', sepa_debit.export(),
                         output_path)
コード例 #5
0
ファイル: views.py プロジェクト: henryk/byro-directdebit
    def form_valid(self, form):
        config = DirectDebitConfiguration.get_solo()
        global_config = Configuration.get_solo()
        members = self._get_members()
        now_ = now()

        dd_config = {
            "name": form.cleaned_data['own_name'],
            "IBAN": str(form.cleaned_data['own_iban']),
            "BIC": str(form.cleaned_data['own_bic']),
            "batch": True,
            "creditor_id": config.creditor_id,
            "currency": global_config.currency,
            "instrument": "COR1" if form.cleaned_data['cor1'] else "CORE",
        }
        sepa = SepaDD(dd_config,
                      schema=form.cleaned_data['sepa_format'],
                      clean=True)

        exp_member_numbers = [
            ((int(x.split("-")[0]), int(x.split("-")[1])) if "-" in x else
             (int(x), int(x)))
            for x in form.cleaned_data['exp_member_numbers'].split(",")
        ]

        with atomic():
            debit = DirectDebit(
                datetime=now_,
                multiple=True,
                cor1=form.cleaned_data['cor1'],
                pain_descriptor='urn:iso:std:iso:20022:tech:xsd:' +
                form.cleaned_data['sepa_format'],
                additional_data={
                    'login_pk': self.selected_account_login_pk,
                    'account_iban': form.cleaned_data['own_iban'],
                    'account_bic': form.cleaned_data['own_bic'],
                })
            debit_payments = []

            for member in members:
                ## Experimental gates
                if form.cleaned_data['exp_bank_types'] == "DE":
                    if not member.profile_sepa.iban.upper().startswith("DE"):
                        continue
                elif form.cleaned_data['exp_bank_types'] == "NDE":
                    if member.profile_sepa.iban.upper().startswith("DE"):
                        continue

                if exp_member_numbers:
                    if not any(a <= int(member.number) <= b
                               for (a, b) in exp_member_numbers):
                        continue

                debit_payment = DirectDebitPayment(
                    id=uuid4(),
                    type='FRST',  ## FIXME Based on existing data
                    mandate_reference=member.profile_sepa.mandate_reference,
                    collection_date=form.cleaned_data['debit_date'],
                    amount=-member.balance,
                    direct_debit=debit,
                    member=member,
                )

                payment = {
                    "name": member.name,
                    "IBAN": member.profile_sepa.iban,
                    "BIC": member.profile_sepa.bic_autocomplete,
                    "collection_date": debit_payment.collection_date,
                    "amount": int(debit_payment.amount * 100),  # in cents
                    "type": debit_payment.type,
                    "mandate_id": debit_payment.mandate_reference,
                    "mandate_date": member.profile_sepa.issue_date
                    or now_.date(),
                    "description": form.cleaned_data['debit_text'],
                    "endtoend_id": debit_payment.id.hex,
                }
                sepa.add_payment(payment)
                debit_payments.append(debit_payment)

                context = {
                    'creditor_id':
                    config.creditor_id,
                    'sepa_mandate_reference':
                    debit_payment.mandate_reference,
                    'sepa_iban':
                    member.profile_sepa.iban,
                    'sepa_bic':
                    member.profile_sepa.bic_autocomplete,
                    'contact':
                    global_config.mail_from,
                    'association_name':
                    global_config.name,
                    'additional_information':
                    '',
                    'debit_date':
                    form.cleaned_data['debit_date'],
                    'amount':
                    "%.2f %s" % (debit_payment.amount, global_config.currency),
                }

                mail = config.debit_notification_template.to_mail(
                    member.email,
                    context=context,
                    save=False,
                )
                mail.text = form.cleaned_data['text'].format(**context)
                mail.subject = form.cleaned_data['subject'].format(**context)
                mail.save()
                mail.members.add(member)

            debit.sepa_xml = sepa.export(validate=True).decode('utf-8')
            debit.save()
            for p in debit_payments:
                p.save()

        return HttpResponseRedirect(
            reverse('plugins:byro_directdebit:finance.directdebit.transmit_dd',
                    kwargs={'pk': debit.pk}))
コード例 #6
0
class SepaExport:
    def __init__(self):
        self.invoices = []
        self.config = {
            "name": app.config.get('SEPADD_CREDITOR_NAME'),
            "IBAN": app.config.get('SEPADD_CREDITOR_IBAN'),
            "BIC": app.config.get('SEPADD_CREDITOR_BIC'),
            "batch": app.config.get('SEPADD_BATCH'),
            "creditor_id": app.config.get('SEPADD_CREDITOR_ID'),
            "currency": app.config.get('SEPADD_CURRENCY'),
            "instrument": app.config.get('SEPADD_INSTRUMENT')
        }
        self.sepa = SepaDD(self.config, schema=app.config.get('SEPADD_SCHEMA'))

    def __len__(self):
        return len(self.invoices)

    def add_invoice(self, invoice):
        if (len(invoice.items) == 0):
            # skip invoices without items
            return

        if not invoice.sent:
            raise Exception("Invoice %s has not yet been sent." %
                            invoice.number)
        if invoice.cancelled:
            raise Exception("Invoice %s is cancelled." % invoice.number)
        if not invoice.contact.has_sepa_mandate:
            raise Exception("Invoice %s: No sepa mandate for %s" %
                            (invoice.number, invoice.contact))
        if invoice.payment_type != 'SEPA-DD':
            raise Exception("Invoice %s: Payment Type is not SEPA-DD" %
                            invoice.number)

        if self.sepa.check_payment(self._gen_payment(invoice)):
            self.invoices.append(invoice)

    def _gen_payment(self, invoice):
        if invoice.contact.sepa_mandate_first:
            payment_type = "FRST"
            collection_date = date.today() + timedelta(days=+5)
        else:
            payment_type = "RCUR"
            collection_date = date.today() + timedelta(days=+3)

        payment = {
            "name":
            invoice.contact.name,
            "IBAN":
            invoice.contact.sepa_iban,
            "mandate_id":
            invoice.contact.sepa_mandate_id,
            "mandate_date":
            invoice.contact.sepa_mandate_date,
            "amount":
            int(invoice.amount * 100),
            "type":
            payment_type,  # FRST,RCUR,OOFF,FNAL
            "collection_date":
            collection_date,
            "endtoend_id":
            invoice.exported_id,
            "description":
            "Funkfeuer %s%d %s" %
            (app.config.get('BILLING_REFERENCE_UID_PREFIX'),
             invoice.contact.id, invoice.number)
        }
        return payment

    def add_invoices(self, invoices):
        for invoice in invoices:
            self.add_invoice(invoice)

    @property
    def msg_id(self):
        return self.sepa.msg_id

    def export(self):
        if len(self.invoices) < 1:
            raise Exception("no invoices to export")

        for invoice in self.invoices:
            if invoice.exported_id is None:
                invoice.exported_id = make_id(
                    invoice.number, app.config.get('SEPADD_CREDITOR_NAME'))
                invoice.exported = True

            self.sepa.add_payment(self._gen_payment(invoice))
            if invoice.contact.sepa_mandate_first:
                invoice.contact.sepa_mandate_first = False

        export = self.sepa.export()

        db.session.add(
            model.Job(type='sepa_export',
                      note=self.msg_id,
                      user=current_user,
                      started=datetime.utcnow(),
                      finished=datetime.utcnow()))
        db.session.commit()

        return export
コード例 #7
0
    def generate_xml_file(self):
        from sepaxml import SepaDD

        sepa_settings = frappe.get_doc("Sepa Direct Debit Settings",
                                       self.company)
        company_iban, company_bic = frappe.db.get_value(
            "Bank Account", sepa_settings.bank_account,
            ["iban", "swift_number"])

        config = {
            "name": sepa_settings.company_name,
            "IBAN": company_iban,
            "BIC": company_bic,
            "batch": self.batch_booking,
            "creditor_id": sepa_settings.
            creditor_identifier,  # supplied by your bank or financial authority
            "currency": self.currency,  # ISO 4217
            "instrument": sepa_settings.instrument  # - default is CORE (B2C)
        }
        sepa = SepaDD(config,
                      schema=sepa_settings.schema or "pain.008.001.02",
                      clean=True)

        for payment_entry in self.payment_entries:
            payment_types = {
                "One-off": "OOFF",
                "First": "FRST",
                "Recurrent": "RCUR",
                "Final": "FNAL"
            }
            payment_type = self.direct_debit_type

            customer = payment_entry.against_account
            if not frappe.db.exists(
                    "Sepa Mandate",
                    dict(customer=customer,
                         registered_on_gocardless=0,
                         status="Active")):
                frappe.throw(
                    _("Please create or activate a SEPA Mandate for customer {0}"
                      .format(customer)))
            else:
                mandate = frappe.get_doc("Sepa Mandate",
                                         dict(customer=customer))
                customer_iban, customer_bic = frappe.db.get_value(
                    "Bank Account", mandate.bank_account,
                    ["iban", "swift_number"])

            pe = frappe.get_doc("Payment Entry", payment_entry.payment_entry)
            sales_invoices = ""

            for ref in pe.references:
                sales_invoices += "/" + ref.reference_name

            payment_amount = cint(payment_entry.amount * 100)

            payment = {
                "name": customer,
                "IBAN": customer_iban,
                "BIC": customer_bic,
                "amount": payment_amount,  # in cents
                "type": payment_types.get(payment_type),  # FRST,RCUR,OOFF,FNAL
                "collection_date": getdate(payment_entry.reference_date),
                "mandate_id": mandate.mandate,
                "mandate_date": mandate.creation_date,
                "description": sepa_settings.reference_prefix + sales_invoices,
                "endtoend_id": pe.reference_no  # autogenerated if obmitted
            }
            sepa.add_payment(payment)
        try:
            sepa_export = sepa.export(
                validate=False)  # TODO: correct false positive upon validation
        except Exception as e:
            frappe.throw(str(e))
        self.save_sepa_export(sepa_export)

        return sepa_export