From 377fd4a4c78aef6c82b3416e89c9a023688bb658 Mon Sep 17 00:00:00 2001 From: Eric Costa Date: Wed, 16 Oct 2024 15:25:28 -0300 Subject: [PATCH 1/5] feat: removing sync_active_contacts --- connect/common/tasks.py | 174 +++++++++++++++------------------- connect/common/tests/tests.py | 97 +++++++++---------- 2 files changed, 125 insertions(+), 146 deletions(-) diff --git a/connect/common/tasks.py b/connect/common/tasks.py index 02c1dd1b..d9c66810 100644 --- a/connect/common/tasks.py +++ b/connect/common/tasks.py @@ -17,13 +17,17 @@ BillingPlan, Invoice, GenericBillingData, - RecentActivity + RecentActivity, ) from connect.api.v1.internal.chats.chats_rest_client import ChatsRESTClient from connect.api.v1.internal.flows.flows_rest_client import FlowsRESTClient -from connect.api.v1.internal.integrations.integrations_rest_client import IntegrationsRESTClient -from connect.api.v1.internal.intelligence.intelligence_rest_client import IntelligenceRESTClient +from connect.api.v1.internal.integrations.integrations_rest_client import ( + IntegrationsRESTClient, +) +from connect.api.v1.internal.intelligence.intelligence_rest_client import ( + IntelligenceRESTClient, +) from connect.common.keycloak import KeycloakCleanup import logging @@ -43,19 +47,19 @@ def delete_organization(inteligence_organization: int, user_email): @app.task(name="update_organization") -def update_organization(inteligence_organization: int, organization_name: str, user_email: str): +def update_organization( + inteligence_organization: int, organization_name: str, user_email: str +): ai_client = IntelligenceRESTClient() ai_client.update_organization( organization_id=inteligence_organization, organization_name=organization_name, - user_email=user_email + user_email=user_email, ) return True -@app.task( - name="update_user_permission_organization" -) +@app.task(name="update_user_permission_organization") def update_user_permission_organization( inteligence_organization: int, user_email: str, permission: int ): @@ -120,14 +124,10 @@ def update_user_permission_project( permission=permission, ) integrations_client.update_user_permission_project( - project_uuid=project_uuid, - user_email=user_email, - role=permission + project_uuid=project_uuid, user_email=user_email, role=permission ) chats_client.update_user_permission( - permission=permission, - user_email=user_email, - project_uuid=project_uuid + permission=permission, user_email=user_email, project_uuid=project_uuid ) return True @@ -146,8 +146,7 @@ def migrate_organization(user_email: str): ) role = ai_client.get_user_organization_permission_role( - user_email=user_email, - organization_id=organization.get("id") + user_email=user_email, organization_id=organization.get("id") ) org.authorizations.create(user=user, role=role) @@ -250,15 +249,11 @@ def search_project(organization_id: int, project_uuid: str, text: str): else: flows_client = FlowsRESTClient() flow_result = flows_client.get_project_flows( - project_uuid=project_uuid, - flow_name=text + project_uuid=project_uuid, flow_name=text ) - inteligence_result = ( - IntelligenceRESTClient().get_organization_intelligences( - intelligence_name=text, - organization_id=organization_id - ) + inteligence_result = IntelligenceRESTClient().get_organization_intelligences( + intelligence_name=text, organization_id=organization_id ) return { "flow": flow_result, @@ -282,7 +277,7 @@ def check_organization_free_plan(): now = pendulum.now(project_timezone) before = now.strftime("%Y-%m-%d %H:%M") # first day of month - after = now.start_of('month').strftime("%Y-%m-%d %H:%M") + after = now.start_of("month").strftime("%Y-%m-%d %H:%M") contact_count = flow_instance.get_billing_total_statistics( project_uuid=str(project.flow_organization), before=before, after=after @@ -305,27 +300,6 @@ def check_organization_free_plan(): return True -@app.task(name="sync_active_contacts") -def sync_active_contacts(): - for project in Project.objects.all()[:10]: - try: - if project.organization.organization_billing.plan in [BillingPlan.PLAN_CUSTOM, BillingPlan.PLAN_ENTERPRISE]: - before = pendulum.now().end_of("month") - after = pendulum.now().start_of("month") - else: - last_invoice_date = project.organization.organization_billing.last_invoice_date - next_due_date = project.organization.organization_billing.next_due_date - created_at = project.organization.created_at - before = timezone.now() if next_due_date is None else next_due_date - after = created_at if last_invoice_date is None else last_invoice_date - except BillingPlan.DoesNotExist: - logger.error("Org: {project.organization} does not have a billing plan object") - contact_count = utils.count_contacts(project=project, after=str(after), before=str(before)) - project.contact_count = int(contact_count) - project.save(update_fields=["contact_count"]) - return True - - @app.task(name="sync_total_contact_count") def sync_total_contact_count(): if settings.USE_FLOW_REST: @@ -354,10 +328,14 @@ def sync_project_statistics(): project_uuid=str(project.uuid), ) if len(statistic_project_result) > 0: - project.flow_count = int(statistic_project_result.get("active_flows")) + project.flow_count = int( + statistic_project_result.get("active_flows") + ) project.save(update_fields=["flow_count"]) except ConnectionError as c: - logger.error(f"Remote end closed connection without: {c} - Project: {project}") + logger.error( + f"Remote end closed connection without: {c} - Project: {project}" + ) continue except Exception as e: logger.error(f"Sync Project Statistics Exception {e}") @@ -402,9 +380,7 @@ def sync_channels_statistics(): flow_instance = utils.get_grpc_types().get("flow") for project in Project.objects.all(): project.extra_active_integration = len( - list( - flow_instance.list_channel(project_uuid=str(project.uuid)) - ) + list(flow_instance.list_channel(project_uuid=str(project.uuid))) ) project.save(update_fields=["extra_active_integration"]) @@ -415,14 +391,23 @@ def generate_project_invoice(): sync_channels_statistics() for org in Organization.objects.filter( - organization_billing__next_due_date__lte=pendulum.now().date(), is_suspended=False).exclude( - organization_billing__plan__in=[BillingPlan.PLAN_TRIAL, BillingPlan.PLAN_CUSTOM, BillingPlan.PLAN_ENTERPRISE]): + organization_billing__next_due_date__lte=pendulum.now().date(), + is_suspended=False, + ).exclude( + organization_billing__plan__in=[ + BillingPlan.PLAN_TRIAL, + BillingPlan.PLAN_CUSTOM, + BillingPlan.PLAN_ENTERPRISE, + ] + ): invoice = org.organization_billing_invoice.create( due_date=pendulum.now(), - invoice_random_id=1 - if org.organization_billing_invoice.last() is None - else org.organization_billing_invoice.last().invoice_random_id + 1, + invoice_random_id=( + 1 + if org.organization_billing_invoice.last() is None + else org.organization_billing_invoice.last().invoice_random_id + 1 + ), discount=org.organization_billing.fixed_discount, extra_integration=org.extra_active_integrations, cost_per_whatsapp=settings.BILLING_COST_PER_WHATSAPP, @@ -430,19 +415,17 @@ def generate_project_invoice(): after = ( org.created_at.strftime("%Y-%m-%d %H:%M") if org.organization_billing.last_invoice_date is None - else org.organization_billing.last_invoice_date.strftime( - "%Y-%m-%d %H:%M" - ) + else org.organization_billing.last_invoice_date.strftime("%Y-%m-%d %H:%M") ) before = ( timezone.now().strftime("%Y-%m-%d %H:%M") if org.organization_billing.next_due_date is None - else org.organization_billing.next_due_date.strftime( - "%Y-%m-%d %H:%M" - ) + else org.organization_billing.next_due_date.strftime("%Y-%m-%d %H:%M") ) for project in org.project.all(): - contact_count = utils.count_contacts(project=project, after=str(after), before=str(before)) + contact_count = utils.count_contacts( + project=project, after=str(after), before=str(before) + ) invoice.organization_billing_invoice_project.create( project=project, @@ -532,10 +515,7 @@ def update_user_photo(user_email: str, photo_url: str): user_email=user_email, photo_url=photo_url, ) - chats_client.update_user( - user_email=user_email, - photo_url=photo_url - ) + chats_client.update_user(user_email=user_email, photo_url=photo_url) return True @@ -550,14 +530,10 @@ def update_user_name(user_email: str, first_name: str, last_name: str): if user.exists(): user = user.first() integrations_client.update_user( - user_email=user_email, - first_name=first_name, - last_name=last_name + user_email=user_email, first_name=first_name, last_name=last_name ) chats_client.update_user( - user_email=user_email, - first_name=first_name, - last_name=last_name + user_email=user_email, first_name=first_name, last_name=last_name ) return True @@ -584,20 +560,18 @@ def get_billing_total_statistics(project_uuid: str, before: str, after: str): retry_kwargs={"max_retries": 5}, retry_backoff=True, ) -def delete_user_permission_project(flow_organization: str, project_uuid: str, user_email: str, permission: int): +def delete_user_permission_project( + flow_organization: str, project_uuid: str, user_email: str, permission: int +): flow_instance = FlowsRESTClient() chats_instance = ChatsRESTClient() flow_instance.delete_user_permission_project( - project_uuid=flow_organization, - user_email=user_email, - permission=permission + project_uuid=flow_organization, user_email=user_email, permission=permission ) chats_instance.delete_user_permission_project( - project_uuid=project_uuid, - user_email=user_email, - permission=permission + project_uuid=project_uuid, user_email=user_email, permission=permission ) @@ -622,7 +596,7 @@ def list_channels(channel_type): config=channel.get("config"), address=channel.get("address"), project_uuid=str(project.uuid), - is_active=channel.get("is_active") + is_active=channel.get("is_active"), ) else: channel_data = dict( @@ -637,7 +611,7 @@ def list_channels(channel_type): return channels -@app.task(name='release_channel') +@app.task(name="release_channel") def realease_channel(channel_uuid, user): if settings.USE_FLOW_REST: flow_instance = FlowsRESTClient() @@ -650,7 +624,7 @@ def realease_channel(channel_uuid, user): return True -@app.task(name='create_channel') +@app.task(name="create_channel") def create_channel(user, project_uuid, data, channeltype_code): if settings.USE_FLOW_REST: flow_instance = FlowsRESTClient() @@ -658,7 +632,7 @@ def create_channel(user, project_uuid, data, channeltype_code): user=user, project_uuid=project_uuid, data=data, - channeltype_code=channeltype_code + channeltype_code=channeltype_code, ) else: flow_instance = utils.get_grpc_types().get("flow") @@ -668,13 +642,13 @@ def create_channel(user, project_uuid, data, channeltype_code): user=user, project_uuid=project_uuid, data=data, - channeltype_code=channeltype_code + channeltype_code=channeltype_code, ) return dict( uuid=response.uuid, name=response.name, config=response.config, - address=response.address + address=response.address, ) except grpc.RpcError as error: raise error @@ -703,7 +677,7 @@ def create_wac_channel(user, flow_organization, config, phone_number_id): uuid=response.uuid, name=response.name, config=response.config, - address=response.address + address=response.address, ) except grpc.RpcError as error: raise error @@ -741,7 +715,9 @@ def destroy_classifier(classifier_uuid: str, user_email: str): @app.task(name="create_classifier") -def create_classifier(project_uuid: str, user_email: str, classifier_name: str, access_token): +def create_classifier( + project_uuid: str, user_email: str, classifier_name: str, access_token +): if settings.USE_FLOW_REST: flow_instance = FlowsRESTClient() else: @@ -756,7 +732,7 @@ def create_classifier(project_uuid: str, user_email: str, classifier_name: str, return response.get("data", {}) -@app.task(name='list_classifier') +@app.task(name="list_classifier") def list_classifier(project_uuid: str): classifiers = {"data": []} if settings.USE_FLOW_REST: @@ -769,14 +745,20 @@ def list_classifier(project_uuid: str): is_active=True, ) for i in response: - authorization = i.get("access_token") if settings.USE_FLOW_REST else i.get("authorization_uuid") - classifiers["data"].append({ - "authorization_uuid": authorization, - "classifier_type": i.get("classifier_type"), - "name": i.get("name"), - "is_active": i.get("is_active"), - "uuid": i.get("uuid"), - }) + authorization = ( + i.get("access_token") + if settings.USE_FLOW_REST + else i.get("authorization_uuid") + ) + classifiers["data"].append( + { + "authorization_uuid": authorization, + "classifier_type": i.get("classifier_type"), + "name": i.get("name"), + "is_active": i.get("is_active"), + "uuid": i.get("uuid"), + } + ) return classifiers diff --git a/connect/common/tests/tests.py b/connect/common/tests/tests.py index ea4a5197..1958b451 100644 --- a/connect/common/tests/tests.py +++ b/connect/common/tests/tests.py @@ -337,10 +337,12 @@ def setUp(self): ) self.invoice = self.organization.organization_billing_invoice.create( due_date=pendulum.now().add(months=1), - invoice_random_id=1 - if self.organization.organization_billing_invoice.last() is None - else self.organization.organization_billing_invoice.last().invoice_random_id - + 1, + invoice_random_id=( + 1 + if self.organization.organization_billing_invoice.last() is None + else self.organization.organization_billing_invoice.last().invoice_random_id + + 1 + ), discount=self.organization.organization_billing.fixed_discount, extra_integration=self.organization.extra_integration, cost_per_whatsapp=settings.BILLING_COST_PER_WHATSAPP, @@ -431,18 +433,20 @@ def test_send_email_organization_create(self): email1 = ( self.test_user1.email, self.test_user1.username, - self.test_user1.language + self.test_user1.language, ) email2 = ( self.test_user2.email, self.test_user2.username, - self.test_user2.language + self.test_user2.language, ) email_list = [email1, email2] self.organization.send_email_organization_create(email_list) self.assertEqual(len(mail.outbox), 2) outbox = mail.outbox[0] - self.assertEqual(outbox.subject, f"You just gave life to {self.organization.name}") + self.assertEqual( + outbox.subject, f"You just gave life to {self.organization.name}" + ) self.assertEqual(outbox.from_email, settings.DEFAULT_FROM_EMAIL) self.assertEqual(outbox.to[0], self.test_user1.email) @@ -469,8 +473,13 @@ def test_send_email_delete_organization(self): self.organization.send_email_delete_organization() self.assertEqual(len(mail.outbox), 2) - self.assertEqual(mail.outbox[0].subject, "The organization Test Organization no longer exists") - self.assertEqual(mail.outbox[1].subject, "A organização Test Organization deixou de existir") + self.assertEqual( + mail.outbox[0].subject, + "The organization Test Organization no longer exists", + ) + self.assertEqual( + mail.outbox[1].subject, "A organização Test Organization deixou de existir" + ) self.assertIn(f"{self.test_user1.username}", mail.outbox[0].body) self.assertIn(f"{self.test_user2.username}", mail.outbox[1].body) @@ -481,7 +490,9 @@ def test_send_email_change_organization_name(self): (self.test_user1.email, self.test_user1.username, self.test_user1.language), (self.test_user2.email, self.test_user2.username, self.test_user2.language), ] - self.organization.send_email_change_organization_name(prev_name, new_name, emails) + self.organization.send_email_change_organization_name( + prev_name, new_name, emails + ) self.assertEqual(len(mail.outbox), 2) for email in mail.outbox: @@ -498,7 +509,9 @@ def test_send_email_access_code(self): self.assertTrue(result) self.assertEqual(len(mail.outbox), 1) sent_email = mail.outbox[0] - self.assertEqual(sent_email.subject, "You receive an access code to Weni Platform") + self.assertEqual( + sent_email.subject, "You receive an access code to Weni Platform" + ) def test_send_email_permission_change(self): sended_email = self.organization.send_email_permission_change( @@ -506,7 +519,10 @@ def test_send_email_permission_change(self): ) self.assertEqual(len(sended_email.outbox), 1) outbox = sended_email.outbox[0] - self.assertEqual(outbox.subject, f"An administrator of {self.organization.name} has updated your permission") + self.assertEqual( + outbox.subject, + f"An administrator of {self.organization.name} has updated your permission", + ) self.assertEqual(outbox.from_email, settings.DEFAULT_FROM_EMAIL) self.assertEqual(outbox.to[0], self.test_email) @@ -581,9 +597,7 @@ def test_send_email_changed_card(self): def test_send_email_finished_plan(self): email_list = [self.test_user1.email, self.test_user2.email] - self.billing.send_email_finished_plan( - self.test_user1.username, email_list - ) + self.billing.send_email_finished_plan(self.test_user1.username, email_list) self.assertEqual(len(mail.outbox), 2) outbox = mail.outbox[0] if self.test_user1.language == "en-us": @@ -595,9 +609,7 @@ def test_send_email_finished_plan(self): self.assertEqual(outbox.to[0], self.test_email[0]) def test_send_email_reactivated_plan(self): - self.billing.send_email_reactivated_plan( - self.test_user_name, self.test_email - ) + self.billing.send_email_reactivated_plan(self.test_user_name, self.test_email) self.assertEqual(len(mail.outbox), 1) outbox = mail.outbox[0] self.assertEqual( @@ -663,12 +675,18 @@ def test_send_email_changed_plan(self): def test_send_email_plan_is_about_to_expire(self): self.billing.plan = BillingPlan.PLAN_TRIAL - user1 = (self.test_user1.email, self.test_user1.username, self.test_user1.language) - user2 = (self.test_user2.email, self.test_user2.username, self.test_user2.language) - email_list = [user1, user2] - self.billing.send_email_plan_is_about_to_expire( - email_list + user1 = ( + self.test_user1.email, + self.test_user1.username, + self.test_user1.language, + ) + user2 = ( + self.test_user2.email, + self.test_user2.username, + self.test_user2.language, ) + email_list = [user1, user2] + self.billing.send_email_plan_is_about_to_expire(email_list) self.assertEqual(len(mail.outbox), 2) outbox = mail.outbox[0] self.assertEqual(outbox.from_email, settings.DEFAULT_FROM_EMAIL) @@ -676,9 +694,7 @@ def test_send_email_plan_is_about_to_expire(self): def test_send_email_end_trial(self): email_list = [self.test_user1.email] - self.billing.send_email_end_trial( - email_list - ) + self.billing.send_email_end_trial(email_list) self.assertEqual(len(mail.outbox), 1) outbox = mail.outbox[0] self.assertEqual(outbox.from_email, settings.DEFAULT_FROM_EMAIL) @@ -845,27 +861,6 @@ def test_create_request_permission(self, mock_permission): self.assertEqual(auth.role, OrganizationRole.VIEWER.value) -@skipIf(True, "can't run that without port-forward") -class SyncUpdateTasksTestCase(TestCase): - - def setUp(self): - self.organization = Organization.objects.create( - name="Test", inteligence_organization=0, - organization_billing__cycle=BillingPlan.BILLING_CYCLE_MONTHLY, - organization_billing__plan="free", - ) - self.billing = self.organization.organization_billing - self.project = self.organization.project.create( - name="project test", - timezone="America/Sao_Paulo", - flow_organization=uuid4.uuid4(), - ) - - def test_okay(self): - from connect.common.tasks import sync_active_contacts - self.assertTrue(sync_active_contacts()) - - @skipIf(not settings.ROCKET_TEST_MODE, "Skip if rocket isnt in test mode") class TestRocket(TestCase): def setUp(self): @@ -884,7 +879,9 @@ def test_change_user_role(self): def test_fail_to_get_keycloak_authorization_token(self): self.rocket = Rocket() - self.rocket.username = '' + self.rocket.username = "" response = self.rocket.get_keycloak_authorization_token() - self.assertEquals(response['status'], 'FAILED') - self.assertEquals(response['message']['error_description'], 'Invalid user credentials') + self.assertEquals(response["status"], "FAILED") + self.assertEquals( + response["message"]["error_description"], "Invalid user credentials" + ) From 3d1454d5174ceed39efec9db38fd058337708f80 Mon Sep 17 00:00:00 2001 From: Eric Costa Date: Wed, 16 Oct 2024 15:32:21 -0300 Subject: [PATCH 2/5] feat: removing generate_project_invoice and sync_channels_statistics --- connect/api/v1/tests/test_v2_organization.py | 212 +++++++------------ connect/celery.py | 54 ++--- connect/common/tasks.py | 70 ------ 3 files changed, 98 insertions(+), 238 deletions(-) diff --git a/connect/api/v1/tests/test_v2_organization.py b/connect/api/v1/tests/test_v2_organization.py index d41d32ce..e388b421 100644 --- a/connect/api/v1/tests/test_v2_organization.py +++ b/connect/api/v1/tests/test_v2_organization.py @@ -16,16 +16,19 @@ ProjectAuthorization, RequestPermissionOrganization, BillingPlan, - Invoice + Invoice, ) from connect.common.mocks import StripeMockGateway from unittest.mock import patch import pendulum from freezegun import freeze_time -from connect.billing.tasks import end_trial_plan, check_organization_plans, daily_contact_count +from connect.billing.tasks import ( + end_trial_plan, + check_organization_plans, + daily_contact_count, +) from rest_framework import status from connect.api.v1.billing.views import BillingViewSet -from connect.common.tasks import generate_project_invoice class CreateOrganizationAPITestCase(TestCase): @@ -64,19 +67,14 @@ def test_create(self, mock_get_gateway, mock_permission): "name": "name", "description": "desc", "plan": "plan", - "authorizations": [ - { - "user_email": "e@mail.com", - "role": 3 - } - ] + "authorizations": [{"user_email": "e@mail.com", "role": 3}], }, "project": { "date_format": "D", "name": "Test Project", "organization": "2575d1f9-f7f8-4a5d-ac99-91972e309511", "timezone": "America/Argentina/Buenos_Aires", - } + }, } response, content_data = self.request(data, self.owner_token) @@ -93,19 +91,14 @@ def test_create_org_with_customer(self, mock_get_gateway, mock_permission): "description": "Customer", "plan": BillingPlan.PLAN_SCALE, "customer": "cus_tomer", - "authorizations": [ - { - "user_email": "e@mail.com", - "role": 3 - } - ] + "authorizations": [{"user_email": "e@mail.com", "role": 3}], }, "project": { "date_format": "D", "name": "Test Project", "timezone": "America/Argentina/Buenos_Aires", - "template": True - } + "template": True, + }, } response, content_data = self.request(data, self.owner_token) org = Organization.objects.get(uuid=content_data["organization"]["uuid"]) @@ -121,12 +114,7 @@ def test_create_template_project(self, mock_get_gateway, mock_permission): "name": "name", "description": "desc", "plan": "plan", - "authorizations": [ - { - "user_email": "e@mail.com", - "role": 3 - } - ] + "authorizations": [{"user_email": "e@mail.com", "role": 3}], }, "project": { "date_format": "D", @@ -134,15 +122,22 @@ def test_create_template_project(self, mock_get_gateway, mock_permission): "organization": "2575d1f9-f7f8-4a5d-ac99-91972e309511", "timezone": "America/Argentina/Buenos_Aires", "template": True, - "template_type": "support" - } + "template_type": "support", + }, } response, content_data = self.request(data, self.owner_token) self.assertEquals(response.status_code, 201) self.assertEquals(content_data.get("project").get("first_access"), True) - self.assertEquals(content_data.get("project").get("wa_demo_token"), "wa-demo-12345") - self.assertEquals(content_data.get("project").get("project_type"), "template:support") - self.assertEquals(content_data.get("project").get("redirect_url"), "https://wa.me/5582123456?text=wa-demo-12345") + self.assertEquals( + content_data.get("project").get("wa_demo_token"), "wa-demo-12345" + ) + self.assertEquals( + content_data.get("project").get("project_type"), "template:support" + ) + self.assertEquals( + content_data.get("project").get("redirect_url"), + "https://wa.me/5582123456?text=wa-demo-12345", + ) self.assertEquals(OrganizationAuthorization.objects.count(), 1) self.assertEquals(RequestPermissionOrganization.objects.count(), 1) self.assertEquals(Project.objects.count(), 1) @@ -150,7 +145,9 @@ def test_create_template_project(self, mock_get_gateway, mock_permission): @patch("connect.common.signals.update_user_permission_project") @patch("connect.billing.get_gateway") - def test_create_template_project_type_support(self, mock_get_gateway, mock_permission): + def test_create_template_project_type_support( + self, mock_get_gateway, mock_permission + ): mock_get_gateway.return_value = StripeMockGateway() mock_permission.return_value = True data = { @@ -158,12 +155,7 @@ def test_create_template_project_type_support(self, mock_get_gateway, mock_permi "name": "name", "description": "desc", "plan": "plan", - "authorizations": [ - { - "user_email": "e@mail.com", - "role": 3 - } - ] + "authorizations": [{"user_email": "e@mail.com", "role": 3}], }, "project": { "date_format": "D", @@ -171,8 +163,8 @@ def test_create_template_project_type_support(self, mock_get_gateway, mock_permi "organization": "2575d1f9-f7f8-4a5d-ac99-91972e309511", "timezone": "America/Argentina/Buenos_Aires", "template": True, - "template_type": Project.TYPE_SUPPORT - } + "template_type": Project.TYPE_SUPPORT, + }, } response, content_data = self.request(data, self.owner_token) self.assertEquals(response.status_code, 201) @@ -201,9 +193,7 @@ def setUp(self, mock_get_gateway, mock_permission) -> None: ) self.project = self.organization.project.create( - name="will fail", - flow_organization=uuid.uuid4(), - is_template=True + name="will fail", flow_organization=uuid.uuid4(), is_template=True ) def request(self, project_uuid, token=None): @@ -242,7 +232,7 @@ def setUp(self, mock_get_gateway, mock_permission) -> None: organization_billing__cycle=BillingPlan.BILLING_CYCLE_MONTHLY, organization_billing__plan="free", inteligence_organization=1, - organization_billing__stripe_customer="cus_MYOrndkgpPHGK9" + organization_billing__stripe_customer="cus_MYOrndkgpPHGK9", ) self.trial = Organization.objects.create( name="Trial org", @@ -306,19 +296,26 @@ def request_upgrade_plan(self, organization_uuid=None, data=None, token=None): format="json", **authorization_header, ) - response = OrganizationViewSet.as_view({"patch": "upgrade_plan"})(request, organization_uuid) + response = OrganizationViewSet.as_view({"patch": "upgrade_plan"})( + request, organization_uuid + ) content_data = json.loads(response.content) return response, content_data def test_stripe_customer_kwarg(self): """Test new kwarg organization_billing__stripe_customer at organization create.""" - self.assertEqual(self.organization.organization_billing.stripe_customer, "cus_MYOrndkgpPHGK9") + self.assertEqual( + self.organization.organization_billing.stripe_customer, "cus_MYOrndkgpPHGK9" + ) def test_assert_plans(self): """Test trial plan creation. Check if BillingPlan save method sets a end date to trial""" self.assertEqual(self.trial.organization_billing.plan, BillingPlan.PLAN_TRIAL) - self.assertEqual(self.trial.organization_billing.trial_end_date, pendulum.now().end_of("day").add(months=1)) + self.assertEqual( + self.trial.organization_billing.trial_end_date, + pendulum.now().end_of("day").add(months=1), + ) def test_end_trial_period(self): """Test BillingPlan method end_trial_period. @@ -351,13 +348,9 @@ def test_upgrade_plan(self, mock_get_gateway): mock_get_gateway.return_value = StripeMockGateway() """Test upgrade plan view""" self.assertEqual(self.trial.organization_billing.plan, BillingPlan.PLAN_TRIAL) - data = { - "organization_billing_plan": BillingPlan.PLAN_START - } + data = {"organization_billing_plan": BillingPlan.PLAN_START} response, content_data = self.request_upgrade_plan( - organization_uuid=self.trial.uuid, - data=data, - token=self.owner_token + organization_uuid=self.trial.uuid, data=data, token=self.owner_token ) upgraded_org = Organization.objects.get(uuid=self.trial.uuid) @@ -370,13 +363,11 @@ def test_upgrade_plan_stripe_failure(self): """Test response if stripe charge fails""" data = { "organization_billing_plan": BillingPlan.PLAN_START, - "stripe_failure": True + "stripe_failure": True, } response, content_data = self.request_upgrade_plan( - organization_uuid=self.trial.uuid, - data=data, - token=self.owner_token + organization_uuid=self.trial.uuid, data=data, token=self.owner_token ) self.assertEqual(content_data["status"], "FAILURE") @@ -389,9 +380,7 @@ def test_upgrade_plan_change_failure(self): "organization_billing_plan": "baic", } response, content_data = self.request_upgrade_plan( - organization_uuid=self.trial.uuid, - data=data, - token=self.owner_token + organization_uuid=self.trial.uuid, data=data, token=self.owner_token ) self.assertEqual(content_data["status"], "FAILURE") self.assertEqual(content_data["message"], "Invalid plan choice") @@ -403,9 +392,7 @@ def test_upgrade_plan_empty_failure(self): "organization_billing_plan": "plus", } response, content_data = self.request_upgrade_plan( - organization_uuid=self.basic.uuid, - data=data, - token=self.owner_token + organization_uuid=self.basic.uuid, data=data, token=self.owner_token ) self.assertEqual(content_data["status"], "FAILURE") self.assertEqual(content_data["message"], "Empty customer") @@ -458,7 +445,9 @@ def test_setup_plan(self, mock_get_gateway, mock_permission): "plan": BillingPlan.PLAN_START, "customer": "cus_MYOrndkgpPHGK9", } - response, content_data = self.request(data=data, path="setup-plan", method="setup_plan") + response, content_data = self.request( + data=data, path="setup-plan", method="setup_plan" + ) customer = content_data["customer"] self.assertEqual(content_data["status"], "SUCCESS") @@ -473,26 +462,36 @@ def test_setup_plan(self, mock_get_gateway, mock_permission): "description": "basic", "plan": BillingPlan.PLAN_START, "customer": customer, - "authorizations": [ - { - "user_email": "e@mail.com", - "role": 3 - } - ] + "authorizations": [{"user_email": "e@mail.com", "role": 3}], }, "project": { "date_format": "D", "name": "Test Project basic", "organization": "2575d1f9-f7f8-4a5d-ac99-91972e309511", "timezone": "America/Argentina/Buenos_Aires", - } + }, } - response, content_data = self.request_create_org(create_org_data, self.owner_token) - self.assertEqual(content_data["organization"]["organization_billing"]["plan"], BillingPlan.PLAN_START) - self.assertEqual(content_data["organization"]["organization_billing"]["final_card_number"], '42') - organization = Organization.objects.get(uuid=content_data["organization"]["uuid"]) - self.assertEqual(organization.organization_billing_invoice.first().payment_status, Invoice.PAYMENT_STATUS_PAID) - self.assertEqual(organization.organization_billing_invoice.first().stripe_charge, "ch_teste") + response, content_data = self.request_create_org( + create_org_data, self.owner_token + ) + self.assertEqual( + content_data["organization"]["organization_billing"]["plan"], + BillingPlan.PLAN_START, + ) + self.assertEqual( + content_data["organization"]["organization_billing"]["final_card_number"], + "42", + ) + organization = Organization.objects.get( + uuid=content_data["organization"]["uuid"] + ) + self.assertEqual( + organization.organization_billing_invoice.first().payment_status, + Invoice.PAYMENT_STATUS_PAID, + ) + self.assertEqual( + organization.organization_billing_invoice.first().stripe_charge, "ch_teste" + ) self.tearDown(organization) @@ -518,7 +517,7 @@ def setUp(self, mock_get_gateway, mock_permission): organization_billing__cycle=BillingPlan.BILLING_CYCLE_MONTHLY, organization_billing__plan=BillingPlan.PLAN_START, inteligence_organization=1, - organization_billing__stripe_customer="cus_MYOrndkgpPHGK9" + organization_billing__stripe_customer="cus_MYOrndkgpPHGK9", ) self.billing = self.organization.organization_billing @@ -545,64 +544,9 @@ def request_upgrade_plan(self, organization_uuid=None, data=None, token=None): format="json", **authorization_header, ) - response = OrganizationViewSet.as_view({"patch": "upgrade_plan"})(request, organization_uuid) + response = OrganizationViewSet.as_view({"patch": "upgrade_plan"})( + request, organization_uuid + ) content_data = json.loads(response.content) return response, content_data - - @patch("connect.billing.get_gateway") - def test_plan_limits(self, mock_get_gateway): - mock_get_gateway.return_value = StripeMockGateway() - # Creates more contacts than the plan limit allows - num_contacts = BillingPlan.plan_info(self.organization.organization_billing.plan)["limit"] * 5 + 1 - self.assertTrue(self.organization.organization_billing.is_active) - self.assertFalse(self.organization.is_suspended) - create_contacts(num_contacts) - - daily_contact_count() - # Verify if the organizations have more contacts than the plan limit - check_organization_plans() - organization = Organization.objects.get(uuid=self.organization.uuid) - self.assertFalse(organization.organization_billing.is_active) - self.assertTrue(organization.is_suspended) - - self.assertEqual(organization.organization_billing.plan, BillingPlan.PLAN_START) - self.assertEqual(self.billing.contract_on, pendulum.now().date()) - self.assertEqual(self.billing.next_due_date, pendulum.now().add(months=1).date()) - - # Upgrade plan, request made in a diferent day to validade - # changes in BillingPlan.contract_on and next_due_date - data = { - "organization_billing_plan": BillingPlan.PLAN_SCALE - } - freezer = freeze_time(f"{pendulum.now().add(days=5)}") - freezer.start() - response, content_data = self.request_upgrade_plan( - organization_uuid=self.organization.uuid, - data=data, - token=self.owner_token - ) - - self.assertEqual(content_data["status"], "SUCCESS") - self.assertEqual(content_data["old_plan"], BillingPlan.PLAN_START) - self.assertEqual(content_data["plan"], BillingPlan.PLAN_SCALE) - - organization = Organization.objects.get(uuid=self.organization.uuid) - - # New due date, contract on and plan - self.assertEqual(organization.organization_billing.contract_on, pendulum.now().date()) - self.assertEqual(organization.organization_billing.next_due_date, pendulum.now().add(months=1).date()) - self.assertEqual(organization.organization_billing.plan, BillingPlan.PLAN_SCALE) - - # Check if the org is active again - self.assertTrue(organization.organization_billing.is_active) - self.assertFalse(organization.is_suspended) - check_organization_plans() - freezer.stop() - freezer = freeze_time(organization.organization_billing.next_due_date) - freezer.start() - - generate_project_invoice() - invoice = organization.organization_billing_invoice.last() - self.assertEqual(invoice.due_date, pendulum.now().date()) - freezer.stop() diff --git a/connect/celery.py b/connect/celery.py index 45a90b77..a4cbddda 100644 --- a/connect/celery.py +++ b/connect/celery.py @@ -18,17 +18,15 @@ # Billing Tasks app.conf.task_routes = { - 'sync_contacts': {'queue': 'billing'}, - 'count_contacts': {'queue': 'billing'}, - 'retry_billing_tasks': {'queue': 'billing'}, - 'create_contacts': {'queue': 'billing'}, - "end_trial_plan": {'queue': 'billing'}, - "check_organization_plans": {'queue': 'billing'}, - "daily_contact_count": {'queue': 'billing'}, - "sync_project_statistics": {'queue': 'sync'}, - "sync_channels_statistics": {'queue': 'sync'}, - "sync_total_contact_count": {'queue': 'sync'}, - "sync_active_contacts": {'queue': 'sync'}, + "sync_contacts": {"queue": "billing"}, + "count_contacts": {"queue": "billing"}, + "retry_billing_tasks": {"queue": "billing"}, + "create_contacts": {"queue": "billing"}, + "end_trial_plan": {"queue": "billing"}, + "check_organization_plans": {"queue": "billing"}, + "daily_contact_count": {"queue": "billing"}, + "sync_project_statistics": {"queue": "sync"}, + "sync_total_contact_count": {"queue": "sync"}, } @@ -43,23 +41,11 @@ }, "sync_project_statistics": { "task": "sync_project_statistics", - "schedule": schedules.crontab(minute="*/6") - }, - "sync_channels_statistics": { - "task": "sync_channels_statistics", - "schedule": schedules.crontab(minute="*/7") - }, - "generate_project_invoice": { - "task": "connect.common.tasks.generate_project_invoice", - "schedule": schedules.crontab(hour="12", minute=0), + "schedule": schedules.crontab(minute="*/6"), }, "sync_total_contact_count": { "task": "connect.common.tasks.sync_total_contact_count", - "schedule": schedules.crontab(hour="3", minute=0) - }, - "sync_active_contacts": { - "task": "connect.common.tasks.sync_active_contacts", - "schedule": schedules.crontab(hour="*/6", minute=0) + "schedule": schedules.crontab(hour="3", minute=0), }, "capture_invoice": { "task": "connect.common.tasks.capture_invoice", @@ -75,36 +61,36 @@ # }, "count_contacts": { "task": "count_contacts", - "schedule": schedules.crontab(hour="*/6", minute=0) + "schedule": schedules.crontab(hour="*/6", minute=0), }, "retry_billing_tasks": { "task": "retry_billing_tasks", - "schedule": schedules.crontab(hour="1") + "schedule": schedules.crontab(hour="1"), }, "problem_capture_invoice": { "task": "problem_capture_invoice", - "schedule": schedules.crontab(hour="9,11,14,16,18", minute=0) + "schedule": schedules.crontab(hour="9,11,14,16,18", minute=0), }, "daily_contact_count": { "task": "daily_contact_count", - "schedule": schedules.crontab(hour="23", minute=59) + "schedule": schedules.crontab(hour="23", minute=59), }, "end_trial_plan": { "task": "end_trial_plan", - "schedule": schedules.crontab(hour="20", minute=0) + "schedule": schedules.crontab(hour="20", minute=0), }, "check_organization_plans": { "task": "check_organization_plans", - "schedule": schedules.crontab(hour="22", minute=0) + "schedule": schedules.crontab(hour="22", minute=0), }, "keycloak_logs_cleanup_routine": { "task": "keycloak_logs_cleanup_routine", - "schedule": schedules.crontab(hour="23", minute=30) + "schedule": schedules.crontab(hour="23", minute=30), }, "recent_activity_cleanup_routine": { "task": "delete_recent_activities", - "schedule": schedules.crontab(hour="23", minute=0) - } + "schedule": schedules.crontab(hour="23", minute=0), + }, } if "test" in sys.argv or getattr(settings, "CELERY_ALWAYS_EAGER", False): diff --git a/connect/common/tasks.py b/connect/common/tasks.py index d9c66810..049b80b7 100644 --- a/connect/common/tasks.py +++ b/connect/common/tasks.py @@ -372,76 +372,6 @@ def sync_repositories_statistics(): project.save(update_fields=["inteligence_count"]) -@app.task(name="sync_channels_statistics") -def sync_channels_statistics(): - if settings.USE_FLOW_REST: - flow_instance = FlowsRESTClient() - else: - flow_instance = utils.get_grpc_types().get("flow") - for project in Project.objects.all(): - project.extra_active_integration = len( - list(flow_instance.list_channel(project_uuid=str(project.uuid))) - ) - project.save(update_fields=["extra_active_integration"]) - - -@app.task() -def generate_project_invoice(): - if not settings.TESTING: - sync_channels_statistics() - - for org in Organization.objects.filter( - organization_billing__next_due_date__lte=pendulum.now().date(), - is_suspended=False, - ).exclude( - organization_billing__plan__in=[ - BillingPlan.PLAN_TRIAL, - BillingPlan.PLAN_CUSTOM, - BillingPlan.PLAN_ENTERPRISE, - ] - ): - - invoice = org.organization_billing_invoice.create( - due_date=pendulum.now(), - invoice_random_id=( - 1 - if org.organization_billing_invoice.last() is None - else org.organization_billing_invoice.last().invoice_random_id + 1 - ), - discount=org.organization_billing.fixed_discount, - extra_integration=org.extra_active_integrations, - cost_per_whatsapp=settings.BILLING_COST_PER_WHATSAPP, - ) - after = ( - org.created_at.strftime("%Y-%m-%d %H:%M") - if org.organization_billing.last_invoice_date is None - else org.organization_billing.last_invoice_date.strftime("%Y-%m-%d %H:%M") - ) - before = ( - timezone.now().strftime("%Y-%m-%d %H:%M") - if org.organization_billing.next_due_date is None - else org.organization_billing.next_due_date.strftime("%Y-%m-%d %H:%M") - ) - for project in org.project.all(): - contact_count = utils.count_contacts( - project=project, after=str(after), before=str(before) - ) - - invoice.organization_billing_invoice_project.create( - project=project, - contact_count=contact_count, - amount=org.organization_billing.calculate_amount( - contact_count=contact_count - ), - ) - - obj = BillingPlan.objects.get(id=org.organization_billing.pk) - due_date = pendulum.parse(str(org.organization_billing.next_due_date)) - obj.next_due_date = due_date.add(months=1) - obj.last_invoice_date = pendulum.now().date() - obj.save(update_fields=["next_due_date", "last_invoice_date"]) - - @app.task() def capture_invoice(): for invoice in Invoice.objects.filter( From bdd280f14b6289cfddb49adb052658cded8100a3 Mon Sep 17 00:00:00 2001 From: Eric Costa Date: Wed, 16 Oct 2024 15:38:59 -0300 Subject: [PATCH 3/5] feat: removing check_organization_plans --- connect/api/v1/tests/test_v2_organization.py | 1 - connect/billing/tasks.py | 48 +--- connect/billing/tests/tests.py | 230 ++++++------------- connect/celery.py | 5 - 4 files changed, 68 insertions(+), 216 deletions(-) diff --git a/connect/api/v1/tests/test_v2_organization.py b/connect/api/v1/tests/test_v2_organization.py index e388b421..73863381 100644 --- a/connect/api/v1/tests/test_v2_organization.py +++ b/connect/api/v1/tests/test_v2_organization.py @@ -24,7 +24,6 @@ from freezegun import freeze_time from connect.billing.tasks import ( end_trial_plan, - check_organization_plans, daily_contact_count, ) from rest_framework import status diff --git a/connect/billing/tasks.py b/connect/billing/tasks.py index bd151dc8..772729a8 100644 --- a/connect/billing/tasks.py +++ b/connect/billing/tasks.py @@ -6,7 +6,7 @@ Project, BillingPlan, NewsletterOrganization, - Newsletter + Newsletter, ) from connect.billing.models import ( Contact, @@ -199,52 +199,6 @@ def end_trial_plan(): organization.organization_billing.send_email_trial_plan_expired_due_time_limit() -@app.task(name="check_organization_plans") -def check_organization_plans(): - # utc-3 or project_timezone - - for organization in Organization.objects.filter(is_suspended=False).exclude( - organization_billing__plan__in=[ - BillingPlan.PLAN_TRIAL, - BillingPlan.PLAN_CUSTOM, - BillingPlan.PLAN_ENTERPRISE, - ] - ): - - next_due_date = pendulum.parse( - str(organization.organization_billing.next_due_date) - ) - after = next_due_date.subtract(months=1).strftime("%Y-%m-%d %H:%M") - before = next_due_date.strftime("%Y-%m-%d %H:%M") - for project in organization.project.all(): - contact_count = utils.count_contacts( - project=project, before=before, after=after - ) - project.contact_count = int(contact_count) - project.save(update_fields=["contact_count"]) - - current_active_contacts = organization.active_contacts - - if current_active_contacts > organization.organization_billing.plan_limit: - organization.organization_billing.end_trial_period() - - organization.organization_billing.send_email_plan_expired_due_attendance_limit() - - elif ( - current_active_contacts > organization.organization_billing.plan_limit - 50 - ): - organization.organization_billing.send_email_plan_is_about_to_expire() - - NewsletterOrganization.objects.create( - newsletter=Newsletter.objects.create(), - title="trial-about-to-end", - description=f"Your trial period of the organization {organization.name}, is about to expire.", - organization=organization - ) - - return True - - @app.task(name="daily_contact_count") def daily_contact_count(): """Daily contacts""" diff --git a/connect/billing/tests/tests.py b/connect/billing/tests/tests.py index ef8e1a6b..66fc88ea 100644 --- a/connect/billing/tests/tests.py +++ b/connect/billing/tests/tests.py @@ -21,8 +21,7 @@ from connect.common.models import Organization, Project, BillingPlan, OrganizationRole from freezegun import freeze_time -from connect.billing.tasks import sync_contacts, check_organization_plans -from connect.api.v1.tests.utils import create_contacts, create_user_and_token +from connect.billing.tasks import sync_contacts @skipIf(not settings.BILLING_SETTINGS.get("stripe", None), "gateway not configured") @@ -43,29 +42,29 @@ def testPurchaseDecimalAmount(self): def test_last_2(self): resp = self.merchant.get_card_data(self.customer) - self.assertEquals(resp['response'][0]['last2'], '42') + self.assertEquals(resp["response"][0]["last2"], "42") def test_brand(self): resp = self.merchant.get_card_data(self.customer) - self.assertEquals(resp['response'][0]['brand'], 'visa') + self.assertEquals(resp["response"][0]["brand"], "visa") def test_get_card_data(self): resp = self.merchant.get_card_data(self.customer) - self.assertEquals(resp['status'], 'SUCCESS') + self.assertEquals(resp["status"], "SUCCESS") def test_get_user_detail_data(self): resp = self.merchant.get_user_detail_data(self.customer) - self.assertEquals(resp['status'], 'SUCCESS') + self.assertEquals(resp["status"], "SUCCESS") def test_get_payment_method_details(self): resp = self.merchant.get_payment_method_details("ch_3K9wZYGB60zUb40p1C0iiskn") - self.assertEquals(resp['status'], 'SUCCESS') - self.assertEquals(resp['response']['final_card_number'], '4242') - self.assertEquals(resp['response']['brand'], 'visa') + self.assertEquals(resp["status"], "SUCCESS") + self.assertEquals(resp["response"]["final_card_number"], "4242") + self.assertEquals(resp["response"]["brand"], "visa") def test_get_payment_method_details_fail(self): resp = self.merchant.get_payment_method_details("ch_3K9wZYGB60zUb40p1C0iisk") - self.assertEquals(resp['status'], 'FAIL') + self.assertEquals(resp["status"], "FAIL") class SyncManagerTest(TestCase): @@ -104,7 +103,7 @@ def setUp(self): before=pendulum.datetime(2022, 4, 8, 9, 0, 0), after=pendulum.datetime(2022, 4, 8, 4, 0, 0), status=True, - finished_at=pendulum.datetime(2022, 4, 8, 9, 0, 0) + finished_at=pendulum.datetime(2022, 4, 8, 9, 0, 0), ) self.first_count_sync = SyncManagerTask.objects.create( @@ -113,7 +112,7 @@ def setUp(self): before=pendulum.datetime(2022, 4, 8, 9, 0, 0), after=pendulum.datetime(2022, 4, 8, 4, 0, 0), status=True, - finished_at=pendulum.datetime(2022, 4, 8, 9, 0, 0) + finished_at=pendulum.datetime(2022, 4, 8, 9, 0, 0), ) self.organization = Organization.objects.create( @@ -128,7 +127,7 @@ def setUp(self): name="project test", timezone="America/Sao_Paulo", flow_organization=uuid.uuid4(), - flow_id=11 + flow_id=11, ) @freeze_time("2022-04-08 14") @@ -162,33 +161,37 @@ class ContactTestCase(TestCase): def setUp(self, mock_get_gateway): mock_get_gateway.return_value = StripeMockGateway() self.organization = Organization.objects.create( - name='org test', - description='desc', + name="org test", + description="desc", inteligence_organization=1, organization_billing__cycle=BillingPlan.BILLING_CYCLE_MONTHLY, organization_billing__payment_method=BillingPlan.PAYMENT_METHOD_CREDIT_CARD, - organization_billing__plan=BillingPlan.PLAN_ENTERPRISE + organization_billing__plan=BillingPlan.PLAN_ENTERPRISE, ) self.project = Project.objects.create( name="project test", timezone="America/Sao_Paulo", flow_organization=uuid4.uuid4(), - organization=self.organization + organization=self.organization, ) self.contact = Contact.objects.create( contact_flow_uuid=uuid4.uuid4(), - name='contact test 1', - last_seen_on=datetime(2022, 4, 8, 10, 20, 0, 0, pytz.UTC) + name="contact test 1", + last_seen_on=datetime(2022, 4, 8, 10, 20, 0, 0, pytz.UTC), ) def test_create_contact(self): self.assertEquals(self.contact.name, "contact test 1") - self.assertEquals(self.contact.last_seen_on, datetime(2022, 4, 8, 10, 20, 0, 0, pytz.UTC)) + self.assertEquals( + self.contact.last_seen_on, datetime(2022, 4, 8, 10, 20, 0, 0, pytz.UTC) + ) def test_create_existing_contact(self): - existing_contact = Contact.objects.create(contact_flow_uuid=self.contact.contact_flow_uuid) + existing_contact = Contact.objects.create( + contact_flow_uuid=self.contact.contact_flow_uuid + ) self.assertEquals(existing_contact, self.contact) @@ -197,143 +200,38 @@ class MessageTestCase(TestCase): def setUp(self): self.organization = Organization.objects.create( - name='org test', - description='desc', + name="org test", + description="desc", inteligence_organization=1, organization_billing__cycle=BillingPlan.BILLING_CYCLE_MONTHLY, organization_billing__payment_method=BillingPlan.PAYMENT_METHOD_CREDIT_CARD, - organization_billing__plan=BillingPlan.PLAN_ENTERPRISE + organization_billing__plan=BillingPlan.PLAN_ENTERPRISE, ) self.project = Project.objects.create( name="project test", timezone="America/Sao_Paulo", flow_organization=uuid4.uuid4(), - organization=self.organization + organization=self.organization, ) self.contact = Contact.objects.create( contact_flow_uuid=uuid4.uuid4(), - name='contact test 1', + name="contact test 1", ) self.message = Message.objects.create( contact=self.contact, - text='test message', + text="test message", sent_on=timezone.now(), message_flow_uuid=uuid4.uuid4(), - direction='test' + direction="test", ) def test_create_message(self): self.assertTrue("test message", self.message.text) -class CheckPlansTestCase(TestCase): - @patch("connect.common.signals.update_user_permission_project") - @patch("connect.billing.get_gateway") - def setUp(self, mock_get_gateway, mock_permission): - mock_get_gateway.return_value = StripeMockGateway() - mock_permission.return_value = True - # Orgs - self.start = Organization.objects.create( - name="Start org", - description="Basic org", - inteligence_organization=1, - organization_billing__cycle=BillingPlan.BILLING_CYCLE_MONTHLY, - organization_billing__plan=BillingPlan.PLAN_START, - ) - self.scale = Organization.objects.create( - name="Scale org", - description="plus org", - inteligence_organization=1, - organization_billing__cycle=BillingPlan.BILLING_CYCLE_MONTHLY, - organization_billing__plan=BillingPlan.PLAN_SCALE, - ) - self.advanced = Organization.objects.create( - name="Advanced org", - description="advanced org", - inteligence_organization=1, - organization_billing__cycle=BillingPlan.BILLING_CYCLE_MONTHLY, - organization_billing__plan=BillingPlan.PLAN_ADVANCED, - ) - self.enterprise = Organization.objects.create( - name="enterprise org", - description="enterprise org", - inteligence_organization=1, - organization_billing__cycle=BillingPlan.BILLING_CYCLE_MONTHLY, - organization_billing__plan=BillingPlan.PLAN_ENTERPRISE, - ) - # Projects - self.start_project = self.start.project.create( - name="start", - flow_organization=uuid.uuid4(), - ) - self.scale_project = self.scale.project.create( - name="scale", - flow_organization=uuid.uuid4(), - ) - self.advanced_project = self.advanced.project.create( - name="advanced", - flow_organization=uuid.uuid4(), - ) - self.enterprise_project = self.enterprise.project.create( - name="enterprise", - flow_organization=uuid.uuid4(), - ) - - # Users - self.admin, self.admin_token = create_user_and_token("admin") - self.admin2, self.owner_token = create_user_and_token("admin2") - self.financial, self.admin_token = create_user_and_token("financial") - self.support, self.admin_token = create_user_and_token("support") - self.contributor, self.admin_token = create_user_and_token("contributor") - self.viewer, self.admin_token = create_user_and_token("viewer") - - # Authorizations - self.start.authorizations.create( - user=self.admin, role=OrganizationRole.ADMIN.value - ) - - self.start.authorizations.create( - user=self.admin2, role=OrganizationRole.ADMIN.value - ) - - self.start.authorizations.create( - user=self.financial, role=OrganizationRole.FINANCIAL.value - ) - - self.start.authorizations.create( - user=self.support, role=OrganizationRole.SUPPORT.value - ) - - self.start.authorizations.create( - user=self.contributor, role=OrganizationRole.CONTRIBUTOR.value - ) - - self.start.authorizations.create( - user=self.viewer, role=OrganizationRole.VIEWER.value - ) - - @skipIf(True, "This test takes a while to run") - def test_task_end_trial_plan(self): - """ - Test if 'check_organization_plans' suspends org that should after the trial periods end - """ - for organization in Organization.objects.all(): - num_contacts = BillingPlan.plan_info(organization.organization_billing.plan)["limit"] * 5 + 1 - create_contacts(num_contacts) - - check_organization_plans() - - for org in Organization.objects.all(): - self.assertGreater(org.active_contacts, org.organization_billing.plan_limit) - self.assertTrue(org.is_suspended) - - def test_billing_emails(self): - self.start.organization_billing.send_email_trial_plan_expired_due_time_limit() - - class ContactCountTestCase(TestCase): @patch("connect.billing.get_gateway") @@ -375,7 +273,7 @@ def setUp(self, mock_get_gateway): inteligence_organization=1, organization_billing__cycle=BillingPlan.BILLING_CYCLE_MONTHLY, organization_billing__plan=BillingPlan.PLAN_START, - is_suspended=False + is_suspended=False, ) now = pendulum.now() self.manager_task = SyncManagerTask.objects.create( @@ -391,9 +289,13 @@ def setUp(self, mock_get_gateway): flow_organization=uuid.uuid4(), ) - @patch("connect.api.v1.internal.flows.flows_rest_client.FlowsRESTClient.suspend_or_unsuspend_project") + @patch( + "connect.api.v1.internal.flows.flows_rest_client.FlowsRESTClient.suspend_or_unsuspend_project" + ) @patch("connect.common.models.BillingPlan.problem_capture_invoice") - def test_problem_capture_invoice(self, mock_problem_capture_invoice, mock_update_suspend_project): + def test_problem_capture_invoice( + self, mock_problem_capture_invoice, mock_update_suspend_project + ): mock_problem_capture_invoice.side_effect = [True] celery_app.send_task(name="problem_capture_invoice") @@ -404,12 +306,10 @@ def test_problem_capture_invoice(self, mock_problem_capture_invoice, mock_update def test_contact_count_task(self): now = pendulum.now() - response = celery_app.send_task(name="count_contacts", args=[ - now, - now.subtract(days=1), - self.project.uuid, - self.manager_task.uuid - ]) + response = celery_app.send_task( + name="count_contacts", + args=[now, now.subtract(days=1), self.project.uuid, self.manager_task.uuid], + ) self.assertTrue(response.result) self.manager_task.refresh_from_db() @@ -418,11 +318,14 @@ def test_contact_count_task(self): def test_contact_count_without_task_uuid(self): now = pendulum.now() - response = celery_app.send_task(name="count_contacts", args=[ - now, - now.subtract(days=1), - self.project.uuid, - ]) + response = celery_app.send_task( + name="count_contacts", + args=[ + now, + now.subtract(days=1), + self.project.uuid, + ], + ) self.assertTrue(response.result) @@ -436,7 +339,9 @@ def test_retry_billing_tasks(self): @patch("connect.elastic.flow.ElasticFlow.clear_scroll") @patch("connect.elastic.flow.ElasticFlow.get_paginated_contacts") - def test_sync_contacts_task_no_projects(self, mock_clear_scroll, mock_get_paginated_contacts): + def test_sync_contacts_task_no_projects( + self, mock_clear_scroll, mock_get_paginated_contacts + ): mock_clear_scroll.return_value = True mock_get_paginated_contacts.return_value = True @@ -445,20 +350,20 @@ def test_sync_contacts_task_no_projects(self, mock_clear_scroll, mock_get_pagina args=[ str(self.manager_task.before), str(self.manager_task.after), - str(self.manager_task.uuid) - ] + str(self.manager_task.uuid), + ], ) self.assertTrue(response.result) @patch("connect.elastic.flow.ElasticFlow.clear_scroll") @patch("connect.elastic.flow.ElasticFlow.get_paginated_contacts") - def test_sync_contacts_else_task(self, mock_clear_scroll, mock_get_paginated_contacts): + def test_sync_contacts_else_task( + self, mock_clear_scroll, mock_get_paginated_contacts + ): mock_clear_scroll.return_value = True mock_get_paginated_contacts.return_value = True - response = celery_app.send_task( - name="sync_contacts" - ) + response = celery_app.send_task(name="sync_contacts") self.assertTrue(response.result) @patch("connect.elastic.flow.ElasticFlow.get_paginated_contacts") @@ -466,10 +371,7 @@ def test_sync_contacts_else_task(self, mock_clear_scroll, mock_get_paginated_con def test_sync_contacts_task(self, mock_clear_scroll, mock_get_paginated_contacts): mock_clear_scroll.return_value = True - mock_scroll = { - "scroll_id": "123", - "scroll_size": 100 - } + mock_scroll = {"scroll_id": "123", "scroll_size": 100} mock_hits = "test" mock_get_paginated_contacts.return_value = mock_scroll, mock_hits @@ -482,14 +384,16 @@ def test_sync_contacts_task(self, mock_clear_scroll, mock_get_paginated_contacts args=[ str(self.manager_task.before), str(self.manager_task.after), - str(self.manager_task.uuid) - ] + str(self.manager_task.uuid), + ], ) self.assertTrue(response.result) @patch("connect.elastic.flow.ElasticFlow.get_paginated_contacts") @patch("connect.elastic.flow.ElasticFlow.clear_scroll") - def test_exception_sync_contacts_task(self, mock_clear_scroll, mock_get_paginated_contacts): + def test_exception_sync_contacts_task( + self, mock_clear_scroll, mock_get_paginated_contacts + ): mock_clear_scroll.return_value = True mock_get_paginated_contacts.side_effect = Exception("test") @@ -501,7 +405,7 @@ def test_exception_sync_contacts_task(self, mock_clear_scroll, mock_get_paginate args=[ str(self.manager_task.before), str(self.manager_task.after), - str(self.manager_task.uuid) - ] + str(self.manager_task.uuid), + ], ) self.assertFalse(response.result) diff --git a/connect/celery.py b/connect/celery.py index a4cbddda..b3c51574 100644 --- a/connect/celery.py +++ b/connect/celery.py @@ -23,7 +23,6 @@ "retry_billing_tasks": {"queue": "billing"}, "create_contacts": {"queue": "billing"}, "end_trial_plan": {"queue": "billing"}, - "check_organization_plans": {"queue": "billing"}, "daily_contact_count": {"queue": "billing"}, "sync_project_statistics": {"queue": "sync"}, "sync_total_contact_count": {"queue": "sync"}, @@ -79,10 +78,6 @@ "task": "end_trial_plan", "schedule": schedules.crontab(hour="20", minute=0), }, - "check_organization_plans": { - "task": "check_organization_plans", - "schedule": schedules.crontab(hour="22", minute=0), - }, "keycloak_logs_cleanup_routine": { "task": "keycloak_logs_cleanup_routine", "schedule": schedules.crontab(hour="23", minute=30), From 400555d36dd01c0859b623763cf1a760bb1ecc6d Mon Sep 17 00:00:00 2001 From: Eric Costa Date: Wed, 16 Oct 2024 15:54:30 -0300 Subject: [PATCH 4/5] feat: removing sync_project_statistics --- connect/celery.py | 5 ----- connect/common/tasks.py | 27 --------------------------- 2 files changed, 32 deletions(-) diff --git a/connect/celery.py b/connect/celery.py index b3c51574..b0d39ce3 100644 --- a/connect/celery.py +++ b/connect/celery.py @@ -24,7 +24,6 @@ "create_contacts": {"queue": "billing"}, "end_trial_plan": {"queue": "billing"}, "daily_contact_count": {"queue": "billing"}, - "sync_project_statistics": {"queue": "sync"}, "sync_total_contact_count": {"queue": "sync"}, } @@ -38,10 +37,6 @@ "task": "connect.common.tasks.check_organization_free_plan", "schedule": schedules.crontab(minute="*/6"), }, - "sync_project_statistics": { - "task": "sync_project_statistics", - "schedule": schedules.crontab(minute="*/6"), - }, "sync_total_contact_count": { "task": "connect.common.tasks.sync_total_contact_count", "schedule": schedules.crontab(hour="3", minute=0), diff --git a/connect/common/tasks.py b/connect/common/tasks.py index 049b80b7..4b41c62b 100644 --- a/connect/common/tasks.py +++ b/connect/common/tasks.py @@ -315,33 +315,6 @@ def sync_total_contact_count(): return True -@app.task(name="sync_project_statistics") -def sync_project_statistics(): - if settings.USE_FLOW_REST: - flow_instance = FlowsRESTClient() - else: - flow_instance = utils.get_grpc_types().get("flow") - - for project in Project.objects.order_by("-created_at"): - try: - statistic_project_result = flow_instance.get_project_statistic( - project_uuid=str(project.uuid), - ) - if len(statistic_project_result) > 0: - project.flow_count = int( - statistic_project_result.get("active_flows") - ) - project.save(update_fields=["flow_count"]) - except ConnectionError as c: - logger.error( - f"Remote end closed connection without: {c} - Project: {project}" - ) - continue - except Exception as e: - logger.error(f"Sync Project Statistics Exception {e}") - continue - - @app.task() def sync_repositories_statistics(): if settings.USE_FLOW_REST: From ee2372b6ce1cfcf35a1f80c8e4203f5cb9c4c135 Mon Sep 17 00:00:00 2001 From: Eric Costa Date: Wed, 16 Oct 2024 16:06:04 -0300 Subject: [PATCH 5/5] feat: removing delete-status-logs --- connect/celery.py | 4 ---- connect/common/tasks.py | 25 ------------------------- 2 files changed, 29 deletions(-) diff --git a/connect/celery.py b/connect/celery.py index b0d39ce3..d4454c64 100644 --- a/connect/celery.py +++ b/connect/celery.py @@ -29,10 +29,6 @@ app.conf.beat_schedule = { - "delete-status-logs": { - "task": "connect.common.tasks.delete_status_logs", - "schedule": schedules.crontab(hour="22", minute=0), - }, "check-organization-free-plan": { "task": "connect.common.tasks.check_organization_free_plan", "schedule": schedules.crontab(minute="*/6"), diff --git a/connect/common/tasks.py b/connect/common/tasks.py index 4b41c62b..eae67e6c 100644 --- a/connect/common/tasks.py +++ b/connect/common/tasks.py @@ -362,31 +362,6 @@ def capture_invoice(): # add send email -@app.task() -def delete_status_logs(): - BATCH_SIZE = 5000 - logs = LogService.objects.filter( - created_at__lt=timezone.now().replace(hour=0, minute=0, second=0, microsecond=0) - - timezone.timedelta(days=10) - ) - - num_updated = 0 - max_id = -1 - while True: - batch = list(logs.filter(id__gt=max_id).order_by("id")[:BATCH_SIZE]) - - if not batch: - break - - max_id = batch[-1].id - with transaction.atomic(): - for log in batch: - log.delete() - - num_updated += len(batch) - print(f" > deleted {num_updated} status logs") - - @app.task( name="update_suspend_project", autoretry_for=(_InactiveRpcError, Exception),