Skip to content

Commit 5cbba95

Browse files
renzonrenzon
authored andcommitted
Created subscription accordingly to payment
close #3763
1 parent 989c47a commit 5cbba95

File tree

8 files changed

+124
-9
lines changed

8 files changed

+124
-9
lines changed

pythonpro/domain/checkout_domain.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from pythonpro.domain import user_domain
77
from pythonpro.domain.hotzapp_domain import verify_purchase, send_purchase_notification
88
from pythonpro.email_marketing import facade as email_marketing_facade
9+
from pythonpro.memberkit import facade as memberkit_facade
910

1011
__all__ = ['contact_info_listener', 'user_factory', 'payment_handler_task', 'payment_change_handler']
1112

@@ -56,6 +57,7 @@ def payment_handler_task(payment_id):
5657
else:
5758
status = payment.status()
5859
if status == django_pagarme_facade.PAID:
60+
memberkit_facade.create_new_subscription(payment, 'Criação como resposta de pagamento no Pagarme')
5961
user = payment.user
6062
if payment.payment_method == django_pagarme_facade.BOLETO:
6163
email_marketing_facade.remove_tags.delay(user.email, user.id, f'{slug}-boleto', f'{slug}-refused')

pythonpro/domain/tests/test_checkout/conftest.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@
33
import pytest
44
from django_pagarme import facade
55
from django_pagarme.models import PagarmeFormConfig, PagarmeItemConfig
6+
from model_bakery import baker
67

78
# Workaround since module beginning with number can't be imported in regular way
9+
from pythonpro.memberkit.models import SubscriptionType, PaymentItemConfigToSubscriptionType
810

911
migration_module = import_module('pythonpro.checkout.migrations.0001_payment_setup')
1012
webdev_migration_module = import_module('pythonpro.checkout.migrations.0002_webdev_setup')
@@ -60,6 +62,13 @@ def execute_migration(db, pytestconfig):
6062
webinar_migration_module.setup_payment_configs_function(PagarmeFormConfig, PagarmeItemConfig)
6163
webserie_migration_module.setup_payment_configs_function(PagarmeFormConfig, PagarmeItemConfig)
6264
thiago_avelino_migration_module.setup_payment_configs_function(PagarmeFormConfig, PagarmeItemConfig)
65+
subscription_type = baker.make(SubscriptionType)
66+
PaymentItemConfigToSubscriptionType.objects.bulk_create(
67+
[
68+
PaymentItemConfigToSubscriptionType(payment_item=config, subscription_type=subscription_type)
69+
for config in PagarmeItemConfig.objects.all()
70+
]
71+
)
6372

6473

6574
@pytest.fixture(autouse=True)

pythonpro/domain/tests/test_checkout/test_boleto_generation.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,8 +142,7 @@ def remove_tags_mock(mocker):
142142

143143

144144
def test_payment_tag_removed_after_payment(resp_logged_user, active_product_item, remove_tags_mock, logged_user,
145-
tag_as_mock,
146-
mocker):
145+
tag_as_mock, mocker):
147146
payment = django_pagarme_facade.find_payment_by_transaction(TRANSACTION_ID)
148147
baker.make(django_pagarme_facade.PagarmeNotification, status=django_pagarme_facade.PAID, payment=payment)
149148
promote_mock = mocker.patch('pythonpro.domain.checkout_domain._promote')

pythonpro/domain/tests/test_checkout/test_payment_handler.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from model_bakery import baker
55

66
from pythonpro.domain import checkout_domain
7+
from pythonpro.memberkit.models import SubscriptionType, Subscription, PaymentItemConfigToSubscriptionType
78

89

910
@pytest.fixture
@@ -31,6 +32,9 @@ def test_pagarme_payment_paid_boleto(db, tag_as_mock, remove_tags_mock, promote_
3132
payment = baker.make(PagarmePayment, payment_method=facade.BOLETO, user=logged_user)
3233
baker.make(PagarmeNotification, status=facade.PAID, payment=payment)
3334
config = baker.make(PagarmeItemConfig, payments=[payment])
35+
subscription_type = baker.make(SubscriptionType)
36+
PaymentItemConfigToSubscriptionType.objects.create(payment_item=config, subscription_type=subscription_type)
37+
3438
checkout_domain.payment_handler_task(payment.id)
3539
assert tag_as_mock.called is False
3640
remove_tags_mock.assert_called_once_with(
@@ -40,11 +44,31 @@ def test_pagarme_payment_paid_boleto(db, tag_as_mock, remove_tags_mock, promote_
4044
send_purchase_notification_mock.asser_called_once_with(payment.id)
4145

4246

47+
def test_subscription_creation(db, tag_as_mock, remove_tags_mock, promote_user_mock, logged_user,
48+
send_purchase_notification_mock):
49+
payment = baker.make(PagarmePayment, payment_method=facade.BOLETO, user=logged_user)
50+
baker.make(PagarmeNotification, status=facade.PAID, payment=payment)
51+
config = baker.make(PagarmeItemConfig, payments=[payment])
52+
subscription_type = baker.make(SubscriptionType)
53+
PaymentItemConfigToSubscriptionType.objects.create(payment_item=config, subscription_type=subscription_type)
54+
checkout_domain.payment_handler_task(payment.id)
55+
subscription = Subscription.objects.first()
56+
assert subscription is not None
57+
assert subscription.subscriber_id == payment.user_id
58+
assert subscription.status == Subscription.Status.INACTIVE
59+
assert subscription.payment_id == payment.id
60+
assert list(subscription.subscription_types.all()) == [subscription_type]
61+
assert subscription.responsible is None
62+
assert subscription.observation == 'Criação como resposta de pagamento no Pagarme'
63+
64+
4365
def test_pagarme_payment_paid_credit_card(db, tag_as_mock, remove_tags_mock, promote_user_mock, logged_user,
4466
send_purchase_notification_mock):
4567
payment = baker.make(PagarmePayment, payment_method=facade.CREDIT_CARD, user=logged_user)
4668
baker.make(PagarmeNotification, status=facade.PAID, payment=payment)
4769
config = baker.make(PagarmeItemConfig, payments=[payment])
70+
subscription_type = baker.make(SubscriptionType)
71+
PaymentItemConfigToSubscriptionType.objects.create(payment_item=config, subscription_type=subscription_type)
4872
checkout_domain.payment_handler_task(payment.id)
4973
assert tag_as_mock.called is False
5074
remove_tags_mock.assert_called_once_with(

pythonpro/memberkit/admin.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
# Register your models here.
88
from pythonpro.memberkit import facade
9-
from pythonpro.memberkit.models import SubscriptionType, PaymentItemConfigToSubscriptionType
9+
from pythonpro.memberkit.models import SubscriptionType, PaymentItemConfigToSubscriptionType, Subscription
1010

1111

1212
class PaymentItemConfigInline(admin.TabularInline):
@@ -45,3 +45,15 @@ def has_delete_permission(self, request, obj=None):
4545
@admin.register(PagarmeItemConfig)
4646
class NewPagarmeItemConfigAdmin(PagarmeItemConfigAdmin):
4747
inlines = [PaymentItemConfigInline]
48+
49+
50+
@admin.register(Subscription)
51+
class SubscriptionAdmin(admin.ModelAdmin):
52+
fields = ['subscriber', 'subscription_types', 'observation']
53+
list_display = ['subscriber', 'responsible', 'status', 'created_at', 'updated_at']
54+
autocomplete_fields = ['subscriber']
55+
search_fields = ['subscriber__email']
56+
list_filter = ['status', 'subscription_types']
57+
58+
def has_delete_permission(self, request, obj=None):
59+
return False

pythonpro/memberkit/facade.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,26 @@
11
from typing import List
22

33
from pythonpro.memberkit import api
4-
from pythonpro.memberkit.models import SubscriptionType
4+
from pythonpro.memberkit.models import SubscriptionType, Subscription
55

66

77
def synchronize_subscription_types() -> List[SubscriptionType]:
88
return [
99
SubscriptionType.objects.update_or_create(id=dct['id'], name=dct['name'])[0]
1010
for dct in api.list_membership_levels()
1111
]
12+
13+
14+
def create_new_subscription(payment, observation: str = '') -> Subscription:
15+
subscription_types = [item.subscription_type_relation.subscription_type for item in payment.items.all()]
16+
if len(subscription_types) == 0:
17+
raise ValueError(f"Payment {payment} doesn't have subscription types")
18+
19+
subscription = Subscription.objects.create(
20+
status=Subscription.Status.INACTIVE,
21+
payment=payment,
22+
subscriber=payment.user,
23+
observation=observation
24+
)
25+
subscription.subscription_types.set(subscription_types)
26+
return subscription
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# Generated by Django 3.2.4 on 2021-06-05 20:15
2+
3+
import django.db.models.deletion
4+
from django.conf import settings
5+
from django.db import migrations, models
6+
7+
8+
class Migration(migrations.Migration):
9+
dependencies = [
10+
('django_pagarme', '0004_pagarme_item_config_available_until'),
11+
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
12+
('memberkit', '0002_create_relationship_with_payment_config_item'),
13+
]
14+
15+
operations = [
16+
migrations.CreateModel(
17+
name='Subscription',
18+
fields=[
19+
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
20+
('status', models.CharField(choices=[('A', 'Ativo'), ('I', 'Inativo')], max_length=1)),
21+
('created_at', models.DateTimeField(auto_now_add=True)),
22+
('updated_at', models.DateTimeField(auto_now=True)),
23+
('observation', models.TextField(blank=True, default='', verbose_name='Observação')),
24+
('payment', models.OneToOneField(null=True, on_delete=django.db.models.deletion.DO_NOTHING,
25+
to='django_pagarme.pagarmepayment')),
26+
('responsible', models.ForeignKey(null=True, on_delete=django.db.models.deletion.DO_NOTHING,
27+
related_name='created_subscriptions', to=settings.AUTH_USER_MODEL)),
28+
('subscriber', models.ForeignKey(null=True, on_delete=django.db.models.deletion.DO_NOTHING,
29+
related_name='subscriptions', to=settings.AUTH_USER_MODEL)),
30+
('subscription_types',
31+
models.ManyToManyField(related_name='subscriptions', to='memberkit.SubscriptionType')),
32+
],
33+
options={
34+
'verbose_name': 'Assinatura',
35+
'verbose_name_plural': 'Assinaturas',
36+
},
37+
),
38+
]

pythonpro/memberkit/models.py

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from django.contrib.auth import get_user_model
12
from django.db import models
23

34

@@ -22,8 +23,23 @@ class PaymentItemConfigToSubscriptionType(models.Model):
2223
def __str__(self):
2324
return f'{self.payment_item} -> {self.subscription_type}'
2425

25-
# class Subscription(models.Model):
26-
# created_at = models.DateTimeField(auto_now_add=True)
27-
# updated_at = models.DateTimeField(auto_now_add=True)
28-
# payment = models.OneToOneField('PagarmePayment', on_delete=models.DO_NOTHING, )
29-
# subscription_type = models.OneToOneField(SubscriptionType, null=False, on_delete=models.DO_NOTHING)
26+
27+
class Subscription(models.Model):
28+
class Meta:
29+
verbose_name = 'Assinatura'
30+
verbose_name_plural = 'Assinaturas'
31+
32+
class Status(models.TextChoices):
33+
ACTIVE = 'A', 'Ativo'
34+
INACTIVE = 'I', 'Inativo'
35+
36+
status = models.CharField(max_length=1, choices=Status.choices)
37+
created_at = models.DateTimeField(auto_now_add=True)
38+
updated_at = models.DateTimeField(auto_now=True)
39+
payment = models.OneToOneField('django_pagarme.PagarmePayment', on_delete=models.DO_NOTHING, null=True)
40+
subscription_types = models.ManyToManyField(SubscriptionType, related_name='subscriptions')
41+
subscriber = models.ForeignKey(get_user_model(), on_delete=models.DO_NOTHING, null=True,
42+
related_name='subscriptions')
43+
responsible = models.ForeignKey(get_user_model(), on_delete=models.DO_NOTHING, null=True,
44+
related_name='created_subscriptions')
45+
observation = models.TextField(verbose_name='Observação', blank=True, default='')

0 commit comments

Comments
 (0)