Skip to content

Commit

Permalink
Merge pull request #3051 from onepercentclub/master
Browse files Browse the repository at this point in the history
Master in develop
  • Loading branch information
eodolphi committed Dec 20, 2017
2 parents ff1083f + 6601c63 commit 0132099
Show file tree
Hide file tree
Showing 19 changed files with 2,249 additions and 34 deletions.
2 changes: 1 addition & 1 deletion bluebottle/cms/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ class GreetingInline(NestedStackedInline):
extra = 0


class ResultPageAdmin(PlaceholderFieldAdmin, TranslatableAdmin):
class ResultPageAdmin(PlaceholderFieldAdmin, TranslatableAdmin, NonSortableParentAdmin):
formfield_overrides = {
models.TextField: {'widget': Textarea(attrs={'rows': 4, 'cols': 40})},
}
Expand Down
20 changes: 20 additions & 0 deletions bluebottle/cms/migrations/0063_auto_20171204_1049.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.8 on 2017-12-04 09:49
from __future__ import unicode_literals

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('cms', '0062_auto_20171128_1355'),
]

operations = [
migrations.AlterField(
model_name='logoscontent',
name='action_text',
field=models.CharField(blank=True, max_length=40, null=True),
),
]
10 changes: 7 additions & 3 deletions bluebottle/cms/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ class Stat(SortableMixin, models.Model):
('projects_online', _('Projects Online')),
('votes_cast', _('Votes casts')),
('time_spent', _('Time spent')),
('members', _("Number of members"))
]

type = models.CharField(
Expand Down Expand Up @@ -419,9 +420,12 @@ class Meta:

class LogosContent(TitledContent):
type = 'logos'
action_text = models.CharField(max_length=40)
action_link = models.CharField(max_length=100, default="/start-project",
blank=True, null=True)
action_text = models.CharField(max_length=40, null=True, blank=True)
action_link = models.CharField(
max_length=100,
default="/start-project",
blank=True, null=True
)

class Meta:
verbose_name = _('Logos')
Expand Down
8 changes: 5 additions & 3 deletions bluebottle/common/management/commands/makemessages.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import json
import tempfile
import os

from django.core.management.commands.makemessages import Command as BaseCommand

Expand All @@ -16,7 +16,7 @@ class Command(BaseCommand):
]

def handle(self, *args, **kwargs):
with tempfile.NamedTemporaryFile(dir='bluebottle', suffix='.py') as temp:
with open('bluebottle/fixtures.py', 'w') as temp:
for app, file in self.fixtures:
with open('bluebottle/{}/fixtures/{}'.format(app, file)) as fixture_file:
strings = [
Expand All @@ -33,4 +33,6 @@ def handle(self, *args, **kwargs):

temp.flush()

return super(Command, self).handle(*args, **kwargs)
super(Command, self).handle(*args, **kwargs)

os.unlink('bluebottle/fixtures.py')
9 changes: 6 additions & 3 deletions bluebottle/payments/adapters.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,12 @@


def has_payment_prodiver(provider):
for account in properties.MERCHANT_ACCOUNTS:
if account['merchant'] == provider:
return True
try:
for account in properties.MERCHANT_ACCOUNTS:
if account['merchant'] == provider:
return True
except AttributeError:
pass
return False


Expand Down
124 changes: 122 additions & 2 deletions bluebottle/payouts/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,16 @@
from django import forms
from django.contrib import admin
from django.contrib.admin.sites import NotRegistered
from django.core.exceptions import PermissionDenied
from django.http import HttpResponse
from django.utils import timezone
from django.utils.translation import ugettext as _

from bluebottle.bb_payouts.models import ProjectPayoutLog
from bluebottle.bb_payouts.models import (ProjectPayoutLog,
OrganizationPayoutLog)
from bluebottle.clients import properties
from bluebottle.payouts.models import ProjectPayout
from bluebottle.payouts.models import ProjectPayout, OrganizationPayout
from bluebottle.utils.admin import export_as_csv_action
from bluebottle.utils.utils import StatusDefinition

from .admin_utils import link_to
Expand All @@ -29,6 +34,10 @@ class PayoutLogInline(PayoutLogBase):
model = ProjectPayoutLog


class OrganizationPayoutLogInline(PayoutLogBase):
model = OrganizationPayoutLog


class ProjectPayoutForm(forms.ModelForm):
payout_rule = forms.ChoiceField(
choices=ProjectPayout.PayoutRules.choices)
Expand Down Expand Up @@ -195,6 +204,69 @@ def rule(self, obj):
admin.site.register(ProjectPayout, BaseProjectPayoutAdmin)


class BaseOrganizationPayoutAdmin(BasePayoutAdmin):
inlines = [OrganizationPayoutLogInline]

can_delete = False

search_fields = ['invoice_reference']

date_hierarchy = 'start_date'

list_filter = ['status', ]

list_display = [
'invoice_reference', 'start_date', 'end_date', 'status',
'organization_fee_incl', 'psp_fee_incl',
'other_costs_incl', 'payable_amount_incl'
]

readonly_fields = [
'invoice_reference', 'organization_fee_excl', 'organization_fee_vat',
'organization_fee_incl', 'psp_fee_excl', 'psp_fee_vat', 'psp_fee_incl',
'payable_amount_excl', 'payable_amount_vat', 'payable_amount_incl',
'other_costs_vat', 'status'
]

fieldsets = (
(None, {
'fields': (
'status', 'invoice_reference'
)
}),
(_('Dates'), {
'fields': (
'start_date', 'end_date', 'planned', 'completed'
)
}),
(_('Organization fee'), {
'fields': (
'organization_fee_excl', 'organization_fee_vat',
'organization_fee_incl'
)
}),
(_('PSP fee'), {
'fields': (
'psp_fee_excl', 'psp_fee_vat', 'psp_fee_incl'
)
}),
(_('Other costs'), {
'fields': (
'other_costs_excl', 'other_costs_vat', 'other_costs_incl'
)
}),
(_('Amount payable'), {
'fields': (
'payable_amount_excl', 'payable_amount_vat',
'payable_amount_incl'
)
})
)


admin.site.register(OrganizationPayout, BaseOrganizationPayoutAdmin)


class PayoutListFilter(admin.SimpleListFilter):
title = _('Payout rule')
parameter_name = 'payout_rule'
Expand Down Expand Up @@ -243,9 +315,37 @@ def queryset(self, request, queryset):
return queryset.filter(payout_rule=self.value())


class OrganizationPayoutAdmin(BaseOrganizationPayoutAdmin):
actions = ('export_sepa',)

def export_sepa(self, request, queryset):
"""
Dowload a sepa file with selected ProjectPayments
"""
objs = queryset.all()
if not request.user.is_staff:
raise PermissionDenied
response = HttpResponse(mimetype='text/xml')
date = timezone.datetime.strftime(timezone.now(), '%Y%m%d%H%I%S')
response['Content-Disposition'] = 'attachment; ' \
'filename=payments_sepa%s.xml' % date
response.write(OrganizationPayout.create_sepa_xml(objs))
return response

export_sepa.short_description = "Export SEPA file."


try:
admin.site.unregister(OrganizationPayout)
except NotRegistered:
pass
admin.site.register(OrganizationPayout, OrganizationPayoutAdmin)


class ProjectPayoutAdmin(BaseProjectPayoutAdmin):
list_display = ['payout', 'status', 'admin_project', 'amount_pending',
'amount_raised', 'amount_pledged', 'amount_payable',
# 'percent',
'admin_has_iban', 'created_date',
'submitted_date', 'completed_date']

Expand All @@ -260,6 +360,10 @@ class ProjectPayoutAdmin(BaseProjectPayoutAdmin):
('submitted', 'submitted')
]

actions = ('change_status_to_new', 'change_status_to_progress',
'change_status_to_settled', 'export_sepa', 'recalculate_amounts',
export_as_csv_action(fields=export_fields))

def get_list_filter(self, request):
# If site has a legacy payout rule then display the legacy filter
if ProjectPayout.objects.filter(
Expand All @@ -269,6 +373,22 @@ def get_list_filter(self, request):
else:
return ['status', PayoutListFilter]

def export_sepa(self, request, queryset):
"""
Dowload a sepa file with selected ProjectPayments
"""
objs = queryset.all()
if not request.user.is_staff:
raise PermissionDenied
response = HttpResponse()
date = timezone.datetime.strftime(timezone.now(), '%Y%m%d%H%I%S')
response['Content-Disposition'] = 'attachment; ' \
'filename=payments_sepa%s.xml' % date
response.write(ProjectPayout.create_sepa_xml(objs))
return response

export_sepa.short_description = "Export SEPA file."


try:
admin.site.unregister(ProjectPayout)
Expand Down
80 changes: 80 additions & 0 deletions bluebottle/payouts/models.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
from decimal import Decimal

from django.db import models
from django.conf import settings
from django.utils import timezone
from django.utils.translation import ugettext as _

from djchoices.choices import DjangoChoices, ChoiceItem

from bluebottle.bb_payouts.models import (BaseProjectPayout,
BaseOrganizationPayout)
from bluebottle.clients import properties
from bluebottle.sepa.sepa import SepaDocument, SepaAccount


class ProjectPayout(BaseProjectPayout):
Expand Down Expand Up @@ -109,6 +112,44 @@ def get_payout_rule(self):
# Not fully funded
return self.PayoutRules.not_fully_funded

@classmethod
def create_sepa_xml(cls, qs):
""" Create a SEPA XML file for Payouts in QuerySet. """

batch_id = timezone.datetime.strftime(timezone.now(), '%Y%m%d%H%I%S')

sepa = SepaDocument(sepa_type='CT')

sepa.set_initiating_party(
name=settings.BANK_ACCOUNT_DONATIONS['name']
)
debtor = SepaAccount(
name=settings.BANK_ACCOUNT_DONATIONS['name'],
iban=settings.BANK_ACCOUNT_DONATIONS['iban'],
bic=settings.BANK_ACCOUNT_DONATIONS['bic']
)

sepa.set_debtor(debtor)
sepa.set_info(message_identification=batch_id, payment_info_id=batch_id)
sepa.set_initiating_party(name=settings.BANK_ACCOUNT_DONATIONS['name'])

for payout in qs.all():
payout.in_progress()
payout.save()
creditor = SepaAccount(
name=payout.receiver_account_name,
iban=payout.receiver_account_iban,
bic=payout.receiver_account_details
)

sepa.add_credit_transfer(
creditor=creditor,
amount=payout.amount_payable,
creditor_payment_id=payout.invoice_reference
)

return sepa.as_xml()


class OrganizationPayout(BaseOrganizationPayout):
def _get_organization_fee(self):
Expand All @@ -133,3 +174,42 @@ def _get_organization_fee(self):
) or Decimal('0.00')

return fee

@classmethod
def create_sepa_xml(cls, qs):
""" Create a SEPA XML file for OrganizationPayouts in QuerySet. """

batch_id = timezone.datetime.strftime(timezone.now(), '%Y%m%d%H%I%S')

sepa = SepaDocument(sepa_type='CT')

sepa.set_initiating_party(
name=settings.BANK_ACCOUNT_DONATIONS['name']
)
debtor = SepaAccount(
name=settings.BANK_ACCOUNT_DONATIONS['name'],
iban=settings.BANK_ACCOUNT_DONATIONS['iban'],
bic=settings.BANK_ACCOUNT_DONATIONS['bic']
)

sepa.set_debtor(debtor)
sepa.set_info(
message_identification=batch_id, payment_info_id=batch_id)
sepa.set_initiating_party(name=settings.BANK_ACCOUNT_DONATIONS['name'])

for payout in qs.all():
payout.in_progress()
payout.save()
creditor = SepaAccount(
name=settings.BANK_ACCOUNT_ORGANISATION['name'],
iban=settings.BANK_ACCOUNT_ORGANISATION['iban'],
bic=settings.BANK_ACCOUNT_ORGANISATION['bic']
)

sepa.add_credit_transfer(
creditor=creditor,
amount=payout.payable_amount_incl,
creditor_payment_id=payout.invoice_reference
)

return sepa.as_xml()
Loading

0 comments on commit 0132099

Please sign in to comment.