diff --git a/stregsystem/admin.py b/stregsystem/admin.py
index 3082c2f0..3091204c 100644
--- a/stregsystem/admin.py
+++ b/stregsystem/admin.py
@@ -24,7 +24,7 @@
class SaleAdmin(admin.ModelAdmin):
list_filter = ('room', 'timestamp')
- list_display = ('get_username', 'get_fullname', 'get_product_name', 'get_room_name', 'timestamp', 'get_price_display')
+ list_display = ('get_username', 'get_fullname', 'get_product_name', 'get_room_name', 'timestamp', 'get_price_display', 'is_reimbursed')
actions = ['refund']
search_fields = ['^member__username', '=product__id', 'product__name']
valid_lookups = ('member')
@@ -224,7 +224,7 @@ def get_queryset(self):
class PaymentAdmin(admin.ModelAdmin):
- list_display = ('get_username', 'timestamp', 'get_amount_display', 'is_mobilepayment')
+ list_display = ('get_username', 'timestamp', 'get_amount_display', 'is_mobilepayment', 'is_reimbursement')
valid_lookups = ('member')
search_fields = ['member__username']
autocomplete_fields = ['member']
diff --git a/stregsystem/migrations/0014_added_reimbursement.py b/stregsystem/migrations/0014_added_reimbursement.py
new file mode 100644
index 00000000..87723475
--- /dev/null
+++ b/stregsystem/migrations/0014_added_reimbursement.py
@@ -0,0 +1,21 @@
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('stregsystem', '0013_mobilepayment_permission_20201123_1344'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='payment',
+ name='is_reimbursement',
+ field=models.BooleanField(default=False, help_text='Viser om en betaling er tilbageført'),
+ ),
+ migrations.AddField(
+ model_name='sale',
+ name='is_reimbursed',
+ field=models.BooleanField(default=False, help_text='Viser om et salg er tilbageført'),
+ ),
+ ]
diff --git a/stregsystem/models.py b/stregsystem/models.py
index 8ead975b..52cbeea3 100644
--- a/stregsystem/models.py
+++ b/stregsystem/models.py
@@ -142,6 +142,18 @@ def execute(self):
# We changed the user balance, so save that
self.member.save()
+class Reimbursement(object):
+ #Limits the amount of hours a reimbursement is available.
+ MAX_REIMBUSEMENT_HOURS = 12
+
+ @transaction.atomic
+ def from_sale(sale_id):
+ sale = Sale.objects.get(id=sale_id)
+ if not sale.is_reimbursable():
+ return
+ sale.is_reimbursed = True
+ sale.save()
+ Payment.objects.create(amount=sale.price, member=sale.member, is_reimbursement=True)
class GetTransaction(MoneyTransaction):
# The change to the users account
@@ -295,6 +307,8 @@ class Meta:
member = models.ForeignKey(Member, on_delete=models.CASCADE)
timestamp = models.DateTimeField(auto_now_add=True)
amount = models.IntegerField() # penge, oere...
+ is_reimbursement = models.BooleanField(default=False, null=False,
+ help_text='Viser om en betaling er tilbageført')
@deprecated
def amount_display(self):
@@ -513,6 +527,8 @@ class Sale(models.Model):
room = models.ForeignKey(Room, on_delete=models.CASCADE, null=True)
timestamp = models.DateTimeField(auto_now_add=True)
price = models.IntegerField()
+ is_reimbursed = models.BooleanField(default=False, null=False,
+ help_text='Viser om et salg er tilbageført',)
class Meta:
index_together = [
@@ -530,6 +546,10 @@ def price_display(self):
# XXX - django bug - kan ikke vaelge mellem desc og asc i admin, som ved normalt felt
price_display.admin_order_field = 'price'
+ def is_reimbursable(self):
+ from datetime import timedelta
+ return (not self.is_reimbursed) and timedelta(hours=Reimbursement.MAX_REIMBUSEMENT_HOURS) >= timezone.now() - self.timestamp
+
@deprecated
def __unicode__(self):
return self.__str__()
@@ -537,10 +557,10 @@ def __unicode__(self):
def __str__(self):
return self.member.username + " " + self.product.name + " (" + money(self.price) + ") " + str(self.timestamp)
- def save(self, *args, **kwargs):
- if self.id:
- raise RuntimeError("Updates of sales are not allowed")
- super(Sale, self).save(*args, **kwargs)
+ #def save(self, *args, **kwargs):
+ # if self.id:
+ # raise RuntimeError("Updates of sales are not allowed")
+ # super(Sale, self).save(*args, **kwargs)
def delete(self, *args, **kwargs):
if self.id:
diff --git a/stregsystem/templates/stregsystem/menu_userinfo.html b/stregsystem/templates/stregsystem/menu_userinfo.html
index 63389b61..d39acd4a 100644
--- a/stregsystem/templates/stregsystem/menu_userinfo.html
+++ b/stregsystem/templates/stregsystem/menu_userinfo.html
@@ -39,6 +39,7 @@
Dato og tidspunkt |
Produkt |
Pris |
+ Tilbagefør |
{% autoescape off %}
{% for sale in last_sale_list %}
@@ -46,6 +47,15 @@
{{sale.timestamp}} |
{{sale.product.name}} |
{{sale.price|money}} |
+
+ {% if sale.is_reimbursable %}
+
+ {% endif %}
+ |
{% endfor %}
{% endautoescape %}
diff --git a/stregsystem/tests.py b/stregsystem/tests.py
index eebfda7a..18e3ce59 100644
--- a/stregsystem/tests.py
+++ b/stregsystem/tests.py
@@ -28,6 +28,7 @@
Payment,
PayTransaction,
Product,
+ Reimbursement,
Room,
Sale,
StregForbudError,
@@ -770,9 +771,7 @@ def test_sale_save_already_saved(self):
price=100
)
sale.save()
-
- with self.assertRaises(RuntimeError):
- sale.save()
+ sale.save()
def test_sale_delete_not_saved(self):
sale = Sale(
@@ -796,6 +795,73 @@ def test_sale_delete_already_saved(self):
self.assertIsNone(sale.id)
+class ReimbursementTests(TestCase):
+ def setUp(self):
+ self.member = Member.objects.create(
+ username="jon",
+ balance=500
+ )
+ self.product = Product.objects.create(
+ name="beer",
+ price=1.0,
+ active=True,
+ )
+ with freeze_time(timezone.now() - datetime.timedelta(hours=11)):
+ self.almost_oldsale = Sale.objects.create(
+ member=self.member,
+ product=self.product,
+ price=200,
+ )
+ with freeze_time(timezone.now() - datetime.timedelta(hours=12, minutes=1)):
+ self.oldsale = Sale.objects.create(
+ member=self.member,
+ product=self.product,
+ price=300,
+ )
+ self.newsale = Sale.objects.create(
+ member=self.member,
+ product=self.product,
+ price=100,
+ )
+
+ def test_reimbursement_success(self):
+ self.assertFalse(Payment.objects.filter(is_reimbursement=True).exists())
+ self.assertFalse(Sale.objects.filter(is_reimbursed=True, id=self.newsale.id).exists())
+ Reimbursement.from_sale(self.newsale.id)
+ self.assertTrue(Payment.objects.filter(is_reimbursement=True).exists())
+ self.assertTrue(Sale.objects.filter(is_reimbursed=True, id=self.newsale.id).exists())
+
+ def test_reimbursement_later_success(self):
+ self.assertFalse(Payment.objects.filter(is_reimbursement=True).exists())
+ self.assertFalse(Sale.objects.filter(is_reimbursed=True, id=self.almost_oldsale.id).exists())
+ Reimbursement.from_sale(self.almost_oldsale.id)
+ self.assertTrue(Payment.objects.filter(is_reimbursement=True).exists())
+ self.assertTrue(Sale.objects.filter(is_reimbursed=True, id=self.almost_oldsale.id).exists())
+
+ def test_reimbursement_fail(self):
+ self.assertFalse(Payment.objects.filter(is_reimbursement=True).exists())
+ self.assertFalse(Sale.objects.filter(is_reimbursed=True, id=self.oldsale.id).exists())
+ Reimbursement.from_sale(self.oldsale.id)
+ self.assertFalse(Payment.objects.filter(is_reimbursement=True).exists())
+ self.assertFalse(Sale.objects.filter(is_reimbursed=True, id=self.oldsale.id).exists())
+
+ def test_reimbursement_balance_updated(self):
+ self.assertEqual(self.member.balance, 500)
+ Reimbursement.from_sale(self.newsale.id)
+ self.member.refresh_from_db()
+ self.assertEqual(self.member.balance, 600)
+
+ def test_reimbursement_balance_updated_another(self):
+ self.assertEqual(self.member.balance, 500)
+ Reimbursement.from_sale(self.almost_oldsale.id)
+ self.member.refresh_from_db()
+ self.assertEqual(self.member.balance, 700)
+
+ def test_reimbursement_balance_not_updated(self):
+ self.assertEqual(self.member.balance, 500)
+ Reimbursement.from_sale(self.oldsale.id)
+ self.member.refresh_from_db()
+ self.assertEqual(self.member.balance, 500)
class MemberTests(TestCase):
def test_fulfill_pay_transaction(self):
diff --git a/stregsystem/views.py b/stregsystem/views.py
index 1787137f..f66f08a4 100644
--- a/stregsystem/views.py
+++ b/stregsystem/views.py
@@ -25,7 +25,8 @@
Room,
Sale,
StregForbudError,
- MobilePayment
+ MobilePayment,
+ Reimbursement,
)
from stregsystem.utils import (
make_active_productlist_query,
@@ -185,11 +186,14 @@ def usermenu(request, room, member, bought, from_sale=False):
def menu_userinfo(request, room_id, member_id):
room = Room.objects.get(pk=room_id)
news = __get_news()
+
+ if request.method == 'POST' and request.POST.get('action') is not None and request.POST['action'] == 'reimburse':
+ Reimbursement.from_sale(int(request.POST['sale_id']))
member = Member.objects.get(pk=member_id, active=True)
- last_sale_list = member.sale_set.order_by('-timestamp')[:10]
+ last_sale_list = member.sale_set.filter(is_reimbursed=False).order_by('-timestamp')[:10]
try:
- last_payment = member.payment_set.order_by('-timestamp')[0]
+ last_payment = member.payment_set.filter(is_reimbursement=False).order_by('-timestamp')[0]
except IndexError:
last_payment = None