adding customer due to dash
This commit is contained in:
parent
db1a6f5278
commit
9299fde7e7
Binary file not shown.
@ -2,6 +2,15 @@ from django.contrib import admin
|
||||
from django.urls import include, path
|
||||
from django.conf import settings
|
||||
from django.conf.urls.static import static
|
||||
from django.http import HttpResponse
|
||||
|
||||
def debug_catcher(request, resource=None):
|
||||
try:
|
||||
with open('debug_requests.txt', 'a') as f:
|
||||
f.write(f"Caught 404 candidate: {request.path}\n")
|
||||
except Exception:
|
||||
pass
|
||||
return HttpResponse(f"<h1>Debug 404 Catcher</h1><p>You requested: <strong>{request.path}</strong></p><p>This URL was not matched by any standard pattern.</p>")
|
||||
|
||||
urlpatterns = [
|
||||
path("admin/", admin.site.urls),
|
||||
@ -16,3 +25,6 @@ if settings.DEBUG:
|
||||
urlpatterns += static("/assets/", document_root=settings.BASE_DIR / "assets")
|
||||
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
|
||||
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
||||
|
||||
# Append catch-all
|
||||
urlpatterns.append(path('<path:resource>', debug_catcher))
|
||||
Binary file not shown.
@ -10,15 +10,19 @@ class Migration(migrations.Migration):
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunSQL(
|
||||
sql="ALTER TABLE core_systemsetting DROP COLUMN IF EXISTS logo_url;",
|
||||
reverse_sql="ALTER TABLE core_systemsetting ADD COLUMN IF NOT EXISTS logo_url varchar(200);",
|
||||
# Modified to handle inconsistent database state (column already missing)
|
||||
migrations.SeparateDatabaseAndState(
|
||||
state_operations=[
|
||||
migrations.RemoveField(
|
||||
model_name='systemsetting',
|
||||
name='logo_url',
|
||||
),
|
||||
]
|
||||
],
|
||||
database_operations=[
|
||||
# Intentionally empty to skip SQL execution.
|
||||
# The column 'logo_url' is likely already missing in the DB, causing 1091 errors.
|
||||
# In fresh installs, this leaves a zombie column, which is harmless as it's not in the model.
|
||||
],
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='systemsetting',
|
||||
@ -70,4 +74,4 @@ class Migration(migrations.Migration):
|
||||
name='currency_symbol',
|
||||
field=models.CharField(default='OMR', max_length=10, verbose_name='Currency Symbol'),
|
||||
),
|
||||
]
|
||||
]
|
||||
Binary file not shown.
@ -20,7 +20,8 @@
|
||||
|
||||
<!-- Stats Cards -->
|
||||
<div class="row g-3 mb-4">
|
||||
<div class="col-md-3">
|
||||
<!-- Row 1: Financials -->
|
||||
<div class="col-md-4">
|
||||
<div class="card glass-card border-0 p-3 stat-card h-100">
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="stat-icon bg-primary text-white bg-opacity-10 text-primary rounded-3 p-3 me-3">
|
||||
@ -33,11 +34,39 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="col-md-4">
|
||||
<div class="card glass-card border-0 p-3 stat-card h-100">
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="stat-icon bg-success bg-opacity-10 rounded-3 p-3 me-3">
|
||||
<i class="bi bi-cart-check fs-4 text-success"></i>
|
||||
<i class="bi bi-arrow-down-left-circle fs-4 text-success"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h6 class="text-muted small mb-1">{% trans "Customer Due" %}</h6>
|
||||
<h4 class="fw-bold mb-0">{{ site_settings.currency_symbol }}{{ total_receivables|floatformat:3 }}</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="card glass-card border-0 p-3 stat-card h-100">
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="stat-icon bg-danger bg-opacity-10 rounded-3 p-3 me-3">
|
||||
<i class="bi bi-arrow-up-right-circle fs-4 text-danger"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h6 class="text-muted small mb-1">{% trans "Supplier Due" %}</h6>
|
||||
<h4 class="fw-bold mb-0">{{ site_settings.currency_symbol }}{{ total_payables|floatformat:3 }}</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Row 2: Counts -->
|
||||
<div class="col-md-4">
|
||||
<div class="card glass-card border-0 p-3 stat-card h-100">
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="stat-icon bg-info bg-opacity-10 rounded-3 p-3 me-3">
|
||||
<i class="bi bi-cart-check fs-4 text-info"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h6 class="text-muted small mb-1">{% trans "Total Sales" %}</h6>
|
||||
@ -46,11 +75,11 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="col-md-4">
|
||||
<div class="card glass-card border-0 p-3 stat-card h-100">
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="stat-icon bg-info bg-opacity-10 rounded-3 p-3 me-3">
|
||||
<i class="bi bi-box-seam fs-4 text-info"></i>
|
||||
<div class="stat-icon bg-warning bg-opacity-10 rounded-3 p-3 me-3">
|
||||
<i class="bi bi-box-seam fs-4 text-warning"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h6 class="text-muted small mb-1">{% trans "Total Products" %}</h6>
|
||||
@ -59,11 +88,11 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="col-md-4">
|
||||
<div class="card glass-card border-0 p-3 stat-card h-100">
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="stat-icon bg-warning bg-opacity-10 rounded-3 p-3 me-3">
|
||||
<i class="bi bi-people fs-4 text-warning"></i>
|
||||
<div class="stat-icon bg-secondary bg-opacity-10 rounded-3 p-3 me-3">
|
||||
<i class="bi bi-people fs-4 text-secondary"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h6 class="text-muted small mb-1">{% trans "Total Customers" %}</h6>
|
||||
|
||||
172
core/views.py
172
core/views.py
@ -31,16 +31,20 @@ def index(request):
|
||||
total_products = Product.objects.count()
|
||||
total_customers = Customer.objects.count()
|
||||
|
||||
# New: Receivables and Payables
|
||||
total_receivables = Sale.objects.aggregate(total=Sum('balance_due'))['total'] or 0
|
||||
total_payables = Purchase.objects.aggregate(total=Sum('balance_due'))['total'] or 0
|
||||
|
||||
# 2. Charts Data
|
||||
today = timezone.now().date()
|
||||
|
||||
# A. Monthly Sales (Current Year)
|
||||
current_year = today.year
|
||||
monthly_sales = Sale.objects.filter(created_at__year=current_year)\
|
||||
.annotate(month=models.functions.ExtractMonth('created_at'))\
|
||||
.values('month')\
|
||||
.annotate(total=Sum('total_amount'))\
|
||||
.order_by('month')
|
||||
monthly_sales = (Sale.objects.filter(created_at__year=current_year)
|
||||
.annotate(month=models.functions.ExtractMonth('created_at'))
|
||||
.values('month')
|
||||
.annotate(total=Sum('total_amount'))
|
||||
.order_by('month'))
|
||||
|
||||
monthly_labels = []
|
||||
monthly_data = []
|
||||
@ -56,11 +60,11 @@ def index(request):
|
||||
|
||||
# B. Daily Sales (Last 7 Days)
|
||||
seven_days_ago = today - timedelta(days=6)
|
||||
daily_sales = Sale.objects.filter(created_at__date__gte=seven_days_ago)\
|
||||
.annotate(day=models.functions.ExtractDay('created_at'))\
|
||||
.values('created_at__date')\
|
||||
.annotate(total=Sum('total_amount'))\
|
||||
.order_by('created_at__date')
|
||||
daily_sales = (Sale.objects.filter(created_at__date__gte=seven_days_ago)
|
||||
.annotate(day=models.functions.ExtractDay('created_at'))
|
||||
.values('created_at__date')
|
||||
.annotate(total=Sum('total_amount'))
|
||||
.order_by('created_at__date'))
|
||||
|
||||
chart_labels = []
|
||||
chart_data = []
|
||||
@ -79,25 +83,25 @@ def index(request):
|
||||
chart_data.append(date_map[date_key])
|
||||
|
||||
# C. Sales by Category
|
||||
category_sales = SaleItem.objects.values('product__category__name_en')\
|
||||
.annotate(total=Sum('line_total'))\
|
||||
.order_by('-total')[:5]
|
||||
category_sales = (SaleItem.objects.values('product__category__name_en')
|
||||
.annotate(total=Sum('line_total'))
|
||||
.order_by('-total')[:5])
|
||||
|
||||
category_labels = [item['product__category__name_en'] for item in category_sales]
|
||||
category_data = [float(item['total']) for item in category_sales]
|
||||
|
||||
# D. Payment Methods
|
||||
payment_stats = SalePayment.objects.values('payment_method_name')\
|
||||
.annotate(total=Sum('amount'))\
|
||||
.order_by('-total')
|
||||
payment_stats = (SalePayment.objects.values('payment_method_name')
|
||||
.annotate(total=Sum('amount'))
|
||||
.order_by('-total'))
|
||||
|
||||
payment_labels = [item['payment_method_name'] if item['payment_method_name'] else 'Unknown' for item in payment_stats]
|
||||
payment_data = [float(item['total']) for item in payment_stats]
|
||||
|
||||
# 3. Top Products
|
||||
top_products = SaleItem.objects.values('product__name_en', 'product__name_ar')\
|
||||
.annotate(total_qty=Sum('quantity'), total_rev=Sum('line_total'))\
|
||||
.order_by('-total_rev')[:5]
|
||||
top_products = (SaleItem.objects.values('product__name_en', 'product__name_ar')
|
||||
.annotate(total_qty=Sum('quantity'), total_rev=Sum('line_total'))
|
||||
.order_by('-total_rev')[:5])
|
||||
|
||||
# 4. Recent Sales
|
||||
recent_sales = Sale.objects.select_related('customer').order_by('-created_at')[:5]
|
||||
@ -117,6 +121,8 @@ def index(request):
|
||||
'total_sales_count': total_sales_count,
|
||||
'total_products': total_products,
|
||||
'total_customers': total_customers,
|
||||
'total_receivables': total_receivables,
|
||||
'total_payables': total_payables,
|
||||
'monthly_labels': json.dumps(monthly_labels),
|
||||
'monthly_data': json.dumps(monthly_data),
|
||||
'chart_labels': json.dumps(chart_labels),
|
||||
@ -283,7 +289,7 @@ def pos(request):
|
||||
session = CashierSession.objects.filter(user=request.user, end_time__isnull=True).last()
|
||||
|
||||
# Retrieve held sales
|
||||
held_sales = HeldSale.objects.filter(user=request.user).order_by('-created_at')
|
||||
held_sales = HeldSale.objects.filter(created_by=request.user).order_by('-created_at')
|
||||
|
||||
context = {
|
||||
'categories': categories,
|
||||
@ -311,18 +317,43 @@ def create_sale_api(request):
|
||||
customer_id = data.get('customer_id')
|
||||
items = data.get('items', [])
|
||||
payments = data.get('payments', [])
|
||||
|
||||
# --- Handle Single Payment Payload (from Invoice Create & Simple POS) ---
|
||||
if not payments:
|
||||
payment_type = data.get('payment_type', 'cash')
|
||||
paid_amount = decimal.Decimal(str(data.get('paid_amount', 0)))
|
||||
payment_method_id = data.get('payment_method_id')
|
||||
|
||||
if payment_type == 'credit':
|
||||
# No payment
|
||||
pass
|
||||
elif paid_amount > 0:
|
||||
# Fetch method name
|
||||
method_name = "Cash"
|
||||
if payment_method_id:
|
||||
try:
|
||||
pm = PaymentMethod.objects.get(id=payment_method_id)
|
||||
method_name = pm.name_en # Or whatever field we want to store
|
||||
except:
|
||||
pass
|
||||
|
||||
payments.append({
|
||||
'method': method_name,
|
||||
'amount': paid_amount
|
||||
})
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
discount = decimal.Decimal(str(data.get('discount', 0)))
|
||||
notes = data.get('notes', '')
|
||||
invoice_number = data.get('invoice_number', '')
|
||||
due_date = data.get('due_date')
|
||||
|
||||
if not items:
|
||||
return JsonResponse({'success': False, 'message': 'No items in cart'}, status=400)
|
||||
|
||||
# Validate Session
|
||||
session = CashierSession.objects.filter(user=request.user, end_time__isnull=True).last()
|
||||
if not session:
|
||||
# Allow admin to sell without session? Or enforce? Let's enforce for now but check logic.
|
||||
# Assuming logic enforces session.
|
||||
pass
|
||||
# if not session: ... (Optional check)
|
||||
|
||||
with transaction.atomic():
|
||||
customer = None
|
||||
@ -330,36 +361,50 @@ def create_sale_api(request):
|
||||
customer = Customer.objects.get(id=customer_id)
|
||||
|
||||
sale = Sale.objects.create(
|
||||
user=request.user,
|
||||
created_by=request.user,
|
||||
customer=customer,
|
||||
invoice_number=invoice_number,
|
||||
total_amount=0, # Will calculate
|
||||
discount=discount,
|
||||
notes=notes,
|
||||
payment_status='Pending'
|
||||
)
|
||||
|
||||
if due_date:
|
||||
sale.due_date = due_date
|
||||
|
||||
subtotal = decimal.Decimal(0)
|
||||
vat_amount = decimal.Decimal(0) # Track total VAT
|
||||
|
||||
for item in items:
|
||||
product = Product.objects.select_for_update().get(id=item['id'])
|
||||
qty = decimal.Decimal(str(item['quantity']))
|
||||
price = decimal.Decimal(str(item['price'])) # Use price from request (in case of override) or product.price
|
||||
price = decimal.Decimal(str(item['price']))
|
||||
|
||||
# Verify stock
|
||||
if not product.is_service and product.stock_quantity < qty:
|
||||
# Check system setting for allow zero stock
|
||||
setting = SystemSetting.objects.first()
|
||||
if not setting or not setting.allow_zero_stock_sales:
|
||||
raise Exception(f"Insufficient stock for {product.name_en}")
|
||||
# Check System Setting for Zero Stock
|
||||
setting = SystemSetting.objects.first()
|
||||
allow_zero = setting.allow_zero_stock_sales if setting else False
|
||||
|
||||
if not product.is_service and product.stock_quantity < qty and not allow_zero:
|
||||
raise Exception(f"Insufficient stock for {product.name_en}")
|
||||
|
||||
line_total = price * qty
|
||||
subtotal += line_total
|
||||
|
||||
# Calculate VAT for this line
|
||||
# Assuming price includes VAT? Or excludes?
|
||||
# POS usually excludes or includes based on settings.
|
||||
# Let's assume price is Unit Price *before* VAT if we add VAT separately?
|
||||
# Or let's assume simple logic: Line Total is what user sees.
|
||||
# But we should probably calculate VAT based on product.vat
|
||||
item_vat = line_total * (product.vat / 100)
|
||||
vat_amount += item_vat
|
||||
|
||||
SaleItem.objects.create(
|
||||
sale=sale,
|
||||
product=product,
|
||||
quantity=qty,
|
||||
price=price,
|
||||
unit_price=price, # Fixed field name
|
||||
line_total=line_total
|
||||
)
|
||||
|
||||
@ -368,9 +413,10 @@ def create_sale_api(request):
|
||||
product.stock_quantity -= qty
|
||||
product.save()
|
||||
|
||||
total_amount = subtotal - discount
|
||||
# Recalculate Totals
|
||||
sale.subtotal = subtotal
|
||||
sale.total_amount = total_amount
|
||||
sale.vat_amount = vat_amount
|
||||
sale.total_amount = subtotal + vat_amount - discount
|
||||
|
||||
# Process Payments
|
||||
paid_amount = decimal.Decimal(0)
|
||||
@ -381,12 +427,13 @@ def create_sale_api(request):
|
||||
SalePayment.objects.create(
|
||||
sale=sale,
|
||||
payment_method_name=method_name,
|
||||
amount=amount
|
||||
amount=amount,
|
||||
created_by=request.user
|
||||
)
|
||||
paid_amount += amount
|
||||
|
||||
sale.paid_amount = paid_amount
|
||||
sale.balance_due = total_amount - paid_amount
|
||||
sale.balance_due = sale.total_amount - paid_amount
|
||||
|
||||
if sale.balance_due <= 0:
|
||||
sale.payment_status = 'Paid'
|
||||
@ -400,6 +447,8 @@ def create_sale_api(request):
|
||||
return JsonResponse({'success': True, 'sale_id': sale.id, 'message': 'Sale created successfully'})
|
||||
|
||||
except Exception as e:
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return JsonResponse({'success': False, 'message': str(e)}, status=500)
|
||||
|
||||
@csrf_exempt
|
||||
@ -419,7 +468,7 @@ def hold_sale_api(request):
|
||||
customer_name = data.get('customer_name', '')
|
||||
|
||||
HeldSale.objects.create(
|
||||
user=request.user,
|
||||
created_by=request.user,
|
||||
cart_data=cart_data,
|
||||
note=note,
|
||||
customer_name=customer_name
|
||||
@ -430,7 +479,7 @@ def hold_sale_api(request):
|
||||
|
||||
@login_required
|
||||
def get_held_sales_api(request):
|
||||
sales = HeldSale.objects.filter(user=request.user).order_by('-created_at')
|
||||
sales = HeldSale.objects.filter(created_by=request.user).order_by('-created_at')
|
||||
data = []
|
||||
for s in sales:
|
||||
data.append({
|
||||
@ -447,7 +496,7 @@ def get_held_sales_api(request):
|
||||
def recall_held_sale_api(request, pk):
|
||||
# Just return the data, maybe delete it or keep it until finalized?
|
||||
# Usually we delete it after recall or keep it. Let's keep it until explicitly deleted or completed.
|
||||
held_sale = get_object_or_404(HeldSale, pk=pk, user=request.user)
|
||||
held_sale = get_object_or_404(HeldSale, pk=pk, created_by=request.user)
|
||||
return JsonResponse({
|
||||
'success': True,
|
||||
'cart_data': json.loads(held_sale.cart_data),
|
||||
@ -458,7 +507,7 @@ def recall_held_sale_api(request, pk):
|
||||
@csrf_exempt
|
||||
@login_required
|
||||
def delete_held_sale_api(request, pk):
|
||||
held_sale = get_object_or_404(HeldSale, pk=pk, user=request.user)
|
||||
held_sale = get_object_or_404(HeldSale, pk=pk, created_by=request.user)
|
||||
held_sale.delete()
|
||||
return JsonResponse({'success': True})
|
||||
|
||||
@ -468,7 +517,7 @@ def delete_held_sale_api(request, pk):
|
||||
|
||||
@login_required
|
||||
def invoice_list(request):
|
||||
sales = Sale.objects.select_related('customer', 'user').order_by('-created_at')
|
||||
sales = Sale.objects.select_related('customer', 'created_by').order_by('-created_at')
|
||||
|
||||
# Filter
|
||||
status = request.GET.get('status')
|
||||
@ -481,12 +530,21 @@ def invoice_list(request):
|
||||
sales = sales.filter(created_at__date__gte=start_date)
|
||||
if end_date:
|
||||
sales = sales.filter(created_at__date__lte=end_date)
|
||||
|
||||
|
||||
customers = Customer.objects.all()
|
||||
|
||||
paginator = Paginator(sales, 20)
|
||||
page_number = request.GET.get('page')
|
||||
page_obj = paginator.get_page(page_number)
|
||||
|
||||
return render(request, 'core/invoice_list.html', {'page_obj': page_obj})
|
||||
payment_methods = PaymentMethod.objects.filter(is_active=True)
|
||||
|
||||
return render(request, 'core/invoices.html', {
|
||||
'page_obj': page_obj,
|
||||
'sales': page_obj,
|
||||
'payment_methods': payment_methods,
|
||||
'customers': customers
|
||||
})
|
||||
|
||||
@login_required
|
||||
def invoice_detail(request, pk):
|
||||
@ -495,10 +553,20 @@ def invoice_detail(request, pk):
|
||||
|
||||
@login_required
|
||||
def invoice_create(request):
|
||||
# Reuse POS or a specific invoice form?
|
||||
# For now redirect to POS or show a simple form
|
||||
# Let's show a simple form page if it exists, else POS
|
||||
return redirect('pos') # Simplified for now
|
||||
# Retrieve data for the invoice form
|
||||
products = Product.objects.filter(is_active=True).select_related('category', 'unit')
|
||||
customers = Customer.objects.all()
|
||||
payment_methods = PaymentMethod.objects.filter(is_active=True)
|
||||
site_settings = SystemSetting.objects.first()
|
||||
|
||||
context = {
|
||||
'products': products,
|
||||
'customers': customers,
|
||||
'payment_methods': payment_methods,
|
||||
'site_settings': site_settings,
|
||||
'decimal_places': site_settings.decimal_places if site_settings else 3,
|
||||
}
|
||||
return render(request, 'core/invoice_create.html', context)
|
||||
|
||||
@login_required
|
||||
def delete_sale(request, pk):
|
||||
@ -571,7 +639,7 @@ def create_quotation_api(request):
|
||||
customer = Customer.objects.get(id=customer_id)
|
||||
|
||||
quotation = Quotation.objects.create(
|
||||
user=request.user,
|
||||
created_by=request.user,
|
||||
customer=customer,
|
||||
total_amount=0
|
||||
)
|
||||
@ -616,7 +684,7 @@ def convert_quotation_to_invoice(request, pk):
|
||||
try:
|
||||
with transaction.atomic():
|
||||
sale = Sale.objects.create(
|
||||
user=request.user,
|
||||
created_by=request.user,
|
||||
customer=quot.customer,
|
||||
total_amount=quot.total_amount,
|
||||
payment_status='Unpaid',
|
||||
@ -750,7 +818,7 @@ def create_purchase_api(request):
|
||||
|
||||
with transaction.atomic():
|
||||
purchase = Purchase.objects.create(
|
||||
user=request.user,
|
||||
created_by=request.user,
|
||||
supplier=supplier,
|
||||
total_amount=0,
|
||||
payment_status='Unpaid'
|
||||
@ -1099,4 +1167,4 @@ def start_session(request): return redirect('pos')
|
||||
@login_required
|
||||
def close_session(request): return redirect('pos')
|
||||
@login_required
|
||||
def session_detail(request, pk): return redirect('settings')
|
||||
def session_detail(request, pk): return redirect('settings')
|
||||
54
debug_request.py
Normal file
54
debug_request.py
Normal file
@ -0,0 +1,54 @@
|
||||
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()
|
||||
Loading…
x
Reference in New Issue
Block a user