# Scrape the CM pages to fetch list of transactions
#
#
-# Copyright (C) 2014, PostgreSQL Europe
+# Copyright (C) 2014-2019, PostgreSQL Europe
#
from django.core.management.base import BaseCommand, CommandError
from django.db import transaction
from postgresqleu.mailqueue.util import send_simple_mail
+from postgresqleu.invoices.util import register_bank_transaction
+from postgresqleu.invoices.models import InvoicePaymentMethod
from pgeusite.cmutuel.models import CMutuelTransaction
@classmethod
def should_run(self):
- if not settings.CM_USER_ACCOUNT:
- return False
- return True
-
+ return InvoicePaymentMethod.objects.filter(active=True, classname='pgeusite.cmutuel.util.CMutuelPayment').exists()
def add_arguments(self, parser):
parser.add_argument('-q', '--quiet', action='store_true')
def handle(self, *args, **options):
- if not settings.CM_USER_ACCOUNT:
- raise CommandError("Must specify CM user account in local_settings.py!")
+ method = InvoicePaymentMethod.objects.get(active=True, classname='pgeusite.cmutuel.util.CMutuelPayment')
+ pm = method.get_implementation()
verbose = not options['quiet']
sess.expect_redirect('https://www.creditmutuel.fr/en/authentification.html',
'https://www.creditmutuel.fr/en/banque/pageaccueil.html', {
- '_cm_user': settings.CM_USER_ACCOUNT,
- '_cm_pwd': settings.CM_USER_PASSWORD,
+ '_cm_user': pm.config('user'),
+ '_cm_pwd': pm.config('password'),
'flag': 'password',
})
balance = Decimal(row[4])
if not CMutuelTransaction.objects.filter(opdate=opdate, valdate=valdate, amount=amount, description=description).exists():
- CMutuelTransaction(opdate=opdate,
- valdate=valdate,
- amount=amount,
- description=description,
- balance=balance).save()
+ trans = CMutuelTransaction(opdate=opdate,
+ valdate=valdate,
+ amount=amount,
+ description=description,
+ balance=balance)
+ trans.save()
+
+ # Also send the transaction into the main system. Unfortunately we don't
+ # know the sender.
+ # register_bank_transaction returns True if the transaction has been fully
+ # processed and thus don't need anything else, so we just consider it
+ # sent already.
+ if register_bank_transaction(method, trans.id, amount, description, ''):
+ trans.sent = True
+ trans.save()
except Exception as e:
sys.stderr.write("Exception '{0}' when parsing row {1}".format(e, row))
# Now send things off if there is anything to send
with transaction.atomic():
- if CMutuelTransaction.objects.filter(sent=False).exclude(
- Q(description__startswith='VIR STG ADYEN ') |
- Q(description__startswith='VIR ADYEN BV ') |
- Q(description__startswith='VIR ADYEN NV ')
- ).exists():
+ if CMutuelTransaction.objects.filter(sent=False).exists():
sio = io.StringIO()
sio.write("One or more new transactions have been recorded in the Credit Mutuel account:\n\n")
sio.write("%-10s %15s %s\n" % ('Date', 'Amount', 'Description'))
sio.write("-" * 50)
sio.write("\n")
- for cmt in CMutuelTransaction.objects.filter(sent=False).order_by('opdate'):
- # Maybe this shouldn't be hardcoded, but for now it is.
- # Exclude Adyen transactions, since they are already reported separately.
- # Still flag them as sent though, so they don't queue up forever.
- if not (cmt.description.startswith('VIR STG ADYEN ') or cmt.description.startswith('VIR ADYEN BV ') or cmt.description.startswith('VIR ADYEN NV ')):
- sio.write("%10s %15s %s\n" % (cmt.opdate, cmt.amount, cmt.description))
+ for cmt in CMutuelTransaction.objects.filter(sent=False).order_by('opdate'):
+ sio.write("%10s %15s %s\n" % (cmt.opdate, cmt.amount, cmt.description))
cmt.sent = True
cmt.save()
+
+ sio.write("\n\nYou will want to go processes these at:\n{0}/admin/invoices/banktransactions/".format(settings.SITEBASE))
+
send_simple_mail(settings.INVOICE_SENDER_EMAIL,
settings.INVOICE_SENDER_EMAIL,
'New Credit Mutuel transactions',
--- /dev/null
+from django import forms
+from django.shortcuts import render
+from django.template import Template, Context
+from django.db.models import Sum
+
+from urllib.parse import urlencode
+
+from postgresqleu.util.payment.banktransfer import BaseManagedBankPayment
+from postgresqleu.util.payment.banktransfer import BaseManagedBankPaymentForm
+from postgresqleu.invoices.models import Invoice, BankTransferFees
+
+
+class BackendCMutuelForm(BaseManagedBankPaymentForm):
+ user = forms.CharField(required=True, label="User account", help_text="Username used to log in")
+ password = forms.CharField(required=True, widget=forms.widgets.PasswordInput(render_value=True))
+
+ managed_fields = ['user', 'password', ]
+ managed_fieldsets = [
+ {
+ 'id': 'cm',
+ 'legend': 'Credit Mutuel',
+ 'fields': ['user', 'password', ],
+ }
+ ]
+
+
+class CMutuelPayment(BaseManagedBankPayment):
+ backend_form_class = BackendCMutuelForm
+ description = """
+Pay using a direct IBAN bank transfer in EUR. We
+<strong>strongly advice</strong> not using this method if
+making a payment from outside the Euro-zone, as amounts
+must be exact and all fees covered by sender.
+"""
+
+ def render_page(self, request, invoice):
+ return render(request, 'cmutuel/payment.html', {
+ 'invoice': invoice,
+ })
--- /dev/null
+{%extends "navbase.html"%}
+{%block title%}Pay with bank transfer{%endblock%}
+{%block content%}
+<h1>Pay with bank transfer</h1>
+<p>
+To pay your invoice using bank transfer, please make a payment
+according to the following:
+</p>
+
+<table border="1" cellspacing="0" cellpadding="3">
+<tr>
+ <th>Account holder</th>
+ <td>Association PostgreSQL Europe</td>
+</tr>
+<tr>
+ <th>Bank name</th>
+ <td>CCM PARIS 1-2 LOUVRE MONTORGUEIL</td>
+</tr>
+<tr>
+ <th>BIC</th>
+ <td>CMCIFR2A</td>
+</tr>
+<tr>
+ <th>IBAN</th>
+ <td>FR76 1027 8060 3100 0205 2290 114</td>
+</tr>
+<tr>
+ <th>Payment reference</th>
+ <td>{{invoice.payment_reference}}</td>
+</tr>
+<tr>
+ <th>Amount</th>
+ <td>€{{invoice.total_amount}}</td>
+</tr>
+</table>
+
+<p>
+<b>Note</b> that it is <b><i>very</i></b> important that you provide the
+correct text on the transfer, or we may not be able to match your payment
+to the correct invoice. In particular, <b>do not</b> use the invoice number,
+use the given payment reference!
+</p>
+
+<p>
+<b>Note</b> that bank transfers take a few days to process, so if your
+payment is nedeed repidly in order to confirm something, this is not a good
+choice of payment method.
+</p>
+
+{%if returnurl%}<a href="{{returnurl}}" class="btn btn-outline-dark">Return to payment options</a>{%endif%}
+
+{%endblock%}