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"

33c73414f2f8b292bc488d845d4686cf9104d614
<mask token>


class BackendTrustlyPaymentForm(BackendInvoicePaymentMethodForm):
    <mask token>
    <mask token>
    <mask token>
    <mask token>
    <mask token>
    <mask token>
    <mask token>
    <mask token>
    <mask token>
    <mask token>
    <mask token>
    <mask token>
    <mask token>

    @classmethod
    def validate_data_for(self, instance):
        pm = instance.get_implementation()
        trustly = Trustly(pm)
        trustly.get_balance()
        return 'Trustly API setup works'


class TrustlyPayment(BasePayment):
    backend_form_class = BackendTrustlyPaymentForm

    @property
    def description(self):
        return (
            '\nPay directly using online banking. Currently supported with most banks in {0}.\n'
            .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):
        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
        refund.payment_reference = trans.orderid
        return True

    def used_method_details(self, invoice):
        return 'Trustly'

<mask token>


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)
        trustly.get_balance()
        return 'Trustly API setup works'


class TrustlyPayment(BasePayment):
    backend_form_class = BackendTrustlyPaymentForm

    @property
    def description(self):
        return (
            '\nPay directly using online banking. Currently supported with most banks in {0}.\n'
            .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):
        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
        refund.payment_reference = trans.orderid
        return True

    def used_method_details(self, invoice):
        return 'Trustly'

<mask token>


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)
        trustly.get_balance()
        return 'Trustly API setup works'


class TrustlyPayment(BasePayment):
    backend_form_class = BackendTrustlyPaymentForm

    @property
    def description(self):
        return (
            '\nPay directly using online banking. Currently supported with most banks in {0}.\n'
            .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):
        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
        refund.payment_reference = trans.orderid
        return True

    def used_method_details(self, invoice):
        return 'Trustly'

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)
        trustly.get_balance()
        return 'Trustly API setup works'


class TrustlyPayment(BasePayment):
    backend_form_class = BackendTrustlyPaymentForm

    @property
    def description(self):
        return (
            '\nPay directly using online banking. Currently supported with most banks in {0}.\n'
            .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):
        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
        refund.payment_reference = trans.orderid
        return True

    def used_method_details(self, invoice):
        return 'Trustly'

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"
