1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
|
from django import forms
from django.core.exceptions import ValidationError
from postgresqleu.invoices.models import Invoice
from postgresqleu.invoices.backendforms import BackendInvoicePaymentMethodForm
from postgresqleu.accounting.util import get_account_choices
from postgresqleu.util.forms import CharToArrayField
from postgresqleu.util.widgets import MonospaceTextarea
from postgresqleu.util.crypto import validate_pem_public_key, validate_pem_private_key
from postgresqleu.trustlypayment.models import TrustlyTransaction, TrustlyLog
from postgresqleu.trustlypayment.util import Trustly
from postgresqleu.trustlypayment.api import TrustlyException
from . import BasePayment
import collections
def validate_country_list(value):
if len(value) == 0:
raise ValidationError("At least one country must be specified")
dupes = [c for c, num in collections.Counter(value).items() if num > 1]
if dupes:
if len(dupes) == 1:
raise ValidationError("Country {} specified more than once!".format(dupes[0]))
else:
raise ValidationError("Countries {} specified more than once!".format(", ".join(dupes)))
class BackendTrustlyPaymentForm(BackendInvoicePaymentMethodForm):
test = forms.BooleanField(required=False)
user = forms.CharField(required=True)
password = forms.CharField(required=True, widget=forms.widgets.PasswordInput(render_value=True))
hold_notifications = forms.BooleanField(required=False)
notification_receiver = forms.EmailField(required=True)
countries = CharToArrayField(required=True, validators=[validate_country_list, ],
label="Available countries",
help_text="Comma separate list of countries available in")
public_key = forms.CharField(required=True, widget=MonospaceTextarea, validators=[validate_pem_public_key, ])
private_key = forms.CharField(required=True, widget=MonospaceTextarea, validators=[validate_pem_private_key, ])
accounting_income = forms.ChoiceField(required=True, choices=get_account_choices,
label="Income account")
accounting_fee = forms.ChoiceField(required=True, choices=get_account_choices,
label="Fees account")
accounting_transfer = forms.ChoiceField(required=True, choices=get_account_choices,
label="Transfer account",
help_text="Account that transfers from Trustly are made to")
config_fields = ['user', 'test', 'password', 'hold_notifications',
'notification_receiver', 'countries',
'public_key', 'private_key',
'accounting_income', 'accounting_fee', 'accounting_transfer', ]
config_fieldsets = [
{
'id': 'trustly',
'legend': 'Trustly',
'fields': ['user', 'test', 'password', 'hold_notifications', ],
},
{
'id': 'integration',
'legend': 'Integration',
'fields': ['notification_receiver', 'countries', ],
},
{
'id': 'keys',
'legend': 'Keys',
'fields': ['public_key', 'private_key', ],
},
{
'id': 'accounting',
'legend': 'Accounting',
'fields': ['accounting_income', 'accounting_fee', 'accounting_transfer', ],
}
]
@classmethod
def validate_data_for(self, instance):
pm = instance.get_implementation()
trustly = Trustly(pm)
# Test the Trustly setup by getting the balance
trustly.get_balance()
return "Trustly API setup works"
class TrustlyPayment(BasePayment):
backend_form_class = BackendTrustlyPaymentForm
@property
def description(self):
return """
Pay directly using online banking. Currently supported with most banks in {0}.
""".format(', '.join(self.config('countries')))
def get_apibase(self):
return self.config('test') and 'https://test.trustly.com/api/1' or 'https://api.trustly.com/1'
def build_payment_url(self, invoicestr, invoiceamount, invoiceid, returnurl=None):
i = Invoice.objects.get(pk=invoiceid)
return '/invoices/trustlypay/{0}/{1}/{2}/'.format(self.id, invoiceid, i.recipient_secret)
def payment_fees(self, invoice):
# For now, we always get our Trustly transactions for free...
return 0
def autorefund(self, refund):
try:
trans = TrustlyTransaction.objects.get(invoiceid=refund.invoice.id)
except TrustlyTransaction.DoesNotExist:
raise Exception("Transaction matching invoice not found")
t = Trustly(self)
try:
t.refund(trans.orderid, refund.fullamount)
except TrustlyException as e:
TrustlyLog(message='Refund API failed: {0}'.format(e), error=True, paymentmethod=self.method).save()
return False
# Will raise exception if something goes wrong
refund.payment_reference = trans.orderid
return True
def used_method_details(self, invoice):
# Bank transfers don't need any extra information
return "Trustly"
|