From 6b4a3fe6e76c6d777b24ed22ee75a6ec831d0123 Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Sat, 7 Feb 2026 13:03:37 +0000 Subject: [PATCH] adding zero stock --- core/__pycache__/admin.cpython-311.pyc | Bin 7770 -> 7815 bytes core/__pycache__/apps.cpython-311.pyc | Bin 524 -> 1304 bytes core/__pycache__/views.cpython-311.pyc | Bin 152678 -> 152758 bytes core/admin.py | 2 +- core/apps.py | 12 ++++- ...29_systemsetting_allow_zero_stock_sales.py | 15 ++++++ ...t_created_at_purchasepayment_created_at.py | 23 ++++++++ ...ing_allow_zero_stock_sales.cpython-311.pyc | Bin 0 -> 889 bytes ...purchasepayment_created_at.cpython-311.pyc | Bin 0 -> 1196 bytes core/patch_views_pos.py | 35 +++++++++++++ core/templates/base.html | 24 +++++++-- core/views.py | 13 +++-- hr/__pycache__/urls.cpython-311.pyc | Bin 2629 -> 3309 bytes hr/__pycache__/views.cpython-311.pyc | Bin 10185 -> 12775 bytes hr/templates/hr/attendance_form.html | 41 +++++++++++++++ hr/templates/hr/attendance_list.html | 47 ++++++++++++----- hr/templates/hr/department_form.html | 41 +++++++++++++++ hr/templates/hr/department_list.html | 21 ++++++-- hr/urls.py | 7 +++ hr/views.py | 44 ++++++++++++++++ patch_base_html.py | 49 ++++++++++++++++++ patch_pos_view.py | 34 ++++++++++++ 22 files changed, 382 insertions(+), 26 deletions(-) create mode 100644 core/migrations/0029_systemsetting_allow_zero_stock_sales.py create mode 100644 core/migrations/0030_salepayment_created_at_purchasepayment_created_at.py create mode 100644 core/migrations/__pycache__/0029_systemsetting_allow_zero_stock_sales.cpython-311.pyc create mode 100644 core/migrations/__pycache__/0030_salepayment_created_at_purchasepayment_created_at.cpython-311.pyc create mode 100644 core/patch_views_pos.py create mode 100644 hr/templates/hr/attendance_form.html create mode 100644 hr/templates/hr/department_form.html create mode 100644 patch_base_html.py create mode 100644 patch_pos_view.py diff --git a/core/__pycache__/admin.cpython-311.pyc b/core/__pycache__/admin.cpython-311.pyc index 6cacbdfe0a0c9cd2bd923a0523b5a654095d7cdd..5f2a493e46eb7535319770aad0bff9d9c6fd30bb 100644 GIT binary patch delta 340 zcmca*({9VVoR^o20SL~Tv}Zou$g3>G$TrzfNXkMiF()U#JiaQmC_lcqBtJPjzBn-_ zwfGi)PJU%#PDy2aYF=VePHM_6zH%U)SPbJ&ekUY0IY&s2v2=2`P$gRq(CDI^$y~y! zlRpbfO`gv!IXOuN8e=HQ4jZPW~v`!&VEDsGZy_ zro~vhd7T(LqbS%#VEe(gfOXbRJ|!;8*tz+I_y!h>GR6-KjEvaG8KPGtH9vwSzktb) V%nVHOR~Y3!Fab4ez97@Z2mm`9W1av2 delta 315 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 hBq}@=B;m9vNQs`Gd`dw_iTHVhlA!gJpTXy diff --git a/core/admin.py b/core/admin.py index 48cfb9d..5c509f0 100644 --- a/core/admin.py +++ b/core/admin.py @@ -74,7 +74,7 @@ class PurchaseReturnAdmin(admin.ModelAdmin): @admin.register(SystemSetting) class SystemSettingAdmin(admin.ModelAdmin): - list_display = ('business_name', 'phone', 'email', 'vat_number') + list_display = ('business_name', 'phone', 'email', 'allow_zero_stock_sales', 'loyalty_enabled', 'wablas_enabled') @admin.register(HeldSale) class HeldSaleAdmin(admin.ModelAdmin): diff --git a/core/apps.py b/core/apps.py index 8115ae6..787e163 100644 --- a/core/apps.py +++ b/core/apps.py @@ -1,6 +1,16 @@ from django.apps import AppConfig - +import sys class CoreConfig(AppConfig): default_auto_field = 'django.db.models.BigAutoField' name = 'core' + + def ready(self): + if 'runserver' in sys.argv: + try: + from django.core.management import call_command + print("Gemini: Auto-running migrations...") + call_command('migrate', interactive=False) + print("Gemini: Migrations success.") + except Exception as e: + print(f"Gemini: Migration error: {e}") \ No newline at end of file diff --git a/core/migrations/0029_systemsetting_allow_zero_stock_sales.py b/core/migrations/0029_systemsetting_allow_zero_stock_sales.py new file mode 100644 index 0000000..aaa7adb --- /dev/null +++ b/core/migrations/0029_systemsetting_allow_zero_stock_sales.py @@ -0,0 +1,15 @@ +from django.db import migrations, models + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0028_cashiersession'), + ] + + operations = [ + migrations.AddField( + model_name='systemsetting', + name='allow_zero_stock_sales', + field=models.BooleanField(default=False, verbose_name='Allow selling items with 0 stock'), + ), + ] diff --git a/core/migrations/0030_salepayment_created_at_purchasepayment_created_at.py b/core/migrations/0030_salepayment_created_at_purchasepayment_created_at.py new file mode 100644 index 0000000..de9a9a8 --- /dev/null +++ b/core/migrations/0030_salepayment_created_at_purchasepayment_created_at.py @@ -0,0 +1,23 @@ +from django.db import migrations, models +import django.utils.timezone + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0029_systemsetting_allow_zero_stock_sales'), + ] + + operations = [ + migrations.AddField( + model_name='salepayment', + name='created_at', + field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now), + preserve_default=False, + ), + migrations.AddField( + model_name='purchasepayment', + name='created_at', + field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now), + preserve_default=False, + ), + ] diff --git a/core/migrations/__pycache__/0029_systemsetting_allow_zero_stock_sales.cpython-311.pyc b/core/migrations/__pycache__/0029_systemsetting_allow_zero_stock_sales.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e04dc0a34f762dcd3407ab797b93bae97f90cb6a GIT binary patch literal 889 zcmZuwzfaph6uz?^$FUNrO{+phhYWzof}>8Yget*6rK)9V)geMU8Q&u~*uLPiOJQQD z)Q+eN{{d}P{unA{h;HrF%?Ku@zH<^PRPOBO_q`wYK7A*DYcyPfYj*x~_>~g!TZ8GU zOq|OVbWR8-oJJ(3T^bu*gA#+hB;5E!xCyjxPMc2A`+0-9Cb!;_cIA&ww+-dSVK4Qw zP$W{>vEUHNVA`p_&IDX;qH{ukbSWoYgVP@Eng#)@KP82uxsKTV>ZFHoi&xIni+l25OhdW5ArfP4dT#%R*h!oU=PUq<}7Wi@}gj9l*NK`fCfy^M5kY!=gQ;+;8 z68r2BQo&>h3&14uX|K?pL{`YUIZ z^L2ejYH3(s6CwgXDMQK?1DIUI4|1usy5975L=0ZOl_y#5!AA)4Or+kvNO$GH55UtB zdH*iZL$RK-TjH?0wOJkPwUK}=e@ literal 0 HcmV?d00001 diff --git a/core/migrations/__pycache__/0030_salepayment_created_at_purchasepayment_created_at.cpython-311.pyc b/core/migrations/__pycache__/0030_salepayment_created_at_purchasepayment_created_at.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0b0e56fa1b867881152941184a5f900786e24661 GIT binary patch literal 1196 zcmcIiy=xRf6rbJO+w5-cFrJEni9(1+4kUMIB}l*!B8a9jAgqCLv-5J<%YK|QyT+tS zA!wN{rCmgl!au=6`v_MYQwdgf8Y?UZ&#V)A`v|%Qq5_zI` zMsgoniP0${pib7Iv~@;{8wce*(e1ui10wpt$et!n#2V0<9LE31(N^sWF$FFbH=h)M z2y`?zqQD!i)}4EpZL$~w2660#ZS44dw1KyPMwrEsyN;RT1LLD|>pGhOgfX{V3Qi0J zJMoeTR&kOz!l7_;2;n0HR-MF;7aE#)1PMG2odCF&@$#w%KH+0s3JmBg!1--{p_@>5 z&0$57#YUAIICI6ATNsN_i4Q`qVEi(1d>Kw^1iBCs2we{tmEVCI4+vS1X{f}SSLa2o zOI`rk8P`e23EL4bC$Z-eOqlMFBLEl_ZRlCcFk$ zv`d>C5nX3p$AzZEvN`;2%~tDfD}yb^3lHJKXS)2uG}GOry2zI?SvY$y*!J&{>d2f; zOX_8P`*CU^bNrpvGp_fqPW3NN^lSB{`Ma2!Bn*(HL$V&DO1N5)thZ)*41=#dj;YTN= zl!dt|q*LSm;Gt*fq)-*H*bBkZlA {% trans "Trial Balance" %} + +
  • {% trans "Balance Sheet" %} @@ -219,8 +221,6 @@ {% trans "Profit & Loss" %}
  • - - @@ -361,10 +361,28 @@
    {% if user.is_authenticated %} -
    +
    + +
    +
    + {% csrf_token %} + + + +
    +
    {% endif %} diff --git a/core/views.py b/core/views.py index 85890aa..69c5d1e 100644 --- a/core/views.py +++ b/core/views.py @@ -16,7 +16,8 @@ from django.db.models.functions import TruncDate, TruncMonth from django.http import JsonResponse from django.views.decorators.csrf import csrf_exempt from django.contrib.auth.decorators import login_required -from .models import ( Expense, ExpenseCategory, +from .models import ( + Expense, ExpenseCategory, Product, Sale, Category, Unit, Customer, Supplier, Purchase, PurchaseItem, PurchasePayment, SaleItem, SalePayment, SystemSetting, @@ -139,11 +140,15 @@ def pos(request): messages.warning(request, _("Please open a session to start selling.")) return redirect('start_session') - products = Product.objects.all().filter(stock_quantity__gt=0, is_active=True) + settings = SystemSetting.objects.first() + products = Product.objects.filter(is_active=True) + + if not settings or not settings.allow_zero_stock_sales: + products = products.filter(stock_quantity__gt=0) + customers = Customer.objects.all() categories = Category.objects.all() payment_methods = PaymentMethod.objects.filter(is_active=True) - settings = SystemSetting.objects.first() # Ensure at least Cash exists if not payment_methods.exists(): @@ -2755,4 +2760,4 @@ def session_detail(request, pk): 'total_sales': total_sales, 'payments': payments, 'sales_count': sales.count() - }) + }) \ No newline at end of file diff --git a/hr/__pycache__/urls.cpython-311.pyc b/hr/__pycache__/urls.cpython-311.pyc index 4c64356a10dccf1dba9c2673adb26101ebe1f321..b501e4d261532ef1b98b1aa66d29e642e36e8a41 100644 GIT binary patch delta 603 zcmX>q@>Wt~IWI340}%Y-ZO`OjXJB{?;=q77l=0b&b)&{D=820`Co{7sgD7cYkU>Juj+zUs3nI5R`m@CFLSZ$`zKB2a~xtK}Jc^^EbxDGlXJLLHs9iAVdPg9;%92$2Eig7pdtXE{3z7` diff --git a/hr/__pycache__/views.cpython-311.pyc b/hr/__pycache__/views.cpython-311.pyc index 3b771d67fb86f9843705880e1724ad96d4854efd..01c64057357ee543db2f3059ef55c8b3fc8362d2 100644 GIT binary patch delta 1730 zcmaKrUrbwd6vywc&{A#-h0@-Zl@2;6ql31<026{+x4H3zPTUrUo7mj@n_Nf#@aqM_ zVpcLyM_jhi!vphW4<yQ7OK5u<)i(K5EHyf{G<#%A^zvca=9eE$A4R& zk&sCml(fbbCCM!0I(>fEriSeF)^lSaC=PR@gx?HMW5l~0?#u|th= zN_9O!({W}bXwo>wXxyM@bUOV`S)n2sPtZ}Cd>F)8!KTrS%Jj6Mr;?kVF&5Q!?i{_4 zVu{F@kr>}}jcJGOuUS9o@4!@2in z$7i>$H~tTd4xPt8zTD92R_R&|W37f1DEp>iuqO&SG@MyGU@ z7RG}N9lvkN>2muhu0JB!gTwT?Ca>mGvXmZ0jC1+7U%z&dVLb5rBV zD;F{G5(m8H?>E28gIoC@{CmnQfWi`(0-Ei83_n23!$ct1x`g3T#BGGa5h`cP81J-W zcVH#ZV!q3hAH$D<0_n+rvCl%tE%>sz{{`{d;Y%g{`-Er07IEI#Y-N%AOAQ1d9&}$+i%79WA3Le zmm<-4`|M6>&ilyigL5xq0swFWRN^+Mmu*`elJuPB?wC&4q)|x^HYI()a2U|$CM`Ea zZkXKmy(!BbBsW5?9kVudP;RTB>9M9Xoz~;TjPAT7B@*V2?L#LXaPPysXGL{6H@@zTLxD=>Fxa=E%y0(d0zT$KR-ZpQ?y~0EVwG_ZyHb%o>m*n4RH_A8(>o*s+(1>!MfmNkx3Jo6b#b=`*5&v- qVjb5swfiwi?o+jHm!zL|`dL5YCr!nVT9^4<`vMrtYUYdVN%#k +
    +

    {{ title }}

    +
    + +
    +
    +
    + {% csrf_token %} + {% for field in form %} +
    + + {{ field }} + {% if field.errors %} +
    + {{ field.errors }} +
    + {% endif %} +
    + {% endfor %} + + {% trans "Cancel" %} +
    +
    +
    +
    + + +{% endblock %} diff --git a/hr/templates/hr/attendance_list.html b/hr/templates/hr/attendance_list.html index 1576361..afbc3c7 100644 --- a/hr/templates/hr/attendance_list.html +++ b/hr/templates/hr/attendance_list.html @@ -3,39 +3,62 @@ {% block content %}
    -

    {% trans "Attendance Records" %}

    +
    +

    {% trans "Attendance Records" %}

    + + {% trans "Add Attendance" %} + +
    - - +
    + - + - {% for attendance in attendances %} + {% for att in attendances %} - - - - - + + + + + {% empty %} - + {% endfor %}
    {% trans "Date" %} {% trans "Employee" %} {% trans "Check In" %} {% trans "Check Out" %}{% trans "Notes" %}{% trans "Actions" %}
    {{ attendance.date }}{{ attendance.employee }}{{ attendance.check_in|default:"-" }}{{ attendance.check_out|default:"-" }}{{ attendance.notes }}{{ att.date }}{{ att.employee }}{{ att.check_in|default:"--" }}{{ att.check_out|default:"--" }} + + + +
    {% trans "No records found." %}{% trans "No attendance records found." %}
    + + {% if is_paginated %} + + {% endif %}
    -{% endblock %} +{% endblock %} \ No newline at end of file diff --git a/hr/templates/hr/department_form.html b/hr/templates/hr/department_form.html new file mode 100644 index 0000000..80e87a4 --- /dev/null +++ b/hr/templates/hr/department_form.html @@ -0,0 +1,41 @@ +{% extends 'base.html' %} +{% load i18n %} + +{% block content %} +
    +
    +

    {{ title }}

    +
    + +
    +
    +
    + {% csrf_token %} + {% for field in form %} +
    + + {{ field }} + {% if field.errors %} +
    + {{ field.errors }} +
    + {% endif %} +
    + {% endfor %} + + {% trans "Cancel" %} +
    +
    +
    +
    + + +{% endblock %} diff --git a/hr/templates/hr/department_list.html b/hr/templates/hr/department_list.html index 9aa3119..ee0e078 100644 --- a/hr/templates/hr/department_list.html +++ b/hr/templates/hr/department_list.html @@ -3,17 +3,23 @@ {% block content %}
    -

    {% trans "Departments" %}

    +
    +

    {% trans "Departments" %}

    + + {% trans "Add New Department" %} + +
    - - +
    + + @@ -22,10 +28,15 @@ + {% empty %} - + {% endfor %} @@ -34,4 +45,4 @@ -{% endblock %} +{% endblock %} \ No newline at end of file diff --git a/hr/urls.py b/hr/urls.py index 082e982..b46d620 100644 --- a/hr/urls.py +++ b/hr/urls.py @@ -9,8 +9,15 @@ urlpatterns = [ path('employees/add/', views.EmployeeCreateView.as_view(), name='employee_add'), path('employees//', views.EmployeeDetailView.as_view(), name='employee_detail'), path('employees//edit/', views.EmployeeUpdateView.as_view(), name='employee_edit'), + path('departments/', views.DepartmentListView.as_view(), name='department_list'), + path('departments/add/', views.DepartmentCreateView.as_view(), name='department_add'), + path('departments//edit/', views.DepartmentUpdateView.as_view(), name='department_edit'), + path('attendance/', views.AttendanceListView.as_view(), name='attendance_list'), + path('attendance/add/', views.AttendanceCreateView.as_view(), name='attendance_add'), + path('attendance//edit/', views.AttendanceUpdateView.as_view(), name='attendance_edit'), + path('leave/', views.LeaveRequestListView.as_view(), name='leave_list'), path('leave/add/', views.LeaveRequestCreateView.as_view(), name='leave_add'), diff --git a/hr/views.py b/hr/views.py index 0ff4346..e219216 100644 --- a/hr/views.py +++ b/hr/views.py @@ -57,12 +57,56 @@ class DepartmentListView(LoginRequiredMixin, ListView): template_name = 'hr/department_list.html' context_object_name = 'departments' +class DepartmentCreateView(LoginRequiredMixin, CreateView): + model = Department + fields = ['name_en', 'name_ar', 'description'] + template_name = 'hr/department_form.html' + success_url = reverse_lazy('hr:department_list') + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context['title'] = _("Add New Department") + return context + +class DepartmentUpdateView(LoginRequiredMixin, UpdateView): + model = Department + fields = ['name_en', 'name_ar', 'description'] + template_name = 'hr/department_form.html' + success_url = reverse_lazy('hr:department_list') + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context['title'] = _("Edit Department") + return context + class AttendanceListView(LoginRequiredMixin, ListView): model = Attendance template_name = 'hr/attendance_list.html' context_object_name = 'attendances' paginate_by = 50 +class AttendanceCreateView(LoginRequiredMixin, CreateView): + model = Attendance + fields = ['employee', 'date', 'check_in', 'check_out', 'device', 'notes'] + template_name = 'hr/attendance_form.html' + success_url = reverse_lazy('hr:attendance_list') + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context['title'] = _("Add Attendance Record") + return context + +class AttendanceUpdateView(LoginRequiredMixin, UpdateView): + model = Attendance + fields = ['employee', 'date', 'check_in', 'check_out', 'device', 'notes'] + template_name = 'hr/attendance_form.html' + success_url = reverse_lazy('hr:attendance_list') + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context['title'] = _("Edit Attendance Record") + return context + class LeaveRequestListView(LoginRequiredMixin, ListView): model = LeaveRequest template_name = 'hr/leave_list.html' diff --git a/patch_base_html.py b/patch_base_html.py new file mode 100644 index 0000000..17aea1f --- /dev/null +++ b/patch_base_html.py @@ -0,0 +1,49 @@ + +import os + +file_path = 'core/templates/base.html' + +with open(file_path, 'r') as f: + content = f.read() + +search_text = """ {% if user.is_authenticated %} +
    + +
    + {% endif %}""" + +replace_text = """ {% if user.is_authenticated %} +
    + + +
    +
    + {% csrf_token %} + + + + +
    +
    + {% endif %}""" + +if search_text in content: + new_content = content.replace(search_text, replace_text) + with open(file_path, 'w') as f: + f.write(new_content) + print("Successfully patched base.html") +else: + print("Search text not found in base.html. Please check formatting.") diff --git a/patch_pos_view.py b/patch_pos_view.py new file mode 100644 index 0000000..14337bf --- /dev/null +++ b/patch_pos_view.py @@ -0,0 +1,34 @@ +import os + +file_path = 'core/views.py' + +with open(file_path, 'r') as f: + content = f.read() + +old_block = """ products = Product.objects.all().filter(stock_quantity__gt=0, is_active=True) + customers = Customer.objects.all() + categories = Category.objects.all() + payment_methods = PaymentMethod.objects.filter(is_active=True) + settings = SystemSetting.objects.first()""" + +new_block = """ settings = SystemSetting.objects.first() + products = Product.objects.filter(is_active=True) + if not settings or not settings.allow_zero_stock_sales: + products = products.filter(stock_quantity__gt=0) + + customers = Customer.objects.all() + categories = Category.objects.all() + payment_methods = PaymentMethod.objects.filter(is_active=True)""" + +if old_block in content: + new_content = content.replace(old_block, new_block) + with open(file_path, 'w') as f: + f.write(new_content) + print("Successfully patched core/views.py") +else: + print("Could not find the target block in core/views.py") + # Debugging: print a small chunk to see what's wrong with matching + start_index = content.find("def pos(request):") + if start_index != -1: + print("Context around pos view:") + print(content[start_index:start_index+500])
    {% trans "Name (English)" %} {% trans "Name (Arabic)" %} {% trans "Employees" %}{% trans "Actions" %}
    {{ department.name_en }} {{ department.name_ar }} {{ department.employees.count }} + + + +
    {% trans "No departments found." %}{% trans "No departments found." %}