Skip to content

Commit

Permalink
Merge pull request #44 from leonardocintra/payments-leave
Browse files Browse the repository at this point in the history
Refatoring Payments
  • Loading branch information
leonardocintra authored Feb 1, 2022
2 parents 0582bbe + e3f4fca commit 920fa69
Show file tree
Hide file tree
Showing 13 changed files with 281 additions and 149 deletions.
8 changes: 4 additions & 4 deletions pagamento/business.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
from pagamento.models import PagamentoMercadoPago


def atualizar_pagamento_mp(payment, mercado_pago_id, payment_id):
def atualizar_pagamento_mp(payment):
# Atualiza os dados do mercado pago na tabela de pagamento
payment_id = payment['id']
PagamentoMercadoPago.objects.filter(
mercado_pago_id=mercado_pago_id).update(
payment_id=payment_id).update(
transaction_amount=payment['transaction_amount'],
installments=payment['installments'],
payment_method_id=payment['payment_method_id'],
mercado_pago_status=payment['status'],
mercado_pago_status_detail=payment['status_detail'],
payment_id=payment_id
mercado_pago_status_detail=payment['status_detail']
)
33 changes: 33 additions & 0 deletions pagamento/tests/test_business.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
from django.test import TestCase
from evento.tests.test_model import create_fakes_status
from pagamento.models import PagamentoMercadoPago

from pedido.business import concluir_pedido
from pedido.models import ItemPedido, Pedido
from pedido.tests.test_model import get_fake_pedido


class ConcluirPedidoTest(TestCase):
def setUp(self):
create_fakes_status()
Pedido.objects.all().delete()
ItemPedido.objects.all().delete()
self.pedido = get_fake_pedido()
PagamentoMercadoPago.objects.create(
pedido=self.pedido,
mercado_pago_id='823948asakfjaslkjfalssasa',
payment_id=1240157386,
)
concluir_pedido(self.pedido, 1240157386)

def test_pedido_existe(self):
self.assertEqual(1, Pedido.objects.count())

def test_pedido_seller_foi_gerado(self):
self.assertIsNotNone(self.pedido.request_seller)

def test_items_do_pedido_criados(self):
items = ItemPedido.objects.filter(pedido=self.pedido)
self.assertEqual(len(items), ItemPedido.objects.count())


38 changes: 32 additions & 6 deletions pagamento/tests/test_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
from django.test.utils import override_settings
from django.urls import reverse as r
from checkout.tests.test_model import get_fake_carrinho_com_items, UUID_FAKE_CARRINHO
from evento.models import EventoPedido
from pedido.models import Pedido
from usuario.tests.test_model import get_fake_endereco, get_fake_user
from usuario.models import Cliente
from evento.tests.test_model import create_fakes_status
Expand Down Expand Up @@ -37,20 +39,42 @@ def test_carrinho_nao_esta_na_session(self):
self.assertRedirects(response, '/')

def test_pagamento(self):
Pedido.objects.all().delete()
session = self.client.session
session['carrinho'] = UUID_FAKE_CARRINHO
session.save()

response = self.client.get(r('pagamento:pagamento'))
self.assertTrue(200, response.status_code)
self.assertEqual(1, Pedido.objects.count())

def test_pagamento_refresh_mais_de_uma_x_nao_pode_criar_novo_pedido(self):
Pedido.objects.all().delete()
EventoPedido.objects.all().delete()

session = self.client.session
session['carrinho'] = UUID_FAKE_CARRINHO
session.save()

class MpNotificationsTest(TestCase):
response = self.client.get(r('pagamento:pagamento'))
self.assertTrue(200, response.status_code)
self.assertEqual(1, Pedido.objects.count())
response = self.client.get(r('pagamento:pagamento'))
self.assertTrue(200, response.status_code)
self.assertEqual(1, Pedido.objects.count())
response = self.client.get(r('pagamento:pagamento'))
self.assertTrue(200, response.status_code)
self.assertEqual(1, Pedido.objects.count())
self.assertEqual(1, EventoPedido.objects.count())


class MercadoPagoNotificationsTest(TestCase):
def setUp(self):
create_fakes_status()
self.client = Client()

@override_settings(DEBUG=True)
def test_notificacao_mp_ipn_pagamento_nao_encontrado(self):
def test_notificacao_mp_ipn_pagamento_mp_nao_encontrado(self):
response = self.client.post(
r('pagamento:mp_notifications') + '?topic=payment&id=123456789')
self.assertJSONEqual(response.content, {"pagamento": "nao-encontrado"})
Expand All @@ -59,14 +83,16 @@ def test_notificacao_mp_ipn_pagamento_nao_encontrado(self):
@override_settings(DEBUG=True)
def test_notificacao_mp_ipn_status_approved(self):
pedido = get_fake_pedido()
pedido.uuid = '0d994c6f-aebe-44eb-98ce-73d81e2b477a'
pedido.save()
PagamentoMercadoPago.objects.create(
pedido=pedido,
mercado_pago_id='qualquercoisa',
payment_id=1240157386,
payment_id=1245751670,
)
response = self.client.post(
r('pagamento:mp_notifications') + '?topic=payment&id=1240157386')
self.assertJSONEqual(response.content, {"pagamento": "aprovado"})
r('pagamento:mp_notifications') + '?topic=payment&id=1245751670')
self.assertJSONEqual(response.content, {"pagamento": "dado-recebido"})
self.assertEqual(201, response.status_code)

@override_settings(DEBUG=True)
Expand All @@ -87,5 +113,5 @@ def test_notificacao_mp_webhook_pagamento_nao_encontrado(self):
}
response = self.client.post(
r('pagamento:webhook'), json.dumps(data), "application/json")
self.assertJSONEqual(response.content, {"pagamento": "nao-encontrado"})
self.assertJSONEqual(response.content, {"pagamento": "webhook-nao-configurado"})
self.assertEqual(200, response.status_code)
153 changes: 91 additions & 62 deletions pagamento/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,31 @@

from evento.models import criar_evento
from checkout.models import Carrinho, ItemCarrinho
from pedido.models import Pedido
from pedido.views import gerar_venda
from pagamento.business import atualizar_pagamento_mp
from pedido.business import _gerar_venda, concluir_pedido
from pedido.models import ItemPedido, Pedido
from usuario.models import Cliente, EnderecoCliente
from services.mercadopago.mercadopago import create_preference, montar_payload_preference, get_payment, get_merchant_order
from services.mercadopago.mercadopago import create_preference, montar_payload_preference, get_payment, get_merchant_order, get_pagamento_by_external_reference
from services.dimona.api import get_frete
from services.telegram.api import enviar_mensagem
from .models import PagamentoMercadoPago
import decimal
import json

def _buscar_pedido_by_external_reference(external_reference):
return Pedido.objects.get(uuid=external_reference)

def _create_items_pedido(pedido, items):
ItemPedido.objects.filter(pedido=pedido).delete()
for item in items:
ItemPedido.objects.create(
pedido=pedido,
produto=item.produto,
cor=item.cor,
tamanho=item.tamanho,
modelo_produto=item.modelo_produto,
quantidade=item.quantidade
)

@login_required
def pagamento(request):
Expand Down Expand Up @@ -47,7 +62,7 @@ def pagamento(request):

# monta o frete
frete_items = get_frete(cep, quantidade_total)
valor_frete = 10.0
valor_frete = 15.0
transportadora = ''
delivery_method_id = 0
if 'cotacao_frete' in request.session:
Expand All @@ -71,31 +86,54 @@ def pagamento(request):
valor_frete = round(float(valor_frete), 2)
valor_total = round(valor_carrinho + decimal.Decimal(valor_frete), 2)

# Cria o pedido
# TODO: todo F5 esta criando um novo pedido - arrumar
pedido = Pedido.objects.create(
user=user,
valor_total=valor_total,
valor_frete=valor_frete,
valor_items=valor_carrinho,
frete_id=delivery_method_id,
frete_nome=transportadora,
endereco_cliente=endereco
)
# Cria o pedido. Se pedido ja existe, apenas faz update
pedido = None
if 'pedido_uuid' in request.session:
try:
pedido = Pedido.objects.get(uuid=request.session['pedido_uuid'])
if pedido.session_ativa == False:
del request.session['pedido_uuid']
Pedido.objects.filter(
uuid=request.session['pedido_uuid']).update(
user=user,
valor_total=valor_total,
valor_frete=valor_frete,
valor_items=valor_carrinho,
frete_id=delivery_method_id,
frete_nome=transportadora,
endereco_cliente=endereco,
)
except Exception as e:
pedido = None

if pedido is None:
pedido = Pedido.objects.create(
user=user,
valor_total=valor_total,
valor_frete=valor_frete,
valor_items=valor_carrinho,
frete_id=delivery_method_id,
frete_nome=transportadora,
endereco_cliente=endereco,
session_ativa=True
)
# Cria o evento inicial
criar_evento(1, pedido)

# Cria o evento inicial
criar_evento(1, pedido)
_create_items_pedido(pedido, items)
request.session['pedido_uuid'] = str(pedido.uuid)

# Monta o payload para enviar pro mercado pago
preference_data = montar_payload_preference(
request, pedido.id, items, cliente, endereco, valor_frete)
request, pedido.uuid, items, cliente, endereco, valor_frete)

# Cria a preferencia no mercado pago
preference = create_preference(preference_data)
preference_id = preference['id']

# Atualiza informações na tabela de pagamento
frase_padrao = 'PEDIDO_NAO_FINALIZADO'
PagamentoMercadoPago.objects.filter(pedido=pedido).delete()
PagamentoMercadoPago.objects.create(
pedido=pedido,
mercado_pago_id=preference_id,
Expand All @@ -104,7 +142,6 @@ def pagamento(request):
payment_method_id=frase_padrao
)

# TODO: toda vez que da F5 ele cria um novo pedido. Validar isso
request.session['mercado_pago_id'] = preference_id

context = {
Expand All @@ -120,37 +157,19 @@ def pagamento(request):
return render(request, 'pagamento/pagamento.html', context)


def atualizar_pagamento(payment_id):
obj_mp = get_payment(payment_id)

if obj_mp['status'] == 'approved':
PagamentoMercadoPago.objects.filter(payment_id=payment_id).update(
mercado_pago_status=obj_mp['status'],
mercado_pago_status_detail=obj_mp['status_detail'],
)
pagamento_mp = PagamentoMercadoPago.objects.get(payment_id=payment_id)
gerar_venda(pagamento_mp=pagamento_mp)

if obj_mp['status'] == 404:
return JsonResponse({"pagamento": "nao-encontrado"}, status=200)

if obj_mp['status'] != 'approved':
return JsonResponse({"pagamento": "nao-aprovado"}, status=200)

return JsonResponse({"pagamento": "aprovado"}, status=201)


@require_POST
@csrf_exempt
def mp_notifications(request):
# Notificações do Mercado Pago IPN
# Mercado Pago nao notificica em STAGE, entao tem que fazer os POST na mão
try:
if request.GET.get('topic') != 'payment' and request.GET.get('topic') != 'merchant_order':
enviar_mensagem('Recebeu uma notificação IPN do mercado pago mas não foi um topic payment: {0} - ID: {1}'.format(
enviar_mensagem('Recebeu uma notificação IPN do mercado pago mas não foi um topic mapeado: {0} - ID: {1}'.format(
request.GET.get('topic'), request.GET.get('id')), 'IPN do Mercado pago')
return JsonResponse({"erro": "topico nao mapeado"}, status=200)

payment_id = request.GET.get('id')
pedido = None

if request.GET.get('topic') == 'merchant_order':
merchant_order = get_merchant_order(request.GET.get('id'))
Expand All @@ -160,32 +179,42 @@ def mp_notifications(request):
request.GET.get('topic'), request.GET.get('id')), 'IPN do Mercado pago')
return JsonResponse({"merchant_order": "merchant_order nao encontrado. "}, status=200)

payment_id = merchant_order['payments'][0]['id']

return atualizar_pagamento(payment_id)
external_reference = merchant_order['external_reference']
datas = get_pagamento_by_external_reference(external_reference)

# TODO: as vezes pode ter mais de um resuts. Entao fazer um loog para ppegar sempre o ultimo
payment_id = datas['results'][0]['id']

Pedido.objects.filter(uuid=external_reference).update(session_ativa=False)
pedido = _buscar_pedido_by_external_reference(external_reference)
PagamentoMercadoPago.objects.filter(pedido=pedido).update(payment_id=payment_id)

payment = get_payment(payment_id)
if payment['status'] == 404:
return JsonResponse({"pagamento": "nao-encontrado"}, status=200)

atualizar_pagamento_mp(payment)
try:
if pedido is None:
pedido = _buscar_pedido_by_external_reference(payment['external_reference'])
concluir_pedido(pedido, payment_id)
except Exception as e:
print(e)
return JsonResponse({"pagamento": "ocorreu um erro no concluir-pedido"}, status=201)

return JsonResponse({"pagamento": "dado-recebido"}, status=201)

except PagamentoMercadoPago.DoesNotExist:
return JsonResponse({"payment": "not found"}, status=200)
except:
enviar_mensagem('ERRO ao receber IPN: {0}'.format(str(request)))
return JsonResponse({"payment": "not found"}, status=200)
return JsonResponse({"payment": "pagamento não encontrado"}, status=200)
except Exception as ex:
enviar_mensagem('ERRO ao receber IPN: {0} - {1}'.format(str(request)), ex)
return JsonResponse({"payment": "ocorreu um excetipon ao processar"}, status=200)


@require_POST
@csrf_exempt
def webhook(request):
# Notificações do Mercado Pago Webhook
payload = json.loads(request.body)
payment_id = payload['id']

if payload['live_mode']:
enviar_mensagem(payload, payment_id, 'Webhook do Mercado pago')

try:
return atualizar_pagamento(payment_id)
except PagamentoMercadoPago.DoesNotExist:
enviar_mensagem('Pagamento não encontrato apos receber um Webhook do mercado pago',
payment_id, 'Webhook do Mercado pago')
return JsonResponse({"foo": "bar"}, status=200)
except:
enviar_mensagem('ERRO ao receber Webhook: {0}'.format(request.body))
return JsonResponse({"foo": "bar"}, status=200)
# Repetir mesma regra do IPN
enviar_mensagem('MENSAGEM Webhook: {0}'.format(str(request)))
return JsonResponse({"pagamento": "webhook-nao-configurado"}, status=200)
Loading

0 comments on commit 920fa69

Please sign in to comment.