Transactions funtzen, kaufen fast
This commit is contained in:
parent
4615033732
commit
9450f3326b
|
@ -29,3 +29,7 @@ class Purchase(models.Model):
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return "%s%s, %s by %s" % (self.buyable.name, self.isDeposit and " (deposit)" or "", self.price, self.user)
|
return "%s%s, %s by %s" % (self.buyable.name, self.isDeposit and " (deposit)" or "", self.price, self.user)
|
||||||
|
|
||||||
|
def create(self, buyable):
|
||||||
|
self.dateTime = datetime.datetime.now()
|
||||||
|
self.buyable = buyable
|
|
@ -0,0 +1,9 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block "content" %}
|
||||||
|
{% if item %}
|
||||||
|
You got the item {{ item }}
|
||||||
|
{% else %}
|
||||||
|
No item found :(
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,7 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block "content" %}
|
||||||
|
{% for item in items %}
|
||||||
|
<img src="{{ MEDIA_URL }}{{ item.image }}">{{ item }} <a href="/store/show/{{ item.id }}">{{ item.name }}</a>
|
||||||
|
{% endfor %}
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,8 @@
|
||||||
|
from django.conf.urls.defaults import *
|
||||||
|
|
||||||
|
|
||||||
|
urlpatterns = patterns('',
|
||||||
|
(r'^$', 'buyable.views.showItems'),
|
||||||
|
(r'^show/(\d+)/$', 'buyable.views.showItem'),
|
||||||
|
(r'^buy/(\d+)/$', 'buyable.views.buyItem'),
|
||||||
|
)
|
|
@ -1 +1,33 @@
|
||||||
# Create your views here.
|
# Create your views here.
|
||||||
|
from django.shortcuts import render_to_response
|
||||||
|
from django.template import RequestContext
|
||||||
|
from django.contrib.auth.decorators import login_required
|
||||||
|
from django.http import HttpResponseRedirect
|
||||||
|
from models import Buyable
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def showItems(request):
|
||||||
|
# FIXME: Implement pagination here
|
||||||
|
items = Buyable.objects.all()
|
||||||
|
return render_to_response("buyables/showItems.html", {'items': items}, RequestContext(request))
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def showItem(request, itemid):
|
||||||
|
try:
|
||||||
|
item = Buyable.objects.get(id=itemid)
|
||||||
|
except Buyable.DoesNotExist:
|
||||||
|
# baww, kein item mit der id :( (oder mutax trollt rum)
|
||||||
|
return HttpResponseRedirect("/buy/")
|
||||||
|
return render_to_response("buyables/showItem.html", {'item': item}, RequestContext(request))
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def buyItem(request, itemid):
|
||||||
|
try:
|
||||||
|
item = Buyable.objects.get(id=itemid)
|
||||||
|
except Buyable.DoesNotExist:
|
||||||
|
# oh no! kein item mit der id :( mutax trollt rum)
|
||||||
|
return HttpResponseRedirect("/buy/")
|
||||||
|
purchase = Purchase(user=request.user, price=item.price, isDeposit=false )
|
||||||
|
purchase.create(item)
|
||||||
|
purchase.save()
|
||||||
|
return render_to_response("buyables/itemBought.html", {'item': item}, RequestContext(request))
|
BIN
k4ever/k4ever.db
BIN
k4ever/k4ever.db
Binary file not shown.
|
@ -0,0 +1,5 @@
|
||||||
|
from models import UserProfile
|
||||||
|
from django.contrib import admin
|
||||||
|
|
||||||
|
admin.site.register(UserProfile)
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
from django import forms
|
||||||
|
from django.core.exceptions import ValidationError
|
||||||
|
import re
|
||||||
|
|
||||||
|
#class CurrencyField(forms.IntegerField):
|
||||||
|
# default_error_message = {
|
||||||
|
# 'invalid': _(u'Enter a number.'),
|
||||||
|
# }
|
||||||
|
# def __init__(self, positive=True, *args, **kwargs):
|
||||||
|
# super(IntegerField, self).__init__(*args, **kwargs)
|
||||||
|
# self.positive = positive
|
||||||
|
# def to_python(self, value):
|
||||||
|
# value = super(IntegerField, self).to_python(value)
|
||||||
|
# if value in validators.EMPTY_VALUES:
|
||||||
|
# return None
|
||||||
|
# try:
|
||||||
|
# value = float(value.replace(",", "."))
|
||||||
|
# except:
|
||||||
|
# pass
|
||||||
|
|
||||||
|
class CurrencyInput (forms.TextInput):
|
||||||
|
def render(self, name, value, attrs=None):
|
||||||
|
if value != '':
|
||||||
|
try:
|
||||||
|
value = u"%.2f" % value
|
||||||
|
except TypeError:
|
||||||
|
pass
|
||||||
|
return super(CurrencyInput, self).render(name, value, attrs)
|
||||||
|
|
||||||
|
|
||||||
|
class CurrencyField (forms.RegexField):
|
||||||
|
widget = CurrencyInput
|
||||||
|
currencyRe = re.compile(r'^[0-9]{1,5}([,\.][0-9][0-9]?)?$')
|
||||||
|
|
||||||
|
#currencyRe = re.compile(r'^[0-9]{1,5}(.[0-9][0-9]?)?$')
|
||||||
|
# currencyRe = re.compile(r"^[0-9]")
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(CurrencyField, self).__init__(
|
||||||
|
self.currencyRe, None, None, *args, **kwargs)
|
||||||
|
|
||||||
|
#class CurrencyField(forms.FloatField):
|
||||||
|
# widget = CurrencyInput
|
||||||
|
# moneyre = re.compile(r"^[0-9]{1,5}([\.][0-9][0-9])?$")
|
||||||
|
# def __init__(self, positive=False, allowPerCent=False, *args, **kwargs):
|
||||||
|
# super(forms.FloatField, self).__init__(*args, **kwargs)
|
||||||
|
# self.positive = positive
|
||||||
|
# self.allowPerCent = allowPerCent
|
||||||
|
def to_python(self, value):
|
||||||
|
#return super(forms.FloatField, self).to_python(value)
|
||||||
|
#raise ValidationError("WTF WTF WTF %s " % value)
|
||||||
|
#value = value.replace(",", ".")
|
||||||
|
#try:
|
||||||
|
# value = super(forms.FloatField, self).to_python(value)
|
||||||
|
#except ValidationError, e:
|
||||||
|
# raise NotImplementedError("%s %s" % (e, value))
|
||||||
|
#return value
|
||||||
|
value = value.replace(",", ".")
|
||||||
|
try:
|
||||||
|
value = float(value)
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
raise ValidationError("Bitte gib eine Zahl ein")
|
||||||
|
# if not self.allowPerCent:
|
||||||
|
# tmpval = 100.0*value
|
||||||
|
# if tmpval == int(tmpval):
|
||||||
|
# raise ValidationError("Deine Zahl sollte nicht mehr als zwei Nachkommastellen haben. %s %s %s" % (tmpval, int(tmpval), tmpval-int(tmpval)))
|
||||||
|
# if self.positive and self.value < 0.0:
|
||||||
|
# raise ValidationError("Bitte gib eine positive Zahl an.")
|
||||||
|
return value
|
||||||
|
def clean(self, value):
|
||||||
|
value = super(CurrencyField, self).clean(value)
|
||||||
|
return float(value)
|
|
@ -3,7 +3,7 @@ from django.contrib.auth.models import User
|
||||||
|
|
||||||
class UserProfile(models.Model):
|
class UserProfile(models.Model):
|
||||||
user = models.ForeignKey(User, unique=True)
|
user = models.ForeignKey(User, unique=True)
|
||||||
balance = models.FloatField()
|
balance = models.FloatField(default=0.0)
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return "%s (Kontostand: %s)" % (self.user ,self.balance)
|
return "%s (Kontostand: %s)" % (self.user ,self.balance)
|
|
@ -1,5 +1,5 @@
|
||||||
<b>Main</b><br />
|
<b>Main</b><br />
|
||||||
<a href="/buy/">Buy</a><br />
|
<a href="/store/">Buy</a><br />
|
||||||
<a href="/transaction/">Konto</a><br />
|
<a href="/transaction/">Konto</a><br />
|
||||||
<a href="/">History</a><br />
|
<a href="/">History</a><br />
|
||||||
{% if user.is_staff %}
|
{% if user.is_staff %}
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 48 KiB |
Binary file not shown.
After Width: | Height: | Size: 20 KiB |
|
@ -50,7 +50,7 @@ MEDIA_ROOT = 'media/'
|
||||||
# URL that handles the media served from MEDIA_ROOT. Make sure to use a
|
# URL that handles the media served from MEDIA_ROOT. Make sure to use a
|
||||||
# trailing slash if there is a path component (optional in other cases).
|
# trailing slash if there is a path component (optional in other cases).
|
||||||
# Examples: "http://media.lawrence.com", "http://example.com/media/"
|
# Examples: "http://media.lawrence.com", "http://example.com/media/"
|
||||||
MEDIA_URL = 'media/'
|
MEDIA_URL = '/media/'
|
||||||
|
|
||||||
# URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a
|
# URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a
|
||||||
# trailing slash.
|
# trailing slash.
|
||||||
|
@ -61,7 +61,7 @@ ADMIN_MEDIA_PREFIX = '/media/admin/'
|
||||||
SECRET_KEY = 'l(f*a$l)_n_n_5#lh@rvhv(na^!lj1u#bow=c!*90(1w$5%b^j'
|
SECRET_KEY = 'l(f*a$l)_n_n_5#lh@rvhv(na^!lj1u#bow=c!*90(1w$5%b^j'
|
||||||
|
|
||||||
# User Profile / Login stuff
|
# User Profile / Login stuff
|
||||||
AUTH_PROFILE_MODULE = 'main.models.UserProfile'
|
AUTH_PROFILE_MODULE = 'main.UserProfile'
|
||||||
LOGIN_URL = '/user/login/'
|
LOGIN_URL = '/user/login/'
|
||||||
LOGIN_REDIRECT_URL = '/'
|
LOGIN_REDIRECT_URL = '/'
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,24 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
from models import Transaction, TransactionType
|
from models import Transaction, TransactionType
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
|
||||||
admin.site.register(Transaction)
|
class TransactionAdmin(admin.ModelAdmin):
|
||||||
|
actions = ['really_delete_selected']
|
||||||
|
|
||||||
|
def get_actions(self, request):
|
||||||
|
actions = super(TransactionAdmin, self).get_actions(request)
|
||||||
|
del actions['delete_selected']
|
||||||
|
return actions
|
||||||
|
# FIXME: Can we instead of replacing the whole page just
|
||||||
|
# hook the release process? Also - make this nicer
|
||||||
|
# in terms of localization/naming foo
|
||||||
|
def really_delete_selected(self, request, queryset):
|
||||||
|
for obj in queryset:
|
||||||
|
obj.delete()
|
||||||
|
num = queryset.count()
|
||||||
|
message = "%s transaction%s" % (num, (num != 1 and "s" or ""))
|
||||||
|
self.message_user(request, u"Erfolgreich %s gelöscht." % message)
|
||||||
|
really_delete_selected.short_description = u"Ausgewählte transactions löschen"
|
||||||
|
|
||||||
|
admin.site.register(Transaction, TransactionAdmin)
|
||||||
admin.site.register(TransactionType)
|
admin.site.register(TransactionType)
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
from django import forms
|
||||||
|
from models import Transaction
|
||||||
|
from main.fields import CurrencyField
|
||||||
|
|
||||||
|
class TransactionForm(forms.ModelForm):
|
||||||
|
amount = CurrencyField()
|
||||||
|
class Meta:
|
||||||
|
model = Transaction
|
||||||
|
exclude = ('user', 'dateTime', 'checked')
|
||||||
|
def clean_amount(self):
|
||||||
|
data = self.cleaned_data['amount']
|
||||||
|
return data
|
|
@ -1,13 +1,12 @@
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
|
|
||||||
|
|
||||||
class TransactionType(models.Model):
|
class TransactionType(models.Model):
|
||||||
name = models.CharField(max_length=100)
|
name = models.CharField(max_length=100)
|
||||||
needsCheck = models.BooleanField(default=True)
|
needsCheck = models.BooleanField(default=True)
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return unicode(self.name + (self.needsCheck and " (needs Check)" or ""))
|
return unicode(self.name)
|
||||||
|
|
||||||
class Transaction(models.Model):
|
class Transaction(models.Model):
|
||||||
user = models.ForeignKey(User)
|
user = models.ForeignKey(User)
|
||||||
|
@ -18,6 +17,22 @@ class Transaction(models.Model):
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return u"%s for user %s (%s),%schecked" % (self.amount, self.user, self.transactionType, (self.checked and " " or " not "))
|
return u"%s for user %s (%s),%schecked" % (self.amount, self.user, self.transactionType, (self.checked and " " or " not "))
|
||||||
|
# TODO: Find out what would happen if parent save/delete does not like us
|
||||||
|
def save(self, *args, **kwargs):
|
||||||
|
profile = self.user.get_profile()
|
||||||
|
if self.id == None:
|
||||||
|
# insert
|
||||||
|
profile.balance += self.amount
|
||||||
|
else:
|
||||||
|
# update
|
||||||
|
oldobj = Transaction.objects.get(id=self.id)
|
||||||
|
profile.balance += (self.amount-oldobj.amount)
|
||||||
|
profile.save()
|
||||||
|
super(Transaction, self).save(*args, **kwargs)
|
||||||
|
def delete(self, *args, **kwargs):
|
||||||
|
profile = self.user.get_profile()
|
||||||
|
profile.balance -= self.amount
|
||||||
|
profile.save()
|
||||||
|
super(Transaction, self).delete(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,31 @@
|
||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
|
|
||||||
{% block "content" %}
|
{% block "content" %}
|
||||||
|
{% if transacted %}
|
||||||
|
<font color="green"><b>YOU DID IT!</b></font>. You transacted money!
|
||||||
|
{% endif %}
|
||||||
|
<form method="POST" action="/transaction/">
|
||||||
|
{% csrf_token %}
|
||||||
|
<table>
|
||||||
|
{{ form.as_table }}
|
||||||
|
</table>
|
||||||
|
<input type="submit" value="Senden">
|
||||||
|
</form>
|
||||||
|
|
||||||
|
|
||||||
{% for transaction in history %}
|
{% for transaction in history %}
|
||||||
{{ transaction.amount }}, got that by {{ transaction.type }}
|
{% if forloop.first and transacted %}
|
||||||
|
<b>
|
||||||
|
{% endif %}
|
||||||
|
[ {{ transaction.dateTime }} ] {{ transaction.amount|floatformat:2 }} Euronen, got that by {{ transaction.transactionType }}
|
||||||
{% if transaction.checked %}
|
{% if transaction.checked %}
|
||||||
ist eingegangen
|
ist eingegangen
|
||||||
{% else %}
|
{% else %}
|
||||||
noch nicht da
|
noch nicht da
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% if forloop.first and transacted %}
|
||||||
|
</b>
|
||||||
|
{% endif %}
|
||||||
<br />
|
<br />
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block "content" %}
|
||||||
|
No content here.
|
||||||
|
{% endblock %}
|
|
@ -3,6 +3,7 @@ from django.conf.urls.defaults import *
|
||||||
|
|
||||||
urlpatterns = patterns('',
|
urlpatterns = patterns('',
|
||||||
(r'^$', 'transaction.views.overview'),
|
(r'^$', 'transaction.views.overview'),
|
||||||
|
#(r'^transact/$', 'transaction.views.transact'),
|
||||||
#(r'^transfer/$', 'transaction.views.transfer'),
|
#(r'^transfer/$', 'transaction.views.transfer'),
|
||||||
#(r'^checkTransfers/$', 'transaction.views.checkTransfers'),
|
#(r'^checkTransfers/$', 'transaction.views.checkTransfers'),
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,20 +1,36 @@
|
||||||
from django.shortcuts import render_to_response
|
from django.shortcuts import render_to_response
|
||||||
from django.template import RequestContext
|
from django.template import RequestContext
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
|
from django.http import HttpResponseRedirect
|
||||||
from models import Transaction, TransactionType
|
from models import Transaction, TransactionType
|
||||||
|
from forms import TransactionForm
|
||||||
|
import datetime
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def overview(request):
|
def overview(request):
|
||||||
history = Transaction.objects.filter(user=request.user).order_by("dateTime")
|
history = Transaction.objects.filter(user=request.user).order_by("-dateTime")
|
||||||
return render_to_response("transaction/overview.html", {'history': history}, RequestContext(request))
|
transacted = False
|
||||||
|
if request.method == 'POST':
|
||||||
|
transaction = Transaction(user=request.user, dateTime=datetime.datetime.now())
|
||||||
|
form = TransactionForm(request.POST, instance=transaction)
|
||||||
|
if form.is_valid():
|
||||||
|
form.save()
|
||||||
|
form = TransactionForm()
|
||||||
|
transacted = True
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
form = TransactionForm()
|
||||||
|
return render_to_response("transaction/overview.html", {'history': history, 'form': form, 'transacted': transacted}, RequestContext(request))
|
||||||
|
|
||||||
#@login_required
|
@login_required
|
||||||
#def transfer(request):
|
def transact(request):
|
||||||
# if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
#
|
return render_to_response("transaction/transfered.html", RequestContext(request))
|
||||||
# return render_to_response("transaction/transfered.html", RequestContext(request))
|
else:
|
||||||
|
return HttpResponseRedirect("/transaction/")
|
||||||
|
|
||||||
#@kassenwart_required
|
#@kassenwart_required
|
||||||
#def checkTransfers(request):
|
#def checkTransfers(request):
|
||||||
# transfers = Transaction.objects.filter(checked=False).sort("dateTime")
|
# transfers = Transaction.objects.filter(checked=False).order_by("dateTime")
|
||||||
# return render_to_response("transaction/uncheckedTransfers.html", {'transfers' : tranfers}, RequestContext(request))
|
# return render_to_response("transaction/uncheckedTransfers.html", {'transfers' : tranfers}, RequestContext(request))
|
|
@ -15,7 +15,8 @@ urlpatterns = patterns('',
|
||||||
(r'^$', 'main.views.startpage'),
|
(r'^$', 'main.views.startpage'),
|
||||||
(r'^user/', include('main.urls')),
|
(r'^user/', include('main.urls')),
|
||||||
(r'^transaction/', include('transaction.urls')),
|
(r'^transaction/', include('transaction.urls')),
|
||||||
#(r'^buy/', include('buyable.urls')),
|
(r'^store/', include('buyable.urls')),
|
||||||
|
(r'^media/(?P<path>.*)$', 'django.views.static.serve', {'document_root': 'media'}),
|
||||||
|
|
||||||
# Uncomment the next line to enable the admin:
|
# Uncomment the next line to enable the admin:
|
||||||
(r'^admin/', include(admin.site.urls)),
|
(r'^admin/', include(admin.site.urls)),
|
||||||
|
|
Loading…
Reference in New Issue