Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Max retry payment limit #392

Merged
merged 2 commits into from
Sep 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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'),
),
Comment on lines +13 to +17
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clarify the purpose of the is_retired field.

There seems to be an inconsistency between the field name is_retired and the help text "Is Payment sync retried". The field name suggests that the field is used to mark a bill as retired, but the help text suggests that the field is used to track whether payment sync has been retried for the bill.

Please clarify the purpose of the field and update either the field name or the help text to ensure consistency and clarity. For example:

  • If the field is used to mark a bill as retired, update the help text to "Is the bill retired?".
  • If the field is used to track whether payment sync has been retried for the bill, update the field name to 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
Loading