43. Finalizing orders and treating errors
Currently, in our checkout.html
file, submitting the forms does not trigger any action since no action is linked to them. We need to capture the form data and integrate it with the Mercado Pago API to handle payments.
For better organization, whenever we use an external API, we will create a separate file dedicated to consolidating all functions and functionalities related to that API.
Therefore, inside our store
folder, we will create a new file named api_mercadopago.py
to manage all functions and integrations related to the Mercado Pago API.
When the user finalizes their order, we want to redirect them to a page where they can complete the purchase. To do this, we will create a new view function called finish_order
. For now, this function will simply redirect the user back to the store.
def finish_order(request) :
return redirect("store")
Don't forget to add the new finish_order
URL pattern to the urls.py
file to ensure the view function is properly linked and accessible.
path('finishorder/',finish_order, name="finish_order"),
The finish_order
view function will handle the integration of the features from api_mercadopago.py
with the form data. Therefore, inside the checkout.html
file, we will reference this view function in the form's action
attribute to ensure the data is processed correctly during checkout.
<form method="POST" action="{% url 'finish_order' %}">
Before integrating the payment system, we need to handle potential error cases. For example, we should ensure that the user has provided their email address if they are not logged in. This will prevent issues during the checkout process and ensure all necessary information is collected.
First, we need to identify which order is being finalized. To do this, we will pass the order ID in the URL within the checkout.html
file. This will allow the order ID to be accessed and utilized in the finish_order
view function.
<form method="POST" action="{% url 'finish_order' order.id %}">
As done previously, we need to include the order ID as a parameter in the finish_order
URL pattern within the urls.py
file. This will ensure that the ID is properly passed to the finish_order
view function.
path('finishorder/<int:order_id>/',finish_order, name="finish_order"),
Lastly, in the checkout.html
file, we need to add a name
attribute to the email input box. Without it, we won't be able to capture the email data in our view function.
<input type="email" name="email" placeholder="email"> <!--Placeholder is the transparent text that appears before-->
Now, we will begin updating the finish_order
function to handle error cases, such as:
Missing address or email fields.
Incorrect pricing information.
This will ensure that any issues are caught and addressed before proceeding with the payment process.
def finish_order(request, order_id) :
if request.method == "POST" :
error = None
data = request.POST.dict()
total = data.get("total")
order = Order.objects.get(id=order_id) #? used get because it is only one order
if float(total) != float(order.total_cost) :
error = "conflicting_cost" #? in case the user tries to manipulate the html
if not "adress" in data :
error = "adress"
else :
adress = data.get("adress")
if not request.user.is_authenticated :
email = data.get("email")
try :
validate_email(email)
except ValidationError :
error = "email"
context = {"error" : error}
return redirect("checkout")
else :
return redirect("store")
Explanation of the code above:
Function Definition:
def finish_order(request, order_id)
Defines the view function for finalizing an order with a given
order_id
.
Check Request Method:
if request.method == "POST"
Handles form submissions made via POST.
Initialization:
error = None
: Initializes anerror
variable to store any error messages.data = request.POST.dict()
: Converts the POST data into a dictionary for easier access.
Retrieve Order:
order = Order.objects.get(id=order_id)
Retrieves the
Order
object with the specifiedorder_id
. Assumes only one order with this ID exists.
Cost Validation:
if float(total) != float(order.total_cost)
: Checks if thetotal
amount from the POST data matches the order’stotal_cost
.If they don't match, sets
error = "conflicting_cost"
to indicate a potential manipulation attempt.
Address Validation:
if not "adress" in data
: Checks if the address field is missing from the POST data.If missing, sets
error = "adress"
to indicate that the address is required.If present, retrieves the address value.
Email Validation (if unauthenticated):
if not request.user.is_authenticated
: If the user is not authenticated, validates the provided email.Retrieves the email from POST data and attempts to validate it using
validate_email(email)
.If validation fails, sets
error = "email"
.
Context Preparation:
context = {"error": error}
Prepares a context dictionary with the error message.
Redirect:
return redirect("checkout")
: Redirects to the checkout page if there are no errors.else: return redirect("store")
: Redirects to the store page if the request method is not POST.
Last updated