8
0
Fork 0
mirror of https://gitlab2.federez.net/re2o/re2o synced 2024-12-23 07:23:46 +00:00

Merge branch 'fix-overlapping-invoices' into 'dev'

Fix Overlapping invoices.

See merge request federez/re2o!476
This commit is contained in:
chirac 2019-12-21 12:39:56 +01:00
commit 9e87f796aa
3 changed files with 126 additions and 43 deletions

View file

@ -292,15 +292,40 @@ class Facture(BaseInvoice):
return bool(self.get_subscription())
def reorder_purchases(self):
date = self.date
date_adh = max(self.date, self.user.end_adhesion())
date_con = max(self.date, self.user.end_connexion())
for purchase in self.vente_set.all():
if hasattr(purchase, "cotisation"):
cotisation = purchase.cotisation
cotisation.date_start = date
date += relativedelta(
months=(purchase.duration or 0) * purchase.number,
days=(purchase.duration_days or 0) * purchase.number,
)
if cotisation.type_cotisation == 'Connexion':
cotisation.date_start = date_con
date_con += relativedelta(
months=(purchase.duration or 0) * purchase.number,
days=(purchase.duration_days or 0) * purchase.number,
)
cotisation.date_end = date_con
elif cotisation.type_cotisation == 'Adhesion':
cotisation.date_start = date_adh
date_adh += relativedelta(
months=(purchase.duration or 0) * purchase.number,
days=(purchase.duration_days or 0) * purchase.number,
)
cotisation.date_end = date_adh
else: # it is assumed that adhesion is required for a connexion
date = min(date_adh, date_con)
cotisation.date_start = date
date_adh += relativedelta(
months=(purchase.duration or 0) * purchase.number,
days=(purchase.duration_days or 0) * purchase.number,
)
date_con += relativedelta(
months=(purchase.duration or 0) * purchase.number,
days=(purchase.duration_days or 0) * purchase.number,
)
date = max(date_adh, date_con)
cotisation.date_end = date
cotisation.save()
purchase.facture = self
purchase.save()
def save(self, *args, **kwargs):
@ -488,9 +513,7 @@ class Vente(RevMixin, AclMixin, models.Model):
def create_cotis(self, date_start=False):
"""
Update and create a 'cotisation' related object if there is a
cotisation_type defined (which means the article sold represents
a cotisation)
Creates a cotisation without initializing the dates (start and end ar set to self.facture.facture.date) and without saving it. You should use Facture.reorder_purchases to set the right dates.
"""
try:
invoice = self.facture.facture
@ -500,33 +523,16 @@ class Vente(RevMixin, AclMixin, models.Model):
cotisation = Cotisation(vente=self)
cotisation.type_cotisation = self.type_cotisation
if date_start:
end_cotisation = (
Cotisation.objects.filter(
vente__in=Vente.objects.filter(
facture__in=Facture.objects.filter(
user=invoice.user
).exclude(valid=False)
)
)
.filter(
Q(type_cotisation="All")
| Q(type_cotisation=self.type_cotisation)
)
.filter(date_start__lt=date_start)
.aggregate(Max("date_end"))["date_end__max"]
cotisation.date_start = date_start
cotisation.date_end = cotisation.date_start + relativedelta(
months=(self.duration or 0) * self.number,
days=(self.duration_days or 0) * self.number,
)
elif self.type_cotisation == "Adhesion":
end_cotisation = invoice.user.end_adhesion()
self.save()
cotisation.save()
else:
end_cotisation = invoice.user.end_connexion()
date_start = date_start or timezone.now()
end_cotisation = end_cotisation or date_start
date_max = max(end_cotisation, date_start)
cotisation.date_start = date_max
cotisation.date_end = cotisation.date_start + relativedelta(
months=(self.duration or 0) * self.number,
days=(self.duration_days or 0) * self.number,
)
cotisation.date_start = invoice.date
cotisation.date_end = invoice.date
def save(self, *args, **kwargs):
"""

View file

@ -10,7 +10,7 @@ from .models import Vente, Facture, Cotisation, Paiement
class VenteModelTests(TestCase):
def setUp(self):
self.user = User.objects.create(pseudo="testUser", email="test@example.org")
self.user = User.objects.create(pseudo="testUserPlop", email="test@example.org")
self.paiement = Paiement.objects.create(moyen="test payment")
self.f = Facture.objects.create(
user=self.user, paiement=self.paiement, valid=True
@ -30,6 +30,7 @@ class VenteModelTests(TestCase):
type_cotisation="All",
prix=0,
)
self.f.reorder_purchases()
self.assertAlmostEqual(
self.user.end_connexion() - date,
datetime.timedelta(days=1),
@ -41,7 +42,7 @@ class VenteModelTests(TestCase):
It should be possible to have one day membership.
"""
date = timezone.now()
purchase = Vente.objects.create(
Vente.objects.create(
facture=self.f,
number=1,
name="Test purchase",
@ -50,16 +51,19 @@ class VenteModelTests(TestCase):
type_cotisation="All",
prix=0,
)
delta = relativedelta(self.user.end_connexion(), date)
delta.microseconds = 0
self.assertEqual(delta, relativedelta(months=1))
self.f.reorder_purchases()
end = self.user.end_connexion()
expected_end = date + relativedelta(months=1)
self.assertEqual(end.day, expected_end.day)
self.assertEqual(end.month, expected_end.month)
self.assertEqual(end.year, expected_end.year)
def test_one_month_and_one_week_cotisation(self):
"""
It should be possible to have one day membership.
"""
date = timezone.now()
purchase = Vente.objects.create(
Vente.objects.create(
facture=self.f,
number=1,
name="Test purchase",
@ -68,11 +72,82 @@ class VenteModelTests(TestCase):
type_cotisation="All",
prix=0,
)
delta = relativedelta(self.user.end_connexion(), date)
delta.microseconds = 0
self.assertEqual(delta, relativedelta(months=1, days=7))
self.f.reorder_purchases()
end = self.user.end_connexion()
expected_end = date + relativedelta(months=1, days=7)
self.assertEqual(end.day, expected_end.day)
self.assertEqual(end.month, expected_end.month)
self.assertEqual(end.year, expected_end.year)
def test_date_start_cotisation(self):
"""
It should be possible to add a cotisation with a specific start date
"""
v = Vente(
facture=self.f,
number=1,
name="Test purchase",
duration=0,
duration_days=1,
type_cotisation = 'All',
prix=0
)
v.create_cotis(date_start=timezone.make_aware(datetime.datetime(1998, 10, 16)))
v.save()
self.assertEqual(v.cotisation.date_end, timezone.make_aware(datetime.datetime(1998, 10, 17)))
def tearDown(self):
self.f.delete()
self.user.delete()
self.paiement.delete()
class FactureModelTests(TestCase):
def setUp(self):
self.user = User.objects.create(pseudo="testUserPlop", email="test@example.org")
self.paiement = Paiement.objects.create(moyen="test payment")
def tearDown(self):
self.user.delete()
self.paiement.delete()
def test_cotisations_prolongation(self):
"""When user already have one valid cotisation, the new one should be
added at the end of the existing one."""
date = timezone.now()
invoice1 = Facture.objects.create(
user=self.user, paiement=self.paiement, valid=True
)
Vente.objects.create(
facture=invoice1,
number=1,
name="Test purchase",
duration=1,
duration_days=0,
type_cotisation="All",
prix=0,
)
invoice1.reorder_purchases()
invoice2 = Facture.objects.create(
user=self.user, paiement=self.paiement, valid=True
)
Vente.objects.create(
facture=invoice2,
number=1,
name="Test purchase",
duration=1,
duration_days=0,
type_cotisation="All",
prix=0,
)
invoice1.reorder_purchases()
delta = relativedelta(self.user.end_connexion(), date)
delta.microseconds = 0
try:
self.assertEqual(delta, relativedelta(months=2))
except Exception as e:
invoice1.delete()
invoice2.delete()
raise e
invoice1.delete()
invoice2.delete()

View file

@ -144,6 +144,8 @@ def new_facture(request, user, userid):
price_ok = True
if price_ok:
new_invoice_instance.save()
# Saving purchases so the invoice can find them. Invoice
# will modify them after being validated to put the right dates.
for p in purchases:
p.facture = new_invoice_instance
p.save()