Autosave: 20260213-030304
This commit is contained in:
parent
7166fdc776
commit
3360fbcad2
Binary file not shown.
Binary file not shown.
@ -155,6 +155,8 @@ SESSION_COOKIE_SECURE = True
|
||||
CSRF_COOKIE_SECURE = True
|
||||
SESSION_COOKIE_SAMESITE = "None"
|
||||
CSRF_COOKIE_SAMESITE = "None"
|
||||
SECURE_CROSS_ORIGIN_OPENER_POLICY = None
|
||||
SECURE_REFERRER_POLICY = 'no-referrer-when-downgrade'
|
||||
# X_FRAME_OPTIONS = 'SAMEORIGIN'
|
||||
|
||||
# Email Settings
|
||||
|
||||
@ -20,12 +20,11 @@ try:
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
# --- FIX: Preload libraries for WeasyPrint/Pango ---
|
||||
# Manually load libraries using absolute paths
|
||||
import ctypes
|
||||
import ctypes.util
|
||||
# --- WeasyPrint Library Preloading ---
|
||||
import traceback
|
||||
import sys
|
||||
import ctypes
|
||||
import ctypes.util
|
||||
|
||||
lib_paths = [
|
||||
'/usr/lib/x86_64-linux-gnu/libglib-2.0.so.0',
|
||||
@ -42,31 +41,13 @@ for path in lib_paths:
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
# Try to import weasyprint
|
||||
try:
|
||||
import weasyprint
|
||||
except Exception as e:
|
||||
# Log error to file and stderr
|
||||
error_msg = f"WeasyPrint Import Error: {str(e)}\n{traceback.format_exc()}"
|
||||
sys.stderr.write(error_msg)
|
||||
try:
|
||||
with open("weasyprint_wsgi_error.log", "w") as f:
|
||||
f.write(error_msg)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# Fallback to mock
|
||||
import types
|
||||
class MockHTML:
|
||||
def __init__(self, string=None, base_url=None):
|
||||
pass
|
||||
def write_pdf(self, target=None):
|
||||
raise OSError("WeasyPrint system dependencies are missing. PDF generation is disabled.")
|
||||
|
||||
mock_wp = types.ModuleType("weasyprint")
|
||||
mock_wp.HTML = MockHTML
|
||||
sys.modules["weasyprint"] = mock_wp
|
||||
# ---------------------------------------------------
|
||||
with open("/tmp/weasyprint_wsgi_error.log", "w") as f:
|
||||
f.write(error_msg)
|
||||
# -------------------------------------
|
||||
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings')
|
||||
|
||||
|
||||
Binary file not shown.
@ -34,7 +34,6 @@
|
||||
{% block head %}{% endblock %}
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="wrapper">
|
||||
<!-- Sidebar -->
|
||||
{% if user.is_authenticated %}
|
||||
|
||||
@ -636,7 +636,12 @@ def sale_receipt(request, pk):
|
||||
|
||||
@login_required
|
||||
def quotations(request):
|
||||
quotations = Quotation.objects.all().order_by('-created_at')
|
||||
quotations_qs = Quotation.objects.all().order_by('-created_at')
|
||||
|
||||
paginator = Paginator(quotations_qs, 20)
|
||||
page_number = request.GET.get('page')
|
||||
quotations = paginator.get_page(page_number)
|
||||
|
||||
return render(request, 'core/quotations.html', {'quotations': quotations})
|
||||
|
||||
@login_required
|
||||
@ -690,11 +695,60 @@ def delete_quotation(request, pk):
|
||||
messages.success(request, _("Quotation deleted."))
|
||||
return redirect('quotations')
|
||||
|
||||
@csrf_exempt
|
||||
@login_required
|
||||
def create_quotation_api(request):
|
||||
# Simplified API stub
|
||||
return JsonResponse({'success': True})
|
||||
if request.method != 'POST':
|
||||
return JsonResponse({'success': False, 'error': 'Method not allowed'})
|
||||
|
||||
try:
|
||||
data = json.loads(request.body)
|
||||
customer_id = data.get('customer_id')
|
||||
quotation_number = data.get('quotation_number')
|
||||
items = data.get('items', [])
|
||||
total_amount = data.get('total_amount', 0)
|
||||
discount = data.get('discount', 0)
|
||||
valid_until = data.get('valid_until')
|
||||
terms_and_conditions = data.get('terms_and_conditions', '')
|
||||
notes = data.get('notes', '')
|
||||
|
||||
if not items:
|
||||
return JsonResponse({'success': False, 'error': _('Cannot save an empty quotation.')})
|
||||
|
||||
with transaction.atomic():
|
||||
customer = None
|
||||
if customer_id:
|
||||
customer = Customer.objects.get(id=customer_id)
|
||||
|
||||
quotation = Quotation.objects.create(
|
||||
customer=customer,
|
||||
quotation_number=quotation_number,
|
||||
total_amount=total_amount,
|
||||
discount=discount,
|
||||
valid_until=valid_until if valid_until else None,
|
||||
terms_and_conditions=terms_and_conditions,
|
||||
notes=notes,
|
||||
created_by=request.user
|
||||
)
|
||||
|
||||
for item in items:
|
||||
product = Product.objects.get(id=item['id'])
|
||||
QuotationItem.objects.create(
|
||||
quotation=quotation,
|
||||
product=product,
|
||||
quantity=item['quantity'],
|
||||
unit_price=item['price'],
|
||||
line_total=item['line_total']
|
||||
)
|
||||
|
||||
messages.success(request, _("Quotation created successfully."))
|
||||
return JsonResponse({'success': True, 'quotation_id': quotation.id})
|
||||
except Customer.DoesNotExist:
|
||||
return JsonResponse({'success': False, 'error': _('Customer not found.')})
|
||||
except Product.DoesNotExist:
|
||||
return JsonResponse({'success': False, 'error': _('One or more products not found.')})
|
||||
except Exception as e:
|
||||
logger.error(f"Error creating quotation: {str(e)}")
|
||||
return JsonResponse({'success': False, 'error': str(e)})
|
||||
|
||||
# --- Sales Returns ---
|
||||
|
||||
|
||||
29
manage.py
29
manage.py
@ -14,9 +14,7 @@ def main():
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
# --- FIX: Preload libraries for WeasyPrint/Pango ---
|
||||
# Manually load libraries using absolute paths since LD_LIBRARY_PATH
|
||||
# changes don't affect dlopen() in the running process.
|
||||
# --- WeasyPrint Library Preloading ---
|
||||
import ctypes
|
||||
import ctypes.util
|
||||
import traceback
|
||||
@ -34,34 +32,15 @@ def main():
|
||||
try:
|
||||
ctypes.CDLL(path)
|
||||
except OSError:
|
||||
# Continue even if one fails
|
||||
pass
|
||||
|
||||
# Try to import weasyprint to see if it works
|
||||
try:
|
||||
import weasyprint
|
||||
except Exception as e:
|
||||
# Log the specific error for debugging
|
||||
error_msg = f"WeasyPrint Import Error: {str(e)}\n{traceback.format_exc()}"
|
||||
sys.stderr.write(error_msg)
|
||||
try:
|
||||
with open("weasyprint_error.log", "w") as f:
|
||||
f.write(error_msg)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# Fallback to mock if system dependencies are missing or import fails
|
||||
import types
|
||||
class MockHTML:
|
||||
def __init__(self, string=None, base_url=None):
|
||||
pass
|
||||
def write_pdf(self, target=None):
|
||||
raise OSError("WeasyPrint system dependencies are missing. PDF generation is disabled.")
|
||||
|
||||
mock_wp = types.ModuleType("weasyprint")
|
||||
mock_wp.HTML = MockHTML
|
||||
sys.modules["weasyprint"] = mock_wp
|
||||
# ---------------------------------------------------
|
||||
with open("/tmp/weasyprint_error.log", "w") as f:
|
||||
f.write(error_msg)
|
||||
# -------------------------------------
|
||||
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings')
|
||||
try:
|
||||
|
||||
52
test_pos_render.py
Normal file
52
test_pos_render.py
Normal file
@ -0,0 +1,52 @@
|
||||
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()
|
||||
57
test_render.py
Normal file
57
test_render.py
Normal file
@ -0,0 +1,57 @@
|
||||
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()
|
||||
Loading…
x
Reference in New Issue
Block a user