Commit 7b4fe86e authored by alexAubin's avatar alexAubin
Browse files

Attempt to remove old MembershipFree class, now managed in billing

parent cdc8b970
Pipeline #61 failed with stage
in 2 minutes and 41 seconds
......@@ -13,7 +13,6 @@ from coin.filtering_queryset import LimitedAdminInlineMixin
from coin.billing.models import Invoice, InvoiceDetail, Payment, \
PaymentAllocation, MembershipFee, Donation
from coin.billing.utils import get_bill_from_id_or_number
from coin.billing.membershipfee_filter import MembershipFeeFilter
from coin.members.models import Member
from coin.members.admin import MemberAdmin
from django.core.urlresolvers import reverse
......@@ -320,14 +319,6 @@ class DonationAdmin(admin.ModelAdmin):
list_display = ('member', 'date', '_amount')
form = autocomplete_light.modelform_factory(MembershipFee, fields='__all__')
class MembershipFeeInline(admin.TabularInline):
model = MembershipFee
extra = 0
fields = ('start_date', 'end_date', '_amount')
MemberAdmin.list_filter += ('status', MembershipFeeFilter)
MemberAdmin.inlines += [MembershipFeeInline]
admin.site.register(Invoice, InvoiceAdmin)
admin.site.register(Payment, PaymentAdmin)
admin.site.register(MembershipFee, MembershipFeeAdmin)
......
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.contrib.admin import SimpleListFilter
import datetime
class MembershipFeeFilter(SimpleListFilter):
# Human-readable title which will be displayed in the
# right admin sidebar just above the filter options.
title = 'Cotisations'
# Parameter for the filter that will be used in the URL query.
parameter_name = 'fee_billing'
def lookups(self, request, model_admin):
"""
Returns a list of tuples. The first element in each
tuple is the coded value for the option that will
appear in the URL query. The second element is the
human-readable name for the option that will appear
in the right sidebar.
"""
return (
('paidup', 'À jour de cotisation'),
('late', 'En retard'),
)
def queryset(self, request, queryset):
"""
Returns the filtered queryset based on the value
provided in the query string and retrievable via
`self.value()`.
"""
if self.value() == 'paidup':
return queryset.filter(id__in=[i.id for i in queryset.all() if i.is_paid_up()])
if self.value() == 'late':
return queryset.filter(id__in=[i.id for i in queryset.all() if not i.is_paid_up()])
......@@ -19,6 +19,7 @@ from coin.members.models import (
Member, CryptoKey, LdapUser, Offer, OfferSubscription, RowLevelPermission)
from coin.members.forms import AdminMemberChangeForm, MemberCreationForm
from coin.utils import delete_selected
from coin.billing.models import MembershipFee
class CryptoKeyInline(admin.StackedInline):
model = CryptoKey
......@@ -89,16 +90,16 @@ class DataRetentionFilter(SimpleListFilter):
def queryset(self, request, queryset):
if self.value() == 'pending_deletion':
return queryset.could_be_deleted()
return queryset.filter(id__in=[i.id for i in queryset.all() if i.could_be_deleted()])
class MembershipFeeFilter(SimpleListFilter):
# Human-readable title which will be displayed in the
# right admin sidebar just above the filter options.
title = 'Cotisations'
title = 'cotisations'
# Parameter for the filter that will be used in the URL query.
parameter_name = 'fee'
parameter_name = 'fee_billing'
def lookups(self, request, model_admin):
return (
......@@ -108,10 +109,14 @@ class MembershipFeeFilter(SimpleListFilter):
def queryset(self, request, queryset):
if self.value() == 'paidup':
return queryset.paidup_fee()
return queryset.filter(id__in=[i.id for i in queryset.all() if i.is_paid_up()])
if self.value() == 'late':
return queryset.no_fee_or_late()
return queryset.filter(id__in=[i.id for i in queryset.all() if not i.is_paid_up()])
class MembershipFeeInline(admin.TabularInline):
model = MembershipFee
extra = 0
fields = ('start_date', 'end_date', '_amount')
class MemberAdmin(UserAdmin):
SERVICE_NO_FEE_MSG = (
......@@ -224,7 +229,7 @@ class MemberAdmin(UserAdmin):
save_on_top = True
inlines = [CryptoKeyInline, OfferSubscriptionInline]
inlines = [CryptoKeyInline, OfferSubscriptionInline, MembershipFeeInline]
def add_member_warnings(self, request, member):
has_active_subscriptions = member.get_active_subscriptions().exists()
......
......@@ -158,6 +158,9 @@ class AbstractMemberChangeForm(forms.ModelForm):
return helper
def save_m2m(self):
pass
class AdminMemberChangeForm(AbstractMemberChangeForm):
password = ReadOnlyPasswordHashField()
......
......@@ -8,8 +8,7 @@ from django.db.models import Max
from django.conf import settings
from coin.utils import respect_language
from coin.members.models import Member, MembershipFee
from coin.members.models import Member
class Command(BaseCommand):
args = '[date=2011-07-04]'
......
......@@ -24,30 +24,6 @@ from coin.offers.models import Offer, OfferSubscription
from coin.mixins import CoinLdapSyncMixin
from coin import utils
class MemberQuerySet(models.QuerySet):
paidup_q = Q(
# we have at least one fee
membership_fees__isnull=False,
# and it is still running
membership_fees__end_date__gte=datetime.date.today)
def paidup_fee(self):
return self.filter(self.paidup_q)
def no_fee_or_late(self):
return self.exclude(self.paidup_q)
def could_be_deleted(self):
return self.exclude(
# we have at least one subscription
Q(offersubscription__isnull=False),
# still running or resigned less than one year ago
Q(offersubscription__resign_date__isnull=True)
|
Q(offersubscription__resign_date__gte=utils.one_year_ago())
).exclude(self.paidup_q)
class MemberManager(UserManager):
use_in_migrations = False
......@@ -143,8 +119,6 @@ class Member(CoinLdapSyncMixin, AbstractUser):
balance = models.DecimalField(max_digits=6, decimal_places=2, default=0,
verbose_name='solde')
objects = MemberManager.from_queryset(MemberQuerySet)()
# Following fields are managed by the parent class AbstractUser :
# username, first_name, last_name, email
# However we hack the model to force theses fields to be required. (see
......@@ -185,6 +159,7 @@ class Member(CoinLdapSyncMixin, AbstractUser):
from coin.billing.models import MembershipFee
aggregate = MembershipFee.objects.filter(member=self).aggregate(end=Max('end_date'))
return aggregate['end']
end_date_of_membership.short_description = "Date de fin d'adhésion"
def is_paid_up(self, date=None):
......@@ -198,6 +173,10 @@ class Member(CoinLdapSyncMixin, AbstractUser):
return False
return (end_date >= date)
def could_be_deleted(self):
return self.is_paid_up() and not self.get_active_subscriptions(date=utils.one_year_ago())
def set_password(self, new_password, *args, **kwargs):
"""
Définit le mot de passe a sauvegarder en base et dans le LDAP
......@@ -510,58 +489,6 @@ class CryptoKey(CoinLdapSyncMixin, models.Model):
def default_membership_fee():
return settings.DEFAULT_MEMBERSHIP_FEE
class MembershipFee(models.Model):
PAYMENT_METHOD_CHOICES = (
('cash', 'Espèces'),
('check', 'Chèque'),
('transfer', 'Virement'),
('other', 'Autre')
)
member = models.ForeignKey('Member', related_name='membership_fees',
verbose_name='membre')
amount = models.DecimalField(null=False, max_digits=5, decimal_places=2,
default=default_membership_fee,
verbose_name='montant', help_text='en €')
start_date = models.DateField(
null=False,
blank=False,
verbose_name='date de début de cotisation')
end_date = models.DateField(
null=False,
blank=True,
verbose_name='date de fin de cotisation',
help_text='par défaut, la cotisation dure un an')
payment_method = models.CharField(max_length=100, null=True, blank=True,
choices=PAYMENT_METHOD_CHOICES,
verbose_name='moyen de paiement')
reference = models.CharField(max_length=125, null=True, blank=True,
verbose_name='référence du paiement',
help_text='numéro de chèque, '
'référence de virement, commentaire...')
payment_date = models.DateField(null=True, blank=True,
verbose_name='date du paiement')
def clean(self):
if self.start_date is not None and self.end_date is None:
self.end_date = self.start_date + datetime.timedelta(364)
def save(self, *args, **kwargs):
ret = super(MembershipFee, self).save(*args, **kwargs)
today = datetime.date.today()
if self.start_date <= today and today <= self.end_date:
self.member.status = self.member.MEMBER_STATUS_MEMBER
self.member.save()
return ret
def __unicode__(self):
return '%s - %s - %i€' % (self.member, self.start_date, self.amount)
class Meta:
verbose_name = 'cotisation'
class LdapUser(ldapdb.models.Model):
# "ou=users,ou=unix,o=ILLYSE,l=Villeurbanne,st=RHA,c=FR"
base_dn = settings.LDAP_USER_BASE_DN
......
......@@ -17,7 +17,8 @@ from django.test import TestCase, Client
from django.core import mail, management
from django.core.exceptions import ValidationError
from coin.members.models import Member, MembershipFee, LdapUser
from coin.members.models import Member, LdapUser
from coin.billing.models import MembershipFee
from coin.offers.models import OfferSubscription, Offer
from coin.validation import chatroom_url_validator
......@@ -306,11 +307,10 @@ class MemberTests(TestCase):
first_name='a', last_name='b', username='c',
status=Member.MEMBER_STATUS_PENDING)
# Créé une cotisation passée
MembershipFee.objects.create(
member=member, amount=20,
start_date=date(2015, 12, 12),
end_date=date(2016, 12, 12))
membershipfee = MembershipFee(member=member, amount=20,
start_date=date(2015, 12, 12),
end_date=date(2016, 12, 12))
membershipfee.save()
member = Member.objects.get(pk=member.pk)
self.assertEqual(member.status, member.MEMBER_STATUS_MEMBER)
......@@ -387,13 +387,6 @@ class MemberTestCallForMembershipCommand(TestCase):
self.member.delete()
MembershipFee.objects.all().delete()
def create_membership_fee(self, end_date):
# Créé une cotisation passée se terminant dans un mois
membershipfee = MembershipFee(member=self.member, amount=20,
start_date=end_date + relativedelta(years=-1),
end_date=end_date)
membershipfee.save()
def create_membership_fee(self, end_date):
# Créé une cotisation se terminant à la date indiquée
membershipfee = MembershipFee(member=self.member, amount=20,
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment