Aula 58 – Loja Online – Django – Associando o Perfil ao Pedido

Aula 58 – Loja Online – Django – Associando o Pedido ao Perfil

Loja Online - Django - Associando o Pedido ao Perfil

Loja Online – Django – Associando o Pedido ao Perfil

Voltar para página principal do blog

Todas as aulas desse curso

Aula 57               Aula 59

Se gostarem do conteúdo dêem um joinha 👍 na página do Código Fluente no
Facebook

Esse é o link do código fluente no Pinterest

Meus links de afiliados:

Hostinger

Digital Ocean

One.com

Melhore seu NETWORKING

https://digitalinnovation.one/

Participe de comunidades de desenvolvedores:

Fiquem a vontade para me adicionar ao linkedin.

E também para me seguir no https://github.com/toticavalcanti.

Código final da aula:

https://github.com/toticavalcanti

Quer aprender python3 de graça e com certificado? Acesse então:

https://workover.com.br/python-codigo-fluente

Toti:

https://www.youtube.com/channel/UCUEtjLuDpcOvR3mIUr-viOA

Backing track / Play-along:

https://www.youtube.com/channel/UCT3TryVMqTqYBjf5g5WAHfA

Código Fluente

https://www.youtube.com/channel/UCgn-O-88XBAwdG9gUWkkb0w

Putz!

https://www.youtube.com/channel/UCZXop2-CECwyFYmHbhnAkAw

Aula 58 – Loja Online – Django – Associando o Order ao Profile

O que vamos fazer agora é ajustar a forma como um pedido (Order) será criado, baseado no perfil de pagamento do usuário (Billing Profile).

Temos um carrinho, devemos criar um pedido para esse carrinho apenas quando a gente tiver um perfil de pagamento do usuário.

Um usuário pode explorar o site como convidado, mas, na hora de fechar a compra, necessariamente ele deve fazer o login, pra que possa acessar as informações de seu perfil de pagamento.

Atualizando o Pedido (Order)

É preciso ter as duas coisas para criar um pedido: o billing profile e o cart.

Queremos também nos livrar do guest_email_id quando o usuário convidado logar.

guest_email_obj = GuestEmail.objects.get(id=guest_email_id)

OBS: Não é para deletar a parte em vermelho no código abaixo, a cor foi só para chamar atenção da lógica que estamos trabalhando.

django_ecommerce/e_commerce/carts/views.py  


from django.shortcuts import render, redirect

from accounts.forms import LoginForm, GuestForm
from accounts.models import GuestEmail
from billing.models import BillingProfile
from orders.models import Order
from products.models import Product
from .models import Cart

def cart_home(request):
    cart_obj, new_obj  = Cart.objects.new_or_get(request)
    return render(request, "carts/home.html", {"cart": cart_obj})

def cart_update(request):
    print(request.POST)
    product_id = request.POST.get('product_id')
    if product_id is not None:
        try:
            product_obj = Product.objects.get(id = product_id)
        except Product.DoesNotExist:
            print("Mostrar mensagem ao usuário, esse produto acabou!")
            return redirect("cart:home")
        cart_obj, new_obj = Cart.objects.new_or_get(request) 
        if product_obj in cart_obj.products.all(): 
            cart_obj.products.remove(product_obj) 
        else: 
            cart_obj.products.add(product_obj)
        request.session['cart_items'] = cart_obj.products.count()
    return redirect("cart:home")

def checkout_home(request):
    #aqui a gente pega o carrinho
    cart_obj, cart_created= Cart.objects.new_or_get(request)
    order_obj = None
    #se o carrinho acabou de ser criado, ele tá zerado
    #ou se o carrinho já existir mas não tiver nada dentro
    if cart_created or cart_obj.products.count() == 0:
        return redirect("cart:home")
    #aqui a order associada ao carrinho
    else:
        order_obj, new_order_obj = Order.objects.get_or_create(cart = cart_obj)
    user = request.user
    billing_profile = None
    login_form = LoginForm()
    guest_form = GuestForm()
    guest_email_id = request.session.get('guest_email_id')
    if user.is_authenticated:
        billing_profile, billing_profile_created = BillingProfile.objects.get_or_create(
            user=user, email=user.email)
    elif guest_email_id is not None:
        guest_email_obj = GuestEmail.objects.get(id=guest_email_id)
        billing_profile, billing_guest_profile_created = BillingProfile.objects.get_or_create(
            email=guest_email_obj.email)
    else:
        pass

    context = {
        "object": order_obj,
        "billing_profile": billing_profile,
        "login_form": login_form,
        "guest_form": guest_form
    }
    return render(request, "carts/checkout.html", context)

Para remover o guest_email_id vamos abrir o views do accounts  e colocar o que tá em azul no código abaixo.

O que tá sendo feito é, se o usuário está logado, pode deletar o guest_email_id, não vamos precisar mais dessa informação.

django_ecommerce/e_commerce/accounts/views.py 


from django.contrib.auth import authenticate, login, logout, get_user_model
from django.http import HttpResponse
from django.shortcuts import render,redirect
from django.utils.http import url_has_allowed_host_and_scheme

from .forms import LoginForm, RegisterForm, GuestForm
from .models import GuestEmail


def guest_register_view(request):
    form = GuestForm(request.POST or None)
    context = {
        "form": form
    }
    next_ = request.GET.get('next')
    next_post = request.POST.get('next')
    redirect_path = next_ or next_post or None
    if form.is_valid():
        email       = form.cleaned_data.get("email")
        new_guest_email = GuestEmail.objects.create(email=email)
        request.session['guest_email_id'] = new_guest_email.id
        if url_has_allowed_host_and_scheme(redirect_path, request.get_host()):
            return redirect(redirect_path)
        else:
            return redirect("/register/")
    return redirect("/register/")

def login_page(request):
    form = LoginForm(request.POST or None)
    context = {
                    "form": form
              }
    next_ = request.GET.get('next')
    next_post = request.POST.get('next')
    redirect_path = next_ or next_post or None
    if form.is_valid():
        username = form.cleaned_data.get("username")
        password = form.cleaned_data.get("password")
        user = authenticate(request, username=username, password=password) 
        if user is not None:
            login(request, user)
            try:
                del request.session['guest_email_id']
            except:
                pass
            if url_has_allowed_host_and_scheme( redirect_path, request.get_host() ):
                return redirect( redirect_path )
            else:
                # Redireciona para uma página de sucesso.
                return redirect("/")
        else:
            #Retorna uma mensagem de erro de 'invalid login'.
            print("Login inválido")
    return render(request, "accounts/login.html", context)

def logout_page(request):
    context = {
                "content": "Você efetuou o logout com sucesso! :)"
              }
    logout(request)
    return render(request, "accounts/logout.html", context)

User = get_user_model()
def register_page(request):
    form = RegisterForm(request.POST or None)
    context = {
                "form": form
              }
    if form.is_valid():
        print(form.cleaned_data)
        username = form.cleaned_data.get("username")
        email = form.cleaned_data.get("email")
        password = form.cleaned_data.get("password")
        new_user = User.objects.create_user(username, email, password)
        print(new_user)
    return render(request, "accounts/register.html", context)

Agoa no models do order vamos criar o campo billing_profile, é o campo associativo com o perfil de pagamento de usuário.

django_ecommerce/e_commerce/orders/models.py  


import math
from django.db import models
from django.db.models.signals import pre_save, post_save
from billing.models import BillingProfile
from carts.models import Cart
from e_commerce.utils import unique_order_id_generator

ORDER_STATUS_CHOICES = (
    ('created', 'Criado'),
    ('paid', 'Pago'),
    ('shipped', 'Enviado'),
    ('refunded', 'Devolvido'),
)

class Order(models.Model):
    billing_profile = models.ForeignKey(BillingProfile, on_delete=models.CASCADE, null = True, blank = True)
    order_id = models.CharField(max_length = 120, blank = True)
    # billing_profile = ?
    # shipping_address = ?
    # billing_address
    cart = models.ForeignKey(Cart, on_delete=models.CASCADE, null = True)
    status = models.CharField(max_length = 120, default = 'created', choices = ORDER_STATUS_CHOICES )
    shipping_total = models.DecimalField(default = 5.99, max_digits = 100, decimal_places = 2)
    total = models.DecimalField(default = 0.00, max_digits = 100, decimal_places = 2)
    active = models.BooleanField(default=True)

    def __str__(self):
        return self.order_id
    def update_total(self):
        cart_total = self.cart.total
        shipping_total = self.shipping_total
        new_total = math.fsum([cart_total, shipping_total])
        formatted_total = format(new_total, '.2f')
        self.total = formatted_total 
        self.save()
        return new_total

def pre_save_create_order_id(sender, instance, *args, **kwargs):
    if not instance.order_id:
        instance.order_id = unique_order_id_generator(instance)

pre_save.connect(pre_save_create_order_id, sender = Order)

def post_save_cart_total(sender, instance, created, *args, **kwargs):
    if not created:
        cart_obj = instance
        cart_total = cart_obj.total
        cart_id = cart_obj.id
        qs = Order.objects.filter(cart__id=cart_id)
        if qs.count() == 1:
            order_obj = qs.first()
            order_obj.update_total()

post_save.connect(post_save_cart_total, sender=Cart)

def post_save_order(sender, instance, created, *args, **kwargs):
    print("Executando")
    if created:
        print("Atualizando")
        instance.update_total()

post_save.connect(post_save_order, sender=Order)

Como alteramos nosso modelo Order, precisamos rodar o makemigrations e o migrate.


python manage.py makemigrations
python manage.py migrate

Vamos colocar essa linha em azul no checkout.html do carts, pra gente ter um print na tela do id do objeto Pedido e o do carrinho e poder fazer alguns testes.

django_ecommerce/e_commerce/carts/templates/carts/checkout.html 


{% extends "base.html" %}
{% block content %}
{{ object.order_id }} -- {{ object.cart }}
{% if not billing_profile %}
<div class='row text-center'>
  <div class='col-12 col-md-6'>
    <p class='lead'>Login</p>
    {% include 'accounts/snippets/form.html' with form=login_form next_url=request.build_absolute_uri %}
  </div>
  <div class='col-12 col-md-6'> 
    <p class='lead'>Continuar como Convidado</p>
    {% url "guest_register" as guest_register_url %}
    {% include 'accounts/snippets/form.html' with form=guest_form next_url=request.build_absolute_uri action_url=guest_register_url %}
  </div>
</div>
{% else %}
  <h1>Checkout</h1>
  <p>Total do carrinho: {{ object.cart.total }}</p>
  <p>Frete: {{ object.shipping_total }}</p>
  <p>Total: {{ object.total }}</p>
{% endif %}
{% endblock %}

Pode ser que aconteça de várias orders ficarem associadas a um mesmo carrinho.

Para ajustar isso, abra o views do carts, e coloque o código que está em azul.

django_ecommerce/e_commerce/carts/views.py  


from django.shortcuts import render, redirect

from accounts.forms import LoginForm, GuestForm
from accounts.models import GuestEmail
from billing.models import BillingProfile
from orders.models import Order
from products.models import Product
from .models import Cart

def cart_home(request):
    cart_obj, new_obj  = Cart.objects.new_or_get(request)
    return render(request, "carts/home.html", {"cart": cart_obj})

def cart_update(request):
    print(request.POST)
    product_id = request.POST.get('product_id')
    if product_id is not None:
        try:
            product_obj = Product.objects.get(id = product_id)
        except Product.DoesNotExist:
            print("Mostrar mensagem ao usuário, esse produto acabou!")
            return redirect("cart:home")
        cart_obj, new_obj = Cart.objects.new_or_get(request) 
        if product_obj in cart_obj.products.all(): 
            cart_obj.products.remove(product_obj) 
        else: 
            cart_obj.products.add(product_obj)
        request.session['cart_items'] = cart_obj.products.count()
    return redirect("cart:home")

def checkout_home(request):
    #aqui a gente pega o carrinho
    cart_obj, cart_created= Cart.objects.new_or_get(request)
    order_obj = None
    #se o carrinho acabou de ser criado, ele tá zerado
    #ou se o carrinho já existir mas não tiver nada dentro
    if cart_created or cart_obj.products.count() == 0:
        return redirect("cart:home")
    #aqui a order associada ao carrinho
    user = request.user
    billing_profile = None
    login_form = LoginForm()
    guest_form = GuestForm()
    guest_email_id = request.session.get('guest_email_id')
    if user.is_authenticated:
        billing_profile, billing_profile_created = BillingProfile.objects.get_or_create(
            user=user, email=user.email)
    elif guest_email_id is not None:
        guest_email_obj = GuestEmail.objects.get(id=guest_email_id)
        billing_profile, billing_guest_profile_created = BillingProfile.objects.get_or_create(
            email=guest_email_obj.email)
    else:
        pass

    if billing_profile is not None:
        order_qs = Order.objects.filter(billing_profile = billing_profile, cart = cart_obj, active = True)
        if order_qs.count() == 1:
            order_obj = order_qs.first()
        else:
            old_order_qs = Order.objects.exclude(billing_profile = billing_profile).filter(cart = cart_obj, active = True)
            if old_order_qs.exists():
                old_order_qs.update(active = False)
            order_obj = Order.objects.create(billing_profile = billing_profile, cart = cart_obj)
    context = {
        "object": order_obj,
        "billing_profile": billing_profile,
        "login_form": login_form,
        "guest_form": guest_form
    }
    return render(request, "carts/checkout.html", context)

O que código faz é verificar se existe um billing_profile, se existir, roda todo o código abaixo que associa um objeto cart ao billing profile no order.

Logado, adicione alguns produtos no carrinho, depois clique em checkout e veja o order_id e o número do cart na tela.

Faça o logout e adicione alguns produtos no carrinho, veja o número do cart e do order_id.

Agora escolha a opção de continuar como convidado, informando o email.

Faça testes e observe o que acontece com os números do cart e do order_id.

Lembrando que o order é criado quando temos um billing profile e um cart, ela é a associação das duas coisas.

É isso, ficamos por aqui e até a próxima. 😉

Voltar para página principal do blog

Todas as aulas desse curso

Aula 57               Aula 59

Código final da aula:

https://github.com/toticavalcanti

Outros canais

Toti:

https://www.youtube.com/channel/UCUEtjLuDpcOvR3mIUr-viOA

Backing track / Play-along:

https://www.youtube.com/channel/UCT3TryVMqTqYBjf5g5WAHfA

Código Fluente

https://www.youtube.com/channel/UCgn-O-88XBAwdG9gUWkkb0w

Putz!

https://www.youtube.com/channel/UCZXop2-CECwyFYmHbhnAkAw

Se gostarem do conteúdo dêem um joinha 👍 na página do Código Fluente no
Facebook

Esse é o link do código fluente no Pinterest

Meus links de afiliados:

Hostinger

Digital Ocean

One.com

Nos vemos na próxima então, \o/  😉 Bons Estudos!

 

 

About The Author
-

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>