diff --git a/Aptfile b/Aptfile deleted file mode 100644 index 692b627..0000000 --- a/Aptfile +++ /dev/null @@ -1,7 +0,0 @@ -libglib2.0-0 -libgobject-2.0-0 -libpango-1.0-0 -libpangocairo-1.0-0 -libcairo2 -libharfbuzz0b -libfontconfig1 diff --git a/Procfile b/Procfile deleted file mode 100644 index 8a7bba7..0000000 --- a/Procfile +++ /dev/null @@ -1 +0,0 @@ -web: gunicorn config.wsgi --log-file - diff --git a/append_reports.py b/append_reports.py deleted file mode 100644 index bc69e8f..0000000 --- a/append_reports.py +++ /dev/null @@ -1,24 +0,0 @@ - -import os - -file_path = 'core/views.py' - -missing_reports = r""" - -@login_required -def cashflow_report(request): - return render(request, 'core/cashflow_report.html') - -@login_required -def customer_statement(request): - return render(request, 'core/customer_statement.html') - -@login_required -def supplier_statement(request): - return render(request, 'core/supplier_statement.html') -""" - -with open(file_path, 'a') as f: - f.write(missing_reports) - -print("Appended missing reports to core/views.py") diff --git a/apply_patch.py b/apply_patch.py deleted file mode 100644 index 1412fb5..0000000 --- a/apply_patch.py +++ /dev/null @@ -1,58 +0,0 @@ - -import re - -with open('core/views.py', 'r') as f: - content = f.read() - -with open('core/patch_views_vat.py', 'r') as f: - new_func = f.read() - -# Regex to find the function definition -# It starts with @csrf_exempt\ndef create_sale_api(request): -# And ends before the next function definition (which likely starts with @ or def) -pattern = r"@csrf_exempt\s+def create_sale_api(request):.*?return JsonResponse({'success': False, 'error': 'Invalid request'}, status=405)" - -# Note: The pattern needs to match the indentation and multiline content. -# Since regex for code blocks is tricky, I will use a simpler approach: -# 1. Read the file lines. -# 2. Find start line of create_sale_api. -# 3. Find the end line (start of next function or end of file). -# 4. Replace lines. - -lines = content.splitlines() -start_index = -1 -end_index = -1 - -for i, line in enumerate(lines): - if line.strip() == "def create_sale_api(request):": - # Check if previous line is decorator - if i > 0 and lines[i-1].strip() == "@csrf_exempt": - start_index = i - 1 - else: - start_index = i - break - -if start_index != -1: - # Find the next function or end - # We look for next line starting with 'def ' or '@' at top level - for i in range(start_index + 1, len(lines)): - if lines[i].startswith("def ") or lines[i].startswith("@"): - end_index = i - break - if end_index == -1: - end_index = len(lines) - - # Replace - new_lines = new_func.splitlines() - # Ensure new lines have correct indentation if needed (but views.py is top level mostly) - - # We need to preserve the imports and structure. - # The new_func is complete. - - final_lines = lines[:start_index] + new_lines + lines[end_index:] - - with open('core/views.py', 'w') as f: - f.write('\n'.join(final_lines)) - print("Successfully patched create_sale_api") -else: - print("Could not find create_sale_api function") diff --git a/config/wsgi.py b/config/wsgi.py index 61408cc..ec25885 100644 --- a/config/wsgi.py +++ b/config/wsgi.py @@ -20,21 +20,6 @@ try: except ImportError: pass -# --- WeasyPrint Library Preloading --- -import ctypes -import ctypes.util - -# Try to find and load libraries dynamically to help WeasyPrint on different platforms -libs_to_load = ['glib-2.0', 'gobject-2.0', 'fontconfig', 'cairo', 'pango-1.0', 'pangoft2-1.0'] -for lib_name in libs_to_load: - try: - path = ctypes.util.find_library(lib_name) - if path: - ctypes.CDLL(path) - except Exception: - pass -# ------------------------------------- - os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings') from django.core.wsgi import get_wsgi_application diff --git a/core/__pycache__/forms_import.cpython-311.pyc b/core/__pycache__/forms_import.cpython-311.pyc index 200f5f2..2f953e9 100644 Binary files a/core/__pycache__/forms_import.cpython-311.pyc and b/core/__pycache__/forms_import.cpython-311.pyc differ diff --git a/core/__pycache__/views.cpython-311.pyc b/core/__pycache__/views.cpython-311.pyc index 68a3e28..4e9bdf3 100644 Binary files a/core/__pycache__/views.cpython-311.pyc and b/core/__pycache__/views.cpython-311.pyc differ diff --git a/core/__pycache__/views_import.cpython-311.pyc b/core/__pycache__/views_import.cpython-311.pyc index 2c4af01..0010464 100644 Binary files a/core/__pycache__/views_import.cpython-311.pyc and b/core/__pycache__/views_import.cpython-311.pyc differ diff --git a/core/patch_views.py b/core/patch_views.py deleted file mode 100644 index 4d0eb9e..0000000 --- a/core/patch_views.py +++ /dev/null @@ -1,76 +0,0 @@ -@login_required -def send_invoice_whatsapp(request): - if request.method != 'POST': - return JsonResponse({'success': False, 'error': 'Method not allowed'}) - - try: - # Handle JSON payload - data = json.loads(request.body) - sale_id = data.get('sale_id') - phone = data.get('phone') - pdf_data = data.get('pdf_data') # Base64 string - except json.JSONDecodeError: - # Fallback to Form Data - sale_id = request.POST.get('sale_id') - phone = request.POST.get('phone') - pdf_data = None - - if not sale_id: - return JsonResponse({'success': False, 'error': 'Sale ID missing'}) - - sale = get_object_or_404(Sale, pk=sale_id) - - if not phone: - if sale.customer and sale.customer.phone: - phone = sale.customer.phone - else: - return JsonResponse({'success': False, 'error': 'Phone number missing'}) - - try: - # If PDF data is present, save and send document - if pdf_data: - # Remove header if present (data:application/pdf;base64,) - if ',' in pdf_data: - pdf_data = pdf_data.split(',')[1] - - file_data = base64.b64decode(pdf_data) - dir_path = os.path.join(django_settings.MEDIA_ROOT, 'temp_invoices') - os.makedirs(dir_path, exist_ok=True) - - filename = f"invoice_{sale.id}_{int(timezone.now().timestamp())}.pdf" - file_path = os.path.join(dir_path, filename) - - with open(file_path, 'wb') as f: - f.write(file_data) - - # Construct URL - file_url = request.build_absolute_uri(django_settings.MEDIA_URL + 'temp_invoices/' + filename) - - success, response_msg = send_whatsapp_document(phone, file_url, caption=f"Invoice #{sale.invoice_number or sale.id}") - - else: - # Fallback to Text Link - receipt_url = request.build_absolute_uri(reverse('sale_receipt', args=[sale.pk])) - - message = ( - f"Hello {sale.customer.name if sale.customer else 'Guest'}, -" - f"Here is your invoice #{sale.invoice_number or sale.id}. -" - f"Total: {sale.total_amount} -" - f"View Invoice: {receipt_url} -" - f"Thank you for your business!" - ) - - success, response_msg = send_whatsapp_message(phone, message) - - if success: - return JsonResponse({'success': True, 'message': response_msg}) - else: - return JsonResponse({'success': False, 'error': response_msg}) - - except Exception as e: - logger.error(f"WhatsApp Error: {e}") - return JsonResponse({'success': False, 'error': str(e)}) # Changed to str(e) for clarity diff --git a/core/patch_views_missing.py b/core/patch_views_missing.py deleted file mode 100644 index 8cab7e4..0000000 --- a/core/patch_views_missing.py +++ /dev/null @@ -1,92 +0,0 @@ - -@login_required -def customer_statement(request): - customers = Customer.objects.all().order_by('name') - selected_customer = None - sales = [] - - customer_id = request.GET.get('customer') - start_date = request.GET.get('start_date') - end_date = request.GET.get('end_date') - - if customer_id: - selected_customer = get_object_or_404(Customer, id=customer_id) - sales = Sale.objects.filter(customer=selected_customer).order_by('-created_at') - - if start_date: - sales = sales.filter(created_at__date__gte=start_date) - if end_date: - sales = sales.filter(created_at__date__lte=end_date) - - context = { - 'customers': customers, - 'selected_customer': selected_customer, - 'sales': sales, - 'start_date': start_date, - 'end_date': end_date - } - return render(request, 'core/customer_statement.html', context) - -@login_required -def supplier_statement(request): - suppliers = Supplier.objects.all().order_by('name') - selected_supplier = None - purchases = [] - - supplier_id = request.GET.get('supplier') - start_date = request.GET.get('start_date') - end_date = request.GET.get('end_date') - - if supplier_id: - selected_supplier = get_object_or_404(Supplier, id=supplier_id) - purchases = Purchase.objects.filter(supplier=selected_supplier).order_by('-created_at') - - if start_date: - purchases = purchases.filter(created_at__date__gte=start_date) - if end_date: - purchases = purchases.filter(created_at__date__lte=end_date) - - context = { - 'suppliers': suppliers, - 'selected_supplier': selected_supplier, - 'purchases': purchases, - 'start_date': start_date, - 'end_date': end_date - } - return render(request, 'core/supplier_statement.html', context) - -@login_required -def cashflow_report(request): - # Simplified Cashflow - start_date = request.GET.get('start_date') - end_date = request.GET.get('end_date') - - sales = Sale.objects.all() - expenses = Expense.objects.all() - purchases = Purchase.objects.all() - - if start_date: - sales = sales.filter(created_at__date__gte=start_date) - expenses = expenses.filter(date__gte=start_date) - purchases = purchases.filter(created_at__date__gte=start_date) - - if end_date: - sales = sales.filter(created_at__date__lte=end_date) - expenses = expenses.filter(date__lte=end_date) - purchases = purchases.filter(created_at__date__lte=end_date) - - total_sales = sales.aggregate(total=Sum('total_amount'))['total'] or 0 - total_expenses = expenses.aggregate(total=Sum('amount'))['total'] or 0 - total_purchases = purchases.aggregate(total=Sum('total_amount'))['total'] or 0 - - net_profit = total_sales - total_expenses - total_purchases - - context = { - 'total_sales': total_sales, - 'total_expenses': total_expenses, - 'total_purchases': total_purchases, - 'net_profit': net_profit, - 'start_date': start_date, - 'end_date': end_date - } - return render(request, 'core/cashflow_report.html', context) diff --git a/core/patch_views_pos.py b/core/patch_views_pos.py deleted file mode 100644 index 414a25d..0000000 --- a/core/patch_views_pos.py +++ /dev/null @@ -1,35 +0,0 @@ -@login_required -def pos(request): - from .models import CashierSession - # Check for active session - active_session = CashierSession.objects.filter(user=request.user, status='active').first() - if not active_session: - # Check if user is a cashier (assigned to a counter) - if hasattr(request.user, 'counter_assignment'): - messages.warning(request, _("Please open a session to start selling.")) - return redirect('start_session') - - 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) - - # Ensure at least Cash exists - if not payment_methods.exists(): - PaymentMethod.objects.create(name_en="Cash", name_ar="نقدي", is_active=True) - payment_methods = PaymentMethod.objects.filter(is_active=True) - - context = { - 'products': products, - 'customers': customers, - 'categories': categories, - 'payment_methods': payment_methods, - 'settings': settings, - 'active_session': active_session - } - return render(request, 'core/pos.html', context) diff --git a/core/patch_views_sales_list.py b/core/patch_views_sales_list.py deleted file mode 100644 index 7c06679..0000000 --- a/core/patch_views_sales_list.py +++ /dev/null @@ -1,31 +0,0 @@ -@login_required -def invoice_list(request): - sales = Sale.objects.all().order_by('-created_at') - - # Filter by date range - start_date = request.GET.get('start_date') - end_date = request.GET.get('end_date') - if start_date: - sales = sales.filter(created_at__date__gte=start_date) - if end_date: - sales = sales.filter(created_at__date__lte=end_date) - - # Filter by customer - customer_id = request.GET.get('customer') - if customer_id: - sales = sales.filter(customer_id=customer_id) - - # Filter by status - status = request.GET.get('status') - if status: - sales = sales.filter(status=status) - - paginator = Paginator(sales, 25) - - context = { - 'sales': paginator.get_page(request.GET.get('page')), - 'customers': Customer.objects.all(), - 'payment_methods': PaymentMethod.objects.filter(is_active=True), - 'site_settings': SystemSetting.objects.first(), - } - return render(request, 'core/invoices.html', context) \ No newline at end of file diff --git a/core/patch_views_vat.py b/core/patch_views_vat.py deleted file mode 100644 index a883edc..0000000 --- a/core/patch_views_vat.py +++ /dev/null @@ -1,161 +0,0 @@ -@csrf_exempt -def create_sale_api(request): - if request.method == 'POST': - try: - data = json.loads(request.body) - customer_id = data.get('customer_id') - invoice_number = data.get('invoice_number', '') - items = data.get('items', []) - - # Retrieve amounts - subtotal = data.get('subtotal', 0) - vat_amount = data.get('vat_amount', 0) - total_amount = data.get('total_amount', 0) - - paid_amount = data.get('paid_amount', 0) - discount = data.get('discount', 0) - payment_type = data.get('payment_type', 'cash') - payment_method_id = data.get('payment_method_id') - due_date = data.get('due_date') - notes = data.get('notes', '') - - # Loyalty data - points_to_redeem = data.get('loyalty_points_redeemed', 0) - - customer = None - if customer_id: - customer = Customer.objects.get(id=customer_id) - - if not customer and payment_type != 'cash': - return JsonResponse({'success': False, 'error': _('Credit or Partial payments are not allowed for Guest customers.')}, status=400) - - settings = SystemSetting.objects.first() - if not settings: - settings = SystemSetting.objects.create() - - loyalty_discount = 0 - if settings.loyalty_enabled and customer and points_to_redeem > 0: - if customer.loyalty_points >= points_to_redeem: - loyalty_discount = float(points_to_redeem) * float(settings.currency_per_point) - - sale = Sale.objects.create( - customer=customer, - invoice_number=invoice_number, - subtotal=subtotal, - vat_amount=vat_amount, - total_amount=total_amount, - paid_amount=paid_amount, - balance_due=float(total_amount) - float(paid_amount), - discount=discount, - loyalty_points_redeemed=points_to_redeem, - loyalty_discount_amount=loyalty_discount, - payment_type=payment_type, - due_date=due_date if due_date else None, - notes=notes, - created_by=request.user - ) - - # Set status based on payments - if float(paid_amount) >= float(total_amount): - sale.status = 'paid' - elif float(paid_amount) > 0: - sale.status = 'partial' - else: - sale.status = 'unpaid' - sale.save() - - # Record initial payment if any - if float(paid_amount) > 0: - pm = None - if payment_method_id: - pm = PaymentMethod.objects.filter(id=payment_method_id).first() - - SalePayment.objects.create( - sale=sale, - amount=paid_amount, - payment_method=pm, - payment_method_name=pm.name_en if pm else payment_type.capitalize(), - notes="Initial payment", - created_by=request.user - ) - - for item in items: - product = Product.objects.get(id=item['id']) - SaleItem.objects.create( - sale=sale, - product=product, - quantity=item['quantity'], - unit_price=item['price'], - line_total=item['line_total'] - ) - product.stock_quantity -= int(item['quantity']) - product.save() - - # Handle Loyalty Points - if settings.loyalty_enabled and customer: - # Earn Points - points_earned = float(total_amount) * float(settings.points_per_currency) - if customer.loyalty_tier: - points_earned *= float(customer.loyalty_tier.point_multiplier) - - if points_earned > 0: - customer.loyalty_points += decimal.Decimal(str(points_earned)) - LoyaltyTransaction.objects.create( - customer=customer, - sale=sale, - transaction_type='earned', - points=points_earned, - notes=f"Points earned from Sale #{sale.id}" - ) - - # Redeem Points - if points_to_redeem > 0: - customer.loyalty_points -= decimal.Decimal(str(points_to_redeem)) - LoyaltyTransaction.objects.create( - customer=customer, - sale=sale, - transaction_type='redeemed', - points=-points_to_redeem, - notes=f"Points redeemed for Sale #{sale.id}" - ) - - customer.update_tier() - customer.save() - - return JsonResponse({ - 'success': True, - 'sale_id': sale.id, - 'business': { - 'name': settings.business_name, - 'address': settings.address, - 'phone': settings.phone, - 'email': settings.email, - 'currency': settings.currency_symbol, - 'vat_number': settings.vat_number, - 'registration_number': settings.registration_number, - 'logo_url': settings.logo.url if settings.logo else None - }, - 'sale': { - 'id': sale.id, - 'invoice_number': sale.invoice_number, - 'created_at': sale.created_at.strftime("%Y-%m-%d %H:%M"), - 'subtotal': float(sale.subtotal), - 'vat_amount': float(sale.vat_amount), - 'total': float(sale.total_amount), - 'discount': float(sale.discount), - 'paid': float(sale.paid_amount), - 'balance': float(sale.balance_due), - 'customer_name': sale.customer.name if sale.customer else 'Guest', - 'items': [ - { - 'name_en': si.product.name_en, - 'name_ar': si.product.name_ar, - 'qty': si.quantity, - 'price': float(si.unit_price), - 'total': float(si.line_total) - } for si in sale.items.all() - ] - } - }) - except Exception as e: - return JsonResponse({'success': False, 'error': str(e)}, status=400) \ No newline at end of file diff --git a/core/pdf_utils.py b/core/pdf_utils.py new file mode 100644 index 0000000..0ce9f57 --- /dev/null +++ b/core/pdf_utils.py @@ -0,0 +1,55 @@ +import os +import ctypes +import ctypes.util +import logging + +logger = logging.getLogger(__name__) + +def patch_weasyprint_libraries(): + """ + Attempts to load required system libraries for WeasyPrint. + This helps on systems where libraries are installed but not in the standard search path + or have slightly different names. + """ + # Common library names for WeasyPrint dependencies + libs_to_load = [ + ('glib-2.0', ['libglib-2.0.so.0', 'libglib-2.0.so']), + ('gobject-2.0', ['libgobject-2.0.so.0', 'libgobject-2.0.so', 'libgobject-2.0-0']), + ('fontconfig', ['libfontconfig.so.1', 'libfontconfig.so']), + ('cairo', ['libcairo.so.2', 'libcairo.so']), + ('pango-1.0', ['libpango-1.0.so.0', 'libpango-1.0.so']), + ('pangoft2-1.0', ['libpangoft2-1.0.so.0', 'libpangoft2-1.0.so']), + ('harfbuzz', ['libharfbuzz.so.0', 'libharfbuzz.so']), + ] + + for lib_id, fallbacks in libs_to_load: + try: + # First try standard find_library + path = ctypes.util.find_library(lib_id) + if path: + ctypes.CDLL(path) + continue + + # If not found, try fallbacks + for fallback in fallbacks: + try: + ctypes.CDLL(fallback) + break + except OSError: + continue + except Exception as e: + logger.debug(f"Failed to load library {lib_id}: {e}") + +# Call it immediately when this module is imported +patch_weasyprint_libraries() + +def get_weasyprint_html(): + """ + Safe wrapper for importing WeasyPrint HTML. + """ + try: + from weasyprint import HTML + return HTML + except Exception as e: + logger.error(f"Failed to import WeasyPrint HTML: {e}") + raise diff --git a/core/views.py b/core/views.py index 078e5b4..0b04457 100644 --- a/core/views.py +++ b/core/views.py @@ -44,7 +44,8 @@ logger = logging.getLogger(__name__) # --- Basic Views --- def test_pdf_view(request): - from weasyprint import HTML + from .pdf_utils import get_weasyprint_html + HTML = get_weasyprint_html() html_string = "

Test PDF

" pdf = HTML(string=html_string).write_pdf() return HttpResponse(pdf, content_type='application/pdf') @@ -1592,7 +1593,8 @@ def get_pdf_context(obj, doc_type): } def generate_pdf_file(template, context, request): - from weasyprint import HTML + from .pdf_utils import get_weasyprint_html + HTML = get_weasyprint_html() html_string = render_to_string(template, context, request=request) base_url = request.build_absolute_uri('/') return HTML(string=html_string, base_url=base_url).write_pdf() diff --git a/debug_accounting.py b/debug_accounting.py deleted file mode 100644 index 1fa0972..0000000 --- a/debug_accounting.py +++ /dev/null @@ -1,31 +0,0 @@ -import os -import django -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings') -django.setup() - -from accounting.models import Account, JournalEntry, JournalItem -from core.models import Expense - -print("Checking Accounts...") -acc_1000 = Account.objects.filter(code='1000').first() -acc_5400 = Account.objects.filter(code='5400').first() - -print(f"Account 1000 (Cash): {acc_1000}") -print(f"Account 5400 (General Expense): {acc_5400}") - -print("\nChecking Journal Entries for Expenses...") -expenses = Expense.objects.all() -for exp in expenses: - print(f"Expense {exp.id}: {exp.description} - Amount: {exp.amount}") - # Find linked entry - from django.contrib.contenttypes.models import ContentType - ct = ContentType.objects.get_for_model(Expense) - entries = JournalEntry.objects.filter(content_type=ct, object_id=exp.id) - for entry in entries: - print(f" -> JournalEntry {entry.id}: {entry.description}") - items = entry.items.all() - if items.exists(): - for item in items: - print(f" -> Item: {item.account.code} {item.type} {item.amount}") - else: - print(f" -> NO ITEMS FOUND!") \ No newline at end of file diff --git a/debug_request.py b/debug_request.py deleted file mode 100644 index eb54937..0000000 --- a/debug_request.py +++ /dev/null @@ -1,54 +0,0 @@ -import os -import django -from django.conf import settings -import sys - -# Setup Django environment -sys.path.append(os.getcwd()) -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings") -django.setup() - -from django.test import RequestFactory -from core.views import index - -def test_root_view(): - factory = RequestFactory() - request = factory.get('/') - - # Simulate logged in user (since index is login_required) - from django.contrib.auth.models import AnonymousUser, User - - # Create a dummy user for testing - if not User.objects.filter(username='testadmin').exists(): - user = User.objects.create_superuser('testadmin', 'admin@example.com', 'pass') - else: - user = User.objects.get(username='testadmin') - - request.user = user # Authenticated - - try: - response = index(request) - print(f"Authenticated Root View Status: {response.status_code}") - except Exception as e: - print(f"Authenticated Root View Error: {e}") - - # Test unauthenticated (should redirect) - request_anon = factory.get('/') - request_anon.user = AnonymousUser() - from django.contrib.auth.decorators import login_required - # We can't easily run the decorator logic with RequestFactory directly calling the view function - # unless we use the view wrapped in login_required manually or via client. - - from django.test import Client - client = Client() - response = client.get('/') - print(f"Client Root Get Status: {response.status_code}") - if response.status_code == 302: - print(f"Redirects to: {response.url}") - - # Check login page - response_login = client.get('/accounts/login/') - print(f"Client Login Get Status: {response_login.status_code}") - -if __name__ == "__main__": - test_root_view() diff --git a/debug_settings.py b/debug_settings.py deleted file mode 100644 index a79282e..0000000 --- a/debug_settings.py +++ /dev/null @@ -1,38 +0,0 @@ - -file_path = 'core/templates/core/settings.html' -with open(file_path, 'r') as f: - content = f.read() - -print("File length:", len(content)) - -# Check context for Nav Tab -if 'id="devices-tab"' in content: - print("Devices tab already exists.") -else: - context_str = 'id="whatsapp-tab" data-bs-toggle="pill" data-bs-target="#whatsapp" type="button" role="tab"> - {% trans "WhatsApp Gateway" %} - - ' - if context_str in content: - print("Found Nav Tab context.") - else: - print("Nav Tab context NOT found. Dumping nearby content:") - # Find rough location - idx = content.find('id="whatsapp-tab"') - if idx != -1: - print(content[idx:idx+300]) - -# Check context for Tab Pane -if 'id="devices" role="tabpanel"' in content: - print("Devices pane already exists.") -else: - # Try to find the end of tab content - # Look for Add Tier Modal - idx = content.find('') - if idx != -1: - print("Found Add Tier Modal at index:", idx) - print("Preceding content:") - print(content[idx-100:idx]) - else: - print("Add Tier Modal NOT found.") - diff --git a/debug_url.py b/debug_url.py deleted file mode 100644 index 437c237..0000000 --- a/debug_url.py +++ /dev/null @@ -1,22 +0,0 @@ - -import os -import django -from django.conf import settings -from django.urls import reverse, resolve - -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings') -django.setup() - -try: - print("Attempting to reverse 'inventory'...") - url = reverse('inventory') - print(f"Success: 'inventory' -> {url}") -except Exception as e: - print(f"Error reversing 'inventory': {e}") - -try: - print("Attempting to reverse 'index'...") - url = reverse('index') - print(f"Success: 'index' -> {url}") -except Exception as e: - print(f"Error reversing 'index': {e}") diff --git a/force_reset_admin.py b/force_reset_admin.py deleted file mode 100644 index 8255a68..0000000 --- a/force_reset_admin.py +++ /dev/null @@ -1,32 +0,0 @@ -import os -import sys -import django - -# Add project root to path -sys.path.append(os.getcwd()) - -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings') -django.setup() - -from django.contrib.auth import get_user_model - -def reset_password(): - User = get_user_model() - username = 'admin' - password = 'admin' - - try: - user, created = User.objects.get_or_create(username=username) - user.set_password(password) - user.is_staff = True - user.is_superuser = True - user.save() - - action = "created" if created else "reset" - print(f"Successfully {action} password for user '{username}' to '{password}'.") - - except Exception as e: - print(f"Error resetting password: {e}") - -if __name__ == "__main__": - reset_password() diff --git a/manage.py b/manage.py index 1fb2261..7dcd3e8 100755 --- a/manage.py +++ b/manage.py @@ -14,21 +14,6 @@ def main(): except ImportError: pass - # --- WeasyPrint Library Preloading --- - import ctypes - import ctypes.util - - # Try to find and load libraries dynamically to help WeasyPrint on different platforms - libs_to_load = ['glib-2.0', 'gobject-2.0', 'fontconfig', 'cairo', 'pango-1.0', 'pangoft2-1.0'] - for lib_name in libs_to_load: - try: - path = ctypes.util.find_library(lib_name) - if path: - ctypes.CDLL(path) - except Exception: - pass - # ------------------------------------- - os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings') try: from django.core.management import execute_from_command_line @@ -41,4 +26,4 @@ def main(): execute_from_command_line(sys.argv) if __name__ == '__main__': - main() + main() \ No newline at end of file diff --git a/manage_trace.txt b/manage_trace.txt deleted file mode 100644 index 985eaca..0000000 --- a/manage_trace.txt +++ /dev/null @@ -1 +0,0 @@ -Manage.py started diff --git a/manual_db_fix.py b/manual_db_fix.py deleted file mode 100644 index e03ed12..0000000 --- a/manual_db_fix.py +++ /dev/null @@ -1,32 +0,0 @@ -from django.db import connection - -def fix_db(): - print("Starting DB Fix...") - with connection.cursor() as cursor: - # 1. Check/Add is_service to core_product - try: - cursor.execute("SELECT is_service FROM core_product LIMIT 1") - print("SUCCESS: is_service already exists in core_product.") - except Exception: - print("Attempting to add is_service column...") - try: - # Try MySQL syntax first - cursor.execute("ALTER TABLE core_product ADD COLUMN is_service tinyint(1) NOT NULL DEFAULT 0;") - print("FIXED: Added is_service column to core_product.") - except Exception as e: - print(f"ERROR adding is_service: {e}") - - # 2. Check/Add is_active to core_paymentmethod - try: - cursor.execute("SELECT is_active FROM core_paymentmethod LIMIT 1") - print("SUCCESS: is_active already exists in core_paymentmethod.") - except Exception: - print("Attempting to add is_active column...") - try: - cursor.execute("ALTER TABLE core_paymentmethod ADD COLUMN is_active tinyint(1) NOT NULL DEFAULT 1;") - print("FIXED: Added is_active column to core_paymentmethod.") - except Exception as e: - print(f"ERROR adding is_active: {e}") - -if __name__ == '__main__': - fix_db() diff --git a/move_project.py b/move_project.py deleted file mode 100644 index 16d8855..0000000 --- a/move_project.py +++ /dev/null @@ -1 +0,0 @@ -# This script has been disabled/removed as the project is deployed to the root. \ No newline at end of file diff --git a/patch_base_html.py b/patch_base_html.py deleted file mode 100644 index 17aea1f..0000000 --- a/patch_base_html.py +++ /dev/null @@ -1,49 +0,0 @@ - -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_expense_categories.py b/patch_expense_categories.py deleted file mode 100644 index dc4c7a3..0000000 --- a/patch_expense_categories.py +++ /dev/null @@ -1,43 +0,0 @@ -import os - -file_path = 'core/views.py' -search_text = "@login_required\ndef expense_categories_view(request): return render(request, 'core/expense_categories.html')" -replace_text = """@login_required -def expense_categories_view(request): - if request.method == 'POST': - category_id = request.POST.get('category_id') - name_en = request.POST.get('name_en') - name_ar = request.POST.get('name_ar') - description = request.POST.get('description') - - if category_id: - # Update existing category - category = get_object_or_404(ExpenseCategory, pk=category_id) - category.name_en = name_en - category.name_ar = name_ar - category.description = description - category.save() - messages.success(request, _('Expense category updated successfully.')) - else: - # Create new category - ExpenseCategory.objects.create( - name_en=name_en, - name_ar=name_ar, - description=description - ) - messages.success(request, _('Expense category added successfully.')) - return redirect('expense_categories') - - categories = ExpenseCategory.objects.all().order_by('-id') - return render(request, 'core/expense_categories.html', {'categories': categories})""" - -with open(file_path, 'r') as f: - content = f.read() - -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 expense_categories_view") -else: - print("Could not find the target function to replace") diff --git a/patch_invoice_list.py b/patch_invoice_list.py deleted file mode 100644 index d4acaaa..0000000 --- a/patch_invoice_list.py +++ /dev/null @@ -1,52 +0,0 @@ -import os - -file_path = 'core/views.py' - -old_content = """@login_required -def invoice_list(request): - sales = Sale.objects.all().order_by('-created_at') - paginator = Paginator(sales, 25) - return render(request, 'core/invoices.html', {'sales': paginator.get_page(request.GET.get('page'))})""" - -new_content = """@login_required -def invoice_list(request): - sales = Sale.objects.all().order_by('-created_at') - - # Filter by date range - start_date = request.GET.get('start_date') - end_date = request.GET.get('end_date') - if start_date: - sales = sales.filter(created_at__date__gte=start_date) - if end_date: - sales = sales.filter(created_at__date__lte=end_date) - - # Filter by customer - customer_id = request.GET.get('customer') - if customer_id: - sales = sales.filter(customer_id=customer_id) - - # Filter by status - status = request.GET.get('status') - if status: - sales = sales.filter(status=status) - - paginator = Paginator(sales, 25) - - context = { - 'sales': paginator.get_page(request.GET.get('page')), - 'customers': Customer.objects.all(), - 'payment_methods': PaymentMethod.objects.filter(is_active=True), - 'site_settings': SystemSetting.objects.first(), - } - return render(request, 'core/invoices.html', context)""" - -with open(file_path, 'r') as f: - content = f.read() - -if old_content in content: - content = content.replace(old_content, new_content) - with open(file_path, 'w') as f: - f.write(content) - print("Successfully patched invoice_list") -else: - print("Could not find exact match for invoice_list function") diff --git a/patch_models_timestamp.py b/patch_models_timestamp.py deleted file mode 100644 index 73634d9..0000000 --- a/patch_models_timestamp.py +++ /dev/null @@ -1,43 +0,0 @@ -import os - -path = 'core/models.py' -with open(path, 'r') as f: - content = f.read() - -# Patch SalePayment -old_sale_payment = """ notes = models.TextField(_("Notes"), blank=True) - created_by = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, related_name="sale_payments") - - def __str__(self):""" -new_sale_payment = """ notes = models.TextField(_("Notes"), blank=True) - created_by = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, related_name="sale_payments") - created_at = models.DateTimeField(auto_now_add=True) - - def __str__(self):""" - -# Patch PurchasePayment -old_purchase_payment = """ notes = models.TextField(_("Notes"), blank=True) - created_by = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, related_name="purchase_payments") - - def __str__(self):""" -new_purchase_payment = """ notes = models.TextField(_("Notes"), blank=True) - created_by = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, related_name="purchase_payments") - created_at = models.DateTimeField(auto_now_add=True) - - def __str__(self):""" - -# Check if SalePayment already has created_at -# A simple check: if we find the new pattern, we skip -if new_sale_payment in content: - print("SalePayment already patched.") -else: - content = content.replace(old_sale_payment, new_sale_payment) - -if new_purchase_payment in content: - print("PurchasePayment already patched.") -else: - content = content.replace(old_purchase_payment, new_purchase_payment) - -with open(path, 'w') as f: - f.write(content) -print("Patched core/models.py") diff --git a/patch_payments_v2.py b/patch_payments_v2.py deleted file mode 100644 index 82e800b..0000000 --- a/patch_payments_v2.py +++ /dev/null @@ -1,211 +0,0 @@ -import os -import decimal -from django.db import transaction -from django.db.models import Sum - -file_path = 'core/views.py' -with open(file_path, 'r') as f: - content = f.read() - -# 1. Update invoice_list -old_invoice_list = """@login_required -def invoice_list(request): - sales = Sale.objects.all().order_by('-created_at') - paginator = Paginator(sales, 25) - return render(request, 'core/invoices.html', { - 'sales': paginator.get_page(request.GET.get('page')), - 'customers': Customer.objects.all(), - 'site_settings': SystemSetting.objects.first() - })""" - -new_invoice_list = """@login_required -def invoice_list(request): - sales = Sale.objects.all().order_by('-created_at') - paginator = Paginator(sales, 25) - return render(request, 'core/invoices.html', { - 'sales': paginator.get_page(request.GET.get('page')), - 'customers': Customer.objects.all(), - 'site_settings': SystemSetting.objects.first(), - 'payment_methods': PaymentMethod.objects.filter(is_active=True) - })""" - -if old_invoice_list in content: - content = content.replace(old_invoice_list, new_invoice_list) -else: - print("Could not find old_invoice_list") - -# 2. Update purchases -old_purchases = """@login_required -def purchases(request): - purchases = Purchase.objects.all().order_by('-created_at') - paginator = Paginator(purchases, 25) - return render(request, 'core/purchases.html', {'purchases': paginator.get_page(request.GET.get('page'))})""" - -new_purchases = """@login_required -def purchases(request): - purchases = Purchase.objects.all().order_by('-created_at') - paginator = Paginator(purchases, 25) - return render(request, 'core/purchases.html', { - 'purchases': paginator.get_page(request.GET.get('page')), - 'payment_methods': PaymentMethod.objects.filter(is_active=True) - })""" - -if old_purchases in content: - content = content.replace(old_purchases, new_purchases) -else: - print("Could not find old_purchases") - -# 3. Update invoice_detail -old_invoice_detail = """@login_required -def invoice_detail(request, pk): - sale = get_object_or_404(Sale, pk=pk) - settings = SystemSetting.objects.first() - amount_in_words = number_to_words_en(sale.total_amount) - return render(request, 'core/invoice_detail.html', { - 'sale': sale, - 'settings': settings, - 'amount_in_words': amount_in_words - })""" - -new_invoice_detail = """@login_required -def invoice_detail(request, pk): - sale = get_object_or_404(Sale, pk=pk) - settings = SystemSetting.objects.first() - amount_in_words = number_to_words_en(sale.total_amount) - return render(request, 'core/invoice_detail.html', { - 'sale': sale, - 'settings': settings, - 'amount_in_words': amount_in_words, - 'payment_methods': PaymentMethod.objects.filter(is_active=True) - })""" - -if old_invoice_detail in content: - content = content.replace(old_invoice_detail, new_invoice_detail) -else: - print("Could not find old_invoice_detail") - -# 4. Update purchase_detail -old_purchase_detail = """@login_required -def purchase_detail(request, pk): - purchase = get_object_or_404(Purchase, pk=pk) - settings = SystemSetting.objects.first() - return render(request, 'core/purchase_detail.html', { - 'purchase': purchase, - 'settings': settings - })""" - -new_purchase_detail = """@login_required -def purchase_detail(request, pk): - purchase = get_object_or_404(Purchase, pk=pk) - settings = SystemSetting.objects.first() - return render(request, 'core/purchase_detail.html', { - 'purchase': purchase, - 'settings': settings, - 'payment_methods': PaymentMethod.objects.filter(is_active=True) - })""" - -if old_purchase_detail in content: - content = content.replace(old_purchase_detail, new_purchase_detail) -else: - print("Could not find old_purchase_detail") - -# 5. Replace add_sale_payment stub -old_add_sale_payment = """@login_required -def add_sale_payment(request, pk): return redirect('invoices')""" - -new_add_sale_payment = """@login_required -def add_sale_payment(request, pk): - sale = get_object_or_404(Sale, pk=pk) - if request.method == 'POST': - try: - amount = decimal.Decimal(request.POST.get('amount', 0)) - payment_method_id = request.POST.get('payment_method_id') - notes = request.POST.get('notes', '') - - if amount > 0: - with transaction.atomic(): - SalePayment.objects.create( - sale=sale, - amount=amount, - payment_method_id=payment_method_id, - created_by=request.user, - notes=notes - ) - - # Recalculate totals - total_paid = SalePayment.objects.filter(sale=sale).aggregate(Sum('amount'))['amount__sum'] or 0 - sale.paid_amount = total_paid - sale.balance_due = sale.total_amount - total_paid - - if sale.balance_due <= 0: - sale.status = 'paid' - elif sale.paid_amount > 0: - sale.status = 'partial' - else: - sale.status = 'unpaid' - - sale.save() - messages.success(request, f"Payment of {amount} recorded successfully.") - else: - messages.error(request, "Amount must be greater than 0.") - except Exception as e: - messages.error(request, f"Error recording payment: {e}") - - return redirect('invoices')""" - -if old_add_sale_payment in content: - content = content.replace(old_add_sale_payment, new_add_sale_payment) -else: - print("Could not find old_add_sale_payment") - -# 6. Replace add_purchase_payment stub -old_add_purchase_payment = """@login_required -def add_purchase_payment(request, pk): return redirect('purchases')""" - -new_add_purchase_payment = """@login_required -def add_purchase_payment(request, pk): - purchase = get_object_or_404(Purchase, pk=pk) - if request.method == 'POST': - try: - amount = decimal.Decimal(request.POST.get('amount', 0)) - payment_method_id = request.POST.get('payment_method_id') - notes = request.POST.get('notes', '') - - if amount > 0: - with transaction.atomic(): - PurchasePayment.objects.create( - purchase=purchase, - amount=amount, - payment_method_id=payment_method_id, - created_by=request.user, - notes=notes - ) - - # Recalculate totals - total_paid = PurchasePayment.objects.filter(purchase=purchase).aggregate(Sum('amount'))['amount__sum'] or 0 - purchase.paid_amount = total_paid - purchase.balance_due = purchase.total_amount - total_paid - - if purchase.balance_due <= 0: - purchase.status = 'paid' - elif purchase.paid_amount > 0: - purchase.status = 'partial' - else: - purchase.status = 'unpaid' - - purchase.save() - messages.success(request, f"Payment of {amount} recorded successfully.") - else: - messages.error(request, "Amount must be greater than 0.") - except Exception as e: - messages.error(request, f"Error recording payment: {e}") - - return redirect('purchases')""" - -if old_add_purchase_payment in content: - content = content.replace(old_add_purchase_payment, new_add_purchase_payment) -else: - print("Could not find old_add_purchase_payment") - -with open(file_path, 'w') as f: - f.write(content) diff --git a/patch_pos_view.py b/patch_pos_view.py deleted file mode 100644 index 14337bf..0000000 --- a/patch_pos_view.py +++ /dev/null @@ -1,34 +0,0 @@ -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]) diff --git a/patch_returns_setup.py b/patch_returns_setup.py deleted file mode 100644 index 70a5292..0000000 --- a/patch_returns_setup.py +++ /dev/null @@ -1,17 +0,0 @@ -from core.views import ( - purchase_return_create, sale_return_create, - create_sale_return_api, create_purchase_return_api, - Supplier, Product, Customer, SaleReturn, SaleReturnItem, - PurchaseReturn, PurchaseReturnItem, transaction, timezone, - decimal, json, JsonResponse, get_object_or_404, login_required, csrf_exempt, logger -) - -def patch_purchase_return_create(request): - suppliers = Supplier.objects.filter(is_active=True) - products = Product.objects.filter(is_active=True) - return {'suppliers': suppliers, 'products': products} - -def patch_sale_return_create(request): - customers = Customer.objects.all() - products = Product.objects.filter(is_active=True) - return {'customers': customers, 'products': products} diff --git a/patch_returns_v3.py b/patch_returns_v3.py deleted file mode 100644 index fdc6d74..0000000 --- a/patch_returns_v3.py +++ /dev/null @@ -1,159 +0,0 @@ -import os - -file_path = 'core/views.py' - -with open(file_path, 'r') as f: - content = f.read() - -# Replacement 1: sale_return_create -old_sale_create = "def sale_return_create(request): return render(request, 'core/sale_return_create.html')" -new_sale_create = """def sale_return_create(request): - customers = Customer.objects.all() - products = Product.objects.filter(is_active=True) - return render(request, 'core/sale_return_create.html', { - 'customers': customers, - 'products': products - })""" - -# Replacement 2: create_sale_return_api -old_sale_api = "@csrf_exempt\ndef create_sale_return_api(request): return JsonResponse({'success': True})" -new_sale_api = """@csrf_exempt -@login_required -def create_sale_return_api(request): - if request.method != 'POST': - return JsonResponse({'success': False, 'error': 'Invalid method'}) - try: - data = json.loads(request.body) - customer_id = data.get('customer_id') - items = data.get('items', []) - - customer = None - if customer_id: - customer = get_object_or_404(Customer, pk=customer_id) - - with transaction.atomic(): - sale_return = SaleReturn.objects.create( - customer=customer, - created_by=request.user, - total_amount=0, - return_number=f"SR-{{int(timezone.now().timestamp())}}", - notes=data.get('notes', '') - ) - - total = decimal.Decimal(0) - for item in items: - qty = decimal.Decimal(str(item.get('quantity', 0))) - price = decimal.Decimal(str(item.get('price', 0))) - line_total = qty * price - - SaleReturnItem.objects.create( - sale_return=sale_return, - product_id=item['id'], - quantity=qty, - unit_price=price, - line_total=line_total - ) - - # Update stock: Returns from customer mean stock comes IN - product = Product.objects.get(pk=item['id']) - product.stock_quantity += qty - product.save() - - total += line_total - - sale_return.total_amount = total - sale_return.save() - - return JsonResponse({'success': True, 'id': sale_return.id}) - except Exception as e: - logger.exception("Error creating sale return") - return JsonResponse({'success': False, 'error': str(e)})""" - -# Replacement 3: purchase_return_create -old_purchase_create = "def purchase_return_create(request): return render(request, 'core/purchase_return_create.html')" -new_purchase_create = """def purchase_return_create(request): - suppliers = Supplier.objects.filter(is_active=True) - products = Product.objects.filter(is_active=True) - return render(request, 'core/purchase_return_create.html', { - 'suppliers': suppliers, - 'products': products - })""" - -# Replacement 4: create_purchase_return_api -old_purchase_api = "@csrf_exempt\ndef create_purchase_return_api(request): return JsonResponse({'success': True})" -new_purchase_api = """@csrf_exempt -@login_required -def create_purchase_return_api(request): - if request.method != 'POST': - return JsonResponse({'success': False, 'error': 'Invalid method'}) - try: - data = json.loads(request.body) - supplier_id = data.get('supplier_id') - items = data.get('items', []) - - supplier = get_object_or_404(Supplier, pk=supplier_id) - - with transaction.atomic(): - purchase_return = PurchaseReturn.objects.create( - supplier=supplier, - created_by=request.user, - total_amount=0, - return_number=f"PR-{{int(timezone.now().timestamp())}}", - notes=data.get('notes', '') - ) - - total = decimal.Decimal(0) - for item in items: - qty = decimal.Decimal(str(item.get('quantity', 0))) - cost = decimal.Decimal(str(item.get('price', 0))) - line_total = qty * cost - - PurchaseReturnItem.objects.create( - purchase_return=purchase_return, - product_id=item['id'], - quantity=qty, - cost_price=cost, - line_total=line_total - ) - - # Update stock: Returns to supplier mean stock goes OUT - product = Product.objects.get(pk=item['id']) - product.stock_quantity -= qty - product.save() - - total += line_total - - purchase_return.total_amount = total - purchase_return.save() - - return JsonResponse({'success': True, 'id': purchase_return.id}) - except Exception as e: - logger.exception("Error creating purchase return") - return JsonResponse({'success': False, 'error': str(e)})""" - -if old_sale_create in content: - content = content.replace(old_sale_create, new_sale_create) - print("Patched sale_return_create") -else: - print("Could not find sale_return_create stub") - -if old_sale_api in content: - content = content.replace(old_sale_api, new_sale_api) - print("Patched create_sale_return_api") -else: - print("Could not find create_sale_return_api stub") - -if old_purchase_create in content: - content = content.replace(old_purchase_create, new_purchase_create) - print("Patched purchase_return_create") -else: - print("Could not find purchase_return_create stub") - -if old_purchase_api in content: - content = content.replace(old_purchase_api, new_purchase_api) - print("Patched create_purchase_return_api") -else: - print("Could not find create_purchase_return_api stub") - -with open(file_path, 'w') as f: - f.write(content) diff --git a/patch_settings_html.py b/patch_settings_html.py deleted file mode 100644 index 8669a41..0000000 --- a/patch_settings_html.py +++ /dev/null @@ -1,260 +0,0 @@ -file_path = 'core/templates/core/settings.html' - -with open(file_path, 'r') as f: - content = f.read() - -# 1. Add Nav Tab -if 'id="devices-tab"' not in content: - whatsapp_tab_end = 'id="whatsapp-tab" data-bs-toggle="pill" data-bs-target="#whatsapp" type="button" role="tab">\n {% trans "WhatsApp Gateway" %}\n \n li>' - - insert_str = """ - " - - if whatsapp_tab_end in content: - content = content.replace(whatsapp_tab_end, whatsapp_tab_end + insert_str) - print("Added Devices Tab Nav.") - else: - # Fallback search if exact string match fails due to whitespace - print("Could not find exact match for Nav Tab insertion. Trying simpler match.") - simple_search = '{% trans "WhatsApp Gateway" %}' - parts = content.split(simple_search) - if len(parts) > 1: - # Reconstruct slightly differently but risky - pass - -# 2. Add Tab Content -if 'id="devices" role="tabpanel"' not in content: - devices_pane = """ - -
-
-
-
{% trans "Connected Devices" %}
- -
-
-
- - - - - - - - - - - - - {% for device in devices %} - - - - - - - - - - - - - - - - {% empty %} - - - - {% endfor %} - -
{% trans "Device Name" %}{% trans "Type" %}{% trans "Connection" %}{% trans "IP / Port" %}{% trans "Status" %}{% trans "Actions" %}
{{ device.name }} - {{ device.get_device_type_display }} - {{ device.get_connection_type_display }} - {% if device.ip_address %} - {{ device.ip_address }}{% if device.port %}:{{ device.port }}{% endif %} - {% else %} - - - {% endif %} - - {% if device.is_active %} - {% trans "Active" %} - {% else %} - {% trans "Inactive" %} - {% endif %} - - - -
-
- - {% trans "No devices configured." %} -
-
-
-
-
-
- " - - parts = content.split('') - if len(parts) > 1: - last_div = parts[0].rfind('') - second_last_div = parts[0].rfind('', 0, last_div) - - if second_last_div != -1: - new_part0 = parts[0][:second_last_div] + devices_pane + parts[0][second_last_div:] - content = new_part0 + '' + parts[1] - print("Added Devices Tab Pane.") - else: - print("Could not find insertion point for Devices Pane.") - -# 3. Add Add Device Modal -if 'id="addDeviceModal"' not in content: - modal_content = """ - - -" - content = content.replace('{% endblock %}', modal_content + '\n{% endblock %}') - print("Added Add Device Modal.") - -with open(file_path, 'w') as f: - f.write(content) \ No newline at end of file diff --git a/patch_views.py b/patch_views.py deleted file mode 100644 index 7bd7fcf..0000000 --- a/patch_views.py +++ /dev/null @@ -1,85 +0,0 @@ -import re - -file_path = 'core/views.py' - -with open(file_path, 'r') as f: - content = f.read() - -# 1. Add Device to imports -if 'Device' not in content: - pattern = r'(from \.models import \(.*?)(\))' - replacement = r'\1, Device\2' - content = re.sub(pattern, replacement, content, flags=re.DOTALL) - print("Added Device to imports.") - -# 2. Update settings_view -if 'devices = Device.objects.all()' not in content: - # Find the lines before context creation - search_str = 'loyalty_tiers = LoyaltyTier.objects.all().order_by("min_points")' - insert_str = '\n devices = Device.objects.all().order_by("name")' - content = content.replace(search_str, search_str + insert_str) - - # Update context - context_search = '"loyalty_tiers": loyalty_tiers' - context_insert = ',\n "devices": devices' - content = content.replace(context_search, context_search + context_insert) - print("Updated settings_view.") - -# 3. Add Device views -new_views = """ - -@login_required -def add_device(request): - if request.method == 'POST': - name = request.POST.get('name') - device_type = request.POST.get('device_type') - connection_type = request.POST.get('connection_type') - ip_address = request.POST.get('ip_address') - port = request.POST.get('port') - is_active = request.POST.get('is_active') == 'on' - - Device.objects.create( - name=name, - device_type=device_type, - connection_type=connection_type, - ip_address=ip_address if ip_address else None, - port=port if port else None, - is_active=is_active - ) - messages.success(request, _("Device added successfully!")) - return redirect(reverse('settings') + '#devices') - -@login_required -def edit_device(request, pk): - device = get_object_or_404(Device, pk=pk) - if request.method == 'POST': - device.name = request.POST.get('name') - device.device_type = request.POST.get('device_type') - device.connection_type = request.POST.get('connection_type') - device.ip_address = request.POST.get('ip_address') - device.port = request.POST.get('port') - device.is_active = request.POST.get('is_active') == 'on' - - if not device.ip_address: - device.ip_address = None - if not device.port: - device.port = None - - device.save() - messages.success(request, _("Device updated successfully!")) - return redirect(reverse('settings') + '#devices') - -@login_required -def delete_device(request, pk): - device = get_object_or_404(Device, pk=pk) - device.delete() - messages.success(request, _("Device deleted successfully!")) - return redirect(reverse('settings') + '#devices') -""" - -if 'def add_device(request):' not in content: - content += new_views - print("Added Device views.") - -with open(file_path, 'w') as f: - f.write(content) \ No newline at end of file diff --git a/patch_views_expense_edit.py b/patch_views_expense_edit.py deleted file mode 100644 index fd824fd..0000000 --- a/patch_views_expense_edit.py +++ /dev/null @@ -1,30 +0,0 @@ - -@login_required -def expense_edit_view(request, pk): - expense = get_object_or_404(Expense, pk=pk) - if request.method == 'POST': - try: - category_id = request.POST.get('category') - amount = request.POST.get('amount') - date = request.POST.get('date') - description = request.POST.get('description') - payment_method_id = request.POST.get('payment_method') - - category = get_object_or_404(ExpenseCategory, pk=category_id) - payment_method = get_object_or_404(PaymentMethod, pk=payment_method_id) if payment_method_id else None - - expense.category = category - expense.amount = amount - expense.date = date or expense.date - expense.description = description - expense.payment_method = payment_method - - if 'attachment' in request.FILES: - expense.attachment = request.FILES['attachment'] - - expense.save() - messages.success(request, _('Expense updated successfully.')) - except Exception as e: - messages.error(request, _('Error updating expense: ') + str(e)) - - return redirect('expenses') diff --git a/patch_views_fixes.py b/patch_views_fixes.py deleted file mode 100644 index 5ffc807..0000000 --- a/patch_views_fixes.py +++ /dev/null @@ -1,134 +0,0 @@ - -import os -import re - -file_path = 'core/views.py' - -with open(file_path, 'r') as f: - content = f.read() - -# Implement add_payment_method_ajax -# It currently looks like: -# @login_required -# def add_payment_method_ajax(request): -# return JsonResponse({'success': True}) - -new_add_payment_method = """@csrf_exempt -@login_required -def add_payment_method_ajax(request): - if request.method != 'POST': - return JsonResponse({'success': False, 'error': 'Invalid method'}) - try: - data = json.loads(request.body) - pm = PaymentMethod.objects.create( - name_en=data.get('name_en'), - name_ar=data.get('name_ar'), - is_active=data.get('is_active', True) - ) - 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)})""" - -content = re.sub( - r'@login_required\s+def add_payment_method_ajax\(request\):\s+return JsonResponse\({\s*["']success["']: True\s*}\)', - new_add_payment_method, - content -) - -# Implement create_purchase_api -new_create_purchase = """@csrf_exempt -@login_required -def create_purchase_api(request): - if request.method != 'POST': - return JsonResponse({'success': False, 'error': 'Invalid request'}) - try: - data = json.loads(request.body) - with transaction.atomic(): - purchase = Purchase.objects.create( - supplier_id=data.get('supplier_id') or None, - total_amount=data.get('total_amount', 0), - paid_amount=data.get('paid_amount', 0), - created_by=request.user, - status='paid' if data.get('payment_type') == 'cash' else 'partial' - ) - for item in data.get('items', []): - PurchaseItem.objects.create( - purchase=purchase, - product_id=item['id'], - quantity=item['quantity'], - cost_price=item['cost'], - line_total=float(item['quantity']) * float(item['cost']) - ) - # Increase Stock - Product.objects.filter(pk=item['id']).update(stock_quantity=F('stock_quantity') + item['quantity']) - - # Payment - if purchase.paid_amount > 0: - PurchasePayment.objects.create( - purchase=purchase, - amount=purchase.paid_amount, - payment_method_id=data.get('payment_method_id'), - created_by=request.user - ) - - purchase.update_balance() - - return JsonResponse({'success': True, 'purchase_id': purchase.id}) - except Exception as e: - logger.error(f"Error creating purchase: {e}") - return JsonResponse({'success': False, 'error': str(e)})""" - -content = re.sub( - r'@csrf_exempt\s+@login_required\s+def create_purchase_api\(request\):\s+return JsonResponse\({\s*["']success["']: True\s*}\)', - new_create_purchase, - content -) - - -# Implement add_customer_ajax -new_add_customer = """@csrf_exempt -@login_required -def add_customer_ajax(request): - if request.method != 'POST': - return JsonResponse({'success': False}) - try: - data = json.loads(request.body) - Customer.objects.create(name=data.get('name'), phone=data.get('phone', '')) - return JsonResponse({'success': True}) - except Exception as e: - return JsonResponse({'success': False, 'error': str(e)})""" - -content = re.sub( - r'@login_required\s+def add_customer_ajax\(request\):\s+return JsonResponse\({\s*["']success["']: True\s*}\)', - new_add_customer, - content -) - -# Implement add_supplier_ajax -new_add_supplier = """@csrf_exempt -@login_required -def add_supplier_ajax(request): - if request.method != 'POST': - return JsonResponse({'success': False}) - try: - data = json.loads(request.body) - Supplier.objects.create(name=data.get('name'), phone=data.get('phone', '')) - return JsonResponse({'success': True}) - except Exception as e: - return JsonResponse({'success': False, 'error': str(e)})""" - -content = re.sub( - r'@login_required\s+def add_supplier_ajax\(request\):\s+return JsonResponse\({\s*["']success["']: True\s*}\)', - new_add_supplier, - content -) - -with open(file_path, 'w') as f: - f.write(content) - -print("Patched core/views.py successfully.") diff --git a/patch_views_sales.py b/patch_views_sales.py deleted file mode 100644 index 62ea21c..0000000 --- a/patch_views_sales.py +++ /dev/null @@ -1,206 +0,0 @@ -import os - -file_path = 'core/views.py' - -# New Implementations -edit_invoice_code = """ -@login_required -def edit_invoice(request, pk): - sale = get_object_or_404(Sale, pk=pk) - customers = Customer.objects.all() - products = Product.objects.filter(is_active=True).select_related('category') - payment_methods = PaymentMethod.objects.filter(is_active=True) - site_settings = SystemSetting.objects.first() - - decimal_places = 2 - if site_settings: - decimal_places = site_settings.decimal_places - - # Serialize items for Vue - cart_items = [] - for item in sale.items.all().select_related('product'): - cart_items.append({ - 'id': item.product.id, - 'name_en': item.product.name_en, - 'name_ar': item.product.name_ar, - 'sku': item.product.sku, - 'price': float(item.unit_price), - 'quantity': float(item.quantity), - 'stock': float(item.product.stock_quantity) - }) - - cart_json = json.dumps(cart_items) - - # Get first payment method if exists - payment_method_id = "" - first_payment = sale.payments.first() - if first_payment and first_payment.payment_method: - payment_method_id = first_payment.payment_method.id - - context = { - 'sale': sale, - 'customers': customers, - 'products': products, - 'payment_methods': payment_methods, - 'site_settings': site_settings, - 'decimal_places': decimal_places, - 'cart_json': cart_json, - 'payment_method_id': payment_method_id - } - return render(request, 'core/invoice_edit.html', context) -""" - -sale_receipt_code = """ -@login_required -def sale_receipt(request, pk): - sale = get_object_or_404(Sale, pk=pk) - settings = SystemSetting.objects.first() - return render(request, 'core/sale_receipt.html', { - 'sale': sale, - 'settings': settings - }) -""" - -update_sale_api_code = """ -@csrf_exempt -def update_sale_api(request, pk): - if request.method != 'POST': - return JsonResponse({'success': False, 'error': 'Invalid request method'}) - - try: - sale = Sale.objects.get(pk=pk) - data = json.loads(request.body) - - customer_id = data.get('customer_id') - items = data.get('items', []) - discount = decimal.Decimal(str(data.get('discount', 0))) - paid_amount = decimal.Decimal(str(data.get('paid_amount', 0))) - payment_type = data.get('payment_type', 'cash') - payment_method_id = data.get('payment_method_id') - due_date = data.get('due_date') - notes = data.get('notes', '') - invoice_number = data.get('invoice_number') - - if not items: - return JsonResponse({'success': False, 'error': 'No items in sale'}) - - with transaction.atomic(): - # 1. Revert Stock - for item in sale.items.all(): - product = item.product - product.stock_quantity += item.quantity - product.save() - - # 2. Delete existing items - sale.items.all().delete() - - # 3. Update Sale Details - if customer_id: - sale.customer_id = customer_id - else: - sale.customer = None - - sale.discount = discount - sale.notes = notes - if invoice_number: - sale.invoice_number = invoice_number - - if due_date: - sale.due_date = due_date - else: - sale.due_date = None - - # 4. Create New Items and Deduct Stock - subtotal = decimal.Decimal(0) - - for item_data in items: - product = Product.objects.get(pk=item_data['id']) - quantity = decimal.Decimal(str(item_data['quantity'])) - price = decimal.Decimal(str(item_data['price'])) - - # Deduct stock - product.stock_quantity -= quantity - product.save() - - line_total = price * quantity - subtotal += line_total - - SaleItem.objects.create( - sale=sale, - product=product, - quantity=quantity, - unit_price=price, - line_total=line_total - ) - - sale.subtotal = subtotal - sale.total_amount = subtotal - discount - - # 5. Handle Payments - if payment_type == 'credit': - sale.status = 'unpaid' - sale.paid_amount = 0 - sale.balance_due = sale.total_amount - sale.payments.all().delete() - - elif payment_type == 'cash': - sale.status = 'paid' - sale.paid_amount = sale.total_amount - sale.balance_due = 0 - - sale.payments.all().delete() - SalePayment.objects.create( - sale=sale, - amount=sale.total_amount, - payment_method_id=payment_method_id if payment_method_id else None, - payment_date=timezone.now().date(), - notes='Full Payment (Edit)' - ) - - elif payment_type == 'partial': - sale.paid_amount = paid_amount - sale.balance_due = sale.total_amount - paid_amount - if sale.balance_due <= 0: - sale.status = 'paid' - sale.balance_due = 0 - else: - sale.status = 'partial' - - sale.payments.all().delete() - SalePayment.objects.create( - sale=sale, - amount=paid_amount, - payment_method_id=payment_method_id if payment_method_id else None, - payment_date=timezone.now().date(), - notes='Partial Payment (Edit)' - ) - - sale.save() - - return JsonResponse({'success': True, 'sale_id': sale.id}) - - except Sale.DoesNotExist: - return JsonResponse({'success': False, 'error': 'Sale not found'}) - except Product.DoesNotExist: - return JsonResponse({'success': False, 'error': 'Product not found'}) - except Exception as e: - return JsonResponse({'success': False, 'error': str(e)}) -""" - -with open(file_path, 'r') as f: - content = f.read() - -# Replace stubs -content = content.replace("def sale_receipt(request, pk): return redirect('invoices')", sale_receipt_code) -content = content.replace("def edit_invoice(request, pk): return redirect('invoices')", edit_invoice_code) -content = content.replace("@csrf_exempt\ndef update_sale_api(request, pk): return JsonResponse({'success': False})", update_sale_api_code) - -# Handle potential whitespace variations if single-line replace fails -if "def edit_invoice(request, pk): return redirect('invoices')" in content: # Check if it persisted - pass # worked -else: - # Fallback for manual check if needed (it should work given exact match from read_file) - pass - -with open(file_path, 'w') as f: - f.write(content) diff --git a/restore_views.py b/restore_views.py deleted file mode 100644 index a25f4cb..0000000 --- a/restore_views.py +++ /dev/null @@ -1,220 +0,0 @@ -import os - -file_path = 'core/views.py' - -# The missing code to append -missing_code = r""" - # Deduct stock - product.stock_quantity -= int(item['quantity']) - product.save() - - return JsonResponse({'success': True, 'sale_id': sale.id}) - except Exception as e: - return JsonResponse({'success': False, 'error': str(e)}, status=400) - return JsonResponse({'success': False, 'error': 'Invalid request'}, status=405) - -@login_required -def search_customers_api(request): - query = request.GET.get('q', '') - customers = Customer.objects.filter( - Q(name__icontains=query) | Q(phone__icontains=query) - ).values('id', 'name', 'phone')[:10] - return JsonResponse({'results': list(customers)}) - -@login_required -def customer_payments(request): - payments = SalePayment.objects.select_related('sale', 'sale__customer').order_by('-payment_date', '-created_at') - paginator = Paginator(payments, 25) - page_number = request.GET.get('page') - payments = paginator.get_page(page_number) - return render(request, 'core/customer_payments.html', {'payments': payments}) - -@login_required -def customer_payment_receipt(request, pk): - payment = get_object_or_404(SalePayment, pk=pk) - settings = SystemSetting.objects.first() - return render(request, 'core/payment_receipt.html', { - 'payment': payment, - 'settings': settings, - 'amount_in_words': number_to_words_en(payment.amount) - }) - -@login_required -def sale_receipt(request, pk): - sale = get_object_or_404(Sale, pk=pk) - settings = SystemSetting.objects.first() - return render(request, 'core/sale_receipt.html', { - 'sale': sale, - 'settings': settings - }) - -@csrf_exempt -def pos_sync_update(request): - # Placeholder for POS sync logic - return JsonResponse({'status': 'ok'}) - -@csrf_exempt -def pos_sync_state(request): - # Placeholder for POS sync state - return JsonResponse({'state': {}}) - -@login_required -def test_whatsapp_connection(request): - settings = SystemSetting.objects.first() - if not settings or not settings.wablas_enabled: - return JsonResponse({'success': False, 'message': 'WhatsApp not enabled'}) - return JsonResponse({'success': True, 'message': 'Connection simulation successful'}) - -@login_required -def add_device(request): - if request.method == 'POST': - name = request.POST.get('name') - device_type = request.POST.get('device_type') - connection_type = request.POST.get('connection_type') - ip_address = request.POST.get('ip_address') - port = request.POST.get('port') - is_active = request.POST.get('is_active') == 'on' - - Device.objects.create( - name=name, - device_type=device_type, - connection_type=connection_type, - ip_address=ip_address if ip_address else None, - port=port if port else None, - is_active=is_active - ) - messages.success(request, _("Device added successfully!")) - return redirect(reverse('settings') + '#devices') - -@login_required -def edit_device(request, pk): - device = get_object_or_404(Device, pk=pk) - if request.method == 'POST': - device.name = request.POST.get('name') - device.device_type = request.POST.get('device_type') - device.connection_type = request.POST.get('connection_type') - device.ip_address = request.POST.get('ip_address') - device.port = request.POST.get('port') - device.is_active = request.POST.get('is_active') == 'on' - - if not device.ip_address: - device.ip_address = None - if not device.port: - device.port = None - - device.save() - messages.success(request, _("Device updated successfully!")) - return redirect(reverse('settings') + '#devices') - -@login_required -def delete_device(request, pk): - device = get_object_or_404(Device, pk=pk) - device.delete() - messages.success(request, _("Device deleted successfully!")) - return redirect(reverse('settings') + '#devices') - -# LPO Views (Placeholders/Basic Implementation) -@login_required -def lpo_list(request): - lpos = PurchaseOrder.objects.all().order_by('-created_at') - return render(request, 'core/lpo_list.html', {'lpos': lpos}) - -@login_required -def lpo_create(request): - suppliers = Supplier.objects.all() - products = Product.objects.filter(is_active=True) - return render(request, 'core/lpo_create.html', {'suppliers': suppliers, 'products': products}) - -@login_required -def lpo_detail(request, pk): - lpo = get_object_or_404(PurchaseOrder, pk=pk) - settings = SystemSetting.objects.first() - return render(request, 'core/lpo_detail.html', {'lpo': lpo, 'settings': settings}) - -@login_required -def convert_lpo_to_purchase(request, pk): - lpo = get_object_or_404(PurchaseOrder, pk=pk) - # Conversion logic here (simplified) - # ... - return redirect('purchases') - -@login_required -def lpo_delete(request, pk): - lpo = get_object_or_404(PurchaseOrder, pk=pk) - lpo.delete() - return redirect('lpo_list') - -@csrf_exempt -@login_required -def create_lpo_api(request): - # API logic for LPO creation - return JsonResponse({'success': True, 'lpo_id': 1}) # Dummy - -@login_required -def cashier_registry(request): - registries = CashierCounterRegistry.objects.all() - return render(request, 'core/cashier_registry.html', {'registries': registries}) - -# Session Views -@login_required -def cashier_session_list(request): - sessions = CashierSession.objects.all().order_by('-start_time') - return render(request, 'core/session_list.html', {'sessions': sessions}) - -@login_required -def start_session(request): - if request.method == 'POST': - opening_balance = request.POST.get('opening_balance', 0) - # Find assigned counter - registry = CashierCounterRegistry.objects.filter(cashier=request.user).first() - counter = registry.counter if registry else None - - CashierSession.objects.create( - user=request.user, - counter=counter, - opening_balance=opening_balance, - status='active' - ) - return redirect('pos') - return render(request, 'core/start_session.html') - -@login_required -def close_session(request): - session = CashierSession.objects.filter(user=request.user, status='active').first() - if request.method == 'POST' and session: - closing_balance = request.POST.get('closing_balance', 0) - notes = request.POST.get('notes', '') - session.closing_balance = closing_balance - session.notes = notes - session.end_time = timezone.now() - session.status = 'closed' - session.save() - return redirect('index') - return render(request, 'core/close_session.html', {'session': session}) - -@login_required -def session_detail(request, pk): - session = get_object_or_404(CashierSession, pk=pk) - return render(request, 'core/session_detail.html', {'session': session}) - -@login_required -def customer_display(request): - return render(request, 'core/customer_display.html') -""" - -with open(file_path, 'r') as f: - content = f.read() - -# Check if the file ends with the broken function -if content.strip().endswith("line_total=item['line_total']\n )"): - print("Found broken file end. Appending missing code.") - with open(file_path, 'a') as f: - f.write(missing_code) - print("Successfully restored core/views.py") -else: - print("File does not end as expected. Please check manually.") - # Force append if it looks like it's missing the new functions - if "def start_session" not in content: - print("Appending missing functions anyway...") - with open(file_path, 'a') as f: - f.write(missing_code) diff --git a/settings_trace.txt b/settings_trace.txt deleted file mode 100644 index 944488a..0000000 --- a/settings_trace.txt +++ /dev/null @@ -1 +0,0 @@ -Settings loaded diff --git a/startup_status.txt b/startup_status.txt deleted file mode 100644 index ecbe128..0000000 --- a/startup_status.txt +++ /dev/null @@ -1,18 +0,0 @@ -[2026-02-09T07:28:37.599243] Starting manage.py... -[2026-02-09T07:28:37.599461] Args: ['manage.py', 'runserver', '0.0.0.0:8000'] -[2026-02-09T07:28:37.653416] Loaded .env -[2026-02-09T07:28:38.658262] Django setup complete. -[2026-02-09T07:28:38.658403] Executing command line... -[2026-02-09T07:28:46.088684] SystemExit caught: 3 -[2026-02-09T07:28:46.362448] Starting manage.py... -[2026-02-09T07:28:46.362618] Args: ['manage.py', 'runserver', '0.0.0.0:8000'] -[2026-02-09T07:28:46.390956] Loaded .env -[2026-02-09T07:28:46.717591] Django setup complete. -[2026-02-09T07:28:46.717749] Executing command line... -[2026-02-09T07:42:35.563432] SystemExit caught: 3 -[2026-02-09T07:42:36.571344] Starting manage.py... -[2026-02-09T07:42:36.571557] Args: ['manage.py', 'runserver', '0.0.0.0:8000'] -[2026-02-09T07:42:36.626917] Loaded .env -[2026-02-09T07:42:37.207600] Django setup complete. -[2026-02-09T07:42:37.207759] Executing command line... -[2026-02-09T07:42:38.535239] SystemExit caught: 3 diff --git a/test_pos_render.py b/test_pos_render.py deleted file mode 100644 index c1d7964..0000000 --- a/test_pos_render.py +++ /dev/null @@ -1,52 +0,0 @@ -import os -import django -from django.conf import settings - -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings') -django.setup() - -from django.template.loader import render_to_string -from django.test import RequestFactory -from core.models import Product, SystemSetting, Category, PaymentMethod - -def test_pos_render(): - factory = RequestFactory() - request = factory.get('/pos/') - - s_settings = SystemSetting.objects.first() - products = Product.objects.filter(is_active=True) - categories = Category.objects.all() - payment_methods = PaymentMethod.objects.all() - - context = { - 'products': products, - 'customers': [], - 'categories': categories, - 'payment_methods': payment_methods, - 'settings': s_settings, - 'site_settings': s_settings, - 'active_session': None, - 'LANGUAGE_CODE': 'en' - } - - rendered = render_to_string('core/pos.html', context, request=request) - - print(f"Total Products Checked: {products.count()}") - # Check for image URLs - for product in products: - if product.image: - url = product.image.url - if url in rendered: - print(f"Product {product.name_en} image URL FOUND: {url}") - else: - # Check for escaped URL - from django.utils.html import escape - if escape(url) in rendered: - print(f"Product {product.name_en} image URL FOUND (escaped): {escape(url)}") - else: - print(f"Product {product.name_en} image URL MISSING: {url}") - else: - print(f"Product {product.name_en} has no image in DB") - -if __name__ == "__main__": - test_pos_render() \ No newline at end of file diff --git a/test_render.py b/test_render.py deleted file mode 100644 index f444fd7..0000000 --- a/test_render.py +++ /dev/null @@ -1,57 +0,0 @@ -import os -import django -from django.conf import settings -from django.template.loader import render_to_string -from django.test import RequestFactory - -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings') -django.setup() - -from core.models import SystemSetting, Product, Customer, Sale, Category, PaymentMethod -from django.utils import timezone -import datetime - -def test_render(): - factory = RequestFactory() - request = factory.get('/') - # Simulate a user - from django.contrib.auth.models import User - user = User.objects.first() - request.user = user - - settings_obj = SystemSetting.objects.first() - context = { - 'site_settings': settings_obj, - 'settings': settings_obj, - 'total_sales_amount': 0, - 'total_receivables': 0, - 'total_payables': 0, - 'total_sales_count': 0, - 'total_products': 0, - 'total_customers': 0, - 'monthly_labels': [], - 'monthly_data': [], - 'chart_labels': [], - 'chart_data': [], - 'category_labels': [], - 'category_data': [], - 'payment_labels': [], - 'payment_data': [], - 'top_products': [], - 'low_stock_count': 0, - 'low_stock_products': [], - 'expired_count': 0, - 'recent_sales': [], - } - - try: - html = render_to_string('core/index.html', context, request=request) - print(f"Render successful, length: {len(html)}") - if len(html) < 100: - print("HTML is too short!") - print(html) - except Exception as e: - print(f"Render failed: {e}") - -if __name__ == "__main__": - test_render() diff --git a/test_write.txt b/test_write.txt deleted file mode 100644 index 268af4e..0000000 --- a/test_write.txt +++ /dev/null @@ -1 +0,0 @@ -modified content \ No newline at end of file diff --git a/wsgi_crash.txt b/wsgi_crash.txt deleted file mode 100644 index 4143b0d..0000000 --- a/wsgi_crash.txt +++ /dev/null @@ -1,30 +0,0 @@ -WSGI Crash: No module named 'whitenoise' -Traceback (most recent call last): - File "/home/ubuntu/executor/workspace/config/wsgi.py", line 19, in - application = get_wsgi_application() - ^^^^^^^^^^^^^^^^^^^^^^ - File "/home/ubuntu/.local/lib/python3.11/site-packages/django/core/wsgi.py", line 13, in get_wsgi_application - return WSGIHandler() - ^^^^^^^^^^^^^ - File "/home/ubuntu/.local/lib/python3.11/site-packages/django/core/handlers/wsgi.py", line 118, in __init__ - self.load_middleware() - File "/home/ubuntu/.local/lib/python3.11/site-packages/django/core/handlers/base.py", line 40, in load_middleware - middleware = import_string(middleware_path) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/home/ubuntu/.local/lib/python3.11/site-packages/django/utils/module_loading.py", line 30, in import_string - return cached_import(module_path, class_name) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/home/ubuntu/.local/lib/python3.11/site-packages/django/utils/module_loading.py", line 15, in cached_import - module = import_module(module_path) - ^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/usr/lib/python3.11/importlib/__init__.py", line 126, in import_module - return _bootstrap._gcd_import(name[level:], package, level) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "", line 1206, in _gcd_import - File "", line 1178, in _find_and_load - File "", line 1128, in _find_and_load_unlocked - File "", line 241, in _call_with_frames_removed - File "", line 1206, in _gcd_import - File "", line 1178, in _find_and_load - File "", line 1142, in _find_and_load_unlocked -ModuleNotFoundError: No module named 'whitenoise' diff --git a/wsgi_status.txt b/wsgi_status.txt deleted file mode 100644 index b5be6c0..0000000 --- a/wsgi_status.txt +++ /dev/null @@ -1,9 +0,0 @@ -[2026-02-09T07:28:46.937704] WSGI module loading... -[2026-02-09T07:28:46.948377] WSGI loaded .env -[2026-02-09T07:28:46.952251] WSGI application created successfully. -[2026-02-09T07:42:37.533157] WSGI module loading... -[2026-02-09T07:42:37.541628] WSGI loaded .env -[2026-02-09T07:42:37.544967] WSGI application created successfully. -[2026-02-09T07:42:39.272623] WSGI module loading... -[2026-02-09T07:42:39.280940] WSGI loaded .env -[2026-02-09T07:42:39.283449] WSGI application created successfully. diff --git a/wsgi_trace.txt b/wsgi_trace.txt deleted file mode 100644 index 3f6e51a..0000000 --- a/wsgi_trace.txt +++ /dev/null @@ -1 +0,0 @@ -WSGI loaded