From e9c5a5c21332247ff9fe5f409ea3a4209c2fc25f Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Mon, 2 Feb 2026 16:18:44 +0000 Subject: [PATCH] improving pos --- .../context_processors.cpython-311.pyc | Bin 1331 -> 1419 bytes core/__pycache__/models.cpython-311.pyc | Bin 25636 -> 25783 bytes core/__pycache__/urls.cpython-311.pyc | Bin 7245 -> 7499 bytes core/__pycache__/views.cpython-311.pyc | Bin 67560 -> 74351 bytes core/context_processors.py | 7 +- .../0012_systemsetting_decimal_places.py | 18 + ...stemsetting_decimal_places.cpython-311.pyc | Bin 0 -> 919 bytes core/models.py | 3 +- core/templates/core/customers.html | 167 ++-- core/templates/core/inventory.html | 716 ++++-------------- core/templates/core/pos.html | 220 ++++-- core/templates/core/settings.html | 136 +++- core/templates/core/suppliers.html | 154 ++-- core/templates/core/users.html | 408 ++++++++-- core/urls.py | 4 +- core/views.py | 141 +++- 16 files changed, 1037 insertions(+), 937 deletions(-) create mode 100644 core/migrations/0012_systemsetting_decimal_places.py create mode 100644 core/migrations/__pycache__/0012_systemsetting_decimal_places.cpython-311.pyc diff --git a/core/__pycache__/context_processors.cpython-311.pyc b/core/__pycache__/context_processors.cpython-311.pyc index 268182e70b629d4e59130fb4250ed8130189f5d2..98f88ae80a8d0a8e959405b6b480b55ebe1ca3d1 100644 GIT binary patch delta 313 zcmdnY)y>VjoR^o20SK7RHe?>!$oqwfanocb=H~hu#u~;V_8P`47LY6mAYl@h$fJq^#8BlHyyeX_-aECAZj;i&7IyQdz-@CSPFI z7m)@k69MAlVj$7L@PUbwRdup3i-FGrS=Aesju+%SW@KEEGrb^ZdZ6$FE3*LC2L=ei z$@Sv{2P3QM4FQD(iWm4*E^t86j~_pZd4PsBIdVJlF&yM$a}=9gz@p74J$Vj`6r;lA T?JNm0T#Tw87%+(Ok;t(Lw!0>^Ija6u} z4~v2B4FUND5*PTjE^ui5_`t--Ds+Qiu!9o>fBg7S%mY;2id-;*ru^iW(bL7N_*_zxGjkJj6asP*lT(X}Y=D*& zxlFE&*~ln8SwB{4^5qb*$?>u73b!N!@{2P|GRsnffy#3{^GZ_FQ;Xa(Q*%;^?17pl zFN^hOY?}Nn_O6ns>4dN=qNW=XHzZ!L@VIE^dBx20LU70h(a?*cp;tsh8~iq3imPU1 hl-TT-Fqheqmr>~h112%SZHmuFkoXrYl0_0gD*@j9WVQeR delta 239 zcmdmfl5xoiM!w~|yj%=GptPVNbC2alzLSwmJWP`(iW+R@jPhgTNnuN2TO+oNg@Iu; z%VfD=iOJ`gStr*-3k$8`TE+|%1Y!t?5}bUHS=dl=86!{>h#??F0;nBbrBI4g3qzD} zigYl8rp#pdnCX)*#H?eKnp__%#V9iQy_o#uow2r)#p3)K<0q%Z-QAoPU&Y8MzWHIo dTxLriMx_r7n8XCPDLx-T;$N^x7D)gd0|0fdJWv1t diff --git a/core/__pycache__/urls.cpython-311.pyc b/core/__pycache__/urls.cpython-311.pyc index f373a8fb147388f79b30797478db9b7c70767569..09e0de8dca1f6e6893a69642bce0fe1a1648cb25 100644 GIT binary patch delta 1033 zcmYk5-Ahwp9LIO&v$+>^m^+*29Ca$moVA3o2%R*YGpF;Vt(s`MMw?S}Dsw9}(iI3% z1lrSu1ko;{MtMbsx^& zNB*P(Gt9QhuY<3(X|iMmZ$3=;_gm@RJ}JQXG{uGz+3(l}QG= ziDa4FgkvOji^&>Yv(97_{t`sv789=)Iz++HtEJoZL9Zx|`Iz);OCQ;q&thjc>I)$d zmO&VUu;OQtfpVlVuft89sCyWJpbUZ-1eFUcGN^?Q?V=&TY!n`fqG625IQ&86B9job zNRlzks@`wBdQ_Cvg delta 1042 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 @w{4CBm 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 delta 15531 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 E1#;)Ch5!Hn diff --git a/core/context_processors.py b/core/context_processors.py index 33b1942..5ce8c85 100644 --- a/core/context_processors.py +++ b/core/context_processors.py @@ -22,6 +22,9 @@ def global_settings(request): settings = SystemSetting.objects.first() if not settings: settings = SystemSetting.objects.create() - return {'site_settings': settings} + return { + 'site_settings': settings, + 'decimal_places': settings.decimal_places if settings else 3 + } except: - return {} \ No newline at end of file + return {'decimal_places': 3} \ No newline at end of file diff --git a/core/migrations/0012_systemsetting_decimal_places.py b/core/migrations/0012_systemsetting_decimal_places.py new file mode 100644 index 0000000..8a2c11a --- /dev/null +++ b/core/migrations/0012_systemsetting_decimal_places.py @@ -0,0 +1,18 @@ +# Generated by Django 5.2.7 on 2026-02-02 16:12 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0011_paymentmethod_purchasepayment_payment_method_name_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='systemsetting', + name='decimal_places', + field=models.PositiveSmallIntegerField(default=3, verbose_name='Decimal Places'), + ), + ] diff --git a/core/migrations/__pycache__/0012_systemsetting_decimal_places.cpython-311.pyc b/core/migrations/__pycache__/0012_systemsetting_decimal_places.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4e228af4ec2a6c05811510824f035203e67f946f GIT binary patch literal 919 zcmZuwO>fgc5Z$#M$FY(MA|xpE01~RmrEYSrKu8G0S5>JMNFmb7@lF#5f8n(Y<&*;l zj=l9C6e0Qp_z@h6ltbkM960snsy+3@tP>YiW!E0Rnc1Cr`&RzaXqW`YuODOgHznkc zbjnegfs+*kyMz-?J>t_Y^_8wdi9((bu6!a~1v*m8O?!yGoqJuCYwM&{Ig;s?l9|3c zi0#A;1Ci-|$iWj%xl?|PnRC)ZuuFh+DJNZp(*f}?-{#D`=Uau%hrGqeTFqGguN z(t+&*vjfh2S)d`dMFPHnByod5HpjtnecNM^XFDK{q%I%l9!-O{*NPxEuX5P5Q!mNt zTM+j{0ZdkHsVJ9}sPHmP#F!aGn`)QD* z7JL9FO~TlEAI5J*geSD5iq^k7wouOwyPyfXD9KW^9qU-SFcOH@XvXI=*GX-I=Bjc{ zAHT>=Qd{_JPK;ZJ*B1}3-Z^Y`b`~ei&iD4g^EU_0-p^)l((L6`t!5q*G^f(!s@~Mc z&*Y5f%TB8;Evxa79Sp)H-Y=9X^q6wFA(s_vZz4J~R;Kdaj~CFzzl4ZaXmXWOiu`En cfZV(M
- +
@@ -65,89 +65,6 @@ - - - - - - - {% empty %} - - - {% endfor %}
{% trans "Name" %}
- -

{% trans "No customers found." %}

-
@@ -164,32 +81,68 @@
-
- {% csrf_token %} -
+{% endblock %} + +{% block scripts %} + {% endblock %} \ No newline at end of file diff --git a/core/templates/core/inventory.html b/core/templates/core/inventory.html index 126e0af..8f20e80 100644 --- a/core/templates/core/inventory.html +++ b/core/templates/core/inventory.html @@ -92,7 +92,7 @@
- +
@@ -153,184 +153,6 @@ - - - - - - {% empty %}
{% trans "Item" %}
@@ -349,7 +171,7 @@
- +
@@ -375,37 +197,6 @@ - - - {% empty %} @@ -421,7 +212,7 @@
-
{% trans "Category Name" %}
{% trans "No categories found." %}
+
@@ -447,40 +238,6 @@ - - - {% empty %} @@ -494,6 +251,70 @@ + + + + + + + +
{% trans "Unit Name" %}
{% trans "No units found." %}
+
@@ -159,7 +164,7 @@ {% for pm in payment_methods %} - + -
{% trans "Name (EN)" %}
{{ pm.name_en }} {{ pm.name_ar }} @@ -236,7 +241,7 @@ {% empty %}
+
{% trans "No payment methods found." %} @@ -256,39 +261,37 @@
+ + + + + + + + + {% endblock %} + +{% block scripts %} + +{% endblock %} \ No newline at end of file diff --git a/core/urls.py b/core/urls.py index 2770656..f0f72a4 100644 --- a/core/urls.py +++ b/core/urls.py @@ -55,6 +55,7 @@ urlpatterns = [ path('customers/add/', views.add_customer, name='add_customer'), path('customers/edit//', views.edit_customer, name='edit_customer'), path('customers/delete//', views.delete_customer, name='delete_customer'), + path('api/add-customer-ajax/', views.add_customer_ajax, name='add_customer_ajax'), # Suppliers path('suppliers/add/', views.add_supplier, name='add_supplier'), @@ -86,4 +87,5 @@ urlpatterns = [ path('settings/payment-methods/add/', views.add_payment_method, name='add_payment_method'), path('settings/payment-methods/edit//', views.edit_payment_method, name='edit_payment_method'), path('settings/payment-methods/delete//', views.delete_payment_method, name='delete_payment_method'), -] + path('api/add-payment-method-ajax/', views.add_payment_method_ajax, name='add_payment_method_ajax'), +] \ No newline at end of file diff --git a/core/views.py b/core/views.py index bf82a9d..ca1e637 100644 --- a/core/views.py +++ b/core/views.py @@ -1,3 +1,4 @@ +from django.contrib.auth.models import User, Group, Permission from django.urls import reverse import random import string @@ -74,10 +75,12 @@ def inventory(request): products = Product.objects.all().select_related('category', 'unit', 'supplier') categories = Category.objects.all() suppliers = Supplier.objects.all() + units = Unit.objects.all() context = { 'products': products, 'categories': categories, - 'suppliers': suppliers + 'suppliers': suppliers, + 'units': units } return render(request, 'core/inventory.html', context) @@ -640,7 +643,7 @@ def purchase_return_create(request): purchases = Purchase.objects.all().order_by('-created_at') return render(request, 'core/purchase_return_create.html', { 'products': products, - 'suppliers': suppliers, + 'customers': suppliers, 'purchases': purchases }) @@ -748,6 +751,7 @@ def settings_view(request): settings.email = request.POST.get('email') settings.currency_symbol = request.POST.get('currency_symbol') settings.tax_rate = request.POST.get('tax_rate') + settings.decimal_places = request.POST.get('decimal_places', 3) settings.vat_number = request.POST.get('vat_number') settings.registration_number = request.POST.get('registration_number') @@ -756,7 +760,7 @@ def settings_view(request): settings.save() messages.success(request, "Settings updated successfully!") - return redirect('settings') + return redirect(reverse('settings') + '#profile') payment_methods = PaymentMethod.objects.all() @@ -773,7 +777,7 @@ def add_payment_method(request): is_active = request.POST.get('is_active') == 'on' PaymentMethod.objects.create(name_en=name_en, name_ar=name_ar, is_active=is_active) messages.success(request, "Payment method added successfully!") - return redirect('settings') + return redirect(reverse('settings') + '#payments') @login_required def edit_payment_method(request, pk): @@ -784,14 +788,14 @@ def edit_payment_method(request, pk): pm.is_active = request.POST.get('is_active') == 'on' pm.save() messages.success(request, "Payment method updated successfully!") - return redirect('settings') + return redirect(reverse('settings') + '#payments') @login_required def delete_payment_method(request, pk): pm = get_object_or_404(PaymentMethod, pk=pk) pm.delete() messages.success(request, "Payment method deleted successfully!") - return redirect('settings') + return redirect(reverse('settings') + '#payments') @login_required def add_customer(request): @@ -1165,9 +1169,10 @@ def user_management(request): messages.error(request, "Access denied.") return redirect('index') - from django.contrib.auth.models import User, Group users = User.objects.all().prefetch_related('groups') - groups = Group.objects.all() + groups = Group.objects.all().prefetch_related('permissions') + # Filter for relevant permissions (core and auth) + permissions = Permission.objects.select_related('content_type').all().order_by('content_type__app_label', 'codename') if request.method == 'POST': action = request.POST.get('action') @@ -1175,19 +1180,62 @@ def user_management(request): username = request.POST.get('username') password = request.POST.get('password') email = request.POST.get('email') - group_id = request.POST.get('group') + group_ids = request.POST.getlist('groups') if User.objects.filter(username=username).exists(): messages.error(request, "Username already exists.") else: user = User.objects.create_user(username=username, email=email, password=password) - if group_id: - group = Group.objects.get(id=group_id) - user.groups.add(group) + if group_ids: + selected_groups = Group.objects.filter(id__in=group_ids) + user.groups.set(selected_groups) user.is_staff = True user.save() messages.success(request, f"User {username} created successfully.") + elif action == 'edit_user': + user_id = request.POST.get('user_id') + user = get_object_or_404(User, id=user_id) + user.email = request.POST.get('email') + group_ids = request.POST.getlist('groups') + selected_groups = Group.objects.filter(id__in=group_ids) + user.groups.set(selected_groups) + + password = request.POST.get('password') + if password: + user.set_password(password) + + user.save() + messages.success(request, f"User {user.username} updated.") + + elif action == 'add_group': + name = request.POST.get('name') + permission_ids = request.POST.getlist('permissions') + if Group.objects.filter(name=name).exists(): + messages.error(request, "Group name already exists.") + else: + group = Group.objects.create(name=name) + if permission_ids: + perms = Permission.objects.filter(id__in=permission_ids) + group.permissions.set(perms) + messages.success(request, f"Group {name} created successfully.") + + elif action == 'edit_group': + group_id = request.POST.get('group_id') + group = get_object_or_404(Group, id=group_id) + group.name = request.POST.get('name') + permission_ids = request.POST.getlist('permissions') + perms = Permission.objects.filter(id__in=permission_ids) + group.permissions.set(perms) + group.save() + messages.success(request, f"Group {group.name} updated.") + + elif action == 'delete_group': + group_id = request.POST.get('group_id') + group = get_object_or_404(Group, id=group_id) + group.delete() + messages.success(request, "Group deleted.") + elif action == 'toggle_status': user_id = request.POST.get('user_id') user = get_object_or_404(User, id=user_id) @@ -1198,6 +1246,71 @@ def user_management(request): user.save() messages.success(request, f"User {user.username} status updated.") - return redirect('user_management') + # Determine redirect hash based on action + target_hash = "" + if action in ['add_group', 'edit_group', 'delete_group']: + target_hash = "#groups" - return render(request, 'core/users.html', {'users': users, 'groups': groups}) \ No newline at end of file + return redirect(reverse('user_management') + target_hash) + + return render(request, 'core/users.html', { + 'users': users, + 'groups': groups, + 'permissions': permissions + }) + +@login_required +def group_details_api(request, pk): + group = get_object_or_404(Group, pk=pk) + permissions = group.permissions.all().values_list('id', flat=True) + return JsonResponse({ + 'id': group.id, + 'name': group.name, + 'permissions': list(permissions) + }) + +@csrf_exempt +@login_required +def add_payment_method_ajax(request): + if request.method == 'POST': + try: + data = json.loads(request.body) + name_en = data.get('name_en') + name_ar = data.get('name_ar') + is_active = data.get('is_active', True) + if not name_en or not name_ar: + return JsonResponse({'success': False, 'error': 'Missing names'}, status=400) + + pm = PaymentMethod.objects.create(name_en=name_en, name_ar=name_ar, is_active=is_active) + return JsonResponse({ + 'success': True, + 'id': pm.id, + 'name_en': pm.name_en, + 'name_ar': pm.name_ar + }) + except Exception as e: + return JsonResponse({'success': False, 'error': str(e)}, status=400) + return JsonResponse({'success': False, 'error': 'Invalid request'}, status=405) + +@csrf_exempt +@login_required +def add_customer_ajax(request): + if request.method == 'POST': + try: + data = json.loads(request.body) + name = data.get('name') + phone = data.get('phone', '') + email = data.get('email', '') + address = data.get('address', '') + if not name: + return JsonResponse({'success': False, 'error': 'Missing name'}, status=400) + + customer = Customer.objects.create(name=name, phone=phone, email=email, address=address) + return JsonResponse({ + 'success': True, + 'id': customer.id, + 'name': customer.name + }) + except Exception as e: + return JsonResponse({'success': False, 'error': str(e)}, status=400) + return JsonResponse({'success': False, 'error': 'Invalid request'}, status=405)