updates
This commit is contained in:
commit
c90f8edc5a
@ -25,6 +25,7 @@ from api import routing
|
|||||||
from inventory.notifications.sse import NotificationSSEApp
|
from inventory.notifications.sse import NotificationSSEApp
|
||||||
from django.urls import re_path
|
from django.urls import re_path
|
||||||
from django.core.asgi import get_asgi_application
|
from django.core.asgi import get_asgi_application
|
||||||
|
from django.contrib.staticfiles.handlers import ASGIStaticFilesHandler
|
||||||
|
|
||||||
# application = ProtocolTypeRouter(
|
# application = ProtocolTypeRouter(
|
||||||
# {
|
# {
|
||||||
@ -32,6 +33,9 @@ from django.core.asgi import get_asgi_application
|
|||||||
# # "websocket": AuthMiddlewareStack(URLRouter(routing.websocket_urlpatterns)),
|
# # "websocket": AuthMiddlewareStack(URLRouter(routing.websocket_urlpatterns)),
|
||||||
# }
|
# }
|
||||||
# )
|
# )
|
||||||
|
|
||||||
|
app = get_asgi_application()
|
||||||
|
|
||||||
application = ProtocolTypeRouter(
|
application = ProtocolTypeRouter(
|
||||||
{
|
{
|
||||||
"http": AuthMiddlewareStack(
|
"http": AuthMiddlewareStack(
|
||||||
@ -39,10 +43,13 @@ application = ProtocolTypeRouter(
|
|||||||
[
|
[
|
||||||
path("sse/notifications/", NotificationSSEApp()),
|
path("sse/notifications/", NotificationSSEApp()),
|
||||||
re_path(
|
re_path(
|
||||||
r"", get_asgi_application()
|
r"", app
|
||||||
), # All other routes go to Django
|
), # All other routes go to Django
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if django.conf.settings.DEBUG:
|
||||||
|
application = ASGIStaticFilesHandler(app)
|
||||||
@ -1220,11 +1220,11 @@ urlpatterns = [
|
|||||||
views.permenant_delete_account,
|
views.permenant_delete_account,
|
||||||
name="permenant_delete_account",
|
name="permenant_delete_account",
|
||||||
),
|
),
|
||||||
path(
|
# path(
|
||||||
"<slug:dealer_slug>/management/audit_log_dashboard/",
|
# "<slug:dealer_slug>/management/audit_log_dashboard/",
|
||||||
views.AuditLogDashboardView,
|
# views.AuditLogDashboardView,
|
||||||
name="audit_log_dashboard",
|
# name="audit_log_dashboard",
|
||||||
),
|
# ),
|
||||||
#########
|
#########
|
||||||
# Purchase Order
|
# Purchase Order
|
||||||
path(
|
path(
|
||||||
|
|||||||
@ -1609,11 +1609,11 @@ def _post_sale_and_cogs(invoice, dealer):
|
|||||||
# .first()
|
# .first()
|
||||||
# )
|
# )
|
||||||
cash_acc = invoice.cash_account or dealer.settings.invoice_cash_account
|
cash_acc = invoice.cash_account or dealer.settings.invoice_cash_account
|
||||||
|
|
||||||
vat_acc = dealer.settings.invoice_tax_payable_account or entity.get_default_coa_accounts().filter(role_default=True, role=roles.LIABILITY_CL_TAXES_PAYABLE).first()
|
vat_acc = dealer.settings.invoice_tax_payable_account or entity.get_default_coa_accounts().filter(role_default=True, role=roles.LIABILITY_CL_TAXES_PAYABLE).first()
|
||||||
|
|
||||||
car_rev = dealer.settings.invoice_vehicle_sale_account or entity.get_default_coa_accounts().filter(role_default=True, role=roles.INCOME_OPERATIONAL).first()
|
car_rev = dealer.settings.invoice_vehicle_sale_account or entity.get_default_coa_accounts().filter(role_default=True, role=roles.INCOME_OPERATIONAL).first()
|
||||||
|
|
||||||
add_rev = dealer.settings.invoice_additional_services_account
|
add_rev = dealer.settings.invoice_additional_services_account
|
||||||
|
|
||||||
if not add_rev:
|
if not add_rev:
|
||||||
@ -1636,9 +1636,9 @@ def _post_sale_and_cogs(invoice, dealer):
|
|||||||
if car.get_additional_services_amount > 0 and not add_rev:
|
if car.get_additional_services_amount > 0 and not add_rev:
|
||||||
raise Exception("additional services exist but not account found,please create account for the additional services and set as default in the settings")
|
raise Exception("additional services exist but not account found,please create account for the additional services and set as default in the settings")
|
||||||
cogs_acc = dealer.settings.invoice_cost_of_good_sold_account or entity.get_default_coa_accounts().filter(role_default=True, role=roles.COGS).first()
|
cogs_acc = dealer.settings.invoice_cost_of_good_sold_account or entity.get_default_coa_accounts().filter(role_default=True, role=roles.COGS).first()
|
||||||
|
|
||||||
inv_acc = dealer.settings.invoice_inventory_account or entity.get_default_coa_accounts().filter(role_default=True, role=roles.ASSET_CA_INVENTORY).first()
|
inv_acc = dealer.settings.invoice_inventory_account or entity.get_default_coa_accounts().filter(role_default=True, role=roles.ASSET_CA_INVENTORY).first()
|
||||||
|
|
||||||
net_car_price = Decimal(data["discounted_price"])
|
net_car_price = Decimal(data["discounted_price"])
|
||||||
net_additionals_price = Decimal(data["additional_services"]["total"])
|
net_additionals_price = Decimal(data["additional_services"]["total"])
|
||||||
vat_amount = Decimal(data["vat_amount"])
|
vat_amount = Decimal(data["vat_amount"])
|
||||||
@ -1692,7 +1692,7 @@ def _post_sale_and_cogs(invoice, dealer):
|
|||||||
# tx_type='credit'
|
# tx_type='credit'
|
||||||
# )
|
# )
|
||||||
|
|
||||||
|
|
||||||
if car.get_additional_services_amount > 0:
|
if car.get_additional_services_amount > 0:
|
||||||
# Cr Sales – Additional Services
|
# Cr Sales – Additional Services
|
||||||
if not add_rev:
|
if not add_rev:
|
||||||
@ -1909,23 +1909,22 @@ def create_make_accounts(dealer):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def handle_payment(request, order):
|
def handle_payment(request, dealer):
|
||||||
url = "https://api.moyasar.com/v1/payments"
|
url = "https://api.moyasar.com/v1/payments"
|
||||||
callback_url = request.build_absolute_uri(
|
callback_url = request.build_absolute_uri(
|
||||||
reverse("payment_callback", kwargs={"dealer_slug": request.dealer.slug})
|
reverse("payment_callback", kwargs={"dealer_slug": dealer.slug})
|
||||||
)
|
)
|
||||||
|
|
||||||
if request.user.is_authenticated:
|
email = request.POST.get("email")
|
||||||
email = request.POST["email"]
|
first_name = request.POST.get("first_name")
|
||||||
first_name = request.POST["first_name"]
|
last_name = request.POST.get("last_name")
|
||||||
last_name = request.POST["last_name"]
|
phone = request.POST.get("phone")
|
||||||
phone = request.POST["phone"]
|
card_name = request.POST.get("card_name")
|
||||||
|
card_number = str(request.POST.get("card_number", "")).replace(" ", "").strip()
|
||||||
card_name = request.POST["card_name"]
|
expiry = request.POST.get("card_expiry", "").split("/")
|
||||||
card_number = str(request.POST["card_number"]).replace(" ", "").strip()
|
month = int(expiry[0].strip()) if len(expiry) > 0 else 0
|
||||||
month = int(request.POST["card_expiry"].split("/")[0].strip())
|
year = int(expiry[1].strip()) if len(expiry) > 1 else 0
|
||||||
year = int(request.POST["card_expiry"].split("/")[1].strip())
|
cvv = request.POST.get("card_cvv")
|
||||||
cvv = request.POST["card_cvv"]
|
|
||||||
|
|
||||||
user_data = {
|
user_data = {
|
||||||
"email": email,
|
"email": email,
|
||||||
@ -1933,65 +1932,166 @@ def handle_payment(request, order):
|
|||||||
"last_name": last_name,
|
"last_name": last_name,
|
||||||
"phone": phone,
|
"phone": phone,
|
||||||
}
|
}
|
||||||
try:
|
|
||||||
total = int((order.total() + order.tax * order.total() / 100) * 100)
|
# Get selected plan from session
|
||||||
except (AttributeError, TypeError):
|
selected_plan_id = request.session.get('pending_plan_id')
|
||||||
raise ValueError("Order total or tax is invalid")
|
if not selected_plan_id:
|
||||||
payload = json.dumps(
|
raise ValueError("No pending plan found in session")
|
||||||
{
|
from plans.models import PlanPricing
|
||||||
"amount": total,
|
|
||||||
"currency": "SAR",
|
pp = PlanPricing.objects.get(pk=selected_plan_id)
|
||||||
"description": f"payment issued for {email}",
|
# Calculate amount without creating order
|
||||||
"callback_url": callback_url,
|
amount_sar = pp.price # assuming price is in SAR
|
||||||
"source": {
|
tax_amount = amount_sar * 15 / 100
|
||||||
"type": "creditcard",
|
total = int((amount_sar + tax_amount) * 100) # convert to halalas
|
||||||
"name": card_name,
|
|
||||||
"number": card_number,
|
# Pass plan & dealer info via metadata
|
||||||
"month": month,
|
metadata = {
|
||||||
"year": year,
|
**user_data,
|
||||||
"cvc": cvv,
|
"plan_pricing_id": selected_plan_id,
|
||||||
"statement_descriptor": "Century Store",
|
"dealer_slug": dealer.slug,
|
||||||
"3ds": True,
|
}
|
||||||
"manual": False,
|
|
||||||
"save_card": False,
|
payload = json.dumps({
|
||||||
},
|
"amount": total,
|
||||||
"metadata": user_data,
|
"currency": "SAR",
|
||||||
}
|
"description": f"Payment for plan {pp.plan.name}",
|
||||||
)
|
"callback_url": callback_url,
|
||||||
|
"source": {
|
||||||
|
"type": "creditcard",
|
||||||
|
"name": card_name,
|
||||||
|
"number": card_number,
|
||||||
|
"month": month,
|
||||||
|
"year": year,
|
||||||
|
"cvc": cvv,
|
||||||
|
"statement_descriptor": "Century Store",
|
||||||
|
"3ds": True,
|
||||||
|
"manual": False,
|
||||||
|
"save_card": False,
|
||||||
|
},
|
||||||
|
"metadata": metadata,
|
||||||
|
})
|
||||||
|
|
||||||
headers = {"Content-Type": "application/json", "Accept": "application/json"}
|
headers = {"Content-Type": "application/json", "Accept": "application/json"}
|
||||||
auth = (settings.MOYASAR_SECRET_KEY, "")
|
auth = (settings.MOYASAR_SECRET_KEY, "")
|
||||||
response = requests.request("POST", url, auth=auth, headers=headers, data=payload)
|
response = requests.post(url, auth=auth, headers=headers, data=payload)
|
||||||
if response.status_code == 400:
|
if response.status_code != 201:
|
||||||
data = response.json()
|
logger.error(f"Payment initiation failed: {response.text}")
|
||||||
if data["type"] == "validation_error":
|
return None, response.get("message")
|
||||||
errors = data.get("errors", {})
|
|
||||||
if "source.year" in errors:
|
|
||||||
raise Exception("Invalid expiry year")
|
|
||||||
else:
|
|
||||||
raise Exception("Validation Error: ", errors)
|
|
||||||
else:
|
|
||||||
print("Failed to process payment:", data)
|
|
||||||
#
|
|
||||||
data = response.json()
|
data = response.json()
|
||||||
|
|
||||||
# order.status = AbstractOrder.STATUS.NEW
|
# Create PaymentHistory WITHOUT linking to order (since order doesn't exist yet)
|
||||||
order.save()
|
amount_decimal = Decimal("{0:.2f}".format(Decimal(total) / Decimal(100)))
|
||||||
#
|
|
||||||
amount = Decimal("{0:.2f}".format(Decimal(total) / Decimal(100)))
|
|
||||||
|
|
||||||
models.PaymentHistory.objects.create(
|
models.PaymentHistory.objects.create(
|
||||||
user=request.user,
|
user=request.user,
|
||||||
user_data=user_data,
|
user_data=json.dumps(metadata),
|
||||||
amount=amount,
|
amount=amount_decimal,
|
||||||
currency=data["currency"],
|
currency=data["currency"],
|
||||||
status=data["status"],
|
status=data["status"],
|
||||||
transaction_id=data["id"],
|
transaction_id=data["id"],
|
||||||
payment_date=data["created_at"],
|
payment_date=data["created_at"],
|
||||||
gateway_response=data,
|
gateway_response=data,
|
||||||
)
|
)
|
||||||
transaction_url = data["source"]["transaction_url"]
|
logger.info(f"Payment initiated: {data}")
|
||||||
return transaction_url
|
return data["source"]["transaction_url"],None
|
||||||
|
# def handle_payment(request, order):
|
||||||
|
# logger.info(f"Handling payment for order {order}")
|
||||||
|
# url = "https://api.moyasar.com/v1/payments"
|
||||||
|
# callback_url = request.build_absolute_uri(
|
||||||
|
# reverse("payment_callback", kwargs={"dealer_slug": request.dealer.slug})
|
||||||
|
# )
|
||||||
|
|
||||||
|
# logger.info(f"Got callback_url: {callback_url}")
|
||||||
|
|
||||||
|
# if request.user.is_authenticated:
|
||||||
|
# email = request.POST["email"]
|
||||||
|
# first_name = request.POST["first_name"]
|
||||||
|
# last_name = request.POST["last_name"]
|
||||||
|
# phone = request.POST["phone"]
|
||||||
|
|
||||||
|
# logger.info(f"Got user data: {email}, {first_name}, {last_name}, {phone}")
|
||||||
|
|
||||||
|
# card_name = request.POST["card_name"]
|
||||||
|
# card_number = str(request.POST["card_number"]).replace(" ", "").strip()
|
||||||
|
# month = int(request.POST["card_expiry"].split("/")[0].strip())
|
||||||
|
# year = int(request.POST["card_expiry"].split("/")[1].strip())
|
||||||
|
# cvv = request.POST["card_cvv"]
|
||||||
|
|
||||||
|
# logger.info(f"Got card data: {card_name}, {card_number[:4]}****, {month}, {year}, {cvv}")
|
||||||
|
|
||||||
|
# user_data = {
|
||||||
|
# "email": email,
|
||||||
|
# "first_name": first_name,
|
||||||
|
# "last_name": last_name,
|
||||||
|
# "phone": phone,
|
||||||
|
# }
|
||||||
|
# try:
|
||||||
|
# total = int((order.total() + order.tax * order.total() / 100) * 100)
|
||||||
|
# except (AttributeError, TypeError):
|
||||||
|
# raise ValueError("Order total or tax is invalid")
|
||||||
|
# logger.info(f"Calculated total: {total}")
|
||||||
|
|
||||||
|
# payload = json.dumps(
|
||||||
|
# {
|
||||||
|
# "amount": total,
|
||||||
|
# "currency": "SAR",
|
||||||
|
# "description": f"payment issued for {email}",
|
||||||
|
# "callback_url": callback_url,
|
||||||
|
# "source": {
|
||||||
|
# "type": "creditcard",
|
||||||
|
# "name": card_name,
|
||||||
|
# "number": card_number,
|
||||||
|
# "month": month,
|
||||||
|
# "year": year,
|
||||||
|
# "cvc": cvv,
|
||||||
|
# "statement_descriptor": "Century Store",
|
||||||
|
# "3ds": False,
|
||||||
|
# "manual": False,
|
||||||
|
# "save_card": False,
|
||||||
|
# },
|
||||||
|
# "metadata": user_data,
|
||||||
|
# }
|
||||||
|
# )
|
||||||
|
|
||||||
|
# logger.info(f"Generated payload: {payload}")
|
||||||
|
|
||||||
|
# headers = {"Content-Type": "application/json", "Accept": "application/json"}
|
||||||
|
# auth = (settings.MOYASAR_SECRET_KEY, "")
|
||||||
|
# response = requests.request("POST", url, auth=auth, headers=headers, data=payload)
|
||||||
|
# logger.info(f"Sent request to Moyasar API: {response.status_code}")
|
||||||
|
|
||||||
|
# if response.status_code == 400:
|
||||||
|
# data = response.json()
|
||||||
|
# if data["type"] == "validation_error":
|
||||||
|
# errors = data.get("errors", {})
|
||||||
|
# if "source.year" in errors:
|
||||||
|
# raise Exception("Invalid expiry year")
|
||||||
|
# else:
|
||||||
|
# raise Exception("Validation Error: ", errors)
|
||||||
|
# else:
|
||||||
|
# logger.error(f"Failed to process payment: {data}")
|
||||||
|
# #
|
||||||
|
# data = response.json()
|
||||||
|
|
||||||
|
# # order.status = AbstractOrder.STATUS.NEW
|
||||||
|
# order.save()
|
||||||
|
# #
|
||||||
|
# amount = Decimal("{0:.2f}".format(Decimal(total) / Decimal(100)))
|
||||||
|
|
||||||
|
# models.PaymentHistory.objects.create(
|
||||||
|
# user=request.user,
|
||||||
|
# user_data=user_data,
|
||||||
|
# amount=amount,
|
||||||
|
# currency=data["currency"],
|
||||||
|
# status=data["status"],
|
||||||
|
# transaction_id=data["id"],
|
||||||
|
# payment_date=data["created_at"],
|
||||||
|
# gateway_response=data,
|
||||||
|
# )
|
||||||
|
# transaction_url = data["source"]["transaction_url"]
|
||||||
|
# logger.info(f"Created payment history and got transaction_url: {transaction_url}")
|
||||||
|
# return transaction_url
|
||||||
|
|
||||||
|
|
||||||
# def get_user_quota(user):
|
# def get_user_quota(user):
|
||||||
|
|||||||
@ -218,7 +218,7 @@ from .utils import (
|
|||||||
from .tasks import create_accounts_for_make, create_user_dealer, send_email
|
from .tasks import create_accounts_for_make, create_user_dealer, send_email
|
||||||
|
|
||||||
# djago easy audit log
|
# djago easy audit log
|
||||||
from easyaudit.models import RequestEvent, CRUDEvent, LoginEvent
|
# from easyaudit.models import RequestEvent, CRUDEvent, LoginEvent
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
logging.basicConfig(level=logging.INFO)
|
logging.basicConfig(level=logging.INFO)
|
||||||
@ -504,7 +504,8 @@ def general_dashboard(request,dealer_slug):
|
|||||||
total_vat_collected = total_vat_collected_from_cars + total_vat_collected_from_services
|
total_vat_collected = total_vat_collected_from_cars + total_vat_collected_from_services
|
||||||
total_revenue_generated = total_revenue_from_cars + total_revenue_from_services
|
total_revenue_generated = total_revenue_from_cars + total_revenue_from_services
|
||||||
# total_expenses=sum([x.amount_paid for x in dealer.entity.get_bills().filter(bill_items__item_role="expense")])
|
# total_expenses=sum([x.amount_paid for x in dealer.entity.get_bills().filter(bill_items__item_role="expense")])
|
||||||
total_expenses=dealer.entity.get_bills().filter(bill_items__item_role="expense").aggregate(total=Sum('amount_paid'))['total'] or 0
|
|
||||||
|
total_expenses=dealer.entity.get_bills().filter(bill_items__item_role="expense").aggregate(total=Sum('amount_paid'))['total'] or 0
|
||||||
gross_profit = net_profit_from_cars+total_revenue_from_services - total_expenses
|
gross_profit = net_profit_from_cars+total_revenue_from_services - total_expenses
|
||||||
|
|
||||||
# ----------------------------------------------------
|
# ----------------------------------------------------
|
||||||
@ -9889,50 +9890,123 @@ def pricing_page(request, dealer_slug):
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
# @login_required
|
||||||
@permission_required("inventory.change_dealer", raise_exception=True)
|
# @permission_required("inventory.change_dealer", raise_exception=True)
|
||||||
@require_POST
|
# @require_POST
|
||||||
|
# def submit_plan(request, dealer_slug):
|
||||||
|
# logger.info(f"dealer slug : {dealer_slug}")
|
||||||
|
# if request.method == "GET":
|
||||||
|
# logger.info("method is GET, redirecting to pricing page")
|
||||||
|
# return redirect("pricing_page", dealer_slug=dealer_slug)
|
||||||
|
# dealer = get_object_or_404(models.Dealer, slug=dealer_slug)
|
||||||
|
# logger.info(f"Selected dealer : {dealer}")
|
||||||
|
# selected_plan_id = request.POST.get("selected_plan")
|
||||||
|
# logger.info(f"Selected plan id : {selected_plan_id}")
|
||||||
|
# pp = PlanPricing.objects.get(pk=selected_plan_id)
|
||||||
|
# logger.info(f"Selected plan pricing : {pp}")
|
||||||
|
# order = None
|
||||||
|
# try:
|
||||||
|
# order = Order.objects.create(
|
||||||
|
# user=dealer.user,
|
||||||
|
# plan=pp.plan,
|
||||||
|
# pricing=pp.pricing,
|
||||||
|
# amount=pp.price,
|
||||||
|
# currency="SA",
|
||||||
|
# tax=15,
|
||||||
|
# status=1,
|
||||||
|
# )
|
||||||
|
# logger.info(f"order created {order}")
|
||||||
|
# except Exception as e:
|
||||||
|
# logger.error(e)
|
||||||
|
# if not order:
|
||||||
|
# messages.error(request, _("Error creating order"))
|
||||||
|
# logger.error("unable to create order")
|
||||||
|
# return redirect("pricing_page", dealer_slug=dealer_slug)
|
||||||
|
# transaction_url = handle_payment(request, order)
|
||||||
|
# logger.info(f"Redirecting to : {transaction_url}")
|
||||||
|
# return redirect(transaction_url)
|
||||||
def submit_plan(request, dealer_slug):
|
def submit_plan(request, dealer_slug):
|
||||||
|
if request.method == "GET":
|
||||||
|
return redirect("pricing_page", dealer_slug=dealer_slug)
|
||||||
|
|
||||||
dealer = get_object_or_404(models.Dealer, slug=dealer_slug)
|
dealer = get_object_or_404(models.Dealer, slug=dealer_slug)
|
||||||
selected_plan_id = request.POST.get("selected_plan")
|
selected_plan_id = request.POST.get("selected_plan")
|
||||||
pp = PlanPricing.objects.get(pk=selected_plan_id)
|
if not selected_plan_id:
|
||||||
order = None
|
messages.error(request, _("No plan selected."))
|
||||||
try:
|
|
||||||
order = Order.objects.create(
|
|
||||||
user=dealer.user,
|
|
||||||
plan=pp.plan,
|
|
||||||
pricing=pp.pricing,
|
|
||||||
amount=pp.price,
|
|
||||||
currency="SA",
|
|
||||||
tax=15,
|
|
||||||
status=1,
|
|
||||||
)
|
|
||||||
logger.info(f"order created {order}")
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(e)
|
|
||||||
if not order:
|
|
||||||
messages.error(request, _("Error creating order"))
|
|
||||||
logger.error("unable to create order")
|
|
||||||
return redirect("pricing_page", dealer_slug=dealer_slug)
|
return redirect("pricing_page", dealer_slug=dealer_slug)
|
||||||
transaction_url = handle_payment(request, order)
|
|
||||||
|
# Store plan & dealer info in session for use in callback
|
||||||
|
request.session['pending_plan_id'] = selected_plan_id
|
||||||
|
request.session['pending_dealer_slug'] = dealer_slug
|
||||||
|
|
||||||
|
# Initiate payment WITHOUT creating order
|
||||||
|
transaction_url,error = handle_payment(request, dealer)
|
||||||
|
if not transaction_url:
|
||||||
|
messages.error(request, _(f"Payment initiation failed. {error}"))
|
||||||
|
return redirect("pricing_page", dealer_slug=dealer_slug)
|
||||||
|
|
||||||
return redirect(transaction_url)
|
return redirect(transaction_url)
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
# @login_required
|
||||||
@permission_required("inventory.change_dealer", raise_exception=True)
|
|
||||||
def payment_callback(request, dealer_slug):
|
def payment_callback(request, dealer_slug):
|
||||||
message = request.GET.get("message")
|
|
||||||
dealer = get_object_or_404(models.Dealer, slug=dealer_slug)
|
|
||||||
payment_id = request.GET.get("id")
|
payment_id = request.GET.get("id")
|
||||||
history = models.PaymentHistory.objects.filter(transaction_id=payment_id).first()
|
|
||||||
payment_status = request.GET.get("status")
|
payment_status = request.GET.get("status")
|
||||||
logger.info(f"Received payment callback for dealer_slug: {dealer_slug}, payment_id: {payment_id}, status: {payment_status}")
|
message = request.GET.get("message", "")
|
||||||
order = Order.objects.filter(user=dealer.user, status=1).first() # Status 1 = NEW
|
|
||||||
if history.status == "paid":
|
|
||||||
return redirect('home')
|
|
||||||
if payment_status == "paid":
|
|
||||||
logger.info(f"Payment successful for transaction ID {payment_id}. Processing order completion.")
|
|
||||||
|
|
||||||
|
logger.info(f"Received payment callback for dealer_slug: {dealer_slug}, payment_id: {payment_id}, status: {payment_status}")
|
||||||
|
|
||||||
|
history = models.PaymentHistory.objects.filter(transaction_id=payment_id).first()
|
||||||
|
if not history:
|
||||||
|
logger.error(f"No PaymentHistory found for transaction_id: {payment_id}")
|
||||||
|
return render(request, "payment_failed.html", {"message": "Invalid transaction"})
|
||||||
|
|
||||||
|
if history.status == "paid":
|
||||||
|
logger.info("Payment already processed. Redirecting to home.")
|
||||||
|
return redirect('home')
|
||||||
|
|
||||||
|
if payment_status == "paid":
|
||||||
|
logger.info(f"Payment successful for transaction ID {payment_id}. Creating order...")
|
||||||
|
|
||||||
|
# Get metadata from PaymentHistory (passed during handle_payment)
|
||||||
|
metadata = history.user_data
|
||||||
|
if isinstance(metadata, str):
|
||||||
|
try:
|
||||||
|
metadata = json.loads(metadata)
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
logger.error(f"Failed to decode metadata JSON: {metadata}")
|
||||||
|
metadata = {}
|
||||||
|
plan_pricing_id = metadata.get("plan_pricing_id")
|
||||||
|
dealer_slug_from_meta = metadata.get("dealer_slug")
|
||||||
|
|
||||||
|
if not plan_pricing_id or dealer_slug_from_meta != dealer_slug:
|
||||||
|
logger.error("Invalid metadata in payment callback")
|
||||||
|
history.status = "failed"
|
||||||
|
history.save()
|
||||||
|
return render(request, "payment_failed.html", {"message": "Invalid payment data"})
|
||||||
|
|
||||||
|
dealer = get_object_or_404(models.Dealer, slug=dealer_slug)
|
||||||
|
pp = get_object_or_404(PlanPricing, pk=plan_pricing_id)
|
||||||
|
|
||||||
|
# ✅ CREATE ORDER HERE
|
||||||
|
try:
|
||||||
|
order = Order.objects.create(
|
||||||
|
user=dealer.user,
|
||||||
|
plan=pp.plan,
|
||||||
|
pricing=pp.pricing,
|
||||||
|
amount=pp.price,
|
||||||
|
currency="SAR", # Fixed typo: was "SA"
|
||||||
|
tax=15,
|
||||||
|
status=Order.STATUS.NEW, # Use constant if available
|
||||||
|
)
|
||||||
|
logger.info(f"Order {order.id} created for user {dealer.user}")
|
||||||
|
except Exception as e:
|
||||||
|
logger.exception(f"Failed to create order: {e}")
|
||||||
|
history.status = "failed"
|
||||||
|
history.save()
|
||||||
|
return render(request, "payment_failed.html", {"message": "Order creation failed"})
|
||||||
|
|
||||||
|
# Create or get BillingInfo
|
||||||
billing_info, created = BillingInfo.objects.get_or_create(
|
billing_info, created = BillingInfo.objects.get_or_create(
|
||||||
user=dealer.user,
|
user=dealer.user,
|
||||||
defaults={
|
defaults={
|
||||||
@ -9949,8 +10023,8 @@ def payment_callback(request, dealer_slug):
|
|||||||
else:
|
else:
|
||||||
logger.debug(f"Billing info already exists for user {dealer.user}.")
|
logger.debug(f"Billing info already exists for user {dealer.user}.")
|
||||||
|
|
||||||
|
# Create or update UserPlan
|
||||||
if not hasattr(order.user, 'userplan'):
|
if not hasattr(order.user, 'userplan'):
|
||||||
print(order.get_plan_pricing().pricing.period)
|
|
||||||
UserPlan.objects.create(
|
UserPlan.objects.create(
|
||||||
user=order.user,
|
user=order.user,
|
||||||
plan=order.plan,
|
plan=order.plan,
|
||||||
@ -9958,26 +10032,22 @@ def payment_callback(request, dealer_slug):
|
|||||||
)
|
)
|
||||||
logger.info(f"Created new UserPlan for user {order.user} with plan {order.plan}.")
|
logger.info(f"Created new UserPlan for user {order.user} with plan {order.plan}.")
|
||||||
else:
|
else:
|
||||||
|
# Optional: upgrade existing plan
|
||||||
|
# user_plan = order.user.userplan
|
||||||
|
# user_plan.plan = order.plan
|
||||||
|
# user_plan.save()
|
||||||
logger.info(f"UserPlan already exists for user {order.user}.")
|
logger.info(f"UserPlan already exists for user {order.user}.")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
# Complete the order (this may generate invoice, etc.)
|
||||||
# if order.user.userplan:
|
|
||||||
# user = order.user
|
|
||||||
# pricing = order.get_plan_pricing().pricing
|
|
||||||
|
|
||||||
# logger.info(f"Processing order completion for {user} - upgrading to {order.plan}")
|
|
||||||
# user.userplan.plan = order.plan
|
|
||||||
# user.userplan.expire = datetime.now() + timedelta(days=pricing.period)
|
|
||||||
# user.userplan.save()
|
|
||||||
# user.save()
|
|
||||||
# logger.info(f"User {user} upgraded to {order.plan} plan successfully")
|
|
||||||
|
|
||||||
order.complete_order()
|
order.complete_order()
|
||||||
history.status = "paid"
|
history.status = "paid"
|
||||||
|
history.order = order # Link payment to order
|
||||||
history.save()
|
history.save()
|
||||||
logger.info(f"Order {order.id} for user {order.user} completed successfully. Payment history updated.")
|
|
||||||
invoice = order.get_invoices().first()
|
invoice = order.get_invoices().first()
|
||||||
|
|
||||||
|
logger.info(f"Order {order.id} completed. Rendering success page.")
|
||||||
return render(
|
return render(
|
||||||
request,
|
request,
|
||||||
"payment_success.html",
|
"payment_success.html",
|
||||||
@ -9985,13 +10055,14 @@ def payment_callback(request, dealer_slug):
|
|||||||
)
|
)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.exception(f"Error completing order {order.id} for user {order.user}: {e}")
|
logger.exception(f"Error completing order {order.id}: {e}")
|
||||||
logger.error(f"Plan activation failed: {str(e)}")
|
|
||||||
history.status = "failed"
|
history.status = "failed"
|
||||||
history.save()
|
history.save()
|
||||||
return render(request, "payment_failed.html", {"message": "Plan activation error"})
|
return render(request, "payment_failed.html", {"message": "Plan activation error"})
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
if dealer := getattr(order.user,"dealer", None):
|
# Activate dealer & staff if needed
|
||||||
|
if dealer := getattr(order.user, "dealer", None):
|
||||||
if not dealer.user.is_active:
|
if not dealer.user.is_active:
|
||||||
dealer.user.is_active = True
|
dealer.user.is_active = True
|
||||||
dealer.user.save()
|
dealer.user.save()
|
||||||
@ -9999,7 +10070,6 @@ def payment_callback(request, dealer_slug):
|
|||||||
if not staff.user.is_active:
|
if not staff.user.is_active:
|
||||||
staff.activate_account()
|
staff.activate_account()
|
||||||
|
|
||||||
logger.info(f"Order {order.id} for user {order.user} completed successfully. Payment history updated.")
|
|
||||||
elif payment_status == "failed":
|
elif payment_status == "failed":
|
||||||
logger.warning(f"Payment failed for transaction ID {payment_id}. Message: {message}")
|
logger.warning(f"Payment failed for transaction ID {payment_id}. Message: {message}")
|
||||||
history.status = "failed"
|
history.status = "failed"
|
||||||
@ -10007,6 +10077,90 @@ def payment_callback(request, dealer_slug):
|
|||||||
return render(request, "payment_failed.html", {"message": message})
|
return render(request, "payment_failed.html", {"message": message})
|
||||||
|
|
||||||
return render(request, "payment_failed.html", {"message": "Unknown payment status"})
|
return render(request, "payment_failed.html", {"message": "Unknown payment status"})
|
||||||
|
# @login_required
|
||||||
|
# @permission_required("inventory.change_dealer", raise_exception=True)
|
||||||
|
# def payment_callback(request, dealer_slug):
|
||||||
|
# message = request.GET.get("message")
|
||||||
|
# dealer = get_object_or_404(models.Dealer, slug=dealer_slug)
|
||||||
|
# payment_id = request.GET.get("id")
|
||||||
|
# history = models.PaymentHistory.objects.filter(transaction_id=payment_id).first()
|
||||||
|
# payment_status = request.GET.get("status")
|
||||||
|
# logger.info(f"Received payment callback for dealer_slug: {dealer_slug}, payment_id: {payment_id}, status: {payment_status}")
|
||||||
|
# order = Order.objects.filter(user=dealer.user, status=1).first() # Status 1 = NEW
|
||||||
|
# logger.info(f"Retrieved order {order.id} for user {order.user}.")
|
||||||
|
# if history.status == "paid":
|
||||||
|
# logger.info(f"Payment history already marked as paid for transaction ID {payment_id}. Redirecting to home.")
|
||||||
|
# return redirect('home')
|
||||||
|
# if payment_status == "paid":
|
||||||
|
# logger.info(f"Payment successful for transaction ID {payment_id}. Processing order completion.")
|
||||||
|
# billing_info, created = BillingInfo.objects.get_or_create(
|
||||||
|
# user=dealer.user,
|
||||||
|
# defaults={
|
||||||
|
# 'tax_number': dealer.vrn,
|
||||||
|
# 'name': dealer.arabic_name,
|
||||||
|
# 'street': dealer.address,
|
||||||
|
# 'zipcode': dealer.entity.zip_code or " ",
|
||||||
|
# 'city': dealer.entity.city or " ",
|
||||||
|
# 'country': dealer.entity.country or " ",
|
||||||
|
# }
|
||||||
|
# )
|
||||||
|
# if created:
|
||||||
|
# logger.info(f"Created new billing info for user {dealer.user}.")
|
||||||
|
# else:
|
||||||
|
# logger.debug(f"Billing info already exists for user {dealer.user}.")
|
||||||
|
|
||||||
|
# if not hasattr(order.user, 'userplan'):
|
||||||
|
# logger.info(f"Creating new UserPlan for user {order.user} with plan {order.plan}.")
|
||||||
|
# UserPlan.objects.create(
|
||||||
|
# user=order.user,
|
||||||
|
# plan=order.plan,
|
||||||
|
# # expire=datetime.now().date() + timedelta(days=order.get_plan_pricing().pricing.period)
|
||||||
|
# )
|
||||||
|
# else:
|
||||||
|
# logger.info(f"UserPlan already exists for user {order.user}.")
|
||||||
|
|
||||||
|
# try:
|
||||||
|
# logger.info(f"Processing order completion for {order.user} - upgrading to {order.plan}")
|
||||||
|
# order.complete_order()
|
||||||
|
# history.status = "paid"
|
||||||
|
# history.save()
|
||||||
|
# logger.info(f"Order {order.id} for user {order.user} completed successfully. Payment history updated.")
|
||||||
|
# invoice = order.get_invoices().first()
|
||||||
|
# logger.info(f"Redirecting to payment success page with invoice {invoice.id}.")
|
||||||
|
# return render(
|
||||||
|
# request,
|
||||||
|
# "payment_success.html",
|
||||||
|
# {"order": order, "invoice": invoice}
|
||||||
|
# )
|
||||||
|
|
||||||
|
# except Exception as e:
|
||||||
|
# logger.exception(f"Error completing order {order.id} for user {order.user}: {e}")
|
||||||
|
# logger.error(f"Plan activation failed: {str(e)}")
|
||||||
|
# history.status = "failed"
|
||||||
|
# history.save()
|
||||||
|
# logger.info(f"Redirecting to payment failed page with message {message}.")
|
||||||
|
# return render(request, "payment_failed.html", {"message": "Plan activation error"})
|
||||||
|
# finally:
|
||||||
|
# if dealer := getattr(order.user,"dealer", None):
|
||||||
|
# logger.info(f"Activating dealer {dealer} and its staff.")
|
||||||
|
# if not dealer.user.is_active:
|
||||||
|
# logger.info(f"Activating dealer {dealer}.")
|
||||||
|
# dealer.user.is_active = True
|
||||||
|
# dealer.user.save()
|
||||||
|
# for staff in dealer.get_staff():
|
||||||
|
# logger.info(f"Activating staff {staff}.")
|
||||||
|
# if not staff.user.is_active:
|
||||||
|
# staff.activate_account()
|
||||||
|
# logger.info(f"Order {order.id} for user {order.user} completed successfully. Payment history updated.")
|
||||||
|
# elif payment_status == "failed":
|
||||||
|
# logger.warning(f"Payment failed for transaction ID {payment_id}. Message: {message}")
|
||||||
|
# history.status = "failed"
|
||||||
|
# history.save()
|
||||||
|
# logger.info(f"Redirecting to payment failed page with message {message}.")
|
||||||
|
# return render(request, "payment_failed.html", {"message": message})
|
||||||
|
|
||||||
|
# logger.info(f"Redirecting to payment failed page with message {message}.")
|
||||||
|
# return render(request, "payment_failed.html", {"message": "Unknown payment status"})
|
||||||
# def payment_callback(request, dealer_slug):
|
# def payment_callback(request, dealer_slug):
|
||||||
# message = request.GET.get("message")
|
# message = request.GET.get("message")
|
||||||
# dealer = get_object_or_404(models.Dealer, slug=dealer_slug)
|
# dealer = get_object_or_404(models.Dealer, slug=dealer_slug)
|
||||||
@ -10350,140 +10504,140 @@ def user_management(request, dealer_slug):
|
|||||||
return render(request, "admin_management/user_management.html", context)
|
return render(request, "admin_management/user_management.html", context)
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
# @login_required
|
||||||
@permission_required("inventory.change_dealer", raise_exception=True)
|
# @permission_required("inventory.change_dealer", raise_exception=True)
|
||||||
def AuditLogDashboardView(request, dealer_slug):
|
# def AuditLogDashboardView(request, dealer_slug):
|
||||||
"""
|
# """
|
||||||
Displays audit logs (User Actions, Login Events, Request Events) with pagination.
|
# Displays audit logs (User Actions, Login Events, Request Events) with pagination.
|
||||||
Log type is determined by the 'q' query parameter (e.g., ?q=userActions).
|
# Log type is determined by the 'q' query parameter (e.g., ?q=userActions).
|
||||||
Pagination page number is passed as a query parameter (e.g., ?page=2).
|
# Pagination page number is passed as a query parameter (e.g., ?page=2).
|
||||||
"""
|
# """
|
||||||
get_object_or_404(models.Dealer, slug=dealer_slug)
|
# get_object_or_404(models.Dealer, slug=dealer_slug)
|
||||||
q = request.GET.get("q") # Get the log type from the 'q' query parameter
|
# q = request.GET.get("q") # Get the log type from the 'q' query parameter
|
||||||
current_pagination_page = request.GET.get("page", 1)
|
# current_pagination_page = request.GET.get("page", 1)
|
||||||
context = {}
|
# context = {}
|
||||||
template_name = None
|
# template_name = None
|
||||||
logs_per_page = 30 # Define logs per page once
|
# logs_per_page = 30 # Define logs per page once
|
||||||
|
|
||||||
# --- Determine Data Source and Template based on 'q' parameter ---
|
# # --- Determine Data Source and Template based on 'q' parameter ---
|
||||||
if (
|
# if (
|
||||||
q == "userRequests"
|
# q == "userRequests"
|
||||||
): # This block handles cases where 'q' is 'requestEvents', None, or any other invalid value.
|
# ): # This block handles cases where 'q' is 'requestEvents', None, or any other invalid value.
|
||||||
# It defaults to Request Logs if 'q' is not 'userActions' or 'loginEvents'.
|
# # It defaults to Request Logs if 'q' is not 'userActions' or 'loginEvents'.
|
||||||
template_name = "admin_management/request_logs.html"
|
# template_name = "admin_management/request_logs.html"
|
||||||
context["title"] = "Request Logs Dashboard"
|
# context["title"] = "Request Logs Dashboard"
|
||||||
request_events = RequestEvent.objects.all().order_by("-datetime")
|
# request_events = RequestEvent.objects.all().order_by("-datetime")
|
||||||
paginator = Paginator(request_events, logs_per_page)
|
# paginator = Paginator(request_events, logs_per_page)
|
||||||
try:
|
# try:
|
||||||
page_obj = paginator.page(current_pagination_page)
|
# page_obj = paginator.page(current_pagination_page)
|
||||||
except PageNotAnInteger:
|
# except PageNotAnInteger:
|
||||||
page_obj = paginator.page(1)
|
# page_obj = paginator.page(1)
|
||||||
except EmptyPage:
|
# except EmptyPage:
|
||||||
page_obj = paginator.page(paginator.num_pages)
|
# page_obj = paginator.page(paginator.num_pages)
|
||||||
|
|
||||||
elif q == "loginEvents":
|
# elif q == "loginEvents":
|
||||||
template_name = "admin_management/auth_logs.html"
|
# template_name = "admin_management/auth_logs.html"
|
||||||
context["title"] = "Login Events Dashboard"
|
# context["title"] = "Login Events Dashboard"
|
||||||
auth_events = LoginEvent.objects.all().order_by("-datetime")
|
# auth_events = LoginEvent.objects.all().order_by("-datetime")
|
||||||
paginator = Paginator(auth_events, logs_per_page)
|
# paginator = Paginator(auth_events, logs_per_page)
|
||||||
try:
|
# try:
|
||||||
page_obj = paginator.page(current_pagination_page)
|
# page_obj = paginator.page(current_pagination_page)
|
||||||
except PageNotAnInteger:
|
# except PageNotAnInteger:
|
||||||
page_obj = paginator.page(1)
|
# page_obj = paginator.page(1)
|
||||||
except EmptyPage:
|
# except EmptyPage:
|
||||||
page_obj = paginator.page(paginator.num_pages)
|
# page_obj = paginator.page(paginator.num_pages)
|
||||||
|
|
||||||
else:
|
# else:
|
||||||
template_name = "admin_management/model_logs.html"
|
# template_name = "admin_management/model_logs.html"
|
||||||
context["title"] = "User Actions Dashboard"
|
# context["title"] = "User Actions Dashboard"
|
||||||
|
|
||||||
# OPTIMIZATION: Get the QuerySet but don't evaluate it yet
|
# # OPTIMIZATION: Get the QuerySet but don't evaluate it yet
|
||||||
model_events_queryset = CRUDEvent.objects.all().order_by("-datetime")
|
# model_events_queryset = CRUDEvent.objects.all().order_by("-datetime")
|
||||||
|
|
||||||
# 1. Paginate the raw QuerySet FIRST
|
# # 1. Paginate the raw QuerySet FIRST
|
||||||
paginator = Paginator(model_events_queryset, logs_per_page)
|
# paginator = Paginator(model_events_queryset, logs_per_page)
|
||||||
|
|
||||||
try:
|
# try:
|
||||||
# Get the page object, which contains only the raw QuerySet objects for the current page
|
# # Get the page object, which contains only the raw QuerySet objects for the current page
|
||||||
page_obj_raw = paginator.page(current_pagination_page)
|
# page_obj_raw = paginator.page(current_pagination_page)
|
||||||
except PageNotAnInteger:
|
# except PageNotAnInteger:
|
||||||
page_obj_raw = paginator.page(1)
|
# page_obj_raw = paginator.page(1)
|
||||||
except EmptyPage:
|
# except EmptyPage:
|
||||||
page_obj_raw = paginator.page(paginator.num_pages)
|
# page_obj_raw = paginator.page(paginator.num_pages)
|
||||||
|
|
||||||
# 2. Now, process 'field_changes' ONLY for the events on the current page
|
# # 2. Now, process 'field_changes' ONLY for the events on the current page
|
||||||
processed_model_events_for_page = []
|
# processed_model_events_for_page = []
|
||||||
for (
|
# for (
|
||||||
event
|
# event
|
||||||
) in page_obj_raw.object_list: # Loop only through the current page's items
|
# ) in page_obj_raw.object_list: # Loop only through the current page's items
|
||||||
event_data = {
|
# event_data = {
|
||||||
"datetime": event.datetime,
|
# "datetime": event.datetime,
|
||||||
"user": event.user,
|
# "user": event.user,
|
||||||
"event_type_display": event.get_event_type_display(),
|
# "event_type_display": event.get_event_type_display(),
|
||||||
"model_name": event.content_type.model,
|
# "model_name": event.content_type.model,
|
||||||
"object_id": event.object_id,
|
# "object_id": event.object_id,
|
||||||
"object_repr": event.object_repr,
|
# "object_repr": event.object_repr,
|
||||||
"field_changes": [],
|
# "field_changes": [],
|
||||||
}
|
# }
|
||||||
|
|
||||||
if event.changed_fields:
|
# if event.changed_fields:
|
||||||
try:
|
# try:
|
||||||
changes = json.loads(event.changed_fields)
|
# changes = json.loads(event.changed_fields)
|
||||||
if isinstance(changes, dict):
|
# if isinstance(changes, dict):
|
||||||
for field_name, values in changes.items():
|
# for field_name, values in changes.items():
|
||||||
old_value = (
|
# old_value = (
|
||||||
values[0]
|
# values[0]
|
||||||
if isinstance(values, list) and len(values) > 0
|
# if isinstance(values, list) and len(values) > 0
|
||||||
else None
|
# else None
|
||||||
)
|
# )
|
||||||
new_value = (
|
# new_value = (
|
||||||
values[1]
|
# values[1]
|
||||||
if isinstance(values, list) and len(values) > 1
|
# if isinstance(values, list) and len(values) > 1
|
||||||
else None
|
# else None
|
||||||
)
|
# )
|
||||||
event_data["field_changes"].append(
|
# event_data["field_changes"].append(
|
||||||
{
|
# {
|
||||||
"field": field_name,
|
# "field": field_name,
|
||||||
"old": old_value,
|
# "old": old_value,
|
||||||
"new": new_value,
|
# "new": new_value,
|
||||||
}
|
# }
|
||||||
)
|
# )
|
||||||
elif changes is None:
|
# elif changes is None:
|
||||||
event_data["field_changes"].append(
|
# event_data["field_changes"].append(
|
||||||
{
|
# {
|
||||||
"field": "Info",
|
# "field": "Info",
|
||||||
"old": "",
|
# "old": "",
|
||||||
"new": "No specific field changes recorded (JSON was null)",
|
# "new": "No specific field changes recorded (JSON was null)",
|
||||||
}
|
# }
|
||||||
)
|
# )
|
||||||
else: # Handle valid JSON but not a dictionary (e.g., "[]", 123)
|
# else: # Handle valid JSON but not a dictionary (e.g., "[]", 123)
|
||||||
event_data["field_changes"].append(
|
# event_data["field_changes"].append(
|
||||||
{
|
# {
|
||||||
"field": "Error",
|
# "field": "Error",
|
||||||
"old": "",
|
# "old": "",
|
||||||
"new": f"Unexpected JSON format: {type(changes).__name__}",
|
# "new": f"Unexpected JSON format: {type(changes).__name__}",
|
||||||
}
|
# }
|
||||||
)
|
# )
|
||||||
except json.JSONDecodeError:
|
# except json.JSONDecodeError:
|
||||||
# Handle invalid JSON; you might log this error
|
# # Handle invalid JSON; you might log this error
|
||||||
event_data["field_changes"].append(
|
# event_data["field_changes"].append(
|
||||||
{
|
# {
|
||||||
"field": "Error",
|
# "field": "Error",
|
||||||
"old": "",
|
# "old": "",
|
||||||
"new": "Invalid JSON in changed_fields",
|
# "new": "Invalid JSON in changed_fields",
|
||||||
}
|
# }
|
||||||
)
|
# )
|
||||||
processed_model_events_for_page.append(event_data)
|
# processed_model_events_for_page.append(event_data)
|
||||||
|
|
||||||
# 3. Replace the object_list of the original page_obj with the processed data
|
# # 3. Replace the object_list of the original page_obj with the processed data
|
||||||
# This keeps all pagination properties (has_next, number, etc.) intact.
|
# # This keeps all pagination properties (has_next, number, etc.) intact.
|
||||||
page_obj_raw.object_list = processed_model_events_for_page
|
# page_obj_raw.object_list = processed_model_events_for_page
|
||||||
page_obj = page_obj_raw # This will be passed to the context
|
# page_obj = page_obj_raw # This will be passed to the context
|
||||||
|
|
||||||
# Pass the final page object to the context
|
# # Pass the final page object to the context
|
||||||
context["page_obj"] = page_obj
|
# context["page_obj"] = page_obj
|
||||||
|
|
||||||
return render(request, template_name, context)
|
# return render(request, template_name, context)
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user