Autosave: 20260210-152237

This commit is contained in:
Flatlogic Bot 2026-02-10 15:22:38 +00:00
parent 55c69b5fdc
commit b30330b17b
5 changed files with 82 additions and 54 deletions

View File

@ -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})

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

View File

@ -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;
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB