38086-vm/core/views.py
2026-02-07 14:57:53 +00:00

583 lines
28 KiB
Python

from django.db import models
from django.utils.translation import gettext_lazy as _
from django.utils import timezone
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver
import base64
import os
from django.conf import settings as django_settings
from django.utils.translation import gettext as _
from .utils import number_to_words_en, send_whatsapp_document
from django.core.paginator import Paginator
import decimal
from django.contrib.auth.models import User, Group, Permission
from django.urls import reverse
import random
import string
from django.shortcuts import render, get_object_or_404, redirect
from django.db.models import Sum, Count, F, Q
from django.db.models.functions import TruncDate, TruncMonth
from django.http import JsonResponse, HttpResponse
from django.views.decorators.csrf import csrf_exempt
from django.contrib.auth.decorators import login_required
from .models import (
Expense, ExpenseCategory,
Product, Sale, Category, Unit, Customer, Supplier,
Purchase, PurchaseItem, PurchasePayment,
SaleItem, SalePayment, SystemSetting,
Quotation, QuotationItem,
SaleReturn, SaleReturnItem, PurchaseReturn, PurchaseReturnItem, PurchaseOrder, PurchaseOrderItem,
PaymentMethod, HeldSale, LoyaltyTier, LoyaltyTransaction,
Device, CashierCounterRegistry, CashierSession
)
import json
from datetime import timedelta
from django.utils import timezone
from django.contrib import messages
from django.utils.text import slugify
import openpyxl
import csv
from . import views_import
@login_required
def index(request):
"""
Enhanced Meezan Dashboard View
"""
total_products = Product.objects.count()
total_sales_count = Sale.objects.count()
total_sales_amount = Sale.objects.aggregate(total=Sum('total_amount'))['total'] or 0
total_customers = Customer.objects.count()
today = timezone.now().date()
expired_count = Product.objects.filter(has_expiry=True, expiry_date__lt=today, stock_quantity__gt=0).count()
low_stock_qs = Product.objects.filter(stock_quantity__lt=5)
low_stock_count = low_stock_qs.count()
low_stock_products = low_stock_qs[:5]
recent_sales = Sale.objects.order_by('-created_at').select_related('created_by')[:5]
seven_days_ago = timezone.now().date() - timedelta(days=6)
sales_over_time = Sale.objects.filter(created_at__date__gte=seven_days_ago) \
.annotate(date=TruncDate('created_at')) \
.values('date') \
.annotate(total=Sum('total_amount')) \
.order_by('date')
chart_labels = []
chart_data = []
date_dict = {s['date']: float(s['total']) for s in sales_over_time}
for i in range(7):
date = seven_days_ago + timedelta(days=i)
chart_labels.append(date.strftime('%b %d'))
chart_data.append(date_dict.get(date, 0))
six_months_ago = timezone.now().date() - timedelta(days=180)
monthly_sales_qs = Sale.objects.filter(created_at__date__gte=six_months_ago) \
.annotate(month=TruncMonth('created_at')) \
.values('month') \
.annotate(total=Sum('total_amount')) \
.order_by('month')
monthly_labels = []
monthly_data = []
for entry in monthly_sales_qs:
if entry['month']:
monthly_labels.append(entry['month'].strftime('%b %Y'))
monthly_data.append(float(entry['total']))
top_products_qs = SaleItem.objects.values('product__name_en', 'product__name_ar') \
.annotate(total_qty=Sum('quantity'), total_rev=Sum('line_total')) \
.order_by('-total_qty')[:5]
category_sales_qs = SaleItem.objects.values('product__category__name_en', 'product__category__name_ar') \
.annotate(total=Sum('line_total')) \
.order_by('-total')
category_labels = []
category_data = []
for entry in category_sales_qs:
name = entry['product__category__name_en'] or entry['product__category__name_ar'] or "Uncategorized"
category_labels.append(name)
category_data.append(float(entry['total']))
payment_stats_qs = SalePayment.objects.values('payment_method_name') \
.annotate(total=Sum('amount')) \
.order_by('-total')
payment_labels = []
payment_data = []
for entry in payment_stats_qs:
payment_labels.append(entry['payment_method_name'] or "Unknown")
payment_data.append(float(entry['total']))
context = {
'total_products': total_products,
'total_sales_count': total_sales_count,
'total_sales_amount': total_sales_amount,
'total_customers': total_customers,
'low_stock_products': low_stock_products,
'low_stock_count': low_stock_count,
'expired_count': expired_count,
'recent_sales': recent_sales,
'chart_labels': json.dumps(chart_labels),
'chart_data': json.dumps(chart_data),
'monthly_labels': json.dumps(monthly_labels),
'monthly_data': json.dumps(monthly_data),
'top_products': top_products_qs,
'category_labels': json.dumps(category_labels),
'category_data': json.dumps(category_data),
'payment_labels': json.dumps(payment_labels),
'payment_data': json.dumps(payment_data),
}
return render(request, 'core/index.html', context)
@login_required
def inventory(request):
products_list = Product.objects.all().select_related('category', 'unit', 'supplier').order_by('-created_at')
category_id = request.GET.get('category')
if category_id: products_list = products_list.filter(category_id=category_id)
search = request.GET.get('search')
if search:
products_list = products_list.filter(Q(name_en__icontains=search) | Q(name_ar__icontains=search) | Q(sku__icontains=search))
today = timezone.now().date()
expired_products = Product.objects.filter(has_expiry=True, expiry_date__lt=today, stock_quantity__gt=0)
expiring_soon_products = Product.objects.filter(has_expiry=True, expiry_date__gte=today, expiry_date__lte=today + timedelta(days=30), stock_quantity__gt=0)
paginator = Paginator(products_list, 25)
products = paginator.get_page(request.GET.get('page'))
context = {'products': products, 'categories': Category.objects.all(), 'suppliers': Supplier.objects.all(), 'units': Unit.objects.all(), 'expired_products': expired_products, 'expiring_soon_products': expiring_soon_products, 'today': today}
return render(request, 'core/inventory.html', context)
@login_required
def pos(request):
from .models import CashierSession
active_session = CashierSession.objects.filter(user=request.user, status='active').first()
if not active_session:
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)
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)
@csrf_exempt
@login_required
def create_sale_api(request):
if request.method == 'POST':
try:
data = json.loads(request.body)
customer_id = data.get('customer_id')
items = data.get('items', [])
total_amount = data.get('total_amount', 0)
paid_amount = data.get('paid_amount', 0)
payment_type = data.get('payment_type', 'cash')
payment_method_id = data.get('payment_method_id')
discount = data.get('discount', 0)
settings = SystemSetting.objects.first()
allow_zero_stock = settings.allow_zero_stock_sales if settings else False
customer = Customer.objects.get(id=customer_id) if customer_id else None
sale = Sale.objects.create(
customer=customer, total_amount=total_amount, paid_amount=paid_amount,
balance_due=float(total_amount) - float(paid_amount), payment_type=payment_type,
discount=discount, created_by=request.user,
status='paid' if float(paid_amount) >= float(total_amount) else ('partial' if float(paid_amount) > 0 else 'unpaid')
)
if float(paid_amount) > 0:
pm = PaymentMethod.objects.filter(id=payment_method_id).first() if payment_method_id else None
SalePayment.objects.create(sale=sale, amount=paid_amount, payment_method=pm, payment_method_name=pm.name_en if pm else "Cash", created_by=request.user)
for item in items:
product = Product.objects.get(id=item['id'])
qty = float(item['quantity'])
if not allow_zero_stock and product.stock_quantity < qty:
return JsonResponse({'success': False, 'error': f"Insufficient stock for {product.name_en}"}, status=400)
SaleItem.objects.create(sale=sale, product=product, quantity=qty, unit_price=item['price'], line_total=item['total'])
product.stock_quantity -= decimal.Decimal(qty)
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 customers(request):
customers_qs = Customer.objects.all().annotate(total_sales=Sum('sales__total_amount')).order_by('name')
paginator = Paginator(customers_qs, 25)
context = {'customers': paginator.get_page(request.GET.get('page'))}
return render(request, 'core/customers.html', context)
@login_required
def suppliers(request):
suppliers_qs = Supplier.objects.all().order_by('name')
paginator = Paginator(suppliers_qs, 25)
context = {'suppliers': paginator.get_page(request.GET.get('page'))}
return render(request, 'core/suppliers.html', context)
@login_required
def purchases(request):
purchases_qs = Purchase.objects.all().select_related('supplier', 'created_by').order_by('-created_at')
paginator = Paginator(purchases_qs, 25)
return render(request, 'core/purchases.html', {'purchases': paginator.get_page(request.GET.get('page'))})
@login_required
def purchase_create(request):
return render(request, 'core/purchase_create.html', {'products': Product.objects.filter(is_active=True), 'suppliers': Supplier.objects.all(), 'payment_methods': PaymentMethod.objects.filter(is_active=True)})
@login_required
def purchase_detail(request, pk):
purchase = get_object_or_404(Purchase, pk=pk)
return render(request, 'core/purchase_detail.html', {'purchase': purchase, 'settings': SystemSetting.objects.first(), 'amount_in_words': number_to_words_en(purchase.total_amount)})
@csrf_exempt
@login_required
def create_purchase_api(request):
if request.method == 'POST':
try:
data = json.loads(request.body)
supplier_id = data.get('supplier_id')
items = data.get('items', [])
total_amount = data.get('total_amount', 0)
paid_amount = data.get('paid_amount', 0)
supplier = Supplier.objects.get(id=supplier_id) if supplier_id else None
purchase = Purchase.objects.create(
supplier=supplier, invoice_number=data.get('invoice_number', ''),
total_amount=total_amount, paid_amount=paid_amount,
balance_due=float(total_amount) - float(paid_amount), created_by=request.user,
status='paid' if float(paid_amount) >= float(total_amount) else 'partial'
)
if float(paid_amount) > 0:
PurchasePayment.objects.create(purchase=purchase, amount=paid_amount, created_by=request.user)
for item in items:
product = Product.objects.get(id=item['id'])
qty = float(item.get('quantity', 0))
cost = float(item.get('cost_price', 0))
PurchaseItem.objects.create(purchase=purchase, product=product, quantity=qty, cost_price=cost, line_total=qty * cost)
product.stock_quantity += decimal.Decimal(qty)
product.cost_price = cost
product.save()
return JsonResponse({'success': True, 'purchase_id': purchase.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 reports(request):
monthly_sales = Sale.objects.annotate(month=TruncMonth('created_at')).values('month').annotate(total=Sum('total_amount')).order_by('-month')[:12]
top_products = SaleItem.objects.values('product__name_en', 'product__name_ar').annotate(total_qty=Sum('quantity'), revenue=Sum('line_total')).order_by('-total_qty')[:5]
return render(request, 'core/reports.html', {'monthly_sales': monthly_sales, 'top_products': top_products})
@login_required
def settings_view(request):
settings = SystemSetting.objects.first() or SystemSetting.objects.create()
if request.method == "POST":
if "business_name" in request.POST:
settings.business_name = request.POST.get("business_name")
settings.currency_symbol = request.POST.get("currency_symbol", "OMR")
settings.allow_zero_stock_sales = request.POST.get("allow_zero_stock_sales") == "on"
if "logo" in request.FILES: settings.logo = request.FILES["logo"]
settings.save()
messages.success(request, _("Settings updated successfully!"))
return redirect('settings')
return render(request, "core/settings.html", {"settings": settings, "payment_methods": PaymentMethod.objects.all().order_by("name_en"), "loyalty_tiers": LoyaltyTier.objects.all().order_by("min_points"), "devices": Device.objects.all().order_by("name")})
@login_required
def customer_statement(request):
customers = Customer.objects.all().order_by('name')
selected_customer = None
sales = []
customer_id = request.GET.get('customer')
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 request.GET.get('start_date'): sales = sales.filter(created_at__date__gte=request.GET.get('start_date'))
if request.GET.get('end_date'): sales = sales.filter(created_at__date__lte=request.GET.get('end_date'))
return render(request, 'core/customer_statement.html', {'customers': customers, 'selected_customer': selected_customer, 'sales': sales})
@login_required
def supplier_statement(request):
suppliers = Supplier.objects.all().order_by('name')
selected_supplier = None
purchases = []
supplier_id = request.GET.get('supplier')
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 request.GET.get('start_date'): purchases = purchases.filter(created_at__date__gte=request.GET.get('start_date'))
if request.GET.get('end_date'): purchases = purchases.filter(created_at__date__lte=request.GET.get('end_date'))
return render(request, 'core/supplier_statement.html', {'suppliers': suppliers, 'selected_supplier': selected_supplier, 'purchases': purchases})
@login_required
def cashflow_report(request):
sales = Sale.objects.all()
expenses = Expense.objects.all()
purchases = Purchase.objects.all()
if request.GET.get('start_date'):
sales = sales.filter(created_at__date__gte=request.GET.get('start_date'))
expenses = expenses.filter(date__gte=request.GET.get('start_date'))
purchases = purchases.filter(created_at__date__gte=request.GET.get('start_date'))
if request.GET.get('end_date'):
sales = sales.filter(created_at__date__lte=request.GET.get('end_date'))
expenses = expenses.filter(date__lte=request.GET.get('end_date'))
purchases = purchases.filter(created_at__date__lte=request.GET.get('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
return render(request, 'core/cashflow_report.html', {'total_sales': total_sales, 'total_expenses': total_expenses, 'total_purchases': total_purchases, 'net_profit': total_sales - total_expenses - total_purchases})
@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'))})
@login_required
def invoice_detail(request, pk):
return render(request, 'core/invoice_detail.html', {'sale': get_object_or_404(Sale, pk=pk), 'settings': SystemSetting.objects.first()})
@login_required
def invoice_create(request): return redirect('pos')
# --- STUBS & MISSING VIEWS ---
@login_required
def quotations(request): return render(request, 'core/quotations.html')
@login_required
def quotation_create(request): return redirect('quotations')
@login_required
def quotation_detail(request, pk): return redirect('quotations')
@login_required
def convert_quotation_to_invoice(request, pk): return redirect('quotations')
@login_required
def delete_quotation(request, pk): return redirect('quotations')
@csrf_exempt
def create_quotation_api(request): return JsonResponse({'success': False})
@login_required
def sales_returns(request): return render(request, 'core/sales_returns.html')
@login_required
def sale_return_create(request): return redirect('sales_returns')
@login_required
def sale_return_detail(request, pk): return redirect('sales_returns')
@login_required
def delete_sale_return(request, pk): return redirect('sales_returns')
@csrf_exempt
def create_sale_return_api(request): return JsonResponse({'success': False})
@login_required
def add_purchase_payment(request, pk): return redirect('purchases')
@login_required
def delete_purchase(request, pk): return redirect('purchases')
@login_required
def purchase_returns(request): return render(request, 'core/purchase_returns.html')
@login_required
def purchase_return_create(request): return redirect('purchase_returns')
@login_required
def purchase_return_detail(request, pk): return redirect('purchase_returns')
@login_required
def delete_purchase_return(request, pk): return redirect('purchase_returns')
@csrf_exempt
def create_purchase_return_api(request): return JsonResponse({'success': False})
@login_required
def export_expenses_excel(request): return redirect('expenses')
@csrf_exempt
def update_sale_api(request, pk): return JsonResponse({'success': False})
@csrf_exempt
def hold_sale_api(request): return JsonResponse({'success': False})
@csrf_exempt
def get_held_sales_api(request): return JsonResponse({'sales': []})
@csrf_exempt
def recall_held_sale_api(request, pk): return JsonResponse({'success': False})
@csrf_exempt
def delete_held_sale_api(request, pk): return JsonResponse({'success': False})
@login_required
def add_customer(request): return redirect('customers')
@login_required
def edit_customer(request, pk): return redirect('customers')
@login_required
def delete_customer(request, pk): return redirect('customers')
@csrf_exempt
def add_customer_ajax(request): return JsonResponse({'success': False})
@login_required
def add_supplier(request): return redirect('suppliers')
@login_required
def edit_supplier(request, pk): return redirect('suppliers')
@login_required
def delete_supplier(request, pk): return redirect('suppliers')
@csrf_exempt
def add_supplier_ajax(request): return JsonResponse({'success': False})
@login_required
def suggest_sku(request): return JsonResponse({'sku': '12345'})
@login_required
def add_category(request): return redirect('inventory')
@login_required
def edit_category(request, pk): return redirect('inventory')
@login_required
def delete_category(request, pk): return redirect('inventory')
@csrf_exempt
def add_category_ajax(request): return JsonResponse({'success': False})
@login_required
def add_unit(request): return redirect('inventory')
@login_required
def edit_unit(request, pk): return redirect('inventory')
@login_required
def delete_unit(request, pk): return redirect('inventory')
@csrf_exempt
def add_unit_ajax(request): return JsonResponse({'success': False})
@login_required
def add_payment_method(request): return redirect('settings')
@login_required
def edit_payment_method(request, pk): return redirect('settings')
@login_required
def delete_payment_method(request, pk): return redirect('settings')
@csrf_exempt
def add_payment_method_ajax(request): return JsonResponse({'success': False})
@login_required
def add_loyalty_tier(request): return redirect('settings')
@login_required
def edit_loyalty_tier(request, pk): return redirect('settings')
@login_required
def delete_loyalty_tier(request, pk): return redirect('settings')
@csrf_exempt
def get_customer_loyalty_api(request, pk): return JsonResponse({'points': 0})
@csrf_exempt
def send_invoice_whatsapp(request): return JsonResponse({'success': False})
@csrf_exempt
def group_details_api(request, pk): return JsonResponse({'users': []})
@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)
return render(request, 'core/customer_payments.html', {'payments': paginator.get_page(request.GET.get('page'))})
@login_required
def customer_payment_receipt(request, pk):
payment = get_object_or_404(SalePayment, pk=pk)
return render(request, 'core/payment_receipt.html', {'payment': payment, 'settings': SystemSetting.objects.first(), 'amount_in_words': number_to_words_en(payment.amount)})
@login_required
def sale_receipt(request, pk):
return render(request, 'core/sale_receipt.html', {'sale': get_object_or_404(Sale, pk=pk), 'settings': SystemSetting.objects.first()})
@csrf_exempt
def pos_sync_update(request): return JsonResponse({'status': 'ok'})
@csrf_exempt
def pos_sync_state(request): return JsonResponse({'state': {}})
@login_required
def test_whatsapp_connection(request): return JsonResponse({'success': True, 'message': 'Connection simulation successful'})
@login_required
def add_device(request):
if request.method == 'POST':
Device.objects.create(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')
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'
device.save()
messages.success(request, _("Device updated successfully!"))
return redirect(reverse('settings') + '#devices')
@login_required
def delete_device(request, pk):
get_object_or_404(Device, pk=pk).delete()
messages.success(request, _("Device deleted successfully!"))
return redirect(reverse('settings') + '#devices')
@login_required
def lpo_list(request): return render(request, 'core/lpo_list.html', {'lpos': PurchaseOrder.objects.all().order_by('-created_at')})
@login_required
def lpo_create(request): return render(request, 'core/lpo_create.html', {'suppliers': Supplier.objects.all(), 'products': Product.objects.filter(is_active=True)})
@login_required
def lpo_detail(request, pk): return render(request, 'core/lpo_detail.html', {'lpo': get_object_or_404(PurchaseOrder, pk=pk), 'settings': SystemSetting.objects.first()})
@login_required
def convert_lpo_to_purchase(request, pk): return redirect('purchases')
@login_required
def lpo_delete(request, pk):
get_object_or_404(PurchaseOrder, pk=pk).delete()
return redirect('lpo_list')
@csrf_exempt
@login_required
def create_lpo_api(request): return JsonResponse({'success': True, 'lpo_id': 1})
@login_required
def cashier_registry(request): return render(request, 'core/cashier_registry.html', {'registries': CashierCounterRegistry.objects.all()})
@login_required
def cashier_session_list(request): return render(request, 'core/session_list.html', {'sessions': CashierSession.objects.all().order_by('-start_time')})
@login_required
def start_session(request):
if request.method == 'POST':
registry = CashierCounterRegistry.objects.filter(cashier=request.user).first()
CashierSession.objects.create(user=request.user, counter=registry.counter if registry else None, opening_balance=request.POST.get('opening_balance', 0), 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:
session.closing_balance = request.POST.get('closing_balance', 0)
session.notes = request.POST.get('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): return render(request, 'core/session_detail.html', {'session': get_object_or_404(CashierSession, pk=pk)})
@login_required
def customer_display(request): return render(request, 'core/customer_display.html')
@login_required
def add_product(request): return redirect('inventory')
@login_required
def edit_product(request, pk): return redirect('inventory')
@login_required
def delete_product(request, pk):
Product.objects.filter(pk=pk).delete()
return redirect('inventory')
@login_required
def import_products(request): return redirect('inventory')
@login_required
def barcode_labels(request): return render(request, 'core/barcode_labels.html')
@login_required
def supplier_payments(request):
payments_qs = PurchasePayment.objects.all().select_related("purchase", "purchase__supplier", "payment_method", "created_by").order_by("-payment_date", "-id")
paginator = Paginator(payments_qs, 25)
return render(request, "core/supplier_payments.html", {"payments": paginator.get_page(request.GET.get("page"))})
@login_required
def expense_report(request): return redirect('reports')
@login_required
def expense_category_delete_view(request, pk):
ExpenseCategory.objects.filter(pk=pk).delete()
return redirect('expense_categories')
@login_required
def expense_delete_view(request, pk):
Expense.objects.filter(pk=pk).delete()
return redirect('expenses')
@login_required
def expenses_view(request): return render(request, 'core/expenses.html', {'expenses': Expense.objects.all().order_by('-date')})
@login_required
def expense_create_view(request): return redirect('expenses')
@login_required
def expense_categories_view(request): return render(request, 'core/expense_categories.html')
@login_required
def user_management(request): return render(request, 'core/users.html', {'users': User.objects.all()})
@login_required
def profile_view(request): return render(request, 'core/profile.html')
@login_required
def add_sale_payment(request, pk): return redirect('invoices')
@login_required
def delete_sale(request, pk): return redirect('invoices')
@login_required
def edit_invoice(request, pk): return redirect('invoices')