from unittest import mock import freezegun import pytest from anydi import Container from faker import Faker from fansifter_common.auth.identity import Identity from fansifter_common.utils import timezone from dmp.adapters.aws.location import Location from dmp.audiences.enums import AudienceTarget from dmp.audiences.exceptions import AudienceUniqueNameError from dmp.audiences.filters import ( AudienceFilters, CityFilter, CrmCampaignFilter, EmailCampaignAction, EmailCampaignsFilter, Operator, SongwhipCampaignInFilter, SongwhipPresavePageInFilter, ) from dmp.audiences.handlers import UpdateAudienceHandler, UpdateAudienceRequest from dmp.audiences.models import Audience, AudienceFanDataList, AudienceSnapshot from dmp.crm_campaigns.models import CrmCampaignIdFanDbt from dmp.email_campaigns.models import EmailAnalyticsByCampaignFanDbt from dmp.fandata.models import ( AudienceFiltersAdCampaignDbt, GlobalAudienceFiltersEmailCampaignDbt, ) from dmp.locations.models import City from dmp.rosters.enums import FanDataListType from dmp.rosters.exceptions import MainRepArtistOnlyAllowedError from dmp.rosters.models import ArtistRosterLocalRep, ArtistRosterMainRep from dmp.rosters.services import GlobalFanDataAccessService from dmp.songwhip.models import SongwhipCustomPageFanDbt, SongwhipPresavePageFanDbt from tests.unit.faker import FakerTyped from tests.unit.types import ( CreateModel, CreateReportingModel, CreateReportingModelBatch, ) class TestUpdateAudienceHandler: @pytest.mark.db def test_update_audience( self, handler: UpdateAudienceHandler, identity: Identity, create_model: CreateModel, fake: FakerTyped, ) -> None: name = fake.name() target = AudienceTarget.ADS filters = AudienceFilters.model_construct(countries=["EE", "US"]) audience = create_model(Audience) snapshot = create_model(AudienceSnapshot, audience=audience) result = handler.handle( UpdateAudienceRequest( identity=identity, audience_id=snapshot.audience_id, name=name, target=target, filters=filters, ) ) assert result.name == name assert result.target == target assert result.filters == filters @pytest.mark.db def test_update_audience_unique_name( self, handler: UpdateAudienceHandler, identity: Identity, create_model: CreateModel, ) -> None: audience_1 = create_model(Audience) audience_2 = create_model( Audience, vendor_id=audience_1.vendor_id, subaccount_id=audience_1.subaccount_id, ) with pytest.raises(AudienceUniqueNameError): handler.handle( UpdateAudienceRequest( identity=identity, audience_id=audience_2.id, name=audience_1.name, target=AudienceTarget.ADS, filters=AudienceFilters.model_construct(countries=["EE"]), ) ) @pytest.mark.db def test_update_audience_with_events( self, handler: UpdateAudienceHandler, identity: Identity, create_model: CreateModel, create_reporting_model_batch: CreateReportingModelBatch, fake: FakerTyped, ) -> None: size = 10 vendor_id = fake.integer() subaccount_id = fake.integer() global_participant_id = fake.uuid4_string() target = AudienceTarget.ADS create_reporting_model_batch( AudienceFiltersAdCampaignDbt, size=size, vendor_id=vendor_id, subaccount_id=subaccount_id, global_participant_id=global_participant_id, ) audience = create_model( Audience, vendor_id=vendor_id, subaccount_id=subaccount_id, fandata_lists=[ AudienceFanDataList( list_id=global_participant_id, type=FanDataListType.ARTIST, ), ], ) snapshot = create_model(AudienceSnapshot, audience=audience) refreshed_at = timezone.now() with freezegun.freeze_time(refreshed_at): audience = handler.handle( UpdateAudienceRequest( identity=identity, audience_id=snapshot.audience_id, name=fake.name(), target=target, filters=AudienceFilters.model_construct(), ) ) assert audience.fan_count == 10 assert audience.refreshed_at == refreshed_at assert audience.refreshed_by == identity.id @pytest.mark.db def test_update_audience_with_songwhip_presave_page_ids_filter_include( self, handler: UpdateAudienceHandler, identity: Identity, create_model: CreateModel, create_reporting_model_batch: CreateReportingModelBatch, create_reporting_model: CreateReportingModel, fake: FakerTyped, ) -> None: size = 10 vendor_id = fake.integer() subaccount_id = fake.integer() global_participant_id = fake.uuid4_string() target = AudienceTarget.ADS audience_filters_dbt = create_reporting_model_batch( AudienceFiltersAdCampaignDbt, size=size, vendor_id=vendor_id, subaccount_id=subaccount_id, global_participant_id=global_participant_id, ) songwhip_presave_page_fan_dbt = create_reporting_model( SongwhipPresavePageFanDbt, vendor_id=vendor_id, subaccount_id=subaccount_id, global_participant_id=global_participant_id, fan_id=audience_filters_dbt[0].fan_id, ) audience = create_model( Audience, vendor_id=vendor_id, subaccount_id=subaccount_id, fandata_lists=[ AudienceFanDataList( list_id=global_participant_id, type=FanDataListType.ARTIST, ), ], ) snapshot = create_model(AudienceSnapshot, audience=audience) refreshed_at = timezone.now() with freezegun.freeze_time(refreshed_at): audience = handler.handle( UpdateAudienceRequest( identity=identity, audience_id=snapshot.audience_id, name=fake.name(), target=target, filters=AudienceFilters.model_construct( songwhipPresavePageIds=SongwhipPresavePageInFilter( value=[songwhip_presave_page_fan_dbt.id], operator=Operator.INCLUDE, ) ), ) ) assert audience.fan_count == 1 assert audience.refreshed_at == refreshed_at assert audience.refreshed_by == identity.id @pytest.mark.db def test_update_audience_with_songwhip_presave_page_ids_filter_exclude( self, handler: UpdateAudienceHandler, identity: Identity, create_model: CreateModel, create_reporting_model_batch: CreateReportingModelBatch, create_reporting_model: CreateReportingModel, fake: FakerTyped, ) -> None: size = 10 vendor_id = fake.integer() subaccount_id = fake.integer() global_participant_id = fake.uuid4_string() target = AudienceTarget.ADS audience_filters_dbt = create_reporting_model_batch( AudienceFiltersAdCampaignDbt, size=size, vendor_id=vendor_id, subaccount_id=subaccount_id, global_participant_id=global_participant_id, ) songwhip_presave_page_fan_dbt = create_reporting_model( SongwhipPresavePageFanDbt, vendor_id=vendor_id, subaccount_id=subaccount_id, global_participant_id=global_participant_id, fan_id=audience_filters_dbt[0].fan_id, ) audience = create_model( Audience, vendor_id=vendor_id, subaccount_id=subaccount_id, fandata_lists=[ AudienceFanDataList( list_id=global_participant_id, type=FanDataListType.ARTIST, ), ], ) snapshot = create_model(AudienceSnapshot, audience=audience) refreshed_at = timezone.now() with freezegun.freeze_time(refreshed_at): audience = handler.handle( UpdateAudienceRequest( identity=identity, audience_id=snapshot.audience_id, name=fake.name(), target=target, filters=AudienceFilters.model_construct( songwhipPresavePageIds=SongwhipPresavePageInFilter( value=[songwhip_presave_page_fan_dbt.id], operator=Operator.EXCLUDE, ) ), ) ) assert audience.fan_count == 9 assert audience.refreshed_at == refreshed_at assert audience.refreshed_by == identity.id @pytest.mark.db def test_update_audience_with_songwhip_campaign_ids_filter_include_presave( self, handler: UpdateAudienceHandler, identity: Identity, create_model: CreateModel, create_reporting_model_batch: CreateReportingModelBatch, create_reporting_model: CreateReportingModel, fake: FakerTyped, ) -> None: size = 10 vendor_id = fake.integer() subaccount_id = fake.integer() global_participant_id = fake.uuid4_string() target = AudienceTarget.ADS audience_filters_dbt = create_reporting_model_batch( AudienceFiltersAdCampaignDbt, size=size, vendor_id=vendor_id, subaccount_id=subaccount_id, global_participant_id=global_participant_id, ) songwhip_presave_page_fan_dbt = create_reporting_model( SongwhipPresavePageFanDbt, vendor_id=vendor_id, subaccount_id=subaccount_id, global_participant_id=global_participant_id, fan_id=audience_filters_dbt[0].fan_id, ) audience = create_model( Audience, vendor_id=vendor_id, subaccount_id=subaccount_id, fandata_lists=[ AudienceFanDataList( list_id=global_participant_id, type=FanDataListType.ARTIST, ), ], ) snapshot = create_model(AudienceSnapshot, audience=audience) refreshed_at = timezone.now() with freezegun.freeze_time(refreshed_at): audience = handler.handle( UpdateAudienceRequest( identity=identity, audience_id=snapshot.audience_id, name=fake.name(), target=target, filters=AudienceFilters.model_construct( songwhipCampaignIds=SongwhipCampaignInFilter( value=[songwhip_presave_page_fan_dbt.id], operator=Operator.INCLUDE, ) ), ) ) assert audience.fan_count == 1 assert audience.refreshed_at == refreshed_at assert audience.refreshed_by == identity.id @pytest.mark.db def test_update_audience_with_songwhip_campaign_ids_filter_include_custom_page( self, handler: UpdateAudienceHandler, identity: Identity, create_model: CreateModel, create_reporting_model_batch: CreateReportingModelBatch, create_reporting_model: CreateReportingModel, fake: FakerTyped, ) -> None: size = 10 vendor_id = fake.integer() subaccount_id = fake.integer() global_participant_id = fake.uuid4_string() target = AudienceTarget.ADS audience_filters_dbt = create_reporting_model_batch( AudienceFiltersAdCampaignDbt, size=size, vendor_id=vendor_id, subaccount_id=subaccount_id, global_participant_id=global_participant_id, ) songwhip_custom_page_fan_dbt = create_reporting_model( SongwhipCustomPageFanDbt, vendor_id=vendor_id, subaccount_id=subaccount_id, global_participant_id=global_participant_id, fan_id=audience_filters_dbt[0].fan_id, ) audience = create_model( Audience, vendor_id=vendor_id, subaccount_id=subaccount_id, fandata_lists=[ AudienceFanDataList( list_id=global_participant_id, type=FanDataListType.ARTIST, ), ], ) snapshot = create_model(AudienceSnapshot, audience=audience) refreshed_at = timezone.now() with freezegun.freeze_time(refreshed_at): audience = handler.handle( UpdateAudienceRequest( identity=identity, audience_id=snapshot.audience_id, name=fake.name(), target=target, filters=AudienceFilters.model_construct( songwhipCampaignIds=SongwhipCampaignInFilter( value=[songwhip_custom_page_fan_dbt.id], operator=Operator.INCLUDE, ) ), ) ) assert audience.fan_count == 1 assert audience.refreshed_at == refreshed_at assert audience.refreshed_by == identity.id @pytest.mark.db def test_update_audience_with_songwhip_campaign_ids_filter_exclude( self, handler: UpdateAudienceHandler, identity: Identity, create_model: CreateModel, create_reporting_model_batch: CreateReportingModelBatch, create_reporting_model: CreateReportingModel, fake: FakerTyped, ) -> None: size = 10 vendor_id = fake.integer() subaccount_id = fake.integer() global_participant_id = fake.uuid4_string() target = AudienceTarget.ADS audience_filters_dbt = create_reporting_model_batch( AudienceFiltersAdCampaignDbt, size=size, vendor_id=vendor_id, subaccount_id=subaccount_id, global_participant_id=global_participant_id, ) songwhip_presave_page_fan_dbt = create_reporting_model( SongwhipPresavePageFanDbt, vendor_id=vendor_id, subaccount_id=subaccount_id, global_participant_id=global_participant_id, fan_id=audience_filters_dbt[0].fan_id, ) audience = create_model( Audience, vendor_id=vendor_id, subaccount_id=subaccount_id, fandata_lists=[ AudienceFanDataList( list_id=global_participant_id, type=FanDataListType.ARTIST, ), ], ) snapshot = create_model(AudienceSnapshot, audience=audience) refreshed_at = timezone.now() with freezegun.freeze_time(refreshed_at): audience = handler.handle( UpdateAudienceRequest( identity=identity, audience_id=snapshot.audience_id, name=fake.name(), target=target, filters=AudienceFilters.model_construct( songwhipCampaignIds=SongwhipCampaignInFilter( value=[songwhip_presave_page_fan_dbt.id], operator=Operator.EXCLUDE, ) ), ) ) assert audience.fan_count == 9 assert audience.refreshed_at == refreshed_at assert audience.refreshed_by == identity.id @pytest.mark.db @pytest.mark.parametrize("action", list(EmailCampaignAction)) def test_update_audience_with_email_campaigns_filter_include( self, handler: UpdateAudienceHandler, identity: Identity, create_model: CreateModel, create_reporting_model_batch: CreateReportingModelBatch, create_reporting_model: CreateReportingModel, fake: FakerTyped, action: EmailCampaignAction, ) -> None: size = 10 vendor_id = fake.integer() subaccount_id = fake.integer() global_participant_id = fake.uuid4_string() target = AudienceTarget.ADS campaign_id_1 = fake.uuid4_string() campaign_id_2 = fake.uuid4_string() audience_filters_dbt = create_reporting_model_batch( AudienceFiltersAdCampaignDbt, size=size, vendor_id=vendor_id, subaccount_id=subaccount_id, global_participant_id=global_participant_id, ) create_reporting_model( EmailAnalyticsByCampaignFanDbt, campaign_id=campaign_id_1, fan_id=audience_filters_dbt[0].fan_id, delivered=True, opened=True, clicked=True, ) create_reporting_model( EmailAnalyticsByCampaignFanDbt, campaign_id=campaign_id_2, fan_id=audience_filters_dbt[1].fan_id, delivered=True, opened=True, clicked=True, ) audience = create_model( Audience, vendor_id=vendor_id, subaccount_id=subaccount_id, fandata_lists=[ AudienceFanDataList( list_id=global_participant_id, type=FanDataListType.ARTIST, ), ], ) snapshot = create_model(AudienceSnapshot, audience=audience) audience = handler.handle( UpdateAudienceRequest( identity=identity, audience_id=snapshot.audience_id, name=fake.name(), target=target, filters=AudienceFilters.model_construct( emailCampaigns=EmailCampaignsFilter( value=[campaign_id_1, campaign_id_2], operator=Operator.INCLUDE, action=action, ) ), ) ) assert audience.fan_count == 2 @pytest.mark.db def test_update_audience_with_email_campaigns_filter_not_delivered( self, handler: UpdateAudienceHandler, identity: Identity, create_model: CreateModel, create_reporting_model_batch: CreateReportingModelBatch, create_reporting_model: CreateReportingModel, fake: FakerTyped, ) -> None: size = 10 vendor_id = fake.integer() subaccount_id = fake.integer() global_participant_id = fake.uuid4_string() target = AudienceTarget.ADS campaign_id_1 = fake.uuid4_string() campaign_id_2 = fake.uuid4_string() audience_filters_dbt = create_reporting_model_batch( AudienceFiltersAdCampaignDbt, size=size, vendor_id=vendor_id, subaccount_id=subaccount_id, global_participant_id=global_participant_id, ) create_reporting_model( EmailAnalyticsByCampaignFanDbt, campaign_id=campaign_id_1, fan_id=audience_filters_dbt[0].fan_id, delivered=False, opened=False, clicked=False, ) create_reporting_model( EmailAnalyticsByCampaignFanDbt, campaign_id=campaign_id_2, fan_id=audience_filters_dbt[1].fan_id, delivered=True, opened=False, clicked=False, ) create_reporting_model( EmailAnalyticsByCampaignFanDbt, campaign_id=campaign_id_1, fan_id=audience_filters_dbt[2].fan_id, delivered=True, opened=False, clicked=False, ) audience = create_model( Audience, vendor_id=vendor_id, subaccount_id=subaccount_id, fandata_lists=[ AudienceFanDataList( list_id=global_participant_id, type=FanDataListType.ARTIST, ), ], ) snapshot = create_model(AudienceSnapshot, audience=audience) audience = handler.handle( UpdateAudienceRequest( identity=identity, audience_id=snapshot.audience_id, name=fake.name(), target=target, filters=AudienceFilters.model_construct( emailCampaigns=EmailCampaignsFilter( value=[campaign_id_1, campaign_id_2], operator=Operator.EXCLUDE, action=EmailCampaignAction.DELIVERED, ) ), ) ) assert audience.fan_count == 8 @pytest.mark.db @pytest.mark.parametrize( "action", [EmailCampaignAction.OPENED, EmailCampaignAction.CLICKED] ) def test_update_audience_with_email_campaigns_filter_not_opened_and_not_clicked( self, handler: UpdateAudienceHandler, identity: Identity, create_model: CreateModel, create_reporting_model_batch: CreateReportingModelBatch, create_reporting_model: CreateReportingModel, fake: FakerTyped, action: EmailCampaignAction, ) -> None: size = 10 vendor_id = fake.integer() subaccount_id = fake.integer() global_participant_id = fake.uuid4_string() target = AudienceTarget.ADS campaign_id_1 = fake.uuid4_string() campaign_id_2 = fake.uuid4_string() audience_filters_dbt = create_reporting_model_batch( AudienceFiltersAdCampaignDbt, size=size, vendor_id=vendor_id, subaccount_id=subaccount_id, global_participant_id=global_participant_id, ) create_reporting_model( EmailAnalyticsByCampaignFanDbt, campaign_id=campaign_id_1, fan_id=audience_filters_dbt[0].fan_id, delivered=False, opened=False, clicked=False, ) create_reporting_model( EmailAnalyticsByCampaignFanDbt, campaign_id=campaign_id_2, fan_id=audience_filters_dbt[1].fan_id, delivered=True, opened=False, clicked=False, ) create_reporting_model( EmailAnalyticsByCampaignFanDbt, campaign_id=campaign_id_1, fan_id=audience_filters_dbt[2].fan_id, delivered=True, opened=False, clicked=False, ) audience = create_model( Audience, vendor_id=vendor_id, subaccount_id=subaccount_id, fandata_lists=[ AudienceFanDataList( list_id=global_participant_id, type=FanDataListType.ARTIST, ), ], ) snapshot = create_model(AudienceSnapshot, audience=audience) audience = handler.handle( UpdateAudienceRequest( identity=identity, audience_id=snapshot.audience_id, name=fake.name(), target=target, filters=AudienceFilters.model_construct( emailCampaigns=EmailCampaignsFilter( value=[campaign_id_1, campaign_id_2], operator=Operator.EXCLUDE, action=action, ) ), ) ) assert audience.fan_count == 2 @pytest.mark.db def test_update_audience_with_city_filter( self, handler: UpdateAudienceHandler, create_model: CreateModel, create_reporting_model: CreateReportingModel, identity: Identity, fake: FakerTyped, location_client_mock: mock.MagicMock, ) -> None: vendor_id = fake.integer() subaccount_id = fake.integer() global_participant_id = fake.uuid4_string() audience = create_model( Audience, vendor_id=vendor_id, subaccount_id=subaccount_id, fandata_lists=[ AudienceFanDataList( list_id=global_participant_id, type=FanDataListType.ARTIST, ), ], ) # New York City in New York State new_york = create_reporting_model( City, country_code2="US", name="New York City", latitude=40, longitude=-74, ) # New York in Minnesota create_reporting_model( City, country_code2="US", name="New York", latitude=46.51802, longitude=-95.37615, ) location_client_mock.get_location.return_value = Location.model_validate( { "PlaceId": "test", "Title": "New York City, United States", "Address": { "Country": {"Code2": "US", "Name": "United States"}, "Locality": "New York", }, "Position": [-74, 40], "MapView": [-74.1, 40.1, -73.9, 39.9], } ) audience = handler.handle( UpdateAudienceRequest( identity=identity, audience_id=audience.id, name=fake.name(), target=AudienceTarget.ADS, filters=AudienceFilters.model_construct( cities=[CityFilter.model_construct(place_id="test")] ), ) ) assert audience.filters.cities assert audience.filters.cities[0].is_clean assert audience.filters.cities[0].place_id == "test" assert audience.filters.cities[0].title == "New York City, United States" assert audience.filters.cities[0].country_iso2 == new_york.country_code2 assert audience.filters.cities[0].city_id == new_york.id assert audience.filters.cities[0].latitude == new_york.latitude assert audience.filters.cities[0].longitude == new_york.longitude @pytest.mark.db def test_update_audience_is_global( self, container: Container, handler: UpdateAudienceHandler, identity: Identity, create_model: CreateModel, create_reporting_model: CreateReportingModel, faker: Faker, ) -> None: global_participant_id = faker.uuid4() audience = create_model( Audience, fandata_lists=[ AudienceFanDataList( list_id=global_participant_id, type=FanDataListType.ARTIST, ), ], fan_count=0, target=AudienceTarget.ADS, ) create_reporting_model( ArtistRosterMainRep, vendor_id=audience.vendor_id, subaccount_id=audience.subaccount_id, global_participant_id=global_participant_id, ) create_reporting_model( GlobalAudienceFiltersEmailCampaignDbt, global_participant_id=global_participant_id, ) global_fandata_access_service_mock = mock.MagicMock( spec=GlobalFanDataAccessService, is_enabled_for_any_vendor=mock.MagicMock(return_value=True), ) with container.override( GlobalFanDataAccessService, instance=global_fandata_access_service_mock, ): audience = handler.handle( UpdateAudienceRequest( identity=identity, audience_id=audience.id, name=audience.name, target=AudienceTarget.EMAIL, filters=AudienceFilters.model_construct(), ) ) assert audience.fan_count == 1 assert audience.target == AudienceTarget.EMAIL @pytest.mark.db def test_update_audience_local_rep_is_not_allowed( self, container: Container, handler: UpdateAudienceHandler, identity: Identity, create_model: CreateModel, create_reporting_model: CreateReportingModel, faker: Faker, ) -> None: global_participant_id = faker.uuid4() audience = create_model( Audience, fandata_lists=[ AudienceFanDataList( list_id=global_participant_id, type=FanDataListType.ARTIST, ), ], fan_count=0, target=AudienceTarget.ADS, ) create_reporting_model( ArtistRosterLocalRep, vendor_id=audience.vendor_id, subaccount_id=audience.subaccount_id, global_participant_id=global_participant_id, ) create_reporting_model( GlobalAudienceFiltersEmailCampaignDbt, global_participant_id=global_participant_id, ) global_fandata_access_service_mock = mock.MagicMock( spec=GlobalFanDataAccessService, is_enabled_for_any_vendor=mock.MagicMock(return_value=True), ) with ( container.override( GlobalFanDataAccessService, instance=global_fandata_access_service_mock ), pytest.raises(MainRepArtistOnlyAllowedError) as exc_info, ): handler.handle( UpdateAudienceRequest( identity=identity, audience_id=audience.id, name=audience.name, target=AudienceTarget.EMAIL, filters=AudienceFilters.model_construct(), ) ) assert exc_info.value.global_participant_id == global_participant_id @pytest.mark.db def test_update_audience_with_crm_campaigns_filter_include( self, handler: UpdateAudienceHandler, identity: Identity, create_model: CreateModel, create_reporting_model_batch: CreateReportingModelBatch, create_reporting_model: CreateReportingModel, fake: FakerTyped, ) -> None: size = 10 vendor_id = fake.integer() subaccount_id = fake.integer() global_participant_id = fake.uuid4_string() custom_list_id = None target = AudienceTarget.ADS audience_filters_dbt = create_reporting_model_batch( AudienceFiltersAdCampaignDbt, size=size, vendor_id=vendor_id, subaccount_id=subaccount_id, global_participant_id=global_participant_id, ) crm_campaign_id_fan_dbt = create_reporting_model( CrmCampaignIdFanDbt, vendor_id=vendor_id, subaccount_id=subaccount_id, global_participant_id=global_participant_id, custom_list_id=custom_list_id, fan_id=audience_filters_dbt[0].fan_id, ) audience = create_model( Audience, vendor_id=vendor_id, subaccount_id=subaccount_id, fandata_lists=[ AudienceFanDataList( list_id=global_participant_id, type=FanDataListType.ARTIST, ), ], ) snapshot = create_model(AudienceSnapshot, audience=audience) refreshed_at = timezone.now() with freezegun.freeze_time(refreshed_at): audience = handler.handle( UpdateAudienceRequest( identity=identity, audience_id=snapshot.audience_id, name=fake.name(), target=target, filters=AudienceFilters.model_construct( crm_campaigns=CrmCampaignFilter( value=[crm_campaign_id_fan_dbt.id], operator=Operator.INCLUDE, ) ), ) ) assert audience.fan_count == 1 assert audience.refreshed_at == refreshed_at assert audience.refreshed_by == identity.id @pytest.mark.db def test_update_audience_with_crm_campaigns_filter_exclude( self, handler: UpdateAudienceHandler, identity: Identity, create_model: CreateModel, create_reporting_model_batch: CreateReportingModelBatch, create_reporting_model: CreateReportingModel, fake: FakerTyped, ) -> None: size = 10 vendor_id = fake.integer() subaccount_id = fake.integer() global_participant_id = fake.uuid4_string() custom_list_id = None target = AudienceTarget.ADS audience_filters_dbt = create_reporting_model_batch( AudienceFiltersAdCampaignDbt, size=size, vendor_id=vendor_id, subaccount_id=subaccount_id, global_participant_id=global_participant_id, ) crm_campaign_id_fan_dbt = create_reporting_model( CrmCampaignIdFanDbt, vendor_id=vendor_id, subaccount_id=subaccount_id, global_participant_id=global_participant_id, custom_list_id=custom_list_id, fan_id=audience_filters_dbt[0].fan_id, ) audience = create_model( Audience, vendor_id=vendor_id, subaccount_id=subaccount_id, fandata_lists=[ AudienceFanDataList( list_id=global_participant_id, type=FanDataListType.ARTIST, ), ], ) snapshot = create_model(AudienceSnapshot, audience=audience) refreshed_at = timezone.now() with freezegun.freeze_time(refreshed_at): audience = handler.handle( UpdateAudienceRequest( identity=identity, audience_id=snapshot.audience_id, name=fake.name(), target=target, filters=AudienceFilters.model_construct( crm_campaigns=CrmCampaignFilter( value=[crm_campaign_id_fan_dbt.id], operator=Operator.EXCLUDE, ) ), ) ) assert audience.fan_count == 9 assert audience.refreshed_at == refreshed_at assert audience.refreshed_by == identity.id @pytest.mark.db def test_update_audience_with_exclude_countries( self, handler: UpdateAudienceHandler, identity: Identity, create_model: CreateModel, create_reporting_model_batch: CreateReportingModelBatch, fake: FakerTyped, ) -> None: vendor_id = fake.integer() subaccount_id = fake.integer() global_participant_id = fake.uuid4_string() country_1 = "US" country_2 = "GB" country_3 = "EE" country_4 = None create_reporting_model_batch( AudienceFiltersAdCampaignDbt, size=3, vendor_id=vendor_id, subaccount_id=subaccount_id, global_participant_id=global_participant_id, country_iso2=country_1, ) create_reporting_model_batch( AudienceFiltersAdCampaignDbt, size=2, vendor_id=vendor_id, subaccount_id=subaccount_id, global_participant_id=global_participant_id, country_iso2=country_2, ) create_reporting_model_batch( AudienceFiltersAdCampaignDbt, size=4, vendor_id=vendor_id, subaccount_id=subaccount_id, global_participant_id=global_participant_id, country_iso2=country_3, ) create_reporting_model_batch( AudienceFiltersAdCampaignDbt, size=10, vendor_id=vendor_id, subaccount_id=subaccount_id, global_participant_id=global_participant_id, country_iso2=country_4, ) audience = create_model( Audience, vendor_id=vendor_id, subaccount_id=subaccount_id, fandata_lists=[ AudienceFanDataList( list_id=global_participant_id, type=FanDataListType.ARTIST, ), ], ) snapshot = create_model(AudienceSnapshot, audience=audience) result = handler.handle( UpdateAudienceRequest( identity=identity, audience_id=snapshot.audience_id, name=fake.name(), target=AudienceTarget.ADS, filters=AudienceFilters.model_construct( countries=[country_1, country_2], exclude_countries=True, ), ) ) assert result.fan_count == 14 assert result.filters.countries == [country_1, country_2] assert result.filters.exclude_countries is True