diff --git a/speid/models/transaction.py b/speid/models/transaction.py index a8bd9308..3e118cdd 100644 --- a/speid/models/transaction.py +++ b/speid/models/transaction.py @@ -154,10 +154,16 @@ def is_valid_account(self) -> bool: account = Account.objects.get(cuenta=self.cuenta_beneficiario) if account.is_restricted: ordenante = self.rfc_curp_ordenante - is_valid = ( - ordenante == account.allowed_rfc - or ordenante == account.allowed_curp - ) and self.monto >= MIN_AMOUNT + is_valid = all( + [ + ( + ordenante == account.allowed_rfc + or ordenante == account.allowed_curp + ), + self.monto >= MIN_AMOUNT, + account.estado != Estado.pld_blocked, + ] + ) except DoesNotExist: pass return is_valid diff --git a/speid/tasks/accounts.py b/speid/tasks/accounts.py index 99d5b188..47a80a4f 100644 --- a/speid/tasks/accounts.py +++ b/speid/tasks/accounts.py @@ -4,7 +4,7 @@ from stpmex.exc import InvalidRfcOrCurp, StpmexException from stpmex.resources.cuentas import Cuenta -from speid.models import Event, PhysicalAccount +from speid.models import Event, MoralAccount, PhysicalAccount from speid.models.account import Account from speid.tasks import celery from speid.types import Estado, EventType @@ -83,3 +83,14 @@ def deactivate_account(self, cuenta: str) -> None: else: account.estado = Estado.deactivated account.save() + + +@celery.task(bind=True, max_retries=5) +def block_account(self, cuenta: str) -> None: + try: + account = MoralAccount.objects.get(cuenta=cuenta) + except DoesNotExist: + ... + else: + account.estado = Estado.pld_blocked + account.save() diff --git a/speid/types.py b/speid/types.py index 5bb01cd4..a871074f 100644 --- a/speid/types.py +++ b/speid/types.py @@ -22,6 +22,7 @@ class Estado(str, Enum): rejected = 'rejected' error = 'error' # Malformed order deactivated = 'deactivated' + pld_blocked = 'pld_blocked' # Blocked but not deactivated @classmethod def get_state_from_stp(cls, stp_state: str) -> Enum: diff --git a/tests/tasks/test_accounts.py b/tests/tasks/test_accounts.py index 2441e369..505f7208 100644 --- a/tests/tasks/test_accounts.py +++ b/tests/tasks/test_accounts.py @@ -8,6 +8,7 @@ from speid.models import PhysicalAccount from speid.models.account import MoralAccount from speid.tasks.accounts import ( + block_account, create_account, deactivate_account, execute_create_account, @@ -340,3 +341,23 @@ def test_deactivate_account_doesnot_exist( ): deactivate_account('646180157000011122') mock_retry.assert_not_called() + + +@patch('speid.tasks.accounts.block_account.retry') +def test_block_account( + mock_retry: MagicMock, + moral_account: MoralAccount, +): + assert moral_account.estado == Estado.succeeded + block_account(moral_account.cuenta) + moral_account.reload() + assert moral_account.estado == Estado.pld_blocked + mock_retry.assert_not_called() + + +@patch('speid.tasks.accounts.block_account.retry') +def test_block_account_doesnot_exist( + mock_retry: MagicMock, +): + block_account('646180157000011122') + mock_retry.assert_not_called() diff --git a/tests/views/test_general.py b/tests/views/test_general.py index f6e384c0..6388dfff 100644 --- a/tests/views/test_general.py +++ b/tests/views/test_general.py @@ -240,7 +240,7 @@ def test_create_incoming_restricted_account( ): """ Validate reject a depoist to restricted account if the - curp_rfc does not match with ordeenante + curp_rfc does not match with ordenante """ default_income_transaction['CuentaBeneficiario'] = moral_account.cuenta moral_account.is_restricted = True @@ -265,8 +265,25 @@ def test_create_incoming_restricted_account( assert resp.json['estado'] == 'DEVOLUCION' transaction.delete() - # curp and monto match, the transaction is approve, at least $100.0 + # Curp Match and Monto match but account is blocked. + # The transaction is rejected + default_income_transaction['Monto'] = 100.00 + default_income_transaction['RFCCurpOrdenante'] = moral_account.allowed_curp + default_income_transaction['ClaveRastreo'] = 'PRUEBATAMIZI2' + moral_account.estado = Estado.pld_blocked + moral_account.save() + resp = client.post('/ordenes', json=default_income_transaction) + transaction = Transaction.objects.order_by('-created_at').first() + assert transaction.estado is Estado.rejected + assert resp.status_code == 201 + assert resp.json['estado'] == 'DEVOLUCION' + transaction.delete() + + # curp, monto match and account is succeeded + # the transaction is approve, at least $100.0 default_income_transaction['Monto'] = 100.0 + moral_account.estado = Estado.succeeded + moral_account.save() resp = client.post('/ordenes', json=default_income_transaction) transaction = Transaction.objects.order_by('-created_at').first() assert resp.status_code == 201