"""Lambda test module.""" import base64 import json from unittest.mock import call, MagicMock, patch from src import constants, exceptions, main, models from tests.unit.factories import ( EventFactory, MovePayoneerProgramDataFactory, PayoneerStatusDataFactory, PayoneerStatusFactory, ) @patch('src.main.process_event') def test_handler_success(mock_process_event: MagicMock) -> None: event: models.Event = EventFactory.build() msk_event = { 'records': { 'event.payee.programMove-2': [ { 'topic': 'event.payee.programMove', 'partition': 2, 'offset': 0, 'timestamp': 1718198430933, 'timestampType': 'CREATE_TIME', 'key': 'ImYxM2FlZjZkLTVkMGQtNDIxOS1iYjc5LWFkMDljNzcyZTdmOSI=', 'value': base64.b64encode(event.model_dump_json().encode()), 'headers': [], } ] } } main.handler(msk_event, None) assert mock_process_event.call_args_list == [call(event)] mock_process_event.reset_mock() main.handler(event.model_dump(), None) assert mock_process_event.call_args_list == [call(event)] @patch('src.main.process_event') def test_handler_failure(mock_process_event: MagicMock) -> None: event = {'some_key': 'some_value'} msk_event = { 'records': { 'event.payee.programMove-2': [ { 'topic': 'event.payee.programMove', 'partition': 2, 'offset': 0, 'timestamp': 1718198430933, 'timestampType': 'CREATE_TIME', 'key': 'ImYxM2FlZjZkLTVkMGQtNDIxOS1iYjc5LWFkMDljNzcyZTdmOSI=', 'value': base64.b64encode(json.dumps(event).encode()), 'headers': [], } ] } } main.handler(msk_event, None) assert not mock_process_event.called mock_process_event.reset_mock() main.handler(event, None) assert not mock_process_event.called @patch('src.main.ows_abacus_state') @patch('src.main.kafka') @patch('src.main.ows_abacus_account') @patch('src.main.ows_payee') def test_process_event_adopt_and_release_release_from_new_program_error( mock_ows_payee: MagicMock, mock_ows_abacus_account: MagicMock, mock_kafka: MagicMock, mock_ows_abacus_state: MagicMock, ) -> None: """Test ADOPT_AND_RELEASE when release from new program fails.""" previous_status_data: models.PayoneerStatusData = PayoneerStatusDataFactory.build( status=PayoneerStatusFactory.build(type=constants.PayoneerStatusTypes.ACTIVE) ) new_status_data: models.PayoneerStatusData = PayoneerStatusDataFactory.build( status=PayoneerStatusFactory.build(type=constants.PayoneerStatusTypes.ACTIVE) ) mock_ows_payee.get_payoneer_payee_status.side_effect = [ previous_status_data, new_status_data, ] mock_ows_abacus_account.get_payoneer_program_move_type.return_value = ( constants.PayoneerProgramMoveTypes.ADOPT_AND_RELEASE ) # Release from new program fails mock_ows_payee.release_payee_payoneer_program.side_effect = ( exceptions.OwsPayeeException('Release failed') ) event: models.Event = EventFactory.build() main.process_event(event) # Should check status for both programs assert mock_ows_payee.get_payoneer_payee_status.call_args_list == [ call( event.account_payee.account_payee_id, event.account_payee.prev_payoneer_program_id, ), call( event.account_payee.account_payee_id, event.account_payee.payoneer_program_id, ), ] mock_ows_abacus_account.get_payoneer_program_move_type.assert_called_once_with( event.account_payee.prev_payoneer_program_id, event.account_payee.payoneer_program_id, ) # Should attempt to release from new program mock_ows_payee.release_payee_payoneer_program.assert_called_once_with( event.account_payee.account_payee_id, event.account_payee.payoneer_program_id, ) # Should set error state mock_ows_abacus_state.set_payment_eligibility_error.assert_called_once_with( event.account_payee.account_payee_id, constants.MOVE_ERROR_MSG ) # Should not proceed with move mock_ows_payee.move_payoneer_program.assert_not_called() # Should still emit resync event mock_kafka.emit_resync_payment_readiness_event.assert_called_once_with( event.account_payee.account_payee_id ) @patch('src.main.ows_abacus_state') @patch('src.main.kafka') @patch('src.main.ows_abacus_account') @patch('src.main.ows_payee') def test_process_event_adopt_and_release_success( mock_ows_payee: MagicMock, mock_ows_abacus_account: MagicMock, mock_kafka: MagicMock, mock_ows_abacus_state: MagicMock, ) -> None: """Test ADOPT_AND_RELEASE strategy success flow.""" mock_status_data: models.PayoneerStatusData = PayoneerStatusDataFactory.build( status=PayoneerStatusFactory.build(type=constants.PayoneerStatusTypes.ACTIVE) ) new_program_status_data: models.PayoneerStatusData = ( PayoneerStatusDataFactory.build( status=PayoneerStatusFactory.build( type=constants.PayoneerStatusTypes.ACTIVE ) ) ) mock_move_program_data: models.MovePayoneerProgramData = ( MovePayoneerProgramDataFactory.build() ) mock_ows_payee.get_payoneer_payee_status.side_effect = [ mock_status_data, # previous program status new_program_status_data, # new program status (for release check) ] mock_ows_payee.move_payoneer_program.return_value = mock_move_program_data mock_ows_abacus_account.get_payoneer_program_move_type.return_value = ( constants.PayoneerProgramMoveTypes.ADOPT_AND_RELEASE ) mock_ows_abacus_state.banking_details_rejected.return_value = False event: models.Event = EventFactory.build() main.process_event(event) assert mock_ows_payee.get_payoneer_payee_status.call_args_list == [ call( event.account_payee.account_payee_id, event.account_payee.prev_payoneer_program_id, ), call( event.account_payee.account_payee_id, event.account_payee.payoneer_program_id, ), ] mock_ows_abacus_account.get_payoneer_program_move_type.assert_called_once_with( event.account_payee.prev_payoneer_program_id, event.account_payee.payoneer_program_id, ) # Should release from new program first # Then release from old program after move assert mock_ows_payee.release_payee_payoneer_program.call_args_list == [ call( event.account_payee.account_payee_id, event.account_payee.payoneer_program_id, ), call( event.account_payee.account_payee_id, event.account_payee.prev_payoneer_program_id, ), ] mock_ows_payee.move_payoneer_program.assert_called_once_with( event.account_payee.account_payee_id, event.account_payee.prev_payoneer_program_id, event.account_payee.payoneer_program_id, ) mock_ows_abacus_state.banking_details_rejected.assert_called_once_with( event.account_payee.account_payee_id ) mock_kafka.emit_resync_payment_readiness_event.assert_called_once_with( event.account_payee.account_payee_id ) @patch('src.main.kafka') @patch('src.main.ows_abacus_account') @patch('src.main.ows_payee') def test_process_event_inactive_status( mock_ows_payee: MagicMock, mock_ows_abacus_account: MagicMock, mock_kafka: MagicMock, ) -> None: """Test process_event when payee status is inactive.""" mock_status_data = PayoneerStatusDataFactory.build( status=PayoneerStatusFactory.build(type=constants.PayoneerStatusTypes.INACTIVE) ) mock_ows_payee.get_payoneer_payee_status.return_value = mock_status_data event = EventFactory.build() main.process_event(event) mock_ows_payee.get_payoneer_payee_status.assert_called_once_with( event.account_payee.account_payee_id, event.account_payee.prev_payoneer_program_id, ) mock_ows_payee.move_payoneer_program.assert_not_called() mock_kafka.emit_resync_payment_readiness_event.assert_not_called() mock_ows_abacus_account.get_payoneer_program_move_type.assert_not_called() mock_ows_payee.release_payee_payoneer_program.assert_not_called() @patch('src.main.ows_abacus_state') @patch('src.main.kafka') @patch('src.main.ows_abacus_account') @patch('src.main.ows_payee') def test_process_event_adopt_and_release_move_program_error( mock_ows_payee: MagicMock, mock_ows_abacus_account: MagicMock, mock_kafka: MagicMock, mock_ows_abacus_state: MagicMock, ) -> None: """Test ADOPT_AND_RELEASE when move program API fails.""" previous_status_data: models.PayoneerStatusData = PayoneerStatusDataFactory.build( status=PayoneerStatusFactory.build(type=constants.PayoneerStatusTypes.ACTIVE) ) new_status_data: models.PayoneerStatusData = PayoneerStatusDataFactory.build( status=PayoneerStatusFactory.build(type=constants.PayoneerStatusTypes.ACTIVE) ) mock_ows_payee.get_payoneer_payee_status.side_effect = [ previous_status_data, new_status_data, ] mock_ows_abacus_account.get_payoneer_program_move_type.return_value = ( constants.PayoneerProgramMoveTypes.ADOPT_AND_RELEASE ) mock_ows_payee.move_payoneer_program.side_effect = exceptions.OwsPayeeException( 'Move failed' ) event: models.Event = EventFactory.build() main.process_event(event) assert mock_ows_payee.get_payoneer_payee_status.call_args_list == [ call( event.account_payee.account_payee_id, event.account_payee.prev_payoneer_program_id, ), call( event.account_payee.account_payee_id, event.account_payee.payoneer_program_id, ), ] # Should release from new program first mock_ows_payee.release_payee_payoneer_program.assert_called_once_with( event.account_payee.account_payee_id, event.account_payee.payoneer_program_id, ) mock_ows_payee.move_payoneer_program.assert_called_once_with( event.account_payee.account_payee_id, event.account_payee.prev_payoneer_program_id, event.account_payee.payoneer_program_id, ) # Should set error state when move fails mock_ows_abacus_state.set_payment_eligibility_error.assert_called_once_with( event.account_payee.account_payee_id, constants.MOVE_ERROR_MSG ) # Should still emit resync event mock_kafka.emit_resync_payment_readiness_event.assert_called_once_with( event.account_payee.account_payee_id ) @patch('src.main.ows_abacus_state') @patch('src.main.kafka') @patch('src.main.ows_abacus_account') @patch('src.main.ows_payee') def test_process_event_adopt_and_release_release_from_old_program_error( mock_ows_payee: MagicMock, mock_ows_abacus_account: MagicMock, mock_kafka: MagicMock, mock_ows_abacus_state: MagicMock, ) -> None: """Test ADOPT_AND_RELEASE when release from old program fails. This test ensures that even if the release operation fails, the main program move is still considered successful and the kafka event is emitted. """ previous_status_data: models.PayoneerStatusData = PayoneerStatusDataFactory.build( status=PayoneerStatusFactory.build(type=constants.PayoneerStatusTypes.ACTIVE) ) new_status_data: models.PayoneerStatusData = PayoneerStatusDataFactory.build( status=PayoneerStatusFactory.build(type=constants.PayoneerStatusTypes.ACTIVE) ) mock_move_program_data: models.MovePayoneerProgramData = ( MovePayoneerProgramDataFactory.build() ) mock_ows_payee.get_payoneer_payee_status.side_effect = [ previous_status_data, new_status_data, ] mock_ows_payee.move_payoneer_program.return_value = mock_move_program_data mock_ows_abacus_account.get_payoneer_program_move_type.return_value = ( constants.PayoneerProgramMoveTypes.ADOPT_AND_RELEASE ) mock_ows_abacus_state.banking_details_rejected.return_value = False # Release from new program succeeds, but release from old program fails mock_ows_payee.release_payee_payoneer_program.side_effect = [ None, Exception('Release failed'), ] event: models.Event = EventFactory.build() main.process_event(event) assert mock_ows_payee.get_payoneer_payee_status.call_args_list == [ call( event.account_payee.account_payee_id, event.account_payee.prev_payoneer_program_id, ), call( event.account_payee.account_payee_id, event.account_payee.payoneer_program_id, ), ] mock_ows_payee.move_payoneer_program.assert_called_once_with( event.account_payee.account_payee_id, event.account_payee.prev_payoneer_program_id, event.account_payee.payoneer_program_id, ) # Should still emit resync event even though cleanup failed mock_kafka.emit_resync_payment_readiness_event.assert_called_once_with( event.account_payee.account_payee_id ) assert mock_ows_payee.release_payee_payoneer_program.call_args_list == [ call( event.account_payee.account_payee_id, event.account_payee.payoneer_program_id, ), call( event.account_payee.account_payee_id, event.account_payee.prev_payoneer_program_id, ), ] @patch('src.main.kafka') @patch('src.main.ows_abacus_account') @patch('src.main.ows_payee') def test_process_event_release_and_warn_success( mock_ows_payee: MagicMock, mock_ows_abacus_account: MagicMock, mock_kafka: MagicMock, ) -> None: """Test RELEASE_AND_WARN strategy success flow.""" mock_status_data: models.PayoneerStatusData = PayoneerStatusDataFactory.build( status=PayoneerStatusFactory.build(type=constants.PayoneerStatusTypes.ACTIVE) ) mock_ows_payee.get_payoneer_payee_status.return_value = mock_status_data mock_ows_abacus_account.get_payoneer_program_move_type.return_value = ( constants.PayoneerProgramMoveTypes.RELEASE_AND_WARN ) event: models.Event = EventFactory.build() main.process_event(event) mock_ows_payee.get_payoneer_payee_status.assert_called_once_with( event.account_payee.account_payee_id, event.account_payee.prev_payoneer_program_id, ) mock_ows_abacus_account.get_payoneer_program_move_type.assert_called_once_with( event.account_payee.prev_payoneer_program_id, event.account_payee.payoneer_program_id, ) # Should reset banking states mock_ows_payee.reset_banking_states.assert_called_once_with( event.account_payee.account_payee_id ) # Should release from old program mock_ows_payee.release_payee_payoneer_program.assert_called_once_with( event.account_payee.account_payee_id, event.account_payee.prev_payoneer_program_id, ) # Should NOT move program mock_ows_payee.move_payoneer_program.assert_not_called() # Should still emit resync event mock_kafka.emit_resync_payment_readiness_event.assert_called_once_with( event.account_payee.account_payee_id ) @patch('src.main.kafka') @patch('src.main.ows_abacus_account') @patch('src.main.ows_payee') def test_process_event_release_and_warn_release_error( mock_ows_payee: MagicMock, mock_ows_abacus_account: MagicMock, mock_kafka: MagicMock, ) -> None: """Test RELEASE_AND_WARN strategy when release fails.""" mock_status_data: models.PayoneerStatusData = PayoneerStatusDataFactory.build( status=PayoneerStatusFactory.build(type=constants.PayoneerStatusTypes.ACTIVE) ) mock_ows_payee.get_payoneer_payee_status.return_value = mock_status_data mock_ows_abacus_account.get_payoneer_program_move_type.return_value = ( constants.PayoneerProgramMoveTypes.RELEASE_AND_WARN ) mock_ows_payee.release_payee_payoneer_program.side_effect = Exception( 'Release failed' ) event: models.Event = EventFactory.build() main.process_event(event) mock_ows_payee.reset_banking_states.assert_called_once_with( event.account_payee.account_payee_id ) mock_ows_payee.release_payee_payoneer_program.assert_called_once_with( event.account_payee.account_payee_id, event.account_payee.prev_payoneer_program_id, ) # Should still emit resync event even if release fails mock_kafka.emit_resync_payment_readiness_event.assert_called_once_with( event.account_payee.account_payee_id ) @patch('src.main.kafka') @patch('src.main.ows_abacus_account') @patch('src.main.ows_payee') def test_process_event_legacy_wire_program_success( mock_ows_payee: MagicMock, mock_ows_abacus_account: MagicMock, mock_kafka: MagicMock, ) -> None: """Test LEGACY strategy with wire program releases from old program.""" mock_status_data: models.PayoneerStatusData = PayoneerStatusDataFactory.build( status=PayoneerStatusFactory.build(type=constants.PayoneerStatusTypes.ACTIVE) ) mock_move_program_data: models.MovePayoneerProgramData = ( MovePayoneerProgramDataFactory.build() ) mock_ows_payee.get_payoneer_payee_status.return_value = mock_status_data mock_ows_payee.move_payoneer_program.return_value = mock_move_program_data mock_ows_abacus_account.get_payoneer_program_move_type.return_value = ( constants.PayoneerProgramMoveTypes.LEGACY ) mock_ows_abacus_account.is_payoneer_wire_program.return_value = True event: models.Event = EventFactory.build() main.process_event(event) mock_ows_payee.get_payoneer_payee_status.assert_called_once_with( event.account_payee.account_payee_id, event.account_payee.prev_payoneer_program_id, ) mock_ows_abacus_account.get_payoneer_program_move_type.assert_called_once_with( event.account_payee.prev_payoneer_program_id, event.account_payee.payoneer_program_id, ) mock_ows_payee.move_payoneer_program.assert_called_once_with( event.account_payee.account_payee_id, event.account_payee.prev_payoneer_program_id, event.account_payee.payoneer_program_id, ) mock_ows_abacus_account.is_payoneer_wire_program.assert_called_once_with( event.account_payee.payoneer_program_id ) # Should release from old program for wire programs mock_ows_payee.release_payee_payoneer_program.assert_called_once_with( event.account_payee.account_payee_id, event.account_payee.prev_payoneer_program_id, ) mock_kafka.emit_resync_payment_readiness_event.assert_called_once_with( event.account_payee.account_payee_id ) @patch('src.main.kafka') @patch('src.main.ows_abacus_account') @patch('src.main.ows_payee') def test_process_event_legacy_not_wire_program( mock_ows_payee: MagicMock, mock_ows_abacus_account: MagicMock, mock_kafka: MagicMock, ) -> None: """Test LEGACY strategy when program is not wire - should skip release.""" mock_status_data: models.PayoneerStatusData = PayoneerStatusDataFactory.build( status=PayoneerStatusFactory.build(type=constants.PayoneerStatusTypes.ACTIVE) ) mock_move_program_data: models.MovePayoneerProgramData = ( MovePayoneerProgramDataFactory.build() ) mock_ows_payee.get_payoneer_payee_status.return_value = mock_status_data mock_ows_payee.move_payoneer_program.return_value = mock_move_program_data mock_ows_abacus_account.get_payoneer_program_move_type.return_value = ( constants.PayoneerProgramMoveTypes.LEGACY ) mock_ows_abacus_account.is_payoneer_wire_program.return_value = False event: models.Event = EventFactory.build() main.process_event(event) mock_ows_payee.move_payoneer_program.assert_called_once_with( event.account_payee.account_payee_id, event.account_payee.prev_payoneer_program_id, event.account_payee.payoneer_program_id, ) mock_ows_abacus_account.is_payoneer_wire_program.assert_called_once_with( event.account_payee.payoneer_program_id ) # Should NOT release for non-wire programs mock_ows_payee.release_payee_payoneer_program.assert_not_called() mock_kafka.emit_resync_payment_readiness_event.assert_called_once_with( event.account_payee.account_payee_id ) @patch('src.main.kafka') @patch('src.main.ows_abacus_account') @patch('src.main.ows_payee') def test_process_event_get_move_type_error( mock_ows_payee: MagicMock, mock_ows_abacus_account: MagicMock, mock_kafka: MagicMock, ) -> None: """Test when get_payoneer_program_move_type fails.""" mock_status_data: models.PayoneerStatusData = PayoneerStatusDataFactory.build( status=PayoneerStatusFactory.build(type=constants.PayoneerStatusTypes.ACTIVE) ) mock_ows_payee.get_payoneer_payee_status.return_value = mock_status_data mock_ows_abacus_account.get_payoneer_program_move_type.side_effect = ( exceptions.OwsAbacusAccountException('API error') ) event: models.Event = EventFactory.build() main.process_event(event) mock_ows_payee.get_payoneer_payee_status.assert_called_once_with( event.account_payee.account_payee_id, event.account_payee.prev_payoneer_program_id, ) mock_ows_abacus_account.get_payoneer_program_move_type.assert_called_once_with( event.account_payee.prev_payoneer_program_id, event.account_payee.payoneer_program_id, ) # Should NOT proceed with any strategy mock_ows_payee.move_payoneer_program.assert_not_called() mock_ows_payee.release_payee_payoneer_program.assert_not_called() # Should NOT emit resync event mock_kafka.emit_resync_payment_readiness_event.assert_not_called() @patch('src.main.kafka') @patch('src.main.ows_abacus_account') @patch('src.main.ows_payee') def test_process_event_get_status_error( mock_ows_payee: MagicMock, mock_ows_abacus_account: MagicMock, mock_kafka: MagicMock, ) -> None: """Test when get_payoneer_payee_status fails.""" mock_ows_payee.get_payoneer_payee_status.side_effect = exceptions.OwsPayeeException( 'API error' ) event: models.Event = EventFactory.build() main.process_event(event) mock_ows_payee.get_payoneer_payee_status.assert_called_once_with( event.account_payee.account_payee_id, event.account_payee.prev_payoneer_program_id, ) # Should NOT proceed with any operations mock_ows_abacus_account.get_payoneer_program_move_type.assert_not_called() mock_ows_payee.move_payoneer_program.assert_not_called() mock_ows_payee.release_payee_payoneer_program.assert_not_called() mock_kafka.emit_resync_payment_readiness_event.assert_not_called() @patch('src.main.ows_abacus_state') @patch('src.main.kafka') @patch('src.main.ows_abacus_account') @patch('src.main.ows_payee') def test_process_event_adopt_and_release_with_banking_details_rejected( mock_ows_payee: MagicMock, mock_ows_abacus_account: MagicMock, mock_kafka: MagicMock, mock_ows_abacus_state: MagicMock, ) -> None: """Test ADOPT_AND_RELEASE resets banking states when they are rejected.""" mock_status_data: models.PayoneerStatusData = PayoneerStatusDataFactory.build( status=PayoneerStatusFactory.build(type=constants.PayoneerStatusTypes.ACTIVE) ) new_program_status_data: models.PayoneerStatusData = ( PayoneerStatusDataFactory.build( status=PayoneerStatusFactory.build( type=constants.PayoneerStatusTypes.ACTIVE ) ) ) mock_move_program_data: models.MovePayoneerProgramData = ( MovePayoneerProgramDataFactory.build() ) mock_ows_payee.get_payoneer_payee_status.side_effect = [ mock_status_data, new_program_status_data, ] mock_ows_payee.move_payoneer_program.return_value = mock_move_program_data mock_ows_abacus_account.get_payoneer_program_move_type.return_value = ( constants.PayoneerProgramMoveTypes.ADOPT_AND_RELEASE ) mock_ows_abacus_state.banking_details_rejected.return_value = True event: models.Event = EventFactory.build() main.process_event(event) mock_ows_abacus_state.banking_details_rejected.assert_called_once_with( event.account_payee.account_payee_id ) # Should reset banking states when rejected mock_ows_payee.reset_banking_states.assert_called_once_with( event.account_payee.account_payee_id ) mock_ows_payee.move_payoneer_program.assert_called_once_with( event.account_payee.account_payee_id, event.account_payee.prev_payoneer_program_id, event.account_payee.payoneer_program_id, ) mock_kafka.emit_resync_payment_readiness_event.assert_called_once_with( event.account_payee.account_payee_id ) @patch('src.main.kafka') @patch('src.main.ows_abacus_account') @patch('src.main.ows_payee') @patch('src.main.ows_abacus_state') def test_process_event_adopt_and_release_no_new_program_status( mock_ows_abacus_state: MagicMock, mock_ows_payee: MagicMock, mock_ows_abacus_account: MagicMock, mock_kafka: MagicMock, ) -> None: """Test ADOPT_AND_RELEASE when new program status lookup fails (payee not in new program). When the payee doesn't exist in the new program yet, the move should still proceed and release from the old program. """ mock_status_data: models.PayoneerStatusData = PayoneerStatusDataFactory.build( status=PayoneerStatusFactory.build(type=constants.PayoneerStatusTypes.ACTIVE) ) mock_move_program_data: models.MovePayoneerProgramData = ( MovePayoneerProgramDataFactory.build() ) mock_ows_payee.get_payoneer_payee_status.side_effect = [ mock_status_data, exceptions.OwsPayeeException('Not found'), ] mock_ows_payee.move_payoneer_program.return_value = mock_move_program_data mock_ows_abacus_account.get_payoneer_program_move_type.return_value = ( constants.PayoneerProgramMoveTypes.ADOPT_AND_RELEASE ) mock_ows_abacus_state.banking_details_rejected.return_value = False event: models.Event = EventFactory.build() main.process_event(event) # Should attempt to get status for new program but fail gracefully assert mock_ows_payee.get_payoneer_payee_status.call_args_list == [ call( event.account_payee.account_payee_id, event.account_payee.prev_payoneer_program_id, ), call( event.account_payee.account_payee_id, event.account_payee.payoneer_program_id, ), ] # Should still proceed with move even though new program status failed mock_ows_payee.move_payoneer_program.assert_called_once_with( event.account_payee.account_payee_id, event.account_payee.prev_payoneer_program_id, event.account_payee.payoneer_program_id, ) # should check for rejected details mock_ows_abacus_state.banking_details_rejected.assert_called_once_with( event.account_payee.account_payee_id ) # Should release from old program after successful move mock_ows_payee.release_payee_payoneer_program.assert_called_once_with( event.account_payee.account_payee_id, event.account_payee.prev_payoneer_program_id, ) mock_kafka.emit_resync_payment_readiness_event.assert_called_once_with( event.account_payee.account_payee_id )