"""Functional tests for revenue analysis endpoints.""" from contextlib import contextmanager from unittest.mock import patch import pytest from moneyhub.connectors.snowflake import db from moneyhub.constants.constants import ContractType from moneyhub.constants.constants import StatementPeriodStatus from moneyhub.models import AccountStatementPeriods from moneyhub.models import DimSubaccount from moneyhub.models import RevenueByActivityMonth from moneyhub.models import RevenueByArtist from moneyhub.models import RevenueByCountry from moneyhub.models import RevenueByImprint from moneyhub.models import RevenueByProductDistro from moneyhub.models import RevenueByProject from moneyhub.models import RevenueByRecordingDistro from moneyhub.models import RevenueByRecordingNr from moneyhub.models import RevenueByStatementPeriod from moneyhub.models import RevenueByStore from moneyhub.models import RevenueBySubaccount from moneyhub.models import RevenueByTrack from moneyhub.models import RevenueByTransactionType from tests.functional.conftest import insert_mock_data @contextmanager def _using_mock_data(mock_data: dict): """Create the necessary mock tables and fills them with the data. Args: mock_data (dict): Data to enter. """ AccountStatementPeriods.__table__.drop(db.engine, checkfirst=True) RevenueByCountry.__table__.drop(db.engine, checkfirst=True) RevenueByProductDistro.__table__.drop(db.engine, checkfirst=True) RevenueByRecordingDistro.__table__.drop(db.engine, checkfirst=True) RevenueByRecordingNr.__table__.drop(db.engine, checkfirst=True) RevenueByStore.__table__.drop(db.engine, checkfirst=True) RevenueByTransactionType.__table__.drop(db.engine, checkfirst=True) RevenueByTrack.__table__.drop(db.engine, checkfirst=True) RevenueByArtist.__table__.drop(db.engine, checkfirst=True) RevenueByImprint.__table__.drop(db.engine, checkfirst=True) RevenueByProject.__table__.drop(db.engine, checkfirst=True) RevenueByActivityMonth.__table__.drop(db.engine, checkfirst=True) RevenueByStatementPeriod.__table__.drop(db.engine, checkfirst=True) RevenueBySubaccount.__table__.drop(db.engine, checkfirst=True) DimSubaccount.__table__.drop(db.engine, checkfirst=True) db.session.commit() AccountStatementPeriods.__table__.create(db.engine) RevenueByCountry.__table__.create(db.engine) RevenueByProductDistro.__table__.create(db.engine) RevenueByRecordingDistro.__table__.create(db.engine) RevenueByRecordingNr.__table__.create(db.engine) RevenueByStore.__table__.create(db.engine) RevenueByTransactionType.__table__.create(db.engine) RevenueByTrack.__table__.create(db.engine) RevenueByArtist.__table__.create(db.engine) RevenueByImprint.__table__.create(db.engine) RevenueByProject.__table__.create(db.engine) RevenueByActivityMonth.__table__.create(db.engine) RevenueByStatementPeriod.__table__.create(db.engine) RevenueBySubaccount.__table__.create(db.engine) DimSubaccount.__table__.create(db.engine) insert_mock_data(mock_data, database='snowflake') yield db.session.commit() AccountStatementPeriods.__table__.drop(db.engine) RevenueByCountry.__table__.drop(db.engine) RevenueByProductDistro.__table__.drop(db.engine) RevenueByRecordingDistro.__table__.drop(db.engine) RevenueByRecordingNr.__table__.drop(db.engine) RevenueByStore.__table__.drop(db.engine) RevenueByTransactionType.__table__.drop(db.engine) RevenueByTrack.__table__.drop(db.engine) RevenueByArtist.__table__.drop(db.engine) RevenueByImprint.__table__.drop(db.engine) RevenueByProject.__table__.drop(db.engine) RevenueByActivityMonth.__table__.drop(db.engine) RevenueByStatementPeriod.__table__.drop(db.engine) RevenueBySubaccount.__table__.drop(db.engine) DimSubaccount.__table__.drop(db.engine) db.session.close() def test_get_revenue_analysis_by_product_distro_order_by_product(fixture_client): """Test getting revenue analysis by product distro.""" account_id = 24601 mock_data = { 'revenue_by_product_distro_dbt': [ { 'product_id': 1, 'product_name': 'Product', 'display_upc': '1234512345', 'release_date': '2010-09-08', 'artist_name': 'Artist', 'subaccount_id': 1, 'account_id': account_id, 'contract_id': 10001, 'statement_period_id': 123, 'account_payee_currency': 'GBP', 'mechanical_deduction_amount_payee_currency': 20.0, 'publisher_admin_fee_payee_currency': 2.0, 'net_share_payee_currency': 20.0, 'gross_revenue_payee_currency': 30.0, 'project_name': 'Project One', }, { 'product_id': 2, 'product_name': 'Another Product', 'display_upc': '1234512345', 'release_date': '2010-09-08', 'artist_name': 'Artist', 'subaccount_id': 1, 'account_id': account_id, 'contract_id': 10001, 'statement_period_id': 123, 'account_payee_currency': 'GBP', 'mechanical_deduction_amount_payee_currency': 20.0, 'publisher_admin_fee_payee_currency': 2.0, 'net_share_payee_currency': 20.0, 'gross_revenue_payee_currency': 30.0, 'project_name': 'Project Two', }, ], } with _using_mock_data(mock_data): result = fixture_client.get( f'/revenue-analysis/account/{account_id}/product?order_by=product_name') assert result.status_code == 200 assert result.json() == { 'items': [ { 'account_payee_currency': 'GBP', 'gross_revenue_payee_currency': 30.0, 'product_id': 2, 'mechanical_deduction_amount_payee_currency': 20.0, 'publisher_admin_fee_payee_currency': 2.0, 'net_share_payee_currency': 20.0, 'project_name': 'Project Two', 'subaccount_revenue': None }, { 'account_payee_currency': 'GBP', 'gross_revenue_payee_currency': 30.0, 'product_id': 1, 'mechanical_deduction_amount_payee_currency': 20.0, 'publisher_admin_fee_payee_currency': 2.0, 'net_share_payee_currency': 20.0, 'project_name': 'Project One', 'subaccount_revenue': None } ], 'pagination': {'pagination_type': 'standard', 'total_records': 2}, } def test_get_revenue_analysis_by_product_distro_order_by_artist(fixture_client): """Test getting revenue analysis by product distro.""" account_id = 24601 mock_data = { 'revenue_by_product_distro_dbt': [ { 'product_id': 1, 'product_name': 'Product', 'display_upc': '1234512345', 'release_date': '2010-09-08', 'artist_name': 'B Artist', 'subaccount_id': 1, 'account_id': account_id, 'contract_id': 10001, 'statement_period_id': 123, 'account_payee_currency': 'GBP', 'mechanical_deduction_amount_payee_currency': 20.0, 'publisher_admin_fee_payee_currency': 2.0, 'net_share_payee_currency': 20.0, 'gross_revenue_payee_currency': 30.0, 'project_name': 'Project One', }, { 'product_id': 2, 'product_name': 'Another Product', 'display_upc': '1234512345', 'release_date': '2010-09-08', 'artist_name': 'A Artist', 'subaccount_id': 1, 'account_id': account_id, 'contract_id': 10001, 'statement_period_id': 123, 'account_payee_currency': 'GBP', 'mechanical_deduction_amount_payee_currency': 20.0, 'publisher_admin_fee_payee_currency': 2.0, 'net_share_payee_currency': 20.0, 'gross_revenue_payee_currency': 30.0, 'project_name': 'Project Two', }, ], } with _using_mock_data(mock_data): result = fixture_client.get( f'/revenue-analysis/account/{account_id}/product?order_by=artist_name') assert result.status_code == 200 assert result.json() == { 'items': [ { 'account_payee_currency': 'GBP', 'gross_revenue_payee_currency': 30.0, 'product_id': 2, 'mechanical_deduction_amount_payee_currency': 20.0, 'publisher_admin_fee_payee_currency': 2.0, 'net_share_payee_currency': 20.0, 'project_name': 'Project Two', 'subaccount_revenue': None }, { 'account_payee_currency': 'GBP', 'gross_revenue_payee_currency': 30.0, 'product_id': 1, 'mechanical_deduction_amount_payee_currency': 20.0, 'publisher_admin_fee_payee_currency': 2.0, 'net_share_payee_currency': 20.0, 'project_name': 'Project One', 'subaccount_revenue': None } ], 'pagination': {'pagination_type': 'standard', 'total_records': 2}, } def test_get_revenue_analysis_by_product_distro_order_by_release_date(fixture_client): """Test getting revenue analysis by product distro.""" account_id = 24601 mock_data = { 'revenue_by_product_distro_dbt': [ { 'product_id': 1, 'product_name': 'Product', 'display_upc': '1234512345', 'release_date': '2010-09-08', 'artist_name': 'Artist', 'subaccount_id': 1, 'account_id': account_id, 'contract_id': 10001, 'statement_period_id': 123, 'account_payee_currency': 'GBP', 'mechanical_deduction_amount_payee_currency': 20.0, 'publisher_admin_fee_payee_currency': 2.0, 'net_share_payee_currency': 20.0, 'gross_revenue_payee_currency': 30.0, 'project_name': 'Project One', }, { 'product_id': 2, 'product_name': 'Another Product', 'display_upc': '1234512345', 'release_date': '2010-09-09', 'artist_name': 'Artist Second', 'subaccount_id': 1, 'account_id': account_id, 'contract_id': 10001, 'statement_period_id': 123, 'account_payee_currency': 'GBP', 'mechanical_deduction_amount_payee_currency': 20.0, 'publisher_admin_fee_payee_currency': 2.0, 'net_share_payee_currency': 20.0, 'gross_revenue_payee_currency': 30.0, 'project_name': 'Project Two', }, ], } with _using_mock_data(mock_data): result = fixture_client.get( f'/revenue-analysis/account/{account_id}/product?order_by=release_date') assert result.status_code == 200 assert result.json() == { 'items': [ { 'account_payee_currency': 'GBP', 'gross_revenue_payee_currency': 30.0, 'product_id': 1, 'mechanical_deduction_amount_payee_currency': 20.0, 'publisher_admin_fee_payee_currency': 2.0, 'net_share_payee_currency': 20.0, 'project_name': 'Project One', 'subaccount_revenue': None }, { 'account_payee_currency': 'GBP', 'gross_revenue_payee_currency': 30.0, 'product_id': 2, 'mechanical_deduction_amount_payee_currency': 20.0, 'publisher_admin_fee_payee_currency': 2.0, 'net_share_payee_currency': 20.0, 'project_name': 'Project Two', 'subaccount_revenue': None } ], 'pagination': {'pagination_type': 'standard', 'total_records': 2}, } def test_get_revenue_analysis_by_recording_distro(fixture_client): """Test getting revenue analysis by recording (distro).""" account_id = 24601 contract_id = 10001 mock_sql_data = { 'account': {'account_id': account_id}, 'reference_payment_entity': {'reference_payment_entity_id': 1}, 'reference_sap_profit_center': { 'reference_sap_profit_center_id': 1, 'profit_center': 'UK1234', 'company_code': '1234', 'business_group': 'ORC' }, 'reference_signing_entity': { 'reference_signing_entity_id': 1, 'reference_payment_entity_id': 1, 'reference_sap_profit_center_id': 1, 'company_code': '1234', 'tax_entity_company_code': '1234', 'legal_name': 'Company', 'vat_number': '12341234', 'company_registration_number': '12341234', 'address': None, }, 'contract': { 'contract_id': contract_id, 'reference_signing_entity_id': 1, 'contract_type': ContractType.DISTRIBUTION, }, 'abacus_event': {'abacus_event_id': 1}, 'ledger_account_contract': { 'abacus_event_id': 1, 'account_id': account_id, 'contract_id': contract_id, }, } mock_data = { 'revenue_by_recording_distro_dbt': { 'recording_id': 1, 'recording_title': 'Recording', 'artist': 'Artist', 'version': '', 'isrc': 'ABCD1234', 'account_id': account_id, 'contract_id': contract_id, 'statement_period_id': 123, 'account_payee_currency': 'GBP', 'net_share_payee_currency': 10.0, 'gross_revenue_payee_currency': 20.0, }, } insert_mock_data(mock_sql_data) with _using_mock_data(mock_data): result = fixture_client.get(f'/revenue-analysis/account/{account_id}/recording') assert result.status_code == 200 assert result.json() == { 'items': [ { 'account_id': account_id, 'account_payee_currency': 'GBP', 'artist': 'Artist', 'contract_id': None, 'gross_revenue_payee_currency': 20.0, 'isrc': 'ABCD1234', 'net_share_payee_currency': 10.0, 'recording_id': '1', 'recording_title': 'Recording', 'version': '', } ], 'pagination': {'pagination_type': 'standard', 'total_records': 1}, } def test_get_revenue_analysis_by_recording_nr(fixture_client): """Test getting revenue analysis by recording (nr).""" account_id = 24601 contract_id = 10001 mock_sql_data = { 'account': {'account_id': account_id}, 'reference_payment_entity': {'reference_payment_entity_id': 1}, 'reference_sap_profit_center': { 'reference_sap_profit_center_id': 1, 'profit_center': 'UK1234', 'company_code': '1234', 'business_group': 'ORC' }, 'reference_signing_entity': { 'reference_signing_entity_id': 1, 'reference_payment_entity_id': 1, 'reference_sap_profit_center_id': 1, 'company_code': '1234', 'tax_entity_company_code': '1234', 'legal_name': 'Company', 'vat_number': '12341234', 'company_registration_number': '12341234', 'address': None, }, 'contract': { 'contract_id': contract_id, 'reference_signing_entity_id': 1, 'contract_type': ContractType.NEIGHBOURING_RIGHTS, }, 'abacus_event': {'abacus_event_id': 1}, 'ledger_account_contract': { 'abacus_event_id': 1, 'account_id': account_id, 'contract_id': contract_id, }, } mock_data = { 'revenue_by_recording_nr_dbt': { 'recording_id': 1, 'recording_title': 'Recording', 'artist': 'Artist', 'version': '', 'isrc': 'ABCD1234', 'account_id': account_id, 'contract_id': contract_id, 'statement_period_id': 123, 'account_payee_currency': 'GBP', 'net_share_payee_currency': 10.0, 'gross_revenue_payee_currency': 20.0, }, } insert_mock_data(mock_sql_data) with _using_mock_data(mock_data): result = fixture_client.get(f'/revenue-analysis/account/{account_id}/recording') assert result.status_code == 200 assert result.json() == { 'items': [ { 'account_id': account_id, 'account_payee_currency': 'GBP', 'artist': 'Artist', 'contract_id': None, 'gross_revenue_payee_currency': 20.0, 'isrc': 'ABCD1234', 'net_share_payee_currency': 10.0, 'recording_id': '1', 'recording_title': 'Recording', 'version': '', } ], 'pagination': {'pagination_type': 'standard', 'total_records': 1}, } def test_get_revenue_analysis_by_store(fixture_client): """Test getting revenue analysis by store.""" account_id = 24601 mock_data = { 'revenue_by_store_dbt': { 'store_id': 1, 'store_name': 'Store', 'account_id': account_id, 'artist_id': 2, 'subaccount_id': 2, 'product_id': 2, 'track_unique_id': 1234554, 'contract_id': 10001, 'statement_period_id': 123, 'activity_period_id': 1, 'country_code': 'GB', 'imprint_id': 1, 'transaction_type_id': 1, 'account_payee_currency': 'USD', 'net_revenue_payee_currency': 10.0, 'gross_revenue_payee_currency': 20.0 }, } params = { 'artist_id': 2, 'limit': 1, 'subaccount_id': 2, 'activity_period_id_start': 1, 'activity_period_id_end': 1, 'country_codes': ['GB'], 'imprint_ids': 1, 'transaction_type_ids': 1, } with _using_mock_data(mock_data): result = fixture_client.get(f'/revenue-analysis/account/{account_id}/store', params=params) assert result.status_code == 200 assert result.json() == { 'items': [ { 'account_payee_currency': 'USD', 'gross_revenue_payee_currency': 20.0, 'net_revenue_payee_currency': 10.0, 'store_id': 1, 'store_name': 'Store', 'subaccount_revenue': None } ], 'pagination': {'pagination_type': 'standard', 'total_records': 1}, 'totals': { 'gross_revenue_payee_currency': 20.0, 'net_revenue_payee_currency': 10.0, 'subaccount_revenue': None }, } def test_get_revenue_analysis_by_project(fixture_client): """Test getting revenue analysis by project.""" account_id = 24601 mock_data = { 'revenue_by_project_dbt': [ { 'project_id': 1, 'project_name': 'Project One', 'project_code': 'P-001', 'project_artist': 'Artist One', 'product_count': 3, 'account_id': account_id, 'contract_id': 10001, 'subaccount_id': 2, 'statement_period_id': 10, 'activity_period_id': 1, 'store_id': 1, 'country_code': 'GB', 'imprint_id': 1, 'transaction_type_id': 1, 'account_payee_currency': 'USD', 'net_share_payee_currency': 10.0, 'gross_revenue_payee_currency': 20.0, }, { 'project_id': 2, 'project_name': 'Project Two', 'project_code': 'P-002', 'project_artist': 'Artist Two', 'product_count': 5, 'account_id': account_id, 'contract_id': 10001, 'subaccount_id': 2, 'statement_period_id': 20, 'activity_period_id': 1, 'store_id': 2, 'country_code': 'US', 'imprint_id': 2, 'transaction_type_id': 2, 'account_payee_currency': 'USD', 'net_share_payee_currency': 15.0, 'gross_revenue_payee_currency': 30.0, }, ], } body = { 'contract_id': 10001, 'subaccount_id': 2, 'statement_period_id_start': 10, 'statement_period_id_end': 10, 'activity_period_id_start': 1, 'activity_period_id_end': 1, 'country_codes': ['GB'], 'imprint_ids': [1], 'transaction_type_ids': [1], 'store_ids': [1], 'search_term': 'Project', 'order_by': 'project_id', 'order_dir': 'asc', } with _using_mock_data(mock_data): result = fixture_client.post( f'/revenue-analysis/account/{account_id}/project', json=body) assert result.status_code == 200 assert result.json() == { 'items': [ { 'project_id': 1, 'project_name': 'Project One', 'project_code': 'P-001', 'project_artist': 'Artist One', 'product_count': 3, 'account_payee_currency': 'USD', 'net_share_payee_currency': 10.0, 'gross_revenue_payee_currency': 20.0, 'subaccount_revenue': None, } ], 'pagination': {'pagination_type': 'standard', 'total_records': 1} } def test_get_revenue_analysis_by_country(fixture_client): """Test getting revenue analysis by country.""" account_id = 24601 mock_data = { 'revenue_by_country_dbt': { 'account_id': account_id, 'account_payee_currency': 'GBP', 'artist_id': 1, 'subaccount_id': 1, 'product_id': 1234, 'track_unique_id': 1234567, 'contract_id': 10001, 'statement_period_id': 10, 'country_code': 'GB', 'net_revenue_payee_currency': 10.0, 'gross_revenue_payee_currency': 8.0, }, } with _using_mock_data(mock_data): result = fixture_client.get(f'/revenue-analysis/account/{account_id}/country') assert result.status_code == 200 assert result.json() == [ { 'account_id': account_id, 'account_payee_currency': 'GBP', 'country_code': 'GB', 'gross_revenue_payee_currency': 8.0, 'net_revenue_payee_currency': 10.0, 'subaccount_revenue': None, }, ] def test_get_revenue_analysis_by_country_filters(fixture_client): """Test getting revenue analysis by country with filters.""" account_id = 24601 mock_data = { 'revenue_by_country_dbt': [ { 'account_id': account_id, 'account_payee_currency': 'GBP', 'artist_id': 1, 'subaccount_id': 1, 'product_id': 1234, 'track_unique_id': 1234567, 'contract_id': 10001, 'statement_period_id': 10, 'country_code': 'GB', 'net_revenue_payee_currency': 10.0, 'gross_revenue_payee_currency': 8.0, }, { 'account_id': account_id, 'account_payee_currency': 'GBP', 'artist_id': 1, 'subaccount_id': 1, 'product_id': 1234, 'track_unique_id': 1234567, 'contract_id': 10001, 'statement_period_id': 10, 'country_code': 'JP', 'net_revenue_payee_currency': 10.0, 'gross_revenue_payee_currency': 8.0, }, ] } with _using_mock_data(mock_data): result = fixture_client.get( f'/revenue-analysis/account/{account_id}/country?country_codes=GB') assert result.status_code == 200 assert result.json() == [ { 'account_id': account_id, 'account_payee_currency': 'GBP', 'country_code': 'GB', 'gross_revenue_payee_currency': 8.0, 'net_revenue_payee_currency': 10.0, 'subaccount_revenue': None, }, ] def test_get_revenue_analysis_by_transaction_type(fixture_client): """Test getting revenue analysis by transaction type.""" account_id = 24601 artist_id = 1 mock_data = { 'revenue_by_transaction_type_dbt': { 'account_id': account_id, 'artist_id': artist_id, 'product_id': 1, 'track_unique_id': 1, 'account_payee_currency': 'USD', 'contract_id': 10001, 'statement_period_id': 123, 'subaccount_id': 24604, 'transaction_type_id': 1, 'transaction_type_desc': 'Money', 'transaction_type_group_name': 'Money Group', 'quantity': 10, 'net_revenue_payee_currency': 10.0, 'gross_revenue_payee_currency': 20.0, }, } with _using_mock_data(mock_data): result = fixture_client.get(f'/revenue-analysis/account/{account_id}/transaction-type') assert result.status_code == 200 assert result.json() == { 'items': [ { 'account_payee_currency': 'USD', 'gross_revenue_payee_currency': 20.0, 'net_revenue_payee_currency': 10.0, 'transaction_type_desc': 'Money', 'transaction_type_group_name': 'Money Group', 'transaction_type_id': 1, 'quantity': 10, 'subaccount_revenue': None } ], 'totals': { 'gross_revenue_payee_currency': 20.0, 'net_revenue_payee_currency': 10.0, 'subaccount_revenue': None } } def test_get_latest_revenue_by_account_id(fixture_client): """Test getting the latest revenue for a given account.""" account_id = 24601 endpoint = '/revenue-analysis/account/{account_id}/statement_period/{statement_period}' statement_period = 123 mock_sql_data = { 'account': {'account_id': account_id}, 'account_payment_term': { 'account_payment_term_id': 1, 'account_id': account_id }, 'statement_period': { 'statement_period_id': statement_period, 'statement_period_name': 'Test Period', 'statement_period_status': StatementPeriodStatus.CLOSED, }, } insert_mock_data(mock_sql_data) mock_data = { 'revenue_by_statement_period_dbt': { 'account_id': account_id, 'artist_id': 1, 'subaccount_id': 1111, 'product_id': 1234, 'track_unique_id': 1234567, 'contract_id': 1001, 'statement_period_id': statement_period, 'account_payee_currency': 'GBP', 'net_revenue_payee_currency': 80.0, 'gross_revenue_payee_currency': 100.0, }, } with _using_mock_data(mock_data): result = fixture_client.get( endpoint.format(account_id=account_id, statement_period=statement_period)) assert result.status_code == 200 assert result.json() == { 'currency_code': 'GBP', 'gross_revenue_payee_currency': 100.0, 'net_revenue_payee_currency': 80.0, 'gross_publishing_revenue_payee_currency': None, 'net_publishing_revenue_payee_currency': None, 'statement_period_id': statement_period, 'subaccount_revenue': None } def test_get_latest_revenue_by_account_id_with_publishing(fixture_client): """Test getting the latest revenue including publishing revenue.""" account_id = 24601 endpoint = '/revenue-analysis/account/{account_id}/statement_period/{statement_period}' statement_period = 123 mock_sql_data = { 'account': {'account_id': account_id}, 'account_payment_term': { 'account_payment_term_id': 1, 'account_id': account_id }, 'statement_period': { 'statement_period_id': statement_period, 'statement_period_name': 'Test Period', 'statement_period_status': StatementPeriodStatus.CLOSED, }, } insert_mock_data(mock_sql_data) mock_data = { 'revenue_by_statement_period_dbt': [ { 'account_id': account_id, 'artist_id': 1, 'subaccount_id': 1111, 'product_id': 1234, 'track_unique_id': 1234567, 'contract_id': 1001, 'statement_period_id': statement_period, 'account_payee_currency': 'GBP', 'net_revenue_payee_currency': 80.0, 'gross_revenue_payee_currency': 100.0, }, # publishing revenue row; PK columns are non-null here only because the # functional test DB is MySQL, which cannot store NULL in PK columns { 'account_id': account_id, 'artist_id': 2, 'subaccount_id': 2222, 'product_id': None, 'track_unique_id': None, 'contract_id': 1002, 'statement_period_id': statement_period, 'account_payee_currency': 'GBP', 'net_revenue_payee_currency': None, 'gross_revenue_payee_currency': None, 'net_publishing_revenue_payee_currency': 25.5, 'gross_publishing_revenue_payee_currency': 0.0, }, ], } with _using_mock_data(mock_data): result = fixture_client.get( endpoint.format(account_id=account_id, statement_period=statement_period)) assert result.status_code == 200 assert result.json() == { 'currency_code': 'GBP', 'gross_revenue_payee_currency': 100.0, 'net_revenue_payee_currency': 80.0, 'gross_publishing_revenue_payee_currency': 0.0, 'net_publishing_revenue_payee_currency': 25.5, 'statement_period_id': statement_period, 'subaccount_revenue': None } def test_get_latest_revenue_by_account_id_publishing_only(fixture_client): """Test the latest revenue for an account with only publishing revenue. Distro revenue should be returned as NULL (not coalesced to 0) so that a missing revenue stream stays distinguishable from a genuine zero. """ account_id = 24601 endpoint = '/revenue-analysis/account/{account_id}/statement_period/{statement_period}' statement_period = 123 mock_sql_data = { 'account': {'account_id': account_id}, 'account_payment_term': { 'account_payment_term_id': 1, 'account_id': account_id }, 'statement_period': { 'statement_period_id': statement_period, 'statement_period_name': 'Test Period', 'statement_period_status': StatementPeriodStatus.CLOSED, }, } insert_mock_data(mock_sql_data) mock_data = { 'revenue_by_statement_period_dbt': { 'account_id': account_id, 'artist_id': 1, 'subaccount_id': 1111, 'product_id': 1234, 'track_unique_id': 1234567, 'contract_id': 1001, 'statement_period_id': statement_period, 'account_payee_currency': 'GBP', 'net_revenue_payee_currency': None, 'gross_revenue_payee_currency': None, 'net_publishing_revenue_payee_currency': 25.5, 'gross_publishing_revenue_payee_currency': 0.0, }, } with _using_mock_data(mock_data): result = fixture_client.get( endpoint.format(account_id=account_id, statement_period=statement_period)) assert result.status_code == 200 assert result.json() == { 'currency_code': 'GBP', 'gross_revenue_payee_currency': None, 'net_revenue_payee_currency': None, 'gross_publishing_revenue_payee_currency': 0.0, 'net_publishing_revenue_payee_currency': 25.5, 'statement_period_id': statement_period, 'subaccount_revenue': None } @pytest.mark.parametrize('feature_flag_enabled,expected_gross_revenue,expected_net_revenue', [ (False, 100.0, 80.0), (True, 120.0, 90.0), ]) @patch('moneyhub.models.revenue_by_statement_period.is_feature_enabled') def test_get_revenue_account_id( mock_is_feature_enabled, feature_flag_enabled, expected_gross_revenue, expected_net_revenue, fixture_client ): """Test getting revenue for a given account.""" account_id = 24601 statement_period = 123 endpoint = '/revenue-analysis/account/{account_id}/statement_period/{statement_period}/all-time-revenue' # noqa: E501 insert_mock_data({ 'account': {'account_id': account_id}, 'reference_payment_entity': {'reference_payment_entity_id': 1}, 'reference_sap_profit_center': { 'reference_sap_profit_center_id': 1, 'profit_center': 'UK1234', 'company_code': '1234', 'business_group': 'ORC' }, 'reference_signing_entity': { 'reference_signing_entity_id': 1, 'reference_payment_entity_id': 1, 'reference_sap_profit_center_id': 1, 'company_code': '1234', 'tax_entity_company_code': '1234', 'legal_name': 'Company', 'vat_number': '12341234', 'company_registration_number': '12341234', 'address': None, }, 'contract': { 'contract_id': 1001, 'reference_signing_entity_id': 1, }, 'account_contract': {'account_id': account_id, 'contract_id': 1001}, 'statement_period': { 'statement_period_id': statement_period, 'statement_period_status': StatementPeriodStatus.CLOSED, }, }) mock_dbt_data = { 'revenue_by_statement_period_dbt': { 'account_id': account_id, 'statement_period_id': statement_period, 'contract_id': 1001, 'subaccount_id': 1111, 'product_id': 1234, 'track_unique_id': 1234567, 'account_payee_currency': 'GBP', 'gross_revenue_payee_currency': 100.0, 'net_revenue_payee_currency': 80.0, 'gross_publishing_revenue_payee_currency': 20.0, 'net_publishing_revenue_payee_currency': 10.0 }, 'account_statement_periods_dbt': { 'account_id': account_id, 'statement_period_id': statement_period, 'contract_id': 1001, 'statement_period_name': 'July 2009', 'statement_period_status': StatementPeriodStatus.CLOSED, 'currency_code': 'GBP', } } mock_is_feature_enabled.return_value = feature_flag_enabled with _using_mock_data(mock_dbt_data): result = fixture_client.get( endpoint.format(account_id=account_id, statement_period=statement_period)) assert result.status_code == 200 assert result.json() == { 'since_statement_period_id': statement_period, 'currency_code': 'GBP', 'gross_revenue_payee_currency': expected_gross_revenue, 'net_revenue_payee_currency': expected_net_revenue, 'subaccount_revenue': None } def test_get_revenue_analysis_by_track(fixture_client): """Test getting revenue analysis by track.""" account_id = 24601 mock_data = { 'revenue_by_track_dbt': { 'track_unique_id': 12341234, 'track_name': 'Best Name', 'isrc': 'IIIII1234187', 'subaccount_id': 1, 'product_id': 1, 'contract_id': 10001, 'statement_period_id': 10, 'account_id': account_id, 'account_payee_currency': 'JPY', 'mechanical_deduction_amount_payee_currency': 20.0, 'publisher_admin_fee_payee_currency': 2.0, 'net_revenue_payee_currency': 20.0, 'gross_revenue_payee_currency': 16.0, 'project_name': 'Project One', }, } with _using_mock_data(mock_data): result = fixture_client.get(f'/revenue-analysis/account/{account_id}/track') assert result.status_code == 200 assert result.json() == { 'items': [ { 'track_unique_id': 12341234, 'track_name': 'Best Name', 'isrc': 'IIIII1234187', 'account_id': account_id, 'contract_id': None, 'subaccount_id': 1, 'account_payee_currency': 'JPY', 'mechanical_deduction_amount_payee_currency': 20.00, 'publisher_admin_fee_payee_currency': 2.00, 'net_revenue_payee_currency': 20.00, 'gross_revenue_payee_currency': 16.00, 'project_name': 'Project One', 'subaccount_revenue': None } ], 'pagination': {'pagination_type': 'standard', 'total_records': 1}, } def test_get_revenue_analysis_by_artist(fixture_client): """Test getting revenue analysis by artist.""" account_id = 24601 mock_data = { 'revenue_by_artist_dbt': { 'artist_id': 12345, 'artist_name': 'The Artist Formerly Known As Test Artist', 'contract_id': 10001, 'subaccount_id': 1, 'statement_period_id': 10, 'account_id': account_id, 'account_payee_currency': 'JPY', 'mechanical_deduction_amount_payee_currency': 20.0, 'publisher_admin_fee_payee_currency': 2.0, 'net_revenue_payee_currency': 20.0, 'gross_revenue_payee_currency': 16.0 }, 'dim_subaccount': { 'subaccountid': 1111, 'commissionoverride': 0.9, 'subaccount_split_type': 'Net' } } with _using_mock_data(mock_data): result = fixture_client.get(f'/revenue-analysis/account/{account_id}/artist') assert result.status_code == 200 assert result.json() == { 'items': [ { 'artist_id': 12345, 'artist_name': 'The Artist Formerly Known As Test Artist', 'account_id': account_id, 'contract_id': None, 'account_payee_currency': 'JPY', 'mechanical_deduction_amount_payee_currency': 20.00, 'publisher_admin_fee_payee_currency': 2.00, 'publisher_admin_fee_payee_currency': 2.0, 'net_revenue_payee_currency': 20.00, 'gross_revenue_payee_currency': 16.00, 'subaccount_id': 1, 'subaccount_revenue': None } ], 'pagination': {'pagination_type': 'standard', 'total_records': 1}, } def test_get_revenue_analysis_by_subaccount(fixture_client): """Test getting revenue analysis by subaccount.""" account_id = 24601 mock_data = { 'revenue_by_subaccount_dbt': { 'subaccount_id': 112233, 'subaccount_name': 'Subaccount one', 'artist_id': 3, 'contract_id': 10001, 'statement_period_id': 10, 'account_id': account_id, 'account_payee_currency': 'JPY', 'mechanical_deduction_amount_payee_currency': 20.0, 'publisher_admin_fee_payee_currency': 2.0, 'net_revenue_payee_currency': 20.0, 'gross_revenue_payee_currency': 16.0 }, } with _using_mock_data(mock_data): result = fixture_client.get(f'/revenue-analysis/account/{account_id}/subaccount') assert result.status_code == 200 assert result.json() == { 'items': [ { 'subaccount_id': 112233, 'subaccount_name': 'Subaccount one', 'account_id': account_id, 'contract_id': None, 'account_payee_currency': 'JPY', 'mechanical_deduction_amount_payee_currency': 20.00, 'publisher_admin_fee_payee_currency': 2.00, 'net_revenue_payee_currency': 20.00, 'gross_revenue_payee_currency': 16.00, } ], 'pagination': {'pagination_type': 'standard', 'total_records': 1}, } def test_get_revenue_analysis_by_subaccount_filtered(fixture_client): """Test getting revenue analysis by subaccount filtered by parameters.""" account_id = 24601 mock_data = { 'revenue_by_subaccount_dbt': [ { 'subaccount_id': 112233, 'subaccount_name': 'Subaccount one', 'artist_id': 3, 'contract_id': 10001, 'statement_period_id': 10, 'account_id': account_id, 'account_payee_currency': 'JPY', 'mechanical_deduction_amount_payee_currency': 10.0, 'publisher_admin_fee_payee_currency': 1.0, 'net_revenue_payee_currency': 20.0, 'gross_revenue_payee_currency': 30.0, 'store_id': 1, }, { 'subaccount_id': 112233, 'subaccount_name': 'Subaccount one', 'artist_id': 3, 'contract_id': 10001, 'statement_period_id': 11, 'account_id': account_id, 'account_payee_currency': 'JPY', 'mechanical_deduction_amount_payee_currency': 10.0, 'publisher_admin_fee_payee_currency': 1.0, 'net_revenue_payee_currency': 20.0, 'gross_revenue_payee_currency': 30.0, 'store_id': 2, }, { 'subaccount_id': 112233, 'subaccount_name': 'Subaccount one', 'artist_id': 3, 'contract_id': 10001, 'statement_period_id': 12, 'account_id': account_id, 'account_payee_currency': 'JPY', 'mechanical_deduction_amount_payee_currency': 10.0, 'publisher_admin_fee_payee_currency': 1.0, 'net_revenue_payee_currency': 20.0, 'gross_revenue_payee_currency': 30.0, 'store_id': 3, }, ] } with _using_mock_data(mock_data): result = fixture_client.get( f'/revenue-analysis/account/{account_id}/subaccount?store_ids=1&store_ids=2') assert result.status_code == 200 assert result.json() == { 'items': [ { 'subaccount_id': 112233, 'subaccount_name': 'Subaccount one', 'account_id': account_id, 'contract_id': None, 'account_payee_currency': 'JPY', 'mechanical_deduction_amount_payee_currency': 20.00, 'publisher_admin_fee_payee_currency': 2.00, 'net_revenue_payee_currency': 40.00, 'gross_revenue_payee_currency': 60.00, } ], 'pagination': {'pagination_type': 'standard', 'total_records': 1}, } def test_get_revenue_analysis_by_imprint(fixture_client): """Test getting revenue analysis by imprint.""" account_id = 24601 mock_data = { 'revenue_by_imprint_dbt': { 'imprintid': 123456, 'imprint': 'TEST IMPRINT', 'contract_id': 10001, 'statement_period_id': 10, 'account_id': account_id, 'artist_id': 3, 'subaccount_id': None, 'account_payee_currency': 'JPY', 'mechanical_deduction_amount_payee_currency': 20.0, 'publisher_admin_fee_payee_currency': 2.0, 'net_share_payee_currency': 20.0, 'gross_revenue_payee_currency': 16.0 }, } with _using_mock_data(mock_data): result = fixture_client.get(f'/revenue-analysis/account/{account_id}/imprint') assert result.status_code == 200 assert result.json() == { 'items': [ { 'imprintid': 123456, 'imprint': 'TEST IMPRINT', 'account_id': account_id, 'contract_id': None, 'account_payee_currency': 'JPY', 'mechanical_deduction_amount_payee_currency': 20.0, 'publisher_admin_fee_payee_currency': 2.0, 'net_share_payee_currency': 20.0, 'gross_revenue_payee_currency': 16.00, 'subaccount_id': None, 'subaccount_revenue': None } ], 'pagination': {'pagination_type': 'standard', 'total_records': 1}, } def test_get_revenue_analysis_by_imprint_filters(fixture_client): """Test getting revenue analysis by imprint with filters.""" account_id = 24601 mock_data = { 'revenue_by_imprint_dbt': [ { 'imprintid': 123456, 'imprint': 'TEST IMPRINT', 'contract_id': 10001, 'statement_period_id': 10, 'account_id': account_id, 'artist_id': 3, 'subaccount_id': None, 'account_payee_currency': 'JPY', 'mechanical_deduction_amount_payee_currency': 20.0, 'publisher_admin_fee_payee_currency': 2.0, 'net_share_payee_currency': 20.0, 'gross_revenue_payee_currency': 16.0 }, { 'imprintid': 123457, 'imprint': 'ANOTHER IMPRINT', 'contract_id': 10001, 'statement_period_id': 10, 'account_id': account_id, 'artist_id': 3, 'subaccount_id': None, 'account_payee_currency': 'JPY', 'mechanical_deduction_amount_payee_currency': 20.0, 'publisher_admin_fee_payee_currency': 2.0, 'net_share_payee_currency': 20.0, 'gross_revenue_payee_currency': 16.0 }, ] } with _using_mock_data(mock_data): result = fixture_client.get( f'/revenue-analysis/account/{account_id}/imprint', params={ 'imprint_ids': [123456] } ) assert result.status_code == 200 assert result.json() == { 'items': [ { 'imprintid': 123456, 'imprint': 'TEST IMPRINT', 'account_id': account_id, 'contract_id': None, 'account_payee_currency': 'JPY', 'mechanical_deduction_amount_payee_currency': 20.0, 'publisher_admin_fee_payee_currency': 2.0, 'net_share_payee_currency': 20.0, 'gross_revenue_payee_currency': 16.00, 'subaccount_id': None, 'subaccount_revenue': None } ], 'pagination': {'pagination_type': 'standard', 'total_records': 1}, } def test_get_revenue_analysis_by_activity_month(fixture_client): """Test getting revenue analysis by activity month.""" account_id = 24601 mock_data = { 'revenue_by_activity_month_dbt': [ { 'activity_period_id': 8, 'activity_month_name': 'June 2024', 'artist_id': 1, 'subaccount_id': 1111, 'product_id': 1234, 'track_unique_id': 1234567, 'contract_id': 10001, 'statement_period_id': 10, 'account_id': account_id, 'account_payee_currency': 'JPY', 'net_share_payee_currency': 20.0, 'gross_revenue_payee_currency': 16.0, 'net_publishing_revenue_payee_currency': None, 'gross_publishing_revenue_payee_currency': None, }, { 'activity_period_id': 9, 'activity_month_name': 'July 2024', 'artist_id': 1, 'subaccount_id': 1111, 'product_id': 1234, 'track_unique_id': 1234567, 'contract_id': 10001, 'statement_period_id': 10, 'account_id': account_id, 'account_payee_currency': 'JPY', 'net_share_payee_currency': 30.0, 'gross_revenue_payee_currency': 20.0, 'net_publishing_revenue_payee_currency': 10.0, 'gross_publishing_revenue_payee_currency': 20.0, }, ], 'dim_subaccount': { 'subaccountid': 1111, 'commissionoverride': 0.9, 'subaccount_split_type': 'Net' } } with _using_mock_data(mock_data): result = fixture_client.get( f'/revenue-analysis/account/' f'{account_id}/activity-month?is_subaccount=True&subaccount_id=1111') assert result.status_code == 200 assert result.json() == { 'items': [ { 'activity_period_id': 9, 'activity_month_name': 'July 2024', 'account_payee_currency': 'JPY', 'net_share_payee_currency': 30.0, 'gross_revenue_payee_currency': 20.00, 'net_publishing_revenue_payee_currency': 10.0, 'gross_publishing_revenue_payee_currency': 20.0, 'subaccount_revenue': 27 }, { 'activity_period_id': 8, 'activity_month_name': 'June 2024', 'account_payee_currency': 'JPY', 'net_share_payee_currency': 20.0, 'gross_revenue_payee_currency': 16.00, 'net_publishing_revenue_payee_currency': None, 'gross_publishing_revenue_payee_currency': None, 'subaccount_revenue': 18 }, ], 'pagination': {'pagination_type': 'standard', 'total_records': 2}, } def test_get_revenue_analysis_by_statement_period(fixture_client): """Test getting revenue analysis by statement period.""" account_id = 24601 mock_data = { 'revenue_by_statement_period_dbt': [ { 'account_id': account_id, 'artist_id': 1, 'contract_id': 10001, 'statement_period_id': 10, 'statement_period_name': 'January 2024', 'statement_period_status': StatementPeriodStatus.CLOSED, 'subaccount_id': 1, 'product_id': 1234, 'track_unique_id': 1234567, 'account_payee_currency': 'GBP', 'net_revenue_payee_currency': 80.0, 'gross_revenue_payee_currency': 100.0, 'net_publishing_revenue_payee_currency': 50.0, 'gross_publishing_revenue_payee_currency': 60.0, }, { 'account_id': account_id, 'artist_id': 1, 'contract_id': 10001, 'statement_period_id': 11, 'statement_period_name': 'February 2024', 'statement_period_status': StatementPeriodStatus.CLOSED, 'subaccount_id': 1, 'product_id': 1234, 'track_unique_id': 1234567, 'account_payee_currency': 'GBP', 'net_revenue_payee_currency': 160.0, 'gross_revenue_payee_currency': 200.0, 'net_publishing_revenue_payee_currency': 100.0, 'gross_publishing_revenue_payee_currency': 120.0, }, ], } with _using_mock_data(mock_data): result = fixture_client.get( f'/revenue-analysis/account/{account_id}/statement-period' '?statement_period_id_start=10&statement_period_id_end=11') assert result.status_code == 200 assert result.json() == [ { 'statement_period_id': 10, 'account_payee_currency': 'GBP', 'net_revenue_payee_currency': 80.0, 'gross_revenue_payee_currency': 100.0, 'net_publishing_revenue_payee_currency': 50.0, 'gross_publishing_revenue_payee_currency': 60.0, 'subaccount_revenue': None, }, { 'statement_period_id': 11, 'account_payee_currency': 'GBP', 'net_revenue_payee_currency': 160.0, 'gross_revenue_payee_currency': 200.0, 'net_publishing_revenue_payee_currency': 100.0, 'gross_publishing_revenue_payee_currency': 120.0, 'subaccount_revenue': None, }, ] def test_get_revenue_analysis_by_statement_period_subaccount(fixture_client): """Test getting revenue analysis by statement period for a subaccount.""" account_id = 24601 subaccount_id = 1111 mock_data = { 'revenue_by_statement_period_dbt': [ { 'account_id': account_id, 'artist_id': 1, 'contract_id': 10001, 'statement_period_id': 10, 'statement_period_name': 'January 2024', 'statement_period_status': StatementPeriodStatus.CLOSED, 'subaccount_id': subaccount_id, 'product_id': 1234, 'track_unique_id': 1234567, 'account_payee_currency': 'GBP', 'net_revenue_payee_currency': 80.0, 'gross_revenue_payee_currency': 100.0, 'net_publishing_revenue_payee_currency': 50.0, 'gross_publishing_revenue_payee_currency': 60.0, }, ], 'dim_subaccount': { 'subaccountid': subaccount_id, 'commissionoverride': 0.9, 'subaccount_split_type': 'Net', }, } with _using_mock_data(mock_data): result = fixture_client.get( f'/revenue-analysis/account/{account_id}/statement-period' f'?statement_period_id_start=10&statement_period_id_end=10' f'&subaccount_id={subaccount_id}&is_subaccount=True') assert result.status_code == 200 assert result.json() == [ { 'statement_period_id': 10, 'account_payee_currency': 'GBP', 'net_revenue_payee_currency': 80.0, 'gross_revenue_payee_currency': 100.0, 'net_publishing_revenue_payee_currency': 50.0, 'gross_publishing_revenue_payee_currency': 60.0, 'subaccount_revenue': 72.0, }, ]