Add the ability to add refunds
This commit is contained in:
parent
343bc1fd84
commit
b8e7309ee2
11 changed files with 130 additions and 21 deletions
|
@ -1,5 +1,5 @@
|
|||
from django.contrib import admin
|
||||
from refunding.forms import RefundForm
|
||||
from refunding.forms import RefundForm, RefundFormAdmin
|
||||
from refunding.models import Refund, Payment
|
||||
|
||||
|
||||
|
@ -9,7 +9,7 @@ class RefundAdmin(admin.ModelAdmin):
|
|||
list_display_links = ('title',)
|
||||
search_fields = ('title',)
|
||||
date_hierarchy = 'date'
|
||||
form = RefundForm
|
||||
form = RefundFormAdmin
|
||||
readonly_fields = ('eur_value',)
|
||||
|
||||
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
from bootstrap3_datetime.widgets import DateTimePicker
|
||||
from django import forms
|
||||
from django.db.models import Q
|
||||
from refunding.models import Refund, Payment
|
||||
|
||||
|
||||
|
@ -7,18 +9,39 @@ class RefundForm(forms.ModelForm):
|
|||
model = Refund
|
||||
fields = '__all__'
|
||||
|
||||
payments = forms.ModelMultipleChoiceField(queryset=Payment.objects.all())
|
||||
payments = forms.ModelMultipleChoiceField(queryset=Payment.objects.none())
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(RefundForm, self).__init__(*args, **kwargs)
|
||||
if self.instance:
|
||||
self.fields['payments'].initial = self.instance.payment_set.all()
|
||||
self.fields['payments'].queryset = Payment.objects.filter(Q(refund=None) | Q(refund=self.instance))
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
# Save the refund
|
||||
instance = super(RefundForm, self).save(commit=False)
|
||||
instance = super(RefundForm, self).save()
|
||||
# Remove the refund from payments it was previously assigned to
|
||||
self.fields['payments'].initial.update(refund=None)
|
||||
# Add the refund to the selected payments
|
||||
self.cleaned_data['payments'].update(refund=instance)
|
||||
return instance
|
||||
|
||||
|
||||
class RefundFormAdmin(RefundForm):
|
||||
class Meta:
|
||||
model = Refund
|
||||
fields = '__all__'
|
||||
|
||||
|
||||
class RefundFormPublic(RefundForm):
|
||||
class Meta:
|
||||
model = Refund
|
||||
exclude = ('user',)
|
||||
|
||||
date = forms.DateField(
|
||||
widget=DateTimePicker(
|
||||
options={
|
||||
'format': 'YYYY-MM-DD'
|
||||
}
|
||||
)
|
||||
)
|
||||
|
|
22
refunding/migrations/0002_auto_20160604_0140.py
Normal file
22
refunding/migrations/0002_auto_20160604_0140.py
Normal file
|
@ -0,0 +1,22 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.9.6 on 2016-06-04 01:40
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('refunding', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='refund',
|
||||
name='user',
|
||||
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL),
|
||||
),
|
||||
]
|
|
@ -12,11 +12,16 @@ class Refund(models.Model):
|
|||
updated_at = models.DateTimeField(auto_now=True)
|
||||
user = models.ForeignKey(
|
||||
AUTH_USER_MODEL,
|
||||
on_delete=models.PROTECT
|
||||
on_delete=models.PROTECT,
|
||||
null=True
|
||||
)
|
||||
|
||||
def eur_value(self) -> float:
|
||||
return self.payment_set.all().aggregate(Sum('value')).get('value__sum') / 100
|
||||
value_sum = self.payment_set.all().aggregate(Sum('value')).get('value__sum')
|
||||
if value_sum:
|
||||
return value_sum / 100
|
||||
else:
|
||||
return 0
|
||||
|
||||
def __str__(self) -> str:
|
||||
return "{0} on {1} for {2}".format(self.title, self.date, self.eur_value())
|
||||
|
|
27
refunding/templates/refunding/new_refund.html
Normal file
27
refunding/templates/refunding/new_refund.html
Normal file
|
@ -0,0 +1,27 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load crispy_forms_filters %}
|
||||
{% load crispy_forms_field %}
|
||||
|
||||
{% block javascript %}
|
||||
{{ block.super }}
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.13.0/moment.min.js"
|
||||
crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datetimepicker/4.17.37/js/bootstrap-datetimepicker.min.js"
|
||||
crossorigin="anonymous"></script>
|
||||
{% endblock %}
|
||||
|
||||
{% block style %}
|
||||
{{ block.super }}
|
||||
<link rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datetimepicker/4.17.37/css/bootstrap-datetimepicker.min.css">
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>{% block title %}New refund{% endblock %}</h1>
|
||||
<form action="{% url 'new_refund' %}" method="post">
|
||||
{% csrf_token %}
|
||||
{{ form.media }}
|
||||
{{ form|crispy }}
|
||||
<input class="btn btn-primary" type="submit" value="Submit"/>
|
||||
</form>
|
||||
{% endblock %}
|
|
@ -2,6 +2,15 @@
|
|||
{% load l10n %}
|
||||
|
||||
{% block content %}
|
||||
<h1>{% block title %}Latest refunds{% endblock %}</h1>
|
||||
<h1>
|
||||
{% block title %}Latest refunds{% endblock %}
|
||||
{% if user.is_authenticated %}
|
||||
<div class="btn-group pull-right">
|
||||
<a class="btn btn-success" href="{% url 'new_refund' %}">
|
||||
<span class="glyphicon glyphicon-plus"></span>
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</h1>
|
||||
{% include 'refunding/elements_list.html' with elements=refunds %}
|
||||
{% endblock %}
|
|
@ -1,7 +1,8 @@
|
|||
from django.conf.urls import url
|
||||
from refunding.views import not_refunded_payments, latest_refunds
|
||||
from refunding import views
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^payments/$', not_refunded_payments, name='not_refunded_payments'),
|
||||
url(r'^refunds/$', latest_refunds, name='latest_refunds'),
|
||||
url(r'^payments/$', views.not_refunded_payments, name='not_refunded_payments'),
|
||||
url(r'^refunds/$', views.latest_refunds, name='latest_refunds'),
|
||||
url(r'^refunds/new/$', views.new_refund, name='new_refund'),
|
||||
]
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
from django.contrib.auth.decorators import login_required
|
||||
from django.db.models import Sum
|
||||
from django.shortcuts import render
|
||||
from django.shortcuts import render, redirect
|
||||
from refunding.forms import RefundForm, RefundFormPublic
|
||||
from refunding.models import Payment, Refund
|
||||
|
||||
|
||||
|
@ -24,3 +25,21 @@ def latest_refunds(request):
|
|||
'default_nothing': 'No refund to show.'
|
||||
}
|
||||
return render(request, "refunding/refunds.html", context)
|
||||
|
||||
|
||||
@login_required
|
||||
def new_refund(request):
|
||||
if request.method == 'POST':
|
||||
form = RefundFormPublic(request.POST)
|
||||
if form.is_valid():
|
||||
refund = form.save()
|
||||
refund.user = request.user
|
||||
refund.save()
|
||||
return redirect('latest_refunds')
|
||||
else:
|
||||
form = RefundFormPublic()
|
||||
|
||||
context = {
|
||||
'form': form
|
||||
}
|
||||
return render(request, "refunding/new_refund.html", context)
|
|
@ -50,6 +50,7 @@ X_FRAME_OPTIONS = 'DENY'
|
|||
INSTALLED_APPS = [
|
||||
'refunding',
|
||||
'authentication',
|
||||
'bootstrap3_datetime',
|
||||
'crispy_forms',
|
||||
'django.contrib.admin',
|
||||
'django.contrib.auth',
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
dj-database-url==0.4.1
|
||||
Django==1.9.6
|
||||
django-bootstrap3-datetimepicker-2==2.4.2
|
||||
django-crispy-forms==1.6.0
|
||||
django-dotenv==1.4.1
|
||||
gunicorn==19.6.0
|
||||
|
|
|
@ -7,9 +7,19 @@
|
|||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
{% block javascript %}
|
||||
<script src="https://code.jquery.com/jquery-2.2.3.min.js"
|
||||
integrity="sha256-a23g1Nt4dtEYOj7bR+vTu7+T8VP13humZFBJNIYoEJo="
|
||||
crossorigin="anonymous"></script>
|
||||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"
|
||||
integrity="sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS"
|
||||
crossorigin="anonymous"></script>
|
||||
{% endblock javascript %}
|
||||
|
||||
{% block style %}
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
|
||||
<link rel="stylesheet" type="text/css" href="//fonts.googleapis.com/css?family=Open+Sans:400italic,700italic,400,700">
|
||||
<link rel="stylesheet" type="text/css"
|
||||
href="//fonts.googleapis.com/css?family=Open+Sans:400italic,700italic,400,700">
|
||||
<link rel="stylesheet" href="{% static 'default_style.css' %}">
|
||||
{% endblock style %}
|
||||
</head>
|
||||
|
@ -20,14 +30,5 @@
|
|||
{% block content %}
|
||||
{% endblock %}
|
||||
</div>
|
||||
|
||||
{% block javascript %}
|
||||
<script src="https://code.jquery.com/jquery-2.2.3.min.js"
|
||||
integrity="sha256-a23g1Nt4dtEYOj7bR+vTu7+T8VP13humZFBJNIYoEJo="
|
||||
crossorigin="anonymous"></script>
|
||||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"
|
||||
integrity="sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS"
|
||||
crossorigin="anonymous"></script>
|
||||
{% endblock javascript %}
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in a new issue