import decimal from datetime import UTC, datetime from unittest import mock import pytest from anydi import Container from dirty_equals import IsList, IsPartialDataclass from ows_text_campaigns.campaigns.handlers import ( GetCampaignSendTimezonesHandler, GetCampaignSendTimezonesRequest, ) from ows_text_campaigns.campaigns.models import Campaign from ows_text_campaigns.campaigns.repositories import CampaignRepository from ows_text_campaigns.campaigns.types import SendTimezone, TimezoneAdjustment from tests.unit.types import CreateModel class TestGetCampaignSendTimezonesHandler: @pytest.mark.db def test_get_campaign_send_timezones( self, handler: GetCampaignSendTimezonesHandler, container: Container, create_model: CreateModel, identity_id: str, ) -> None: campaign = create_model( Campaign, timezone_adjustments=[ TimezoneAdjustment.model_construct( country_code="US", iana_tz_id="America/Los_Angeles", ) ], ) send_at = datetime(2025, 1, 15, 12, 0, 0, tzinfo=UTC) # Create mock timezones for different countries timezones = [ SendTimezone( country_code="US", state_provinces=["CA", "NY"], iana_tz_id="America/Los_Angeles", utc_offset_std=decimal.Decimal(0), quiet_hours_min="08:00", quiet_hours_max="21:00", next_safe_time=datetime(2025, 1, 15, 16, 0, 0, tzinfo=UTC), is_in_safe_hours=True, send_at_local=datetime(2025, 1, 15, 4, 0, 0), ), SendTimezone( country_code="US", state_provinces=["TX"], iana_tz_id="America/Chicago", utc_offset_std=decimal.Decimal(0), quiet_hours_min="08:00", quiet_hours_max="21:00", next_safe_time=datetime(2025, 1, 15, 18, 0, 0, tzinfo=UTC), is_in_safe_hours=True, send_at_local=datetime(2025, 1, 15, 6, 0, 0), ), SendTimezone( country_code="GB", state_provinces=None, iana_tz_id="Europe/London", utc_offset_std=decimal.Decimal(0), quiet_hours_min="08:00", quiet_hours_max="21:00", next_safe_time=None, is_in_safe_hours=True, send_at_local=datetime(2025, 1, 15, 12, 0, 0), ), ] campaign_repository_mock = mock.MagicMock(spec=CampaignRepository) campaign_repository_mock.get_by_id.return_value = campaign campaign_repository_mock.get_send_timezone.return_value = timezones with container.override(CampaignRepository, campaign_repository_mock): result = handler.handle( GetCampaignSendTimezonesRequest( identity_id=identity_id, campaign_id=campaign.id, send_at=send_at, ) ) campaign_repository_mock.get_send_timezone.assert_called_once_with( campaign_id=mock.ANY, send_at=send_at, ) assert result.send_at == send_at assert result.countries == IsList( IsPartialDataclass( country_code="US", timezones=IsList( IsPartialDataclass( iana_tz_id="America/Los_Angeles", is_adjusted=True, ), IsPartialDataclass( iana_tz_id="America/Chicago", is_adjusted=False, ), ), ), IsPartialDataclass( country_code="GB", timezones=IsList( IsPartialDataclass( iana_tz_id="Europe/London", is_adjusted=False, ), ), ), ) @pytest.mark.db def test_get_campaign_send_timezones_empty( self, handler: GetCampaignSendTimezonesHandler, container: Container, create_model: CreateModel, identity_id: str, ) -> None: campaign = create_model(Campaign) send_at = datetime(2025, 1, 15, 12, 0, 0, tzinfo=UTC) campaign_repository_mock = mock.MagicMock(spec=CampaignRepository) campaign_repository_mock.get_send_timezone.return_value = [] with container.override(CampaignRepository, campaign_repository_mock): result = handler.handle( GetCampaignSendTimezonesRequest( identity_id=identity_id, campaign_id=campaign.id, send_at=send_at, ) ) assert result.send_at == send_at assert not result.countries @pytest.mark.db def test_get_campaign_send_timezones_single_country( self, handler: GetCampaignSendTimezonesHandler, container: Container, create_model: CreateModel, identity_id: str, ) -> None: campaign = create_model(Campaign) send_at = datetime(2025, 1, 15, 12, 0, 0, tzinfo=UTC) timezones = [ SendTimezone( country_code="CA", state_provinces=["ON"], iana_tz_id="America/Toronto", utc_offset_std=decimal.Decimal(0), quiet_hours_min="08:00", quiet_hours_max="21:00", next_safe_time=None, is_in_safe_hours=True, send_at_local=datetime(2025, 1, 15, 7, 0, 0), ), ] campaign_repository_mock = mock.MagicMock(spec=CampaignRepository) campaign_repository_mock.get_send_timezone.return_value = timezones with container.override(CampaignRepository, campaign_repository_mock): result = handler.handle( GetCampaignSendTimezonesRequest( identity_id=identity_id, campaign_id=campaign.id, send_at=send_at, ) ) assert result.send_at == send_at assert result.countries == IsList( IsPartialDataclass( country_code="CA", timezones=IsList( IsPartialDataclass( iana_tz_id="America/Toronto", ) ), ) )