Autosave: 20260210-152237
This commit is contained in:
parent
55c69b5fdc
commit
b30330b17b
Binary file not shown.
125
core/views.py
125
core/views.py
@ -50,11 +50,9 @@ def index(request):
|
||||
except Exception as e:
|
||||
logger.error(f"Migration Fix Failed: {e}")
|
||||
|
||||
settings = None
|
||||
try:
|
||||
settings = SystemSetting.objects.first()
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to load settings in index: {e}")
|
||||
settings = SystemSetting.objects.first()
|
||||
if not settings:
|
||||
settings = SystemSetting.objects.create()
|
||||
|
||||
today = timezone.now().date()
|
||||
|
||||
@ -178,13 +176,9 @@ def inventory(request):
|
||||
next_30_days = today + datetime.timedelta(days=30)
|
||||
|
||||
expired_products = products.filter(has_expiry=True, expiry_date__lt=today)
|
||||
expiring_soon_products = products.filter(has_expiry=True, expiry_date__gte=today, expiry_date__lte=next_30_days)
|
||||
|
||||
settings = None
|
||||
try:
|
||||
settings = SystemSetting.objects.first()
|
||||
except Exception:
|
||||
pass
|
||||
settings = SystemSetting.objects.first()
|
||||
if not settings:
|
||||
settings = SystemSetting.objects.create()
|
||||
|
||||
context = {
|
||||
'products': products,
|
||||
@ -209,14 +203,9 @@ def suppliers(request):
|
||||
|
||||
@login_required
|
||||
def settings_view(request):
|
||||
settings = None
|
||||
try:
|
||||
settings = SystemSetting.objects.first()
|
||||
if not settings:
|
||||
settings = SystemSetting.objects.create()
|
||||
except Exception:
|
||||
# Create a dummy object or just pass None if DB is broken
|
||||
pass
|
||||
settings = SystemSetting.objects.first()
|
||||
if not settings:
|
||||
settings = SystemSetting.objects.create()
|
||||
|
||||
payment_methods = PaymentMethod.objects.filter(is_active=True)
|
||||
expense_categories = ExpenseCategory.objects.all()
|
||||
@ -325,11 +314,9 @@ def pos(request):
|
||||
messages.warning(request, _("Please open a session to start selling."))
|
||||
return redirect('start_session')
|
||||
|
||||
settings = None
|
||||
try:
|
||||
settings = SystemSetting.objects.first()
|
||||
except Exception:
|
||||
pass
|
||||
settings = SystemSetting.objects.first()
|
||||
if not settings:
|
||||
settings = SystemSetting.objects.create()
|
||||
|
||||
products = Product.objects.filter(is_active=True)
|
||||
|
||||
@ -398,14 +385,11 @@ def invoice_list(request):
|
||||
Q(invoice_number__icontains=query)
|
||||
)
|
||||
|
||||
paginator = Paginator(sales, 25)
|
||||
|
||||
settings = None
|
||||
try:
|
||||
settings = SystemSetting.objects.first()
|
||||
except Exception:
|
||||
pass
|
||||
settings = SystemSetting.objects.first()
|
||||
if not settings:
|
||||
settings = SystemSetting.objects.create()
|
||||
|
||||
paginator = Paginator(sales, 20)
|
||||
context = {
|
||||
'sales': paginator.get_page(request.GET.get('page')),
|
||||
'customers': Customer.objects.all(),
|
||||
@ -415,9 +399,25 @@ def invoice_list(request):
|
||||
}
|
||||
return render(request, 'core/invoices.html', context)
|
||||
|
||||
@login_required
|
||||
@login_required
|
||||
def invoice_create(request):
|
||||
return redirect('pos')
|
||||
customers = Customer.objects.all().order_by('name')
|
||||
products = Product.objects.filter(is_active=True).select_related('category')
|
||||
payment_methods = PaymentMethod.objects.filter(is_active=True)
|
||||
site_settings = SystemSetting.objects.first()
|
||||
if not site_settings:
|
||||
site_settings = SystemSetting.objects.create()
|
||||
|
||||
decimal_places = site_settings.decimal_places or 2
|
||||
|
||||
return render(request, 'core/invoice_create.html', {
|
||||
'customers': customers,
|
||||
'products': products,
|
||||
'payment_methods': payment_methods,
|
||||
'site_settings': site_settings,
|
||||
'decimal_places': decimal_places,
|
||||
})
|
||||
|
||||
@login_required
|
||||
def invoice_detail(request, pk):
|
||||
@ -430,11 +430,9 @@ def edit_invoice(request, 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 = None
|
||||
try:
|
||||
site_settings = SystemSetting.objects.first()
|
||||
except Exception:
|
||||
pass
|
||||
site_settings = SystemSetting.objects.first()
|
||||
if not site_settings:
|
||||
site_settings = SystemSetting.objects.create()
|
||||
|
||||
decimal_places = 2
|
||||
if site_settings:
|
||||
@ -638,11 +636,19 @@ def purchases(request):
|
||||
purchases = Purchase.objects.all().order_by('-created_at')
|
||||
return render(request, 'core/purchases.html', {'purchases': purchases})
|
||||
|
||||
@login_required
|
||||
@login_required
|
||||
def purchase_create(request):
|
||||
suppliers = Supplier.objects.all()
|
||||
products = Product.objects.filter(is_active=True)
|
||||
return render(request, 'core/purchase_create.html', {'suppliers': suppliers, 'products': products})
|
||||
payment_methods = PaymentMethod.objects.filter(is_active=True)
|
||||
settings = SystemSetting.objects.first()
|
||||
return render(request, 'core/purchase_create.html', {
|
||||
'suppliers': suppliers,
|
||||
'products': products,
|
||||
'payment_methods': payment_methods,
|
||||
'decimal_places': settings.decimal_places if settings else 3
|
||||
})
|
||||
|
||||
@login_required
|
||||
def purchase_detail(request, pk):
|
||||
@ -888,10 +894,10 @@ def cashflow_report(request):
|
||||
@login_required
|
||||
def add_product(request):
|
||||
if request.method == 'POST':
|
||||
form = ProductForm(request.POST, request.FILES, instance=product)
|
||||
form = ProductForm(request.POST, request.FILES)
|
||||
if form.is_valid():
|
||||
form.save()
|
||||
messages.success(request, _("Product updated."))
|
||||
messages.success(request, _("Product added."))
|
||||
return redirect(reverse('inventory') + '#items')
|
||||
return redirect('inventory')
|
||||
|
||||
@ -1125,7 +1131,7 @@ def send_invoice_whatsapp(request):
|
||||
receipt_url = request.build_absolute_uri(reverse('sale_receipt', args=[sale.pk]))
|
||||
|
||||
message = (
|
||||
f"Hello {sale.customer.name if sale.customer else 'Guest'},
|
||||
f"Hello {sale.customer.name if sale.customer else 'Guest'},\n"
|
||||
f"Here is your invoice #{sale.invoice_number or sale.id}.\n"
|
||||
f"Total: {sale.total_amount}\n"
|
||||
f"View Invoice: {receipt_url}\n"
|
||||
@ -1226,13 +1232,18 @@ def create_sale_api(request):
|
||||
with transaction.atomic():
|
||||
sale = Sale.objects.create(
|
||||
customer_id=data.get('customer_id') or None,
|
||||
invoice_number=data.get('invoice_number', ''),
|
||||
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),
|
||||
payment_type=data.get('payment_type', 'cash'),
|
||||
created_by=request.user,
|
||||
status='paid' if data.get('payment_type') == 'cash' else 'partial',
|
||||
discount=data.get('discount', 0),
|
||||
loyalty_points_redeemed=data.get('loyalty_points_redeemed', 0)
|
||||
loyalty_points_redeemed=data.get('loyalty_points_redeemed', 0),
|
||||
notes=data.get('notes', ''),
|
||||
due_date=data.get('due_date') if data.get('due_date') else None
|
||||
)
|
||||
for item in data.get('items', []):
|
||||
SaleItem.objects.create(
|
||||
@ -1367,20 +1378,36 @@ def create_purchase_api(request):
|
||||
try:
|
||||
data = json.loads(request.body)
|
||||
with transaction.atomic():
|
||||
payment_type = data.get('payment_type', 'cash')
|
||||
paid_amount = decimal.Decimal(str(data.get('paid_amount', 0)))
|
||||
total_amount = decimal.Decimal(str(data.get('total_amount', 0)))
|
||||
|
||||
status = 'paid'
|
||||
if payment_type == 'credit':
|
||||
status = 'unpaid'
|
||||
elif payment_type == 'partial' or (paid_amount < total_amount and paid_amount > 0):
|
||||
status = 'partial'
|
||||
elif paid_amount == 0 and total_amount > 0:
|
||||
status = 'unpaid'
|
||||
|
||||
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),
|
||||
invoice_number=data.get('invoice_number', ''),
|
||||
total_amount=total_amount,
|
||||
paid_amount=paid_amount,
|
||||
payment_type=payment_type,
|
||||
due_date=data.get('due_date') or None,
|
||||
notes=data.get('notes', ''),
|
||||
created_by=request.user,
|
||||
status='paid' if data.get('payment_type') == 'cash' else 'partial'
|
||||
status=status
|
||||
)
|
||||
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'])
|
||||
cost_price=item['price'],
|
||||
line_total=float(item['quantity']) * float(item['price'])
|
||||
)
|
||||
# Increase Stock
|
||||
Product.objects.filter(pk=item['id']).update(stock_quantity=F('stock_quantity') + item['quantity'])
|
||||
@ -1566,4 +1593,4 @@ def recall_held_sale_api(request, pk):
|
||||
|
||||
@login_required
|
||||
def delete_held_sale_api(request, pk):
|
||||
return JsonResponse({'success': True})
|
||||
return JsonResponse({'success': True})
|
||||
BIN
media/profile_pics/meezan.png
Normal file
BIN
media/profile_pics/meezan.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.3 KiB |
@ -57,6 +57,7 @@ body {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
height: 100vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
#sidebar.active {
|
||||
@ -64,16 +65,16 @@ body {
|
||||
}
|
||||
|
||||
#sidebar .sidebar-header {
|
||||
padding: 20px;
|
||||
padding: 15px 20px;
|
||||
background: var(--meezan-sidebar-bg);
|
||||
}
|
||||
|
||||
#sidebar ul.components {
|
||||
padding: 20px 0;
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
#sidebar ul li a {
|
||||
padding: 12px 25px;
|
||||
padding: 8px 25px;
|
||||
font-size: 1rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@ -103,7 +104,7 @@ body {
|
||||
|
||||
/* Collapsible Sidebar Styles */
|
||||
#sidebar ul.components li.sidebar-group-header > a {
|
||||
padding: 12px 25px;
|
||||
padding: 8px 25px;
|
||||
font-size: 0.85rem;
|
||||
text-transform: uppercase;
|
||||
font-weight: 700;
|
||||
@ -306,4 +307,4 @@ body {
|
||||
#productGrid .col {
|
||||
width: 100% !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
staticfiles/pasted-20260210-082544-8d8f3bac.png
Normal file
BIN
staticfiles/pasted-20260210-082544-8d8f3bac.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 49 KiB |
Loading…
x
Reference in New Issue
Block a user