Skip to content

Commit

Permalink
Max retry payment limit (#392)
Browse files Browse the repository at this point in the history
* Max retry payment limit

* resolved flake error
  • Loading branch information
Ashutosh619-sudo authored Sep 4, 2024
1 parent 2582aa0 commit 1ef2887
Show file tree
Hide file tree
Showing 5 changed files with 129 additions and 9 deletions.
18 changes: 18 additions & 0 deletions apps/xero/migrations/0010_bill_is_retired.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 3.2.14 on 2024-09-03 09:24

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('xero', '0009_auto_20220614_1320'),
]

operations = [
migrations.AddField(
model_name='bill',
name='is_retired',
field=models.BooleanField(default=False, help_text='Is Payment sync retried'),
),
]
1 change: 1 addition & 0 deletions apps/xero/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ class Bill(models.Model):
paid_on_xero = models.BooleanField(
help_text="Payment status in Xero", default=False
)
is_retired = models.BooleanField(help_text='Is Payment sync retried', default=False)
export_id = models.CharField(max_length=255, help_text="Export ID", null=True)
created_at = models.DateTimeField(auto_now_add=True, help_text="Created at")
updated_at = models.DateTimeField(auto_now=True, help_text="Updated at")
Expand Down
32 changes: 32 additions & 0 deletions apps/xero/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
from time import sleep
from typing import List

from dateutil.relativedelta import relativedelta
from django.utils import timezone as django_timezone

from django.db import transaction
from fyle_accounting_mappings.models import DestinationAttribute, ExpenseAttribute, Mapping
from fyle_integrations_platform_connector import PlatformConnector
Expand Down Expand Up @@ -699,6 +702,30 @@ def process_payments(
task_log.save()


def validate_for_skipping_payment(bill: Bill, workspace_id: int):
task_log = TaskLog.objects.filter(task_id='PAYMENT_{}'.format(bill.expense_group.id), workspace_id=workspace_id, type='CREATING_PAYMENT').first()
if task_log:
now = django_timezone.now()

if now - relativedelta(months=2) > task_log.created_at:
bill.is_retired = True
bill.save()
return True

elif now - relativedelta(months=1) > task_log.created_at and now - relativedelta(months=2) < task_log.created_at:
# if updated_at is within 1 months will be skipped
if task_log.updated_at > now - relativedelta(months=1):
return True

# If created is within 1 month
elif now - relativedelta(months=1) < task_log.created_at:
# Skip if updated within the last week
if task_log.updated_at > now - relativedelta(weeks=1):
return True

return False


def create_payment(workspace_id):
fyle_credentials = FyleCredential.objects.get(workspace_id=workspace_id)

Expand All @@ -722,6 +749,11 @@ def create_payment(workspace_id):
)

if expense_group_reimbursement_status:

skip_payment = validate_for_skipping_payment(bill=bill, workspace_id=workspace_id)
if skip_payment:
continue

task_log, _ = TaskLog.objects.update_or_create(
workspace_id=workspace_id,
task_id="PAYMENT_{}".format(bill.expense_group.id),
Expand Down
19 changes: 11 additions & 8 deletions tests/sql_fixtures/reset_db_fixtures/reset_db.sql
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
--

-- Dumped from database version 15.7 (Debian 15.7-1.pgdg120+1)
-- Dumped by pg_dump version 15.7 (Debian 15.7-1.pgdg120+1)
-- Dumped by pg_dump version 15.8 (Debian 15.8-1.pgdg120+1)

SET statement_timeout = 0;
SET lock_timeout = 0;
Expand Down Expand Up @@ -298,7 +298,8 @@ CREATE TABLE public.bills (
expense_group_id integer NOT NULL,
paid_on_xero boolean NOT NULL,
payment_synced boolean NOT NULL,
export_id character varying(255)
export_id character varying(255),
is_retired boolean NOT NULL
);


Expand Down Expand Up @@ -2245,11 +2246,11 @@ COPY public.bill_lineitems (id, tracking_categories, item_code, account_id, desc
-- Data for Name: bills; Type: TABLE DATA; Schema: public; Owner: postgres
--

COPY public.bills (id, currency, contact_id, reference, date, created_at, updated_at, expense_group_id, paid_on_xero, payment_synced, export_id) FROM stdin;
1 USD 9eecdd86-78bb-47c9-95df-986369748151 2 - [email protected] 2022-08-02 00:00:00+00 2022-08-02 20:27:44.058777+00 2022-08-02 20:27:44.877194+00 2 f f c35cf4b3-784a-408b-9ddf-df111dd2e073
2 USD 229b7701-21a2-4539-b39e-5c34f56e1711 4 - [email protected] 2022-08-02 00:00:00+00 2022-08-02 20:27:48.290698+00 2022-08-02 20:27:48.932223+00 4 f f 2780aebc-2f8c-4b47-a7e2-64b920c5e7c1
3 USD 9eecdd86-78bb-47c9-95df-986369748151 1 - [email protected] 2022-08-02 00:00:00+00 2022-08-02 20:27:51.443082+00 2022-08-02 20:27:52.020404+00 1 f f c70ce61b-5157-4e11-97c7-6d1f843b2a5f
4 USD 9eecdd86-78bb-47c9-95df-986369748151 3 - [email protected] 2022-08-02 00:00:00+00 2022-08-02 20:27:54.558597+00 2022-08-02 20:27:55.12968+00 3 f f 9520557e-c20c-4fa4-b4b4-702102866beb
COPY public.bills (id, currency, contact_id, reference, date, created_at, updated_at, expense_group_id, paid_on_xero, payment_synced, export_id, is_retired) FROM stdin;
1 USD 9eecdd86-78bb-47c9-95df-986369748151 2 - [email protected] 2022-08-02 00:00:00+00 2022-08-02 20:27:44.058777+00 2022-08-02 20:27:44.877194+00 2 f f c35cf4b3-784a-408b-9ddf-df111dd2e073 f
2 USD 229b7701-21a2-4539-b39e-5c34f56e1711 4 - [email protected] 2022-08-02 00:00:00+00 2022-08-02 20:27:48.290698+00 2022-08-02 20:27:48.932223+00 4 f f 2780aebc-2f8c-4b47-a7e2-64b920c5e7c1 f
3 USD 9eecdd86-78bb-47c9-95df-986369748151 1 - [email protected] 2022-08-02 00:00:00+00 2022-08-02 20:27:51.443082+00 2022-08-02 20:27:52.020404+00 1 f f c70ce61b-5157-4e11-97c7-6d1f843b2a5f f
4 USD 9eecdd86-78bb-47c9-95df-986369748151 3 - [email protected] 2022-08-02 00:00:00+00 2022-08-02 20:27:54.558597+00 2022-08-02 20:27:55.12968+00 3 f f 9520557e-c20c-4fa4-b4b4-702102866beb f
\.


Expand Down Expand Up @@ -2632,6 +2633,7 @@ COPY public.django_migrations (id, app, name, applied) FROM stdin;
151 workspaces 0038_alter_workspace_onboarding_state 2024-05-07 09:15:02.787555+00
152 fyle 0019_expense_paid_on_fyle 2024-06-18 16:26:06.802359+00
153 fyle 0020_expensegroup_export_url 2024-08-03 14:33:54.988078+00
154 xero 0010_bill_is_retired 2024-09-03 11:40:50.93784+00
\.


Expand Down Expand Up @@ -5169,7 +5171,7 @@ SELECT pg_catalog.setval('public.django_content_type_id_seq', 40, true);
-- Name: django_migrations_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
--

SELECT pg_catalog.setval('public.django_migrations_id_seq', 153, true);
SELECT pg_catalog.setval('public.django_migrations_id_seq', 154, true);


--
Expand Down Expand Up @@ -6786,3 +6788,4 @@ ALTER TABLE ONLY public.xero_credentials
--
-- PostgreSQL database dump complete
--

68 changes: 67 additions & 1 deletion tests/test_xero/test_tasks.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import logging
import random
from datetime import datetime
from datetime import datetime, timedelta, timezone
from unittest import mock

from django_q.models import Schedule
Expand Down Expand Up @@ -746,6 +746,11 @@ def test_create_payment_exceptions(mocker, db):
mock_call.side_effect = WrongParamsError(
msg="wrong parameter", response="invalid parameter"
)

now = datetime.now().replace(tzinfo=timezone.utc)
updated_at = now - timedelta(days=10)

task_log = TaskLog.objects.filter(task_id='PAYMENT_{}'.format(bill.expense_group.id)).update(updated_at=updated_at)
create_payment(workspace_id)
task_log = TaskLog.objects.filter(
workspace_id=workspace_id, detail="wrong parameter"
Expand Down Expand Up @@ -1105,3 +1110,64 @@ def test_skipping_schedule_bank_transaction_creation(db):

task_log = TaskLog.objects.filter(expense_group_id=expense_group.id).first()
assert task_log.type == 'CREATING_BANK_TRANSACTION'


def test_skipping_payment(mocker, db):
mocker.patch("apps.xero.utils.XeroConnector.post_payment", return_value={})
workspace_id = 1

mocker.patch(
"fyle.platform.apis.v1beta.admin.Reimbursements.list_all",
return_value=fyle_data["get_all_reimbursements"],
)

mocker.patch('fyle_integrations_platform_connector.apis.Expenses.get', return_value=data['expense'])

bills = Bill.objects.all()
expenses = []

for bill in bills:
expenses.extend(bill.expense_group.expenses.all())

for expense in expenses:
Reimbursement.objects.update_or_create(
settlement_id=expense.settlement_id,
reimbursement_id="qwertyuio",
state="COMPLETE",
workspace_id=workspace_id,
)

general_mappings = GeneralMapping.objects.filter(workspace_id=workspace_id).first()
general_mappings.payment_account_id = "2"
general_mappings.save()

task_log = TaskLog.objects.create(workspace_id=workspace_id, type='CREATING_PAYMENT', task_id='PAYMENT_{}'.format(bill.expense_group.id), status='FAILED')
updated_at = task_log.updated_at
create_payment(workspace_id)

task_log = TaskLog.objects.get(workspace_id=workspace_id, type='CREATING_PAYMENT', task_id='PAYMENT_{}'.format(bill.expense_group.id))
assert task_log.updated_at == updated_at

now = datetime.now().replace(tzinfo=timezone.utc)
updated_at = now - timedelta(days=25)
# Update created_at to more than 2 months ago (more than 60 days)
TaskLog.objects.filter(task_id='PAYMENT_{}'.format(bill.expense_group.id)).update(
created_at=now - timedelta(days=61), # More than 2 months ago
updated_at=updated_at # Updated within the last 1 month
)

task_log = TaskLog.objects.get(task_id='PAYMENT_{}'.format(bill.expense_group.id))

create_payment(workspace_id)
task_log.refresh_from_db()
assert task_log.updated_at == updated_at

updated_at = now - timedelta(days=25)
# Update created_at to between 1 and 2 months ago (between 30 and 60 days)
TaskLog.objects.filter(task_id='PAYMENT_{}'.format(bill.expense_group.id)).update(
created_at=now - timedelta(days=45), # Between 1 and 2 months ago
updated_at=updated_at # Updated within the last 1 month
)
create_payment(workspace_id)
task_log.refresh_from_db()
assert task_log.updated_at == updated_at

0 comments on commit 1ef2887

Please sign in to comment.