@csrf_exempt def create_sale_api(request): if request.method == 'POST': try: data = json.loads(request.body) customer_id = data.get('customer_id') invoice_number = data.get('invoice_number', '') items = data.get('items', []) # Retrieve amounts 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) discount = data.get('discount', 0) payment_type = data.get('payment_type', 'cash') payment_method_id = data.get('payment_method_id') due_date = data.get('due_date') notes = data.get('notes', '') # Loyalty data points_to_redeem = data.get('loyalty_points_redeemed', 0) customer = None if customer_id: customer = Customer.objects.get(id=customer_id) if not customer and payment_type != 'cash': return JsonResponse({'success': False, 'error': _('Credit or Partial payments are not allowed for Guest customers.')}, status=400) settings = SystemSetting.objects.first() if not settings: settings = SystemSetting.objects.create() loyalty_discount = 0 if settings.loyalty_enabled and customer and points_to_redeem > 0: if customer.loyalty_points >= points_to_redeem: loyalty_discount = float(points_to_redeem) * float(settings.currency_per_point) sale = Sale.objects.create( customer=customer, invoice_number=invoice_number, subtotal=subtotal, vat_amount=vat_amount, total_amount=total_amount, paid_amount=paid_amount, balance_due=float(total_amount) - float(paid_amount), discount=discount, loyalty_points_redeemed=points_to_redeem, loyalty_discount_amount=loyalty_discount, payment_type=payment_type, due_date=due_date if due_date else None, notes=notes, created_by=request.user ) # Set status based on payments if float(paid_amount) >= float(total_amount): sale.status = 'paid' elif float(paid_amount) > 0: sale.status = 'partial' else: sale.status = 'unpaid' sale.save() # Record initial payment if any if float(paid_amount) > 0: pm = None if payment_method_id: pm = PaymentMethod.objects.filter(id=payment_method_id).first() SalePayment.objects.create( sale=sale, amount=paid_amount, payment_method=pm, payment_method_name=pm.name_en if pm else payment_type.capitalize(), notes="Initial payment", created_by=request.user ) for item in items: product = Product.objects.get(id=item['id']) SaleItem.objects.create( sale=sale, product=product, quantity=item['quantity'], unit_price=item['price'], line_total=item['line_total'] ) product.stock_quantity -= int(item['quantity']) product.save() # Handle Loyalty Points if settings.loyalty_enabled and customer: # Earn Points points_earned = float(total_amount) * float(settings.points_per_currency) if customer.loyalty_tier: points_earned *= float(customer.loyalty_tier.point_multiplier) if points_earned > 0: customer.loyalty_points += decimal.Decimal(str(points_earned)) LoyaltyTransaction.objects.create( customer=customer, sale=sale, transaction_type='earned', points=points_earned, notes=f"Points earned from Sale #{sale.id}" ) # Redeem Points if points_to_redeem > 0: customer.loyalty_points -= decimal.Decimal(str(points_to_redeem)) LoyaltyTransaction.objects.create( customer=customer, sale=sale, transaction_type='redeemed', points=-points_to_redeem, notes=f"Points redeemed for Sale #{sale.id}" ) customer.update_tier() customer.save() return JsonResponse({ 'success': True, 'sale_id': sale.id, 'business': { 'name': settings.business_name, 'address': settings.address, 'phone': settings.phone, 'email': settings.email, 'currency': settings.currency_symbol, 'vat_number': settings.vat_number, 'registration_number': settings.registration_number, 'logo_url': settings.logo.url if settings.logo else None }, 'sale': { 'id': sale.id, 'invoice_number': sale.invoice_number, 'created_at': sale.created_at.strftime("%Y-%m-%d %H:%M"), 'subtotal': float(sale.subtotal), 'vat_amount': float(sale.vat_amount), 'total': float(sale.total_amount), 'discount': float(sale.discount), 'paid': float(sale.paid_amount), 'balance': float(sale.balance_due), 'customer_name': sale.customer.name if sale.customer else 'Guest', 'items': [ { 'name_en': si.product.name_en, 'name_ar': si.product.name_ar, 'qty': si.quantity, 'price': float(si.unit_price), 'total': float(si.line_total) } for si in sale.items.all() ] } }) except Exception as e: return JsonResponse({'success': False, 'error': str(e)}, status=400)