diff --git a/.gitignore b/.gitignore index cae5b69..645a4b3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ env/ +venv/ collected_static/ prod.py .tox/ diff --git a/p0sx/settings/base.py b/p0sx/settings/base.py index 32845c6..247d9f3 100755 --- a/p0sx/settings/base.py +++ b/p0sx/settings/base.py @@ -129,3 +129,5 @@ MEDIA_ROOT = os.path.join(BASE_DIR, '..', 'media') MEDIA_URL = '/media/' + +LOGIN_REDIRECT_URL = '/littleadmin/scan_user_card' diff --git a/p0sx/urls.py b/p0sx/urls.py index c129baa..f78654a 100644 --- a/p0sx/urls.py +++ b/p0sx/urls.py @@ -4,8 +4,16 @@ from django.contrib import admin from django.core.urlresolvers import reverse_lazy from django.views.generic.base import RedirectView +from django.contrib.auth import views as auth_views -from pos.views.littleadmin import check_credit, credit_edit, credit_overview, crew_report, sale_overview +from pos.views.littleadmin import (add_user, + check_credit, + credit_edit, + credit_overview, + crew_report, + edit_user_credit, + sale_overview, + scan_user_card) from pos.views.shift import AllShiftsViewSet, CurrentShiftViewSet, NewShiftViewSet, ShiftViewSet from pos.views.stock import (CategoryViewSet, CreditCheckViewSet, @@ -27,9 +35,12 @@ url(r'^$', RedirectView.as_view(url=reverse_lazy('littleadmin:overview'))), url(r'check/', check_credit, name='check'), url(r'overview/', credit_overview, name='overview'), - url(r'edit/(?P\w+)', credit_edit, name='edit'), + url(r'edit_crew_credit/(?P\w+)', credit_edit, name='edit_crew_credit'), url(r'sale/', include(sale_url, namespace='sale')), - url(r'crew_report/', crew_report, name='crew_report') + url(r'crew_report/', crew_report, name='crew_report'), + url(r'scan_user_card', scan_user_card, name='scan_user_card'), + url(r'edit_user_credit/(?P\w+)', edit_user_credit, name='edit_user_credit'), + url(r'add_user/(?P\w+)', add_user, name='add_user') ] # Routers provide an easy way of automatically determining the URL conf. @@ -48,8 +59,11 @@ router.register(r'purchases', PurchaseViewSet, 'purchase') router.register(r'credit', CreditCheckViewSet, 'credit') router.register(r'discounts', DiscountViewSet, 'discount') + urlpatterns = [ url(r'^$', RedirectView.as_view(url=reverse_lazy('admin:index'))), + url(r'^login/$', auth_views.login, {'template_name': 'pos/login.djhtml'}, name='login'), + url(r'^logout/$', auth_views.logout, {'next_page': '/login'}, name='logout'), url(r'^admin/', include(admin.site.urls)), url(r'^', include(router.urls)), url(r'littleadmin/', include(littleadmin_url, namespace='littleadmin')) diff --git a/pos/forms.py b/pos/forms.py index 6fbe199..84510ac 100644 --- a/pos/forms.py +++ b/pos/forms.py @@ -4,7 +4,11 @@ class CheckCreditForm(forms.Form): - card = forms.CharField(max_length=100, widget=forms.PasswordInput()) + card = forms.CharField(max_length=100, widget=forms.PasswordInput(attrs={'autofocus': 'autofocus'})) + + +class AddCreditForm(forms.Form): + credit = forms.CharField(widget=forms.NumberInput(attrs={'autofocus': 'autofocus'})) class ChangeCreditForm(forms.ModelForm): @@ -12,3 +16,17 @@ class ChangeCreditForm(forms.ModelForm): class Meta: model = User fields = ['credit'] + widgets = { + 'credit': forms.NumberInput(attrs={'autofocus': 'autofocus'}) + } + + +class AddUserForm(forms.ModelForm): + + class Meta: + model = User + fields = ['first_name', 'last_name', 'phone', 'email', 'credit', 'card'] + widgets = { + 'card': forms.PasswordInput(render_value=True), + 'first_name': forms.TextInput(attrs={'autofocus': 'autofocus'}) + } diff --git a/pos/management/commands/import-ge-crew.py b/pos/management/commands/import-ge-crew.py index 471a2ef..1e79479 100644 --- a/pos/management/commands/import-ge-crew.py +++ b/pos/management/commands/import-ge-crew.py @@ -44,7 +44,8 @@ def handle(self, *args, **options): crew=data['crew'], role=data['role'], email=data['email'], - credit=0 + credit=0, + is_crew=True ) crew.save() # print('Added new user {} {}'.format(data['first_name'], data['last_name'])) diff --git a/pos/migrations/0006_auto_20180925_2035.py b/pos/migrations/0006_auto_20180925_2035.py new file mode 100644 index 0000000..c5f04fd --- /dev/null +++ b/pos/migrations/0006_auto_20180925_2035.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.8 on 2018-09-25 18:35 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('pos', '0005_auto_20170902_1225'), + ] + + operations = [ + migrations.AlterModelOptions( + name='category', + options={'verbose_name_plural': 'Categories'}, + ), + migrations.AlterModelOptions( + name='user', + options={'permissions': (("update_credit", "Can update the credit limit on a user"),)}, + ), + ] diff --git a/pos/migrations/0007_user_is_crew.py b/pos/migrations/0007_user_is_crew.py new file mode 100644 index 0000000..765007f --- /dev/null +++ b/pos/migrations/0007_user_is_crew.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.8 on 2018-09-25 18:49 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('pos', '0006_auto_20180925_2035'), + ] + + operations = [ + migrations.AddField( + model_name='user', + name='is_crew', + field=models.BooleanField(default=False), + ), + ] diff --git a/pos/models/stock.py b/pos/models/stock.py index d9d33ab..a18f0ab 100644 --- a/pos/models/stock.py +++ b/pos/models/stock.py @@ -80,14 +80,17 @@ class Order(models.Model): def __str__(self): return str(self.user) + ' ' + self.date.strftime('%Y-%m-%d %H:%M:%S') + @property + def info(self): + return f"{self.sum} {self.date:%Y-%m-%d %H:%M:%S}" + @classmethod def create(cls, user, cashier, authenticated_user, payment_method, message): order = cls(user=user, cashier=cashier, authenticated_user=authenticated_user, payment_method=payment_method, - message=message - ) + message=message) return order diff --git a/pos/models/user.py b/pos/models/user.py index 2133418..dc6e5ce 100644 --- a/pos/models/user.py +++ b/pos/models/user.py @@ -15,6 +15,7 @@ class User(models.Model): role = models.CharField(max_length=255) email = models.EmailField() is_cashier = models.BooleanField(default=False) + is_crew = models.BooleanField(default=False) @property def used(self): @@ -25,9 +26,25 @@ def used(self): def left(self): return self.credit - self.used + @classmethod + def create(cls, card, credit, first_name, last_name, phone, email): + user = cls(card=card, + credit=credit, + first_name=first_name, + last_name=last_name, + phone=phone, + email=email) + + return user + def __str__(self): return '{} {}'.format(self.first_name, self.last_name) + class Meta: + permissions = ( + ("update_credit", "Can update the credit limit on a user"), + ) + class UserSession(models.Model): start = models.DateTimeField(auto_now_add=True) diff --git a/pos/views/littleadmin.py b/pos/views/littleadmin.py index e63cf69..2037b04 100644 --- a/pos/views/littleadmin.py +++ b/pos/views/littleadmin.py @@ -1,12 +1,13 @@ -from django.contrib.auth.decorators import login_required +from django.contrib.auth.decorators import login_required, permission_required from django.db.models import Case, IntegerField, Sum, When from django.http import HttpResponseRedirect -from django.shortcuts import get_object_or_404, render +from django.shortcuts import get_object_or_404, render, redirect from django.urls import reverse_lazy +from django.contrib import messages -from ..forms import ChangeCreditForm, CheckCreditForm +from ..forms import AddCreditForm, AddUserForm, ChangeCreditForm, CheckCreditForm from ..models.shift import Shift -from ..models.stock import Item, OrderLine +from ..models.stock import Item, OrderLine, Order from ..models.user import User from ..serializers.shift import ShiftSerializer @@ -17,14 +18,16 @@ def check_credit(request): if form.is_valid(): card = form.cleaned_data['card'] - user = User.objects.filter(card=card) if not user: return HttpResponseRedirect(reverse_lazy('littleadmin:check')) + orders = Order.objects.filter(user_id=user.id).order_by('date')[0:3] + return render(request, 'pos/credit_check.djhtml', { 'form': CheckCreditForm(), + 'orders': [o.info for o in orders], 'table': True, 'used': user[0].used, 'credit': user[0].credit, @@ -43,7 +46,6 @@ def check_credit(request): def credit_overview(request): bought = OrderLine.objects.all().exclude(order__user__isnull=True).values('order__user').annotate(used=Sum('price')) users = User.objects.all().values() - print(bought) for user in users: for b in bought: user['used'] = 0 @@ -131,5 +133,90 @@ def sale_overview(request): total['total'] += item['total'] shifts = ShiftSerializer(Shift.objects.all(), many=True) - print(shifts.data) return render(request, 'pos/sale_overview.djhtml', {'overview': overview, 'shifts': shifts.data, 'total': total}) + + +@permission_required("pos.update_credit") +def scan_user_card(request): + if request.POST: + form = CheckCreditForm(request.POST) + + if form.is_valid(): + card = form.cleaned_data['card'] + + user = User.objects.filter(card=card) + + if not user: + return redirect('littleadmin:add_user', card=card) + + return redirect('littleadmin:edit_user_credit', card=card) + else: + return HttpResponseRedirect(reverse_lazy('littleadmin:scan_user_card')) + else: + return render(request, 'pos/scan_card.djhtml', { + 'form': CheckCreditForm(), + 'table': False, + }) + + +@permission_required('pos.update_credit') +def edit_user_credit(request, card=None): + if request.POST: + form = AddCreditForm(request.POST) + if form.is_valid(): + credit = form.cleaned_data['credit'] + user = get_object_or_404(User, card=card) + + if user.is_crew: + messages.error(request, "You cannot change the credit of Crew") + return redirect('littleadmin:scan_user_card') + + user.credit = user.credit + credit + user.save() + messages.success(request, "Credit updated successfully") + return redirect('littleadmin:scan_user_card') + else: + user = get_object_or_404(User, card=card) + + if user.is_crew: + messages.error(request, "You cannot change the credit of Crew") + return redirect('littleadmin:scan_user_card') + + form = AddCreditForm() + + return render(request, 'pos/add_credit.djhtml', {'form': form, 'target': user}) + + +@permission_required('pos.update_credit') +def add_user(request, card=None): + if request.POST: + form = AddUserForm(request.POST) + + if form.is_valid(): + card = form.cleaned_data['card'] + credit = form.cleaned_data['credit'] + first_name = form.cleaned_data['first_name'] + last_name = form.cleaned_data['last_name'] + phone = form.cleaned_data['phone'] + email = form.cleaned_data['email'] + + user = User.create(card, credit, first_name, last_name, phone, email) + + user.save() + messages.success(request, "User added successfully") + return redirect('littleadmin:scan_user_card') + else: + messages.error(request, "Failed to add user") + return HttpResponseRedirect(reverse_lazy('littleadmin:add_user')) + else: + form = AddUserForm(initial={'card': card}) + return render(request, 'pos/add_user.djhtml', { + 'form': form + }) + + + + + + + diff --git a/templates/base.djhtml b/templates/base.djhtml index c2a87ad..c539c54 100644 --- a/templates/base.djhtml +++ b/templates/base.djhtml @@ -4,12 +4,11 @@ - - + + - - + {% block script%} {% endblock script %} @@ -30,34 +29,39 @@ - {% if user.is_authenticated %} + {% if messages %} + + {% endif %} - {% endif %}
{% block content %}{% endblock content %}
-