130:def _async_materialize(db_engine, campaign, recipient_rows, **kw):
149:    return asyncio.run(runner())
155:class TestMaterializeCampaign:
156:    def test_materializes_all_recipients_with_generated_values(self, db_engine):
174:    def test_invoice_numbers_unique_per_campaign(self, db_engine):
186:    def test_invoice_numbers_unique_across_materialize_calls(self, db_engine):
203:    def test_preview_does_not_persist(self, db_engine):
217:    def test_preview_size_defaults_to_campaign_setting(self, db_engine):
225:    def test_no_accounts_marks_skipped(self, db_engine):
237:    def test_template_stop_mode_marks_remaining_skipped(self, db_engine):
250:    def test_subject_assignment_round_robin(self, db_engine):
260:    def test_phone_assignment_round_robin(self, db_engine):
269:    def test_account_rotation_sequential(self, db_engine):
278:    def test_max_per_account_respected_in_plan(self, db_engine):
293:    def test_account_in_cooldown_skipped(self, db_engine):
307:    def test_amount_shipping_disabled_by_config(self, db_engine):
321:    def test_dates_from_config(self, db_engine):
335:    def test_persists_campaign_recipients(self, db_engine):
350:    def test_only_valid_recipients_flow(self, db_engine):
367:    def test_multiple_campaigns_independent_plans(self, db_engine):
382:    def test_plan_warnings_for_skipped_rows(self, db_engine):
397:class TestGetCampaignEntities:
398:    def test_loads_all_entities(self, db_engine):
410:            subs, tpls, phones, accs = asyncio.run(runner())
416:    def test_drops_unauthorized_accounts_and_inactive_phones(self, db_engine):
442:            subs2, tpls2, phones2, accs2 = asyncio.run(runner())
446:    def test_missing_ids_resolved_honestly(self, db_engine):
462:            subs, tpls, _, _ = asyncio.run(runner())
