Browse Source

pep8

master
Fr3deric 7 years ago
parent
commit
e1598090f7
  1. 18
      cashonly/admin.py
  2. 1
      cashonly/auth.py
  3. 1
      cashonly/formfields.py
  4. 7
      cashonly/management/commands/dailydigest.py
  5. 1
      cashonly/management/commands/debtreminder.py
  6. 22
      cashonly/models.py
  7. 17
      cashonly/urls.py
  8. 2
      cashonly/version.py
  9. 45
      cashonly/views.py

18
cashonly/admin.py

@ -8,6 +8,7 @@ from django.utils.translation import ugettext as _
from django.utils.translation import ugettext_lazy from django.utils.translation import ugettext_lazy
from django.utils.translation import ugettext_noop from django.utils.translation import ugettext_noop
class AccountForm(forms.ModelForm): class AccountForm(forms.ModelForm):
credit_change = forms.DecimalField(max_digits=5, decimal_places=2, credit_change = forms.DecimalField(max_digits=5, decimal_places=2,
required=False, required=False,
@ -16,8 +17,6 @@ class AccountForm(forms.ModelForm):
credit_change_comment = forms.CharField(max_length=64, required=False, credit_change_comment = forms.CharField(max_length=64, required=False,
label=ugettext_lazy('comment')) label=ugettext_lazy('comment'))
#pin_change = forms.RegexField(regex='^\d{4,}$', required=False,
# label=ugettext_lazy('PIN'))
pin_change = DigitField(min_length=4, required=False, pin_change = DigitField(min_length=4, required=False,
label=ugettext_lazy('PIN')) label=ugettext_lazy('PIN'))
@ -30,6 +29,7 @@ class AccountForm(forms.ModelForm):
# Include all fields (omitting this causes a RemovedInDjango18Warning) # Include all fields (omitting this causes a RemovedInDjango18Warning)
exclude = [] exclude = []
class AccountAdmin(admin.ModelAdmin): class AccountAdmin(admin.ModelAdmin):
list_display = ('user', 'card_number', 'credit', 'transaction_link') list_display = ('user', 'card_number', 'credit', 'transaction_link')
form = AccountForm form = AccountForm
@ -97,6 +97,7 @@ class ProductBarcodeInline(admin.TabularInline):
model = ProductBarcode model = ProductBarcode
extra = 1 extra = 1
class ProductAdmin(admin.ModelAdmin): class ProductAdmin(admin.ModelAdmin):
list_display = ('name', 'category', 'price', 'active') list_display = ('name', 'category', 'price', 'active')
list_filter = ['category', 'active'] list_filter = ['category', 'active']
@ -104,15 +105,18 @@ class ProductAdmin(admin.ModelAdmin):
inlines = [ProductBarcodeInline] inlines = [ProductBarcodeInline]
fields = ('name', 'price', 'active', 'category', 'image') fields = ('name', 'price', 'active', 'category', 'image')
class ProductCategoryAdmin(admin.ModelAdmin): class ProductCategoryAdmin(admin.ModelAdmin):
list_display = ('name', 'comment') list_display = ('name', 'comment')
class SalesLogEntryAdmin(admin.ModelAdmin): class SalesLogEntryAdmin(admin.ModelAdmin):
list_display = ('account', 'timestamp', 'product', 'count', 'unit_price') list_display = ('account', 'timestamp', 'product', 'count', 'unit_price')
list_filter = ['account', 'timestamp', 'product'] list_filter = ['account', 'timestamp', 'product']
# Make sales log entries completely read-only # Make sales log entries completely read-only
readonly_fields = map(lambda f: f.name, SalesLogEntry._meta.fields) readonly_fields = map(lambda f: f.name, SalesLogEntry._meta.fields)
class TransactionAdmin(admin.ModelAdmin): class TransactionAdmin(admin.ModelAdmin):
list_display = ('account', 'timestamp', 'subject', 'description', 'amount') list_display = ('account', 'timestamp', 'subject', 'description', 'amount')
list_filter = ['account', 'timestamp', 'subject'] list_filter = ['account', 'timestamp', 'subject']
@ -125,10 +129,12 @@ class TransactionAdmin(admin.ModelAdmin):
# Disable tampering with the transactions completely. # Disable tampering with the transactions completely.
def has_add_permission(self, request): def has_add_permission(self, request):
return False return False
def has_change_permission(self, request, obj=None): def has_change_permission(self, request, obj=None):
if obj is None: if obj is None:
return True return True
return False return False
def has_delete_permission(self, request, obj=None): def has_delete_permission(self, request, obj=None):
return False return False
@ -136,13 +142,13 @@ class TransactionAdmin(admin.ModelAdmin):
# FIXME: a bit too hacky # FIXME: a bit too hacky
def changelist_view(self, request, extra_context=None): def changelist_view(self, request, extra_context=None):
self.list_display_links = (None, ) self.list_display_links = (None, )
return super(TransactionAdmin, self).changelist_view(request, return super(TransactionAdmin, self).changelist_view(
extra_context=None) request,
extra_context=None,
)
admin.site.register(Account, AccountAdmin) admin.site.register(Account, AccountAdmin)
admin.site.register(Product, ProductAdmin) admin.site.register(Product, ProductAdmin)
#admin.site.register(ProductBarcode)
admin.site.register(ProductCategory, ProductCategoryAdmin) admin.site.register(ProductCategory, ProductCategoryAdmin)
admin.site.register(Transaction, TransactionAdmin) admin.site.register(Transaction, TransactionAdmin)
admin.site.register(SalesLogEntry, SalesLogEntryAdmin) admin.site.register(SalesLogEntry, SalesLogEntryAdmin)

1
cashonly/auth.py

@ -1,6 +1,7 @@
from django.contrib.auth.models import User from django.contrib.auth.models import User
from cashonly.models import Account from cashonly.models import Account
class CashBackend(object): class CashBackend(object):
def authenticate(self, card_number=None, pin=None): def authenticate(self, card_number=None, pin=None):
if not card_number.isdigit(): if not card_number.isdigit():

1
cashonly/formfields.py

@ -3,6 +3,7 @@ from django.core.exceptions import ValidationError
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.core.validators import EMPTY_VALUES from django.core.validators import EMPTY_VALUES
class DigitField(CharField): class DigitField(CharField):
def clean(self, value): def clean(self, value):
super(DigitField, self).clean(value) super(DigitField, self).clean(value)

7
cashonly/management/commands/dailydigest.py

@ -13,6 +13,7 @@ import datetime
RANGE = 24 RANGE = 24
USERSETTINGS_URL = 'https://cypher/kasse/usersettings/' USERSETTINGS_URL = 'https://cypher/kasse/usersettings/'
class Command(NoArgsCommand): class Command(NoArgsCommand):
help = 'Sends out the daily digest to all users with transactions' + \ help = 'Sends out the daily digest to all users with transactions' + \
'in the last %dh' % RANGE 'in the last %dh' % RANGE
@ -31,8 +32,8 @@ class Command(NoArgsCommand):
'url': USERSETTINGS_URL} 'url': USERSETTINGS_URL}
transactions = Transaction.objects.filter(account=a) \ transactions = Transaction.objects.filter(account=a) \
.filter(timestamp__gte=(datetime.datetime.now() .filter(timestamp__gte=(datetime.datetime.now() -
- datetime.timedelta(hours = RANGE))) datetime.timedelta(hours=RANGE)))
if transactions.count() > 0: if transactions.count() > 0:
lengths = {'timestamp': len(_('date')), lengths = {'timestamp': len(_('date')),
@ -42,7 +43,7 @@ class Command(NoArgsCommand):
sum = 0 sum = 0
for t in transactions: for t in transactions:
lengths['timestamp'] = \ lengths['timestamp'] = \
max(lengths['timestamp'], len(DateFormat(t.timestamp) \ max(lengths['timestamp'], len(DateFormat(t.timestamp)
.format(get_format('SHORT_DATETIME_FORMAT')))) .format(get_format('SHORT_DATETIME_FORMAT'))))
lengths['description'] = \ lengths['description'] = \
max(lengths['description'], len(t.description)) max(lengths['description'], len(t.description))

1
cashonly/management/commands/debtreminder.py

@ -8,6 +8,7 @@ from django.template.loader import get_template
from django.utils import translation from django.utils import translation
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
class Command(NoArgsCommand): class Command(NoArgsCommand):
help = 'Sends a reminder mail to every with a negative credit' help = 'Sends a reminder mail to every with a negative credit'

22
cashonly/models.py

@ -11,12 +11,14 @@ from django.db import transaction
import PIL.Image import PIL.Image
import StringIO import StringIO
class Account(models.Model): class Account(models.Model):
user = models.OneToOneField(User) user = models.OneToOneField(User)
card_number = models.CharField(max_length=32, unique=True, blank=True, card_number = models.CharField(max_length=32, unique=True, blank=True,
null=True, verbose_name=_('card number')) null=True, verbose_name=_('card number'))
pin = models.CharField(max_length=32, blank=True, verbose_name=_('PIN')) pin = models.CharField(max_length=32, blank=True, verbose_name=_('PIN'))
daily_digest = models.BooleanField(verbose_name = _('daily digest'), default=True) daily_digest = models.BooleanField(verbose_name=_('daily digest'),
default=True)
credit = models.DecimalField(max_digits=5, decimal_places=2, default=0, credit = models.DecimalField(max_digits=5, decimal_places=2, default=0,
verbose_name=_('credit')) verbose_name=_('credit'))
@ -36,8 +38,8 @@ class Account(models.Model):
else: else:
# When we already have an account, # When we already have an account,
# we can add the number form LDAP (mongo shit) # we can add the number form LDAP (mongo shit)
if hasattr(instance, 'ldap_user') \ if (hasattr(instance, 'ldap_user') and
and instance.ldap_user.attrs.has_key('employeenumber'): 'employeenumber' in instance.ldap_user.attrs):
instance.account.card_number = \ instance.account.card_number = \
instance.ldap_user.attrs['employeenumber'][0] instance.ldap_user.attrs['employeenumber'][0]
instance.account.save() instance.account.save()
@ -61,7 +63,8 @@ class Account(models.Model):
if min(products.values()) <= 0: if min(products.values()) <= 0:
raise ValueError('Non-positive amount in products dict.') raise ValueError('Non-positive amount in products dict.')
total_value = sum(map(lambda p: p.price * products[p], products.keys())) total_value = sum(map(lambda p: p.price * products[p],
products.keys()))
if self.credit - total_value >= MAX_DEBIT: if self.credit - total_value >= MAX_DEBIT:
desc = '' desc = ''
for product in products.keys(): for product in products.keys():
@ -70,7 +73,8 @@ class Account(models.Model):
amount = products[product] amount = products[product]
logentry = SalesLogEntry(account=self, product=product, logentry = SalesLogEntry(account=self, product=product,
count=amount, unit_price=product.price) count=amount,
unit_price=product.price)
logentry.save() logentry.save()
desc += '%d x %s\n' % (amount, product.name) desc += '%d x %s\n' % (amount, product.name)
@ -95,6 +99,7 @@ class Account(models.Model):
def check_pin(self, pin): def check_pin(self, pin):
return pin == self.pin return pin == self.pin
class ProductCategory(models.Model): class ProductCategory(models.Model):
name = models.CharField(max_length=32, unique=True, name = models.CharField(max_length=32, unique=True,
verbose_name=_('name')) verbose_name=_('name'))
@ -108,6 +113,7 @@ class ProductCategory(models.Model):
verbose_name = _('product category') verbose_name = _('product category')
verbose_name_plural = _('product categories') verbose_name_plural = _('product categories')
class Product(models.Model): class Product(models.Model):
name = models.CharField(max_length=32, unique=True, name = models.CharField(max_length=32, unique=True,
verbose_name=_('name')) verbose_name=_('name'))
@ -129,6 +135,7 @@ class Product(models.Model):
verbose_name = _('product') verbose_name = _('product')
verbose_name_plural = _('products') verbose_name_plural = _('products')
@receiver(pre_save, sender=Product) @receiver(pre_save, sender=Product)
def product_post_save_handler(sender, instance, **kwargs): def product_post_save_handler(sender, instance, **kwargs):
img = instance.image img = instance.image
@ -159,6 +166,7 @@ class ProductBarcode(models.Model):
verbose_name = _('barcode') verbose_name = _('barcode')
verbose_name_plural = _('barcodes') verbose_name_plural = _('barcodes')
class Transaction(models.Model): class Transaction(models.Model):
account = models.ForeignKey(Account, verbose_name=_('account')) account = models.ForeignKey(Account, verbose_name=_('account'))
timestamp = models.DateTimeField(auto_now_add=True, timestamp = models.DateTimeField(auto_now_add=True,
@ -172,6 +180,7 @@ class Transaction(models.Model):
verbose_name = _('transaction') verbose_name = _('transaction')
verbose_name_plural = _('transactions') verbose_name_plural = _('transactions')
class SalesLogEntry(models.Model): class SalesLogEntry(models.Model):
account = models.ForeignKey(Account, verbose_name=_('account')) account = models.ForeignKey(Account, verbose_name=_('account'))
product = models.ForeignKey(Product, verbose_name=_('product')) product = models.ForeignKey(Product, verbose_name=_('product'))
@ -183,10 +192,12 @@ class SalesLogEntry(models.Model):
def __unicode__(self): def __unicode__(self):
return '%dx %s - %s' % (self.count, self.product, self.account) return '%dx %s - %s' % (self.count, self.product, self.account)
class Meta: class Meta:
verbose_name = _('sales log entry') verbose_name = _('sales log entry')
verbose_name_plural = _('sales log entries') verbose_name_plural = _('sales log entries')
@receiver(pre_delete, sender=SalesLogEntry) @receiver(pre_delete, sender=SalesLogEntry)
def logentry_pre_delete_handler(sender, instance, **kwargs): def logentry_pre_delete_handler(sender, instance, **kwargs):
SUBJECT = ugettext_noop('Cancellation') SUBJECT = ugettext_noop('Cancellation')
@ -196,4 +207,3 @@ def logentry_pre_delete_handler(sender, instance, **kwargs):
instance.unit_price * instance.count, instance.unit_price * instance.count,
SUBJECT, DESC % (instance.count, instance.product.name) SUBJECT, DESC % (instance.count, instance.product.name)
) )

17
cashonly/urls.py

@ -4,16 +4,20 @@ from cashonly import views
urlpatterns = [ urlpatterns = [
url(r'^$', views.overview, name='overview'), url(r'^$', views.overview, name='overview'),
url(r'^product/(?P<pk>\d+)/$', views.ProductView.as_view(), name='product'), url(r'^product/(?P<pk>\d+)/$', views.ProductView.as_view(),
name='product'),
url(r'transactions/$', views.transactions, {'detailed': False, 'page':1}, name='transactions'), url(r'transactions/$', views.transactions, {'detailed': False, 'page': 1},
name='transactions'),
url(r'transactions/(?P<page>\d+)/$', views.transactions, {'detailed': False}, name='transactions'), url(r'transactions/(?P<page>\d+)/$', views.transactions,
{'detailed': False}, name='transactions'),
url(r'transactions/(?P<page>\d+)/detailed/$', views.transactions, {'detailed': True}, url(r'transactions/(?P<page>\d+)/detailed/$', views.transactions,
name='transactions_detailed'), {'detailed': True}, name='transactions_detailed'),
url(r'products/((?P<category_id>\d+)/)?$', views.products, name='products'), url(r'products/((?P<category_id>\d+)/)?$', views.products,
name='products'),
url(r'buy/(?P<product_id>\d+)/$', views.buy, name='buy'), url(r'buy/(?P<product_id>\d+)/$', views.buy, name='buy'),
@ -27,4 +31,3 @@ urlpatterns = [
url(r'usersettings(/(?P<submit>\w+))?/$', views.usersettings, url(r'usersettings(/(?P<submit>\w+))?/$', views.usersettings,
name='usersettings'), name='usersettings'),
] ]

2
cashonly/version.py

@ -1,3 +1 @@
CASHONLY_VERSION = '2.1.2' CASHONLY_VERSION = '2.1.2'

45
cashonly/views.py

@ -9,22 +9,27 @@ from django.utils.translation import ugettext_lazy
import cashonly.version import cashonly.version
import datetime import datetime
def version_number_context_processor(request): def version_number_context_processor(request):
return {'version_number': cashonly.version.CASHONLY_VERSION} return {'version_number': cashonly.version.CASHONLY_VERSION}
@login_required @login_required
def overview(request): def overview(request):
a = request.user.account a = request.user.account
time = datetime.datetime.now() - datetime.timedelta(hours=12) time = datetime.datetime.now() - datetime.timedelta(hours=12)
transactions = Transaction.objects.filter(account=a).filter(timestamp__gte=time).order_by('-timestamp') transactions = Transaction.objects.filter(account=a) \
.filter(timestamp__gte=time).order_by('-timestamp')
# FIXME: distinct doesn't work as expected, so fetch 20 rows and hope that there are 3 distinct products # FIXME: distinct doesn't work as expected, so fetch 20 rows and hope that
purchases = Product.objects.filter(saleslogentry__account=a).order_by('-saleslogentry__timestamp').distinct()[:20] # there are 3 distinct products
purchases = Product.objects.filter(saleslogentry__account=a) \
.order_by('-saleslogentry__timestamp').distinct()[:20]
products = [] products = []
# Find 3 products # Find 3 products
for p in purchases: for p in purchases:
if not p in products: if p not in products:
products.append(p) products.append(p)
if len(products) == 3: if len(products) == 3:
@ -53,23 +58,27 @@ def transactions(request, detailed, page):
except paginator.EmptyPage: except paginator.EmptyPage:
transaction_list = paginator.page(paginator.num_pages) transaction_list = paginator.page(paginator.num_pages)
return render(request, 'cashonly/transaction_list.html', { 'transaction_list': transaction_list, return render(request, 'cashonly/transaction_list.html',
{'transaction_list': transaction_list,
'detailed': detailed}) 'detailed': detailed})
def products(request, category_id=None): def products(request, category_id=None):
if category_id is None: if category_id is None:
category = None category = None
products = Product.objects.filter(active=True) products = Product.objects.filter(active=True)
else: else:
category = get_object_or_404(ProductCategory, id=category_id) category = get_object_or_404(ProductCategory, id=category_id)
products = Product.objects.filter(active=True).filter(category=category) products = Product.objects.filter(active=True) \
.filter(category=category)
categories = ProductCategory.objects.all() categories = ProductCategory.objects.all()
return render(request, 'cashonly/product_list.html', { 'product_list': products, return render(request, 'cashonly/product_list.html',
'category': category, {'product_list': products, 'category': category,
'categories': categories}) 'categories': categories})
@login_required @login_required
def buy(request, product_id, confirm=False): def buy(request, product_id, confirm=False):
product = get_object_or_404(Product, id=product_id) product = get_object_or_404(Product, id=product_id)
@ -80,20 +89,25 @@ def buy(request, product_id, confirm=False):
else: else:
return redirect('buy_error') return redirect('buy_error')
else: else:
return render(request, 'cashonly/buy_confirm.html', {'product': product}) return render(request, 'cashonly/buy_confirm.html',
{'product': product})
@login_required @login_required
def buy_thanks(request): def buy_thanks(request):
return render(request, 'cashonly/buy_thanks.html') return render(request, 'cashonly/buy_thanks.html')
@login_required @login_required
def buy_error(request): def buy_error(request):
return render(request, 'cashonly/buy_error.html') return render(request, 'cashonly/buy_error.html')
class UserSettingsForm(forms.Form): class UserSettingsForm(forms.Form):
daily_digest = forms.BooleanField(required=False, daily_digest = forms.BooleanField(required=False,
label=ugettext_lazy('daily digest')) label=ugettext_lazy('daily digest'))
class UserPinForm(forms.Form): class UserPinForm(forms.Form):
pin = forms.CharField(max_length=32, widget=forms.PasswordInput, pin = forms.CharField(max_length=32, widget=forms.PasswordInput,
label=ugettext_lazy('PIN'), required=False) label=ugettext_lazy('PIN'), required=False)
@ -104,14 +118,14 @@ class UserPinForm(forms.Form):
def clean(self): def clean(self):
cleaned_data = super(UserPinForm, self).clean() cleaned_data = super(UserPinForm, self).clean()
if not (cleaned_data.has_key('pin') or if 'pin' not in cleaned_data and 'pin_confirm' not in cleaned_data:
cleaned_data.has_key('pin_confirm')):
return cleaned_data return cleaned_data
if cleaned_data['pin'] != cleaned_data['pin_confirm']: if cleaned_data['pin'] != cleaned_data['pin_confirm']:
raise forms.ValidationError(_('PINs do not match.')) raise forms.ValidationError(_('PINs do not match.'))
return cleaned_data return cleaned_data
@login_required @login_required
def usersettings(request, submit=None): def usersettings(request, submit=None):
daily_digest = request.user.account.daily_digest daily_digest = request.user.account.daily_digest
@ -137,10 +151,5 @@ def usersettings(request, submit=None):
request.user.account.save() request.user.account.save()
return render(request, 'cashonly/usersettings_saved.html') return render(request, 'cashonly/usersettings_saved.html')
return render(request, 'cashonly/usersettings.html', { 'settings_form': settings_form, return render(request, 'cashonly/usersettings.html',
'pin_form': pin_form}) {'settings_form': settings_form, 'pin_form': pin_form})

Loading…
Cancel
Save