diff --git a/configuration/white_labels/co.py b/configuration/white_labels/co.py index 0916bf36..f246ecf9 100644 --- a/configuration/white_labels/co.py +++ b/configuration/white_labels/co.py @@ -146,7 +146,7 @@ def get_white_label(self) -> WhiteLabel: "_label": "referralOptions.fircsummitresourcecenter", "_default_message": "FIRC Summit Resource Center", }, - "ccig": "Colorado Community Insight Group", + "ccig": "Colorado Design Insight Group", "eaglecounty": "Eagle County", "searchEngine": {"_label": "referralOptions.searchEngine", "_default_message": "Google or other search engine"}, "socialMedia": {"_label": "referralOptions.socialMedia", "_default_message": "Social Media"}, diff --git a/integrations/management/commands/health_check.py b/integrations/management/commands/health_check.py index 036e2cf3..36c63b28 100644 --- a/integrations/management/commands/health_check.py +++ b/integrations/management/commands/health_check.py @@ -1,10 +1,8 @@ -from typing import Optional from django.core.management.base import BaseCommand from django.conf import settings from decouple import config from hubspot import HubSpot from hubspot.crm.contacts.exceptions import ForbiddenException -from django.db.models import Q from authentication.models import User from integrations.models import Link from programs.models import Navigator, Program, TranslationOverride, UrgentNeed @@ -57,13 +55,7 @@ def _cant_read_hubspot(self) -> bool: return False def _no_pii_in_db(self) -> bool: - users = User.objects.filter(is_staff=False).filter( - Q(first_name__isnull=False) - | Q(last_name__isnull=False) - | Q(cell__isnull=False) - | Q(email__isnull=False) - | Q(external_id__isnull=True) - ) + users = User.objects.filter(is_staff=False).filter(external_id__isnull=True) if len(users) > 0: return False diff --git a/integrations/services/communications/message.py b/integrations/services/communications/message.py index 9830d6af..32daa863 100644 --- a/integrations/services/communications/message.py +++ b/integrations/services/communications/message.py @@ -81,7 +81,7 @@ def _cell_client(self): return Client(self.cell_account_sid, self.cell_auth_token) def _generate_link(self): - return f"{self.front_end_domain}/{self.screen.uuid}/results" + return f"{self.front_end_domain}/{self.screen.white_label.code}/{self.screen.uuid}/results" def log(self, type: Literal["emailScreen", "textScreen"]): self.screen.last_email_request_date = timezone.now() diff --git a/programs/models.py b/programs/models.py index 30a1f9e1..e94292d5 100644 --- a/programs/models.py +++ b/programs/models.py @@ -153,7 +153,7 @@ def from_model_data(self, data: DataType): @classmethod def create_instance(cls, external_name: str, Model: type["ProgramCategory"]) -> "ProgramCategory": - return Model.objects.new_program_category(external_name, "housing") + return Model.objects.new_program_category("_default", external_name, "housing") class ProgramCategory(models.Model): @@ -229,7 +229,7 @@ def from_model_data(self, data: DataType): @classmethod def create_instance(cls, external_name: str, Model: type["Document"]) -> "Document": - return Model.objects.new_document(external_name) + return Model.objects.new_document("_default", external_name) class Document(models.Model): @@ -397,7 +397,7 @@ def from_model_data(self, data: DataType): @classmethod def create_instance(cls, external_name: str, Model: type["Program"]) -> "Program": - return Model.objects.new_program(external_name) + return Model.objects.new_program("_default", external_name) # This model describes all of the benefit programs available in the screener @@ -615,11 +615,11 @@ def from_model_data(self, data: DataType): for category in data["categories"]: try: cat_instance = UrgentNeedCategory.objects.get(name=category["name"]) + cat_instance.white_label = white_label + cat_instance.save() except UrgentNeedCategory.DoesNotExist: - cat_instance = UrgentNeedFunction.objects.create(name=category["name"]) + cat_instance = UrgentNeedCategory.objects.create(name=category["name"], white_label=white_label) - cat_instance.white_label = white_label - cat_instance.save() categories.append(cat_instance) need.type_short.set(categories) @@ -637,7 +637,7 @@ def from_model_data(self, data: DataType): @classmethod def create_instance(cls, external_name: str, Model: type["UrgentNeed"]) -> "UrgentNeed": - return Model.objects.new_urgent_need(external_name, None) + return Model.objects.new_urgent_need("_default", external_name, None) class UrgentNeed(models.Model): @@ -704,7 +704,7 @@ class NavigatorManager(models.Manager): ) no_auto_fields = ("assistance_link",) - def new_navigator(self, white_label: str, name: str, phone_number: str): + def new_navigator(self, white_label: str, name: str, phone_number: Optional[str] = None): translations = {} for field in self.translated_fields: translations[field] = Translation.objects.add_translation( @@ -779,11 +779,11 @@ def from_model_data(self, data: DataType): for county in data["counties"]: try: county_instance = County.objects.get(name=county["name"]) + county_instance.white_label = white_label + county_instance.save() except County.DoesNotExist: - county_instance = County.objects.create(name=county["name"]) + county_instance = County.objects.create(name=county["name"], white_label=white_label) - county_instance.white_label = white_label - county_instance.save() counties.append(county_instance) navigator.counties.set(counties) @@ -808,7 +808,7 @@ def from_model_data(self, data: DataType): @classmethod def create_instance(cls, external_name: str, Model: type["Navigator"]) -> "Navigator": - return Model.objects.new_navigator(external_name, None) + return Model.objects.new_navigator("_default", external_name, None) class Navigator(models.Model): @@ -909,8 +909,10 @@ def from_model_data(self, data: DataType): for county in data["counties"]: try: county_instance = County.objects.get(name=county["name"]) + county_instance.white_label = white_label + county_instance.save() except County.DoesNotExist: - county_instance = County.objects.create(name=county["name"]) + county_instance = County.objects.create(name=county["name"], white_label=white_label) counties.append(county_instance) warning.counties.set(counties) @@ -925,7 +927,7 @@ def from_model_data(self, data: DataType): @classmethod def create_instance(cls, external_name: str, Model: type["WarningMessage"]) -> "WarningMessage": - return Model.objects.new_warning("_show", external_name) + return Model.objects.new_warning("_default", "_show", external_name) class WarningMessage(models.Model): @@ -1055,8 +1057,10 @@ def from_model_data(self, data: DataType): for county in data["counties"]: try: county_instance = County.objects.get(name=county["name"]) + county_instance.white_label = white_label + county_instance.save() except County.DoesNotExist: - county_instance = County.objects.create(name=county["name"]) + county_instance = County.objects.create(name=county["name"], white_label=white_label) counties.append(county_instance) translation_override.counties.set(counties) @@ -1067,7 +1071,7 @@ def from_model_data(self, data: DataType): @classmethod def create_instance(cls, external_name: str, Model: type["TranslationOverride"]) -> "TranslationOverride": - return Model.objects.new_translation_override("_show", "", external_name) + return Model.objects.new_translation_override("_default", "_show", "", external_name) class TranslationOverride(models.Model): diff --git a/programs/programs/nc/__init__.py b/programs/programs/nc/__init__.py index feff9b0b..fe001050 100644 --- a/programs/programs/nc/__init__.py +++ b/programs/programs/nc/__init__.py @@ -1,9 +1,11 @@ from .nc_aca.calculator import ACASubsidiesNC from .medicaid.emergency_medicaid.calculator import EmergencyMedicaid +from .sun_bucks.calculator import SunBucks from ..calc import ProgramCalculator nc_calculators: dict[str, type[ProgramCalculator]] = { "nc_aca": ACASubsidiesNC, "nc_emergency_medicaid": EmergencyMedicaid, + "sunbucks": SunBucks, } diff --git a/programs/programs/nc/pe/member.py b/programs/programs/nc/pe/member.py index 1e3256a6..aa2aa533 100644 --- a/programs/programs/nc/pe/member.py +++ b/programs/programs/nc/pe/member.py @@ -17,8 +17,8 @@ class NcMedicaid(Medicaid): "YOUNG_ADULT": 512, # * 12 = 6146, Medicaid Expansion Adults "PARENT": 0, "SSI_RECIPIENT": 0, - "AGED": 1519, # * 12 = 13035, Medicaid for the Aged - "DISABLED": 1086, # * 12 = 18227, Medicaid for the Disabled + "AGED": 1086, # * 12 = 13035, Medicaid for the Aged + "DISABLED": 1519, # * 12 = 18227, Medicaid for the Disabled } pe_inputs = [ diff --git a/programs/programs/nc/sun_bucks/__init__.py b/programs/programs/nc/sun_bucks/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/programs/programs/nc/sun_bucks/calculator.py b/programs/programs/nc/sun_bucks/calculator.py new file mode 100644 index 00000000..31b672da --- /dev/null +++ b/programs/programs/nc/sun_bucks/calculator.py @@ -0,0 +1,29 @@ +from programs.programs.calc import MemberEligibility, ProgramCalculator, Eligibility +import programs.programs.messages as messages + + +class SunBucks(ProgramCalculator): + member_amount = 1440 + min_age = 7 + max_age = 16 + fpl_percent = 1.85 + dependencies = ["age", "insurance", "income_amount", "income_frequency", "household_size"] + + def household_eligible(self, e: Eligibility): + # Income + fpl = self.program.fpl + income_limit = int(self.fpl_percent * fpl.get_limit(self.screen.household_size)) + gross_income = int(self.screen.calc_gross_income("yearly", ["all"])) + + # Must not have the following benefits + e.condition(not self.screen.has_benefit("snap"), messages.must_not_have_benefit("snap")) + e.condition(not self.screen.has_benefit("tanf"), messages.must_not_have_benefit("tanf")) + e.condition(not self.screen.has_benefit("medicaid"), messages.must_not_have_benefit("medicaid")) + + e.condition(gross_income < income_limit, messages.income(gross_income, income_limit)) + + def member_eligible(self, e: MemberEligibility): + member = e.member + + # age eligibility + e.condition(SunBucks.min_age <= member.age <= SunBucks.max_age) diff --git a/screener/migrations/0089_screen_has_sunbucks.py b/screener/migrations/0089_screen_has_sunbucks.py new file mode 100644 index 00000000..2111c5e3 --- /dev/null +++ b/screener/migrations/0089_screen_has_sunbucks.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.15 on 2024-12-03 18:08 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("screener", "0088_alter_screen_white_label"), + ] + + operations = [ + migrations.AddField( + model_name="screen", + name="has_sunbucks", + field=models.BooleanField(blank=True, default=False, null=True), + ), + ] diff --git a/screener/migrations/0090_merge_20241213_1726.py b/screener/migrations/0090_merge_20241213_1726.py new file mode 100644 index 00000000..ce555af6 --- /dev/null +++ b/screener/migrations/0090_merge_20241213_1726.py @@ -0,0 +1,13 @@ +# Generated by Django 4.2.15 on 2024-12-13 17:26 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("screener", "0089_screen_has_sunbucks"), + ("screener", "0089_whitelabel_cms_method"), + ] + + operations = [] diff --git a/screener/models.py b/screener/models.py index 1c200a92..99157c93 100644 --- a/screener/models.py +++ b/screener/models.py @@ -51,6 +51,7 @@ class Screen(models.Model): has_tanf = models.BooleanField(default=False, blank=True, null=True) has_wic = models.BooleanField(default=False, blank=True, null=True) has_snap = models.BooleanField(default=False, blank=True, null=True) + has_sunbucks = models.BooleanField(default=False, blank=True, null=True) has_lifeline = models.BooleanField(default=False, blank=True, null=True) has_acp = models.BooleanField(default=False, blank=True, null=True) has_eitc = models.BooleanField(default=False, blank=True, null=True) @@ -280,8 +281,10 @@ def has_benefit(self, name_abbreviated): "nc_tanf": self.has_tanf, "co_tanf": self.has_tanf, "wic": self.has_wic, + "co_wic": self.has_wic, "nc_wic": self.has_wic, "snap": self.has_snap, + "sunbucks": self.has_sunbucks, "co_snap": self.has_snap, "nc_snap": self.has_snap, "lifeline": self.has_lifeline, diff --git a/screener/serializers.py b/screener/serializers.py index 4ffac548..699f2068 100644 --- a/screener/serializers.py +++ b/screener/serializers.py @@ -136,6 +136,7 @@ class Meta: "has_tanf", "has_wic", "has_snap", + "has_sunbucks", "has_lifeline", "has_acp", "has_eitc",