"""Shared fixtures for tests.""" from datetime import datetime import os from abacus_common_logic.connectors.database import db import pytest from abacus_contract.api import create_app from abacus_contract.config import Config from abacus_contract.constants import constants from tests.utils.factories import AccountContractFactory from tests.utils.factories import ContractAdvanceFactory from tests.utils.factories import ContractFactory from tests.utils.factories import ContractLifecycleFactory from tests.utils.factories import ReferencePaymentEntityFactory from tests.utils.factories import ReferenceSapProfitCenterFactory from tests.utils.factories import ReferenceSigningEntityFactory class TestConfig(Config): """Test configuration.""" MYSQL_DB_NAME = os.environ.get( 'MYSQL_TEST_DB_NAME', Config.MYSQL_DB_NAME + '_test') @pytest.fixture(scope='session', autouse=True) def test_app(): """Create a test application.""" return create_app(TestConfig) @pytest.fixture(autouse=True) def test_app_in_context(test_app): """Push the test app onto the context.""" with test_app.app_context(): yield test_app @pytest.fixture(autouse=True) def test_app_request(test_app_in_context): """Push the test app onto the context and trigger preprocessing.""" with test_app_in_context.test_request_context(): test_app_in_context.preprocess_request() yield test_app_in_context @pytest.fixture def fixture_client(test_app_in_context): """Create a client fixture.""" with test_app_in_context.test_client() as test_client: yield test_client @pytest.fixture def fresh_db(): """Refresh the test database.""" top_level_tables = ( 'run_controller', 'run_controller_contract', 'legacy_contract', 'contract', 'abacus_event', 'abacus_state', 'account_contract', 'account_payee', 'account_payment_term', 'account_tax_info', 'account', 'contract_advance', 'contract_flowthrough', 'contract_lifecycle_schedule_detail', 'contract_lifecycle_schedule', 'contract_lifecycle', 'contract_mechanical_deduction', 'contract_party', 'contract_term', 'contract_term_condition', 'contract_term_schedule', 'contract_term_schedule_history', 'contract_template', 'contract_exclusion', 'contract_reserve', 'ledger_contract_advance_applied', 'reference_flowthrough_calculation', 'reference_sap_profit_center', 'reference_signing_entity', 'reference_payment_entity', 'schedule', 'statement_period', 'reference_flowthrough_calculation', 'reference_mechanical_rate', 'reference_payment_type', 'reference_transaction_type_group_transaction_type', 'reference_transaction_type_group', 'reference_transaction_type' ) con = db.engine.connect() con.execute('SET FOREIGN_KEY_CHECKS = 0;') trans = con.begin() for table_name in top_level_tables: con.execute(f'TRUNCATE TABLE `{table_name}`') trans.commit() con.execute('SET FOREIGN_KEY_CHECKS = 1;') @pytest.fixture def create_mock_account(): """Create mock account rows.""" ADD_ACCOUNT = """ INSERT INTO account( `account_id`, `account_name`, `created_by`, `created_at`, `last_modified_by`, `last_modified` ) VALUES (1, 'Test Account 1', '11', NOW(), '11', NOW()), (2, 'Test Account 2', '22', NOW(), '22', NOW()) """ db.engine.execute(ADD_ACCOUNT) @pytest.fixture def create_mock_account_payee(): """Create mock payee and account_payee rows.""" ADD_ACCOUNT_PAYEE = """ INSERT INTO account_payee( `account_id`, `created_by`, `created_at`, `last_modified_by`, `last_modified` ) VALUES (1, 'QA', NOW(), 'QA', NOW()), (2, 'QA', NOW(), 'QA', NOW())""" db.engine.execute(ADD_ACCOUNT_PAYEE) @pytest.fixture def create_mock_account_payment_term(): """Create mock account_payment_term rows.""" mock_reference_payment_entity = ReferencePaymentEntityFactory.create() ADD_ACCOUNT_PAYMENT_TERM = """ INSERT INTO account_payment_term( `account_payment_term_id`, `account_id`, `currency_code`, `payment_minimum`, `payment_entity_id`, `payment_schedule`, `created_by`, `created_at`, `last_modified_by`, `last_modified` ) VALUES (1, 1, 'USD', NULL, {}, '30_days_after_month_end', '', NOW(), '', NOW()), (2, 2, 'USD', NULL, {}, '30_days_after_month_end', '', NOW(), '', NOW()); """ db.engine.execute( ADD_ACCOUNT_PAYMENT_TERM.format( mock_reference_payment_entity.reference_payment_entity_id, mock_reference_payment_entity.reference_payment_entity_id, ) ) @pytest.fixture def create_mock_reference_sap_profit_center(): """Create mock reference_sap_profit_center rows.""" return ReferenceSapProfitCenterFactory.create() @pytest.fixture def create_mock_reference_signing_entity(): """Create mock reference_signing_entity rows.""" mock_reference_signing_entity = ReferenceSigningEntityFactory.create( company_code='4378' ) ReferenceSapProfitCenterFactory.create( company_code=mock_reference_signing_entity.company_code ) return mock_reference_signing_entity @pytest.fixture def create_mock_contract(create_mock_reference_sap_profit_center): """Create mock contract rows.""" ADD_CONTRACT = """ INSERT INTO contract( `contract_id`, `contract_name`, `contract_type`, `term_start`, `term_end`, `reference_signing_entity_id`, `created_by`, `created_at`, `last_modified_by`, `last_modified` ) VALUES (1, 'Test contract', 'distribution', '2021-01-01', '2022-01-01', 1, '', NOW(), '', NOW()), (2, 'Contract test', 'distribution', '2021-01-01', '2022-01-01', 1, '', NOW(), '', NOW()) """ db.engine.execute(ADD_CONTRACT) @pytest.fixture def create_mock_run_controller(): """Create mock run_controller and run_controller_contract rows.""" ADD_RUN_CONTROLLER = """ INSERT INTO run_controller( `run_controller_id`, `run_controller_name`, `created_by`, `created_at`, `last_modified_by`, `last_modified` ) VALUES (1, 'Default Run Controller','2', NOW(), '2', NOW()), (2, 'Second Run Controller', '2', NOW(), '2', NOW()) """ db.engine.execute(ADD_RUN_CONTROLLER) def create_mock_run_controller_contract(contract_ids): """Create mock run_controller_contracts.""" con = db.engine.connect() trans = con.begin() values = list() for contract_id in contract_ids: values.append(f'(1, {contract_id})') ADD_RUN_CONTROLLER_CONTRACT = """ INSERT INTO run_controller_contract( `run_controller_id`, `contract_id` ) VALUES {}; """ db.engine.execute(ADD_RUN_CONTROLLER_CONTRACT.format(','.join(values))) trans.commit() @pytest.fixture def create_mock_account_tax_info(): """Create mock account_tax_info.""" ADD_ACCOUNT_TAX_INFO = """ INSERT INTO account_tax_info( `account_tax_info_id`, `account_id`, `country_of_tax_residence`, `is_sba_signed`, `created_by`, `created_at`, `last_modified_by`, `last_modified` ) VALUES (1, 1, 'GBR', 1, '2', NOW(), '2', NOW()), (2, 2, 'GBR', 0, '2', NOW(), '2', NOW()) """ db.engine.execute(ADD_ACCOUNT_TAX_INFO) @pytest.fixture def create_mock_abacus_event(): """Create mock abacus_event.""" ADD_ABACUS_EVENT = """ INSERT INTO abacus_event ( `abacus_event_id`, `statement_period_id`, `event_date`, `event_name`, `target_type`, `target_id`, `created_by` ) VALUES ( 1, 1, '2022-09-13', 'confirm_advance_payment', 'contract', 1, 'Test' ), ( 2, 1, '2022-09-16', 'confirm_advance_payment', 'contract', 2, 'Test' ), ( 3, 1, '2022-09-16', 'commit_to_subledger', 'contract', 3, 'Test' ) """ db.engine.execute(ADD_ABACUS_EVENT) @pytest.fixture def create_mock_statement_period(): """Insert statement period data.""" STATEMENT_PERIOD_INSERT = """ INSERT INTO statement_period( statement_period_id, statement_period_name, statement_period_status ) VALUES(1, 'Jan 20', 'current'), (2, 'Feb 20', 'open'); """ db.engine.execute(STATEMENT_PERIOD_INSERT) @pytest.fixture def create_mock_paid_advances( create_mock_statement_period, create_mock_account, create_mock_abacus_event ): """Create mock paid advances.""" contract = ContractFactory.create(contract_id=1) ContractAdvanceFactory.create( contract=contract, advance_status=constants.ADVANCE_STATUSES.PAID ) ContractAdvanceFactory.create( contract_id=2, advance_description='Advance Description', amount=11290.90, currency_code='CAD', milestone=constants.MILESTONES.DELIVERY, milestone_description='Milestone Description', milestone_date='2022-09-30', advance_status=constants.ADVANCE_STATUSES.PAID ) ContractAdvanceFactory.create( contract=contract, advance_status=constants.ADVANCE_STATUSES.PENDING_PAYMENT ) LEDGER_CONTRACT_ADVANCE_APPLIED = """ INSERT INTO ledger_contract_advance_applied ( `abacus_event_id`, `account_id`, `contract_id`, `contract_advance_id`, `statement_period_id`, `advance_amount`, `advance_currency_code`, `advance_amount_payee_currency`, `advance_payee_currency_code`, `created_by`, `created_at`, `last_modified_by`, `last_modified` ) VALUES (1, 1, 1, 1, 1, '100.00', 'USD', '100.00','USD', '2', NOW(), '2', NOW()), (2, 1, 2, 2, 1, '11290.90', 'CAD', '11765.28','AUD', '2', NOW(), '2', NOW()), (1, 1, 1, 3, 1, '101.00', 'USD', '101.00','USD', '2', NOW(), '2', NOW()) """ db.engine.execute(LEDGER_CONTRACT_ADVANCE_APPLIED) @pytest.fixture def create_mock_paid_advances_with_worksheets_logic( create_mock_statement_period, create_mock_account, create_mock_abacus_event ): """Create mock paid advances with worksheets logic.""" mock_contract = ContractFactory.create() ContractAdvanceFactory.create( contract=mock_contract, advance_status=constants.ADVANCE_STATUSES.PAID ) ContractAdvanceFactory.create( advance_status=constants.ADVANCE_STATUSES.PAID ) ContractAdvanceFactory.create( contract=mock_contract, advance_status=constants.ADVANCE_STATUSES.PENDING_PAYMENT ) LEDGER_CONTRACT_ADVANCE_APPLIED = """ INSERT INTO ledger_contract_advance_applied ( `abacus_event_id`, `account_id`, `contract_id`, `contract_advance_id`, `statement_period_id`, `advance_amount`, `advance_currency_code`, `advance_amount_payee_currency`, `advance_payee_currency_code`, `created_by`, `created_at`, `last_modified_by`, `last_modified` ) VALUES (1, 1, 1, 1, 1, '100.00', 'USD', '100.00','USD', '2', NOW(), '2', NOW()), (2, 1, 2, 2, 1, '11290.90', 'CAD', '11765.28','AUD', '2', NOW(), '2', NOW()), (3, 1, 1, 3, 1, '101.00', 'USD', '101.00','USD', '2', NOW(), '2', NOW()) """ db.engine.execute(LEDGER_CONTRACT_ADVANCE_APPLIED) @pytest.fixture def create_mock_paid_advances_previously_failed_worksheets( create_mock_statement_period, create_mock_account, create_mock_abacus_event ): """Create mock paid advances with previously rejected worksheets.""" mock_contract = ContractFactory.create() ContractAdvanceFactory.create( contract=mock_contract, advance_status=constants.ADVANCE_STATUSES.PAID ) ABACUS_STATE = """ INSERT INTO abacus_state ( `abacus_state_id`, `action_name`, `action_status`, `parent_table_name`, `parent_table_id`, `created_by`, `created_at`, `last_modified_by`, `last_modified` ) VALUES ( 1, 'send_payments', 'rejected', 'worksheet_payment_contract_advance', 1, '2', now(), '2', now() ), ( 2, 'send_payments', 'complete', 'worksheet_payment_contract_advance', 2, '2', now(), '2', now() ) """ LEDGER_CONTRACT_ADVANCE_APPLIED = """ INSERT INTO ledger_contract_advance_applied ( `abacus_event_id`, `account_id`, `contract_id`, `contract_advance_id`, `worksheet_payment_contract_advance_id`, `statement_period_id`, `advance_amount`, `advance_currency_code`, `advance_amount_payee_currency`, `advance_payee_currency_code`, `created_by`, `created_at`, `last_modified_by`, `last_modified` ) VALUES (1, 1, 1, 1, 1, 1, '100.00', 'USD', '100.00','USD', '2', NOW(), '2', NOW()), (2, 1, 1, 1, 1, 1, '-100.00', 'USD', '-100.00', 'USD', '2', NOW(), '2', NOW()), (3, 1, 1, 1, 2, 1, '100.00', 'USD', '120.00','AUD', '2', NOW(), '2', NOW()) """ db.engine.execute(ABACUS_STATE) db.engine.execute(LEDGER_CONTRACT_ADVANCE_APPLIED) @pytest.fixture def create_mock_paid_advances_running_worksheets( create_mock_statement_period, create_mock_account, create_mock_abacus_event ): """Create mock paid advances with running worksheets.""" mock_contract = ContractFactory.create() ContractAdvanceFactory.create( contract=mock_contract, advance_status=constants.ADVANCE_STATUSES.PAID ) ABACUS_STATE = """ INSERT INTO abacus_state ( `abacus_state_id`, `action_name`, `action_status`, `parent_table_name`, `parent_table_id`, `created_by`, `created_at`, `last_modified_by`, `last_modified` ) VALUES ( 1, 'send_payments', 'running', 'worksheet_payment_contract_advance', 1, '2', now(), '2', now() ) """ LEDGER_CONTRACT_ADVANCE_APPLIED = """ INSERT INTO ledger_contract_advance_applied ( `abacus_event_id`, `account_id`, `contract_id`, `contract_advance_id`, `worksheet_payment_contract_advance_id`, `statement_period_id`, `advance_amount`, `advance_currency_code`, `advance_amount_payee_currency`, `advance_payee_currency_code`, `created_by`, `created_at`, `last_modified_by`, `last_modified` ) VALUES (1, 1, 1, 1, 1, 1, '100.00', 'USD', '100.00','USD', '2', NOW(), '2', NOW()) """ db.engine.execute(ABACUS_STATE) db.engine.execute(LEDGER_CONTRACT_ADVANCE_APPLIED) @pytest.fixture def create_mock_schedule(): """Create mock schedule.""" ADD_SCHEDULE = """ INSERT INTO schedule( `schedule_id`, `schedule_name`, `target_type`, `target_id`, `created_by`, `created_at`, `last_modified_by`, `last_modified` ) VALUES (1, 'Schedule Abrahams, Kyle James', 'contributor', '935657b3-bcfb-4f7f-84d6-74822dea5f39', 'test_user', NOW(), 'test_user', NOW()), (2, 'Contributor Only Schedule', 'contributor', '8931b2f5-f0d9-49b1-bfa7-186b684299b1', 'test_user', NOW(), 'test_user', NOW()), (3, 'Schedule Abbott, Judith', 'contributor', 'f41ca716-19e6-47a5-97c8-b5714d245bb4', 'test_user', NOW(), 'test_user', NOW()) """ db.engine.execute(ADD_SCHEDULE) @pytest.fixture def mock_contract_and_lifecycle_post_payload( create_mock_account ): """Mock POST request payload for contract, contract_lifecycle and schedules.""" continuously_active_renewal_type = \ constants.CONTRACT_LIFECYCLE_SCHEDULE_RENEWAL_TYPES.CONTINUOUSLY_ACTIVE reference_sap_profit_center = ReferenceSapProfitCenterFactory.create( company_code=4914 ) mock_reference_signing_entity = ReferenceSigningEntityFactory.create( company_code=4914, reference_sap_profit_center=reference_sap_profit_center ) mock_contract = { 'account_id': 1, 'contract_name': 'Test Contract', 'contract_type': 'distribution', 'reference_signing_entity_id': mock_reference_signing_entity.reference_signing_entity_id, 'execution_date': None, 'summary_note': 'This is for the test', 'general_note': 'This is for the test (general_note)', 'oa_contract_id': 1 } mock_contract_lifecycle_schedules = [{ 'renewal_type': continuously_active_renewal_type, 'schedule_end': None, 'termination_notice_detail_interval': 1, 'termination_notice_detail_type': 'month', 'renewal_offset_detail_interval': None, 'renewal_offset_detail_type': None, 'collection_period_detail_interval': None, 'collection_period_detail_type': None, }] mock_contract_lifecycle = { 'lifecycle_term_start': '2024-07-30' } mock_post_request_payload = { 'contract': mock_contract, 'contract_lifecycle_schedules': mock_contract_lifecycle_schedules, 'contract_lifecycle': mock_contract_lifecycle } return mock_post_request_payload @pytest.fixture def mock_contracts( create_mock_account, create_mock_run_controller ): """Mock contracts.""" distribution_contracts = [ContractFactory.create( contract_name=f'Distribution Contract {i}', contract_type=constants.CONTRACT_TYPES.DISTRIBUTION, is_excluded_from_accounting_run=0 ) for i in range(1, 4)] distribution_contracts.extend([ ContractFactory.create( contract_name='A1 LaFlare\\Amigo Records, LLC', contract_type=constants.CONTRACT_TYPES.DISTRIBUTION, is_excluded_from_accounting_run=1 ), ContractFactory.create( contract_name='Test Distribution Contract', contract_type=constants.CONTRACT_TYPES.DISTRIBUTION, is_excluded_from_accounting_run=1 ) ]) distribution_contract_ids = [ contract.contract_id for contract in distribution_contracts ] for contract in distribution_contracts: AccountContractFactory.create( contract=contract, account_id=1 ) ContractLifecycleFactory.create( contract=distribution_contracts[0], lifecycle_status=constants.CONTRACT_LIFECYCLE_STATUSES.INIT ) ContractLifecycleFactory.create( contract=distribution_contracts[1], lifecycle_status=constants.CONTRACT_LIFECYCLE_STATUSES.INACTIVE, deleted_by='test account', deleted_at=datetime(2025, 2, 28, 0, 0) ) ContractLifecycleFactory.create( contract=distribution_contracts[2], lifecycle_status=constants.CONTRACT_LIFECYCLE_STATUSES.ACTIVE ) ContractLifecycleFactory.create( contract=distribution_contracts[3], lifecycle_status=constants.CONTRACT_LIFECYCLE_STATUSES.TO_BE_TERMINATED ) nr_contracts = [ContractFactory.create( contract_name=f'NR Contract {i}', contract_type=constants.CONTRACT_TYPES.NEIGHBOURING_RIGHTS, is_excluded_from_accounting_run=1 ) for i in range(1, 4)] nr_contracts.extend([ ContractFactory.create( contract_name='Dylan Bukov 100% t/a Dybbukk', contract_type=constants.CONTRACT_TYPES.NEIGHBOURING_RIGHTS, is_excluded_from_accounting_run=0 ), ContractFactory.create( contract_name='Test NR Contract', contract_type=constants.CONTRACT_TYPES.NEIGHBOURING_RIGHTS, is_excluded_from_accounting_run=1 ) ]) for contract in nr_contracts: AccountContractFactory.create( contract=contract, account_id=2 ) nr_contract_ids = [contract.contract_id for contract in nr_contracts] create_mock_run_controller_contract([ *distribution_contract_ids, *nr_contract_ids ]) ContractLifecycleFactory.create( contract=nr_contracts[0], lifecycle_status=constants.CONTRACT_LIFECYCLE_STATUSES.IN_COLLECTION_PERIOD ) ContractLifecycleFactory.create( contract=nr_contracts[1], lifecycle_status=constants.CONTRACT_LIFECYCLE_STATUSES.TERMINATED ) # Contracts to test sort order with search term search_order_contracts = [ ContractFactory.create( contract_name='Contract 8675309', ), ContractFactory.create( contract_id=8675309, contract_name='Contract sort order', ) ] search_order_contract_ids = [ contract.contract_id for contract in search_order_contracts ] for contract in search_order_contracts: AccountContractFactory.create( contract=contract, account_id=2 ) ContractLifecycleFactory.create( contract=contract, lifecycle_status=constants.CONTRACT_LIFECYCLE_STATUSES.ACTIVE ) create_mock_run_controller_contract([ *search_order_contract_ids, ])