Example #1
0
def network_vars(user, database):
    """Compute vars for a given user for the network email.

    Returns:
        a dict with all vars required for the template, or None if no email
        should be sent.
    """

    if not user.projects:
        logging.info('User has no project')
        return None
    project = user.projects[0]

    registered_months_ago = campaign.get_french_months_ago(
        user.registered_at.ToDatetime())
    if not registered_months_ago:
        logging.warning('User registered only recently (%s)',
                        user.registered_at)
        return None

    job_group_info = jobs.get_group_proto(database,
                                          project.target_job.job_group.rome_id)
    in_target_domain = job_group_info.in_domain
    if not in_target_domain:
        logging.warning('Could not find a target domain (%s)',
                        project.target_job.job_group)
        return None

    worst_frustration = next(
        (f for f in (user_pb2.NO_OFFER_ANSWERS, user_pb2.MOTIVATION)
         if f in user.profile.frustrations), None)

    is_hairdresser_or_in_marseille = \
        project.target_job.job_group.rome_id.startswith('D') or \
        project.mobility.city.departement_id == '13'
    other_job_in_city = 'coiffeur à Marseille'
    if is_hairdresser_or_in_marseille:
        other_job_in_city = 'secrétaire à Lyon'
    return dict(
        campaign.get_default_vars(user), **{
            'registeredMonthsAgo':
            registered_months_ago,
            'inTargetDomain':
            in_target_domain,
            'frustration':
            user_pb2.Frustration.Name(worst_frustration)
            if worst_frustration else '',
            'otherJobInCity':
            other_job_in_city,
            'jobInCity':
            '{} {}'.format(
                french.lower_first_letter(
                    french.genderize_job(project.target_job,
                                         user.profile.gender)),
                french.in_city(strip_district(project.mobility.city.name))),
            'emailInUrl':
            parse.quote(user.profile.email),
            'statusUpdateUrl':
            campaign.get_status_update_link(user.user_id, user.profile),
        })
Example #2
0
def _get_network_vars(user: user_pb2.User,
                      database: Optional[pymongo.database.Database] = None,
                      **unused_kwargs: Any) -> Optional[Dict[str, str]]:
    """Compute vars for a given user for the network email.

    Returns:
        a dict with all vars required for the template, or None if no email
        should be sent.
    """

    project = user.projects[0]

    if project.network_estimate != 1:
        logging.info('User has a good enough network')
        return None

    assert database
    job_group_info = jobs.get_group_proto(database,
                                          project.target_job.job_group.rome_id)
    if not job_group_info:
        logging.warning('Could not find job group info for "%s"',
                        project.target_job.job_group.rome_id)
        return None

    in_target_domain = job_group_info.in_domain
    if not in_target_domain:
        logging.warning('Could not find a target domain (%s)',
                        project.target_job.job_group)
        return None

    worst_frustration = next(
        (f for f in (user_pb2.NO_OFFER_ANSWERS, user_pb2.MOTIVATION)
         if f in user.profile.frustrations), None)

    is_hairdresser_or_in_marseille = \
        project.target_job.job_group.rome_id.startswith('D') or \
        project.city.departement_id == '13'
    other_job_in_city = 'coiffeur à Marseille'
    if is_hairdresser_or_in_marseille:
        other_job_in_city = 'secrétaire à Lyon'
    job = french.lower_first_letter(
        french.genderize_job(project.target_job, user.profile.gender))
    in_city = french.in_city(strip_district(project.city.name))
    return dict(
        campaign.get_default_coaching_email_vars(user), **{
            'inTargetDomain':
            in_target_domain,
            'frustration':
            user_pb2.Frustration.Name(worst_frustration)
            if worst_frustration else '',
            'otherJobInCity':
            other_job_in_city,
            'jobInCity':
            f'{job} {in_city}',
            'emailInUrl':
            parse.quote(user.profile.email),
        })
Example #3
0
def _in_city(scoring_project: scoring_base.ScoringProject) -> str:
    translated = scoring_project.translate_static_string(
        'à {city_name}',
        is_genderized=False,
    ).format(city_name=scoring_project.details.city.name)
    if translated.startswith('à '):
        # This is probably French, let's use a specific rule.
        return french.in_city(scoring_project.details.city.name)
    return translated
Example #4
0
    def test_in_city(self) -> None:
        """Test the in_city function."""

        test_cases = [
            _CityPrefixTestCase('Regular city name', 'Toulouse', 'à Toulouse'),
            _CityPrefixTestCase('Contract "à" + "Le"', 'Le Mans', 'au Mans'),
            _CityPrefixTestCase('Lowercase "La" as first word', 'La Ferté',
                                'à la Ferté'),
            _CityPrefixTestCase('Do not lowercase "La" as prefix', 'Laval',
                                'à Laval'),
            _CityPrefixTestCase('Contract "à" + "Les"', 'Les Ulis',
                                'aux Ulis'),
            _CityPrefixTestCase('Lowercase "L\'"', "L'Arbresle",
                                "à l'Arbresle"),
        ]

        for description, city_name, expected in test_cases:
            self.assertEqual(expected, french.in_city(city_name), description)
Example #5
0
def _get_network_vars(
        user: user_pb2.User, *, database: mongo.NoPiiMongoDatabase,
        **unused_kwargs: Any) -> dict[str, str]:
    """Compute vars for a given user for the network email.

    Returns:
        a dict with all vars required for the template, or None if no email
        should be sent.
    """

    if not user.projects:
        raise scoring.NotEnoughDataException('No project yet', {'projects.0'})

    project = user.projects[0]

    if project.network_estimate != 1:
        raise campaign.DoNotSend('User has a good enough network')

    in_target_domain = _get_in_target_domain(project.target_job.job_group.rome_id, database)
    worst_frustration = next(
        (f for f in (user_profile_pb2.NO_OFFER_ANSWERS, user_profile_pb2.MOTIVATION)
         if f in user.profile.frustrations),
        None)

    is_hairdresser_or_in_marseille = \
        project.target_job.job_group.rome_id.startswith('D') or \
        project.city.departement_id == '13'
    other_job_in_city = 'coiffeur à Marseille'
    if is_hairdresser_or_in_marseille:
        other_job_in_city = 'secrétaire à Lyon'
    job = french.lower_first_letter(french.genderize_job(
        project.target_job, user.profile.gender))
    in_city = french.in_city(strip_district(project.city.name))
    return campaign.get_default_coaching_email_vars(user) | {
        'inTargetDomain': in_target_domain,
        'frustration':
        user_profile_pb2.Frustration.Name(worst_frustration) if worst_frustration else '',
        'otherJobInCity': other_job_in_city,
        'jobInCity': f'{job} {in_city}',
        'emailInUrl': parse.quote(user.profile.email),
    }
Example #6
0
def _get_imt_vars(user: user_pb2.User,
                  database: Optional[pymongo.database.Database] = None,
                  **unused_kwargs: Any) -> Optional[Dict[str, Any]]:
    """Compute vars for the "IMT" email."""

    project = user.projects[0]
    assert database
    scoring_project = scoring.ScoringProject(project, user, database)

    genderized_job_name = french.lower_first_letter(
        french.genderize_job(project.target_job, user.profile.gender))

    departement_id = project.city.departement_id
    rome_id = project.target_job.job_group.rome_id
    local_diagnosis = scoring_project.local_diagnosis()
    if not local_diagnosis.HasField('imt'):
        logging.info('User market has no IMT data')
        return None
    imt = local_diagnosis.imt

    shown_sections = []

    market_stress_section = _make_market_stress_section(
        imt.yearly_avg_offers_per_10_candidates)
    if market_stress_section:
        shown_sections.append('marketStress')

    application_modes_section = _make_application_mode_section(
        scoring_project.get_best_application_mode(), project, user.user_id)
    if application_modes_section:
        shown_sections.append('applicationModes')

    departements_section = _make_departements_section(
        departement_id,
        _get_best_departements_for_job_group(rome_id, database),
        project.area_type, database)
    if departements_section:
        shown_sections.append('departements')

    employment_types_section = _make_employment_type_section(
        imt.employment_type_percentages)
    if employment_types_section:
        shown_sections.append('employmentTypes')

    months_section = _make_months_section(imt.active_months)
    if months_section:
        shown_sections.append('months')

    if len(shown_sections) < 3:
        logging.info('Only %d section(s) to be shown for user (%s).',
                     len(shown_sections), shown_sections)
        return None

    imt_link = 'http://candidat.pole-emploi.fr/marche-du-travail/statistiques?' \
        f'codeMetier={project.target_job.code_ogr}&codeZoneGeographique={departement_id}&' \
        'typeZoneGeographique=DEPARTEMENT'

    in_departement = geo.get_in_a_departement_text(database, departement_id)
    job_name_in_departement = f'{genderized_job_name} {in_departement}'

    return dict(
        campaign.get_default_coaching_email_vars(user), **{
            'applicationModes':
            _make_section(application_modes_section),
            'departements':
            _make_section(departements_section),
            'employmentType':
            _make_section(employment_types_section),
            'imtLink':
            imt_link,
            'inCity':
            french.in_city(project.city.name),
            'jobNameInDepartement':
            job_name_in_departement,
            'loginUrl':
            campaign.create_logged_url(user.user_id),
            'marketStress':
            _make_section(market_stress_section),
            'months':
            _make_section(months_section),
            'ofJobNameInDepartement':
            french.maybe_contract_prefix('de ', "d'", job_name_in_departement),
            'ofJobName':
            french.maybe_contract_prefix('de ', "d'", genderized_job_name),
        })
Example #7
0
def _in_city(scoring_project: ScoringProject) -> str:
    return french.in_city(scoring_project.details.city.name)
Example #8
0
 '%departementId':
 lambda scoring_project: scoring_project.details.mobility.city.
 departement_id,
 '%eFeminine':
 lambda scoring_project:
 ('e' if scoring_project.user_profile.gender == user_pb2.FEMININE else ''),
 '%experienceDuration':
 lambda scoring_project: _EXPERIENCE_DURATION.get(scoring_project.details.
                                                  seniority),
 '%feminineJobName':
 lambda scoring_project: french.lower_first_letter(
     scoring_project.details.target_job.feminine_name),
 '%inAWorkplace':
 lambda scoring_project: scoring_project.job_group_info().in_a_workplace,
 '%inCity':
 lambda scoring_project: french.in_city(scoring_project.details.mobility.
                                        city.name),
 '%inDomain':
 lambda scoring_project: scoring_project.job_group_info().in_domain,
 '%inRegion':
 _in_region,
 '%jobGroupNameUrl':
 lambda scoring_project: parse.quote(
     unidecode.unidecode(scoring_project.details.target_job.job_group.name.
                         lower().replace(' ', '-').replace("'", '-'))),
 '%jobId':
 lambda scoring_project: scoring_project.details.target_job.code_ogr,
 '%jobName':
 _job_name,
 # This in only the **number** of months, use as '%jobSearchLengthMonthsAtCreation mois'.
 '%jobSearchLengthMonthsAtCreation':
 _job_search_length_months_at_creation,
Example #9
0
def christmas_vars(user: user_pb2.User,
                   now: datetime.datetime,
                   database: Optional[pymongo.database.Database] = None,
                   **unused_kwargs: Any) -> Optional[Dict[str, str]]:
    """Compute all variables required for the Christmas campaign."""

    project = next((p for p in user.projects), project_pb2.Project())

    job_search_started_months_ago = campaign.job_search_started_months_ago(
        project, now)
    if job_search_started_months_ago < 0:
        started_searching_since = ''
    elif job_search_started_months_ago < 2:
        started_searching_since = 'depuis peu'
    else:
        try:
            num_months = french.try_stringify_number(
                round(job_search_started_months_ago))
            started_searching_since = f'depuis {num_months} mois'
        except NotImplementedError:
            started_searching_since = 'depuis un moment'

    # A city to commute to.
    commute_city = next(
        (city for a in project.advices for city in a.commute_data.cities), '')
    if commute_city:
        commute_city = french.in_city(commute_city)
    commute_advice_url = campaign.get_deep_link_advice(user.user_id, project,
                                                       'commute')
    if not commute_advice_url:
        commute_city = ''

    # A departement to relocate to.
    relocate_departement = next(
        (departement.name for a in project.advices
         for departement in a.relocate_data.departement_scores), '')
    assert database
    if relocate_departement:
        try:
            departement_id = geo.get_departement_id(database,
                                                    relocate_departement)
            relocate_departement = geo.get_in_a_departement_text(
                database, departement_id)
        except KeyError:
            relocate_departement = ''
    relocate_advice_url = campaign.get_deep_link_advice(
        user.user_id, project, 'relocate')
    if not relocate_advice_url:
        relocate_departement = ''

    # Whether the job may have freelancers.
    job_group_info = jobs.get_group_proto(database,
                                          project.target_job.job_group.rome_id)
    could_freelance = job_group_info and job_group_info.has_freelancers

    return dict(
        campaign.get_default_vars(user), **{
            'adviceUrlBodyLanguage':
            campaign.get_deep_link_advice(user.user_id, project,
                                          'body-language'),
            'adviceUrlCommute':
            commute_advice_url,
            'adviceUrlCreateYourCompany':
            campaign.get_deep_link_advice(user.user_id, project,
                                          'create-your-company'),
            'adviceUrlImproveInterview':
            campaign.get_deep_link_advice(user.user_id, project,
                                          'improve-interview'),
            'adviceUrlRelocate':
            relocate_advice_url,
            'couldFreelance':
            campaign.as_template_boolean(could_freelance),
            'emailInUrl':
            parse.quote(user.profile.email),
            'inCommuteCity':
            commute_city,
            'inRelocateDepartement':
            relocate_departement,
            'startedSearchingSince':
            started_searching_since,
        })
Example #10
0
def _christmas_vars(user: user_pb2.User, *, now: datetime.datetime,
                    database: mongo.NoPiiMongoDatabase,
                    **unused_kwargs: Any) -> dict[str, str]:
    """Compute all variables required for the Christmas campaign."""

    if now.month != 12 and not user.features_enabled.alpha:
        raise campaign.DoNotSend('Only send christmas email in December')

    project = next((p for p in user.projects), project_pb2.Project())

    job_search_started_months_ago = campaign.job_search_started_months_ago(
        project, now)
    if job_search_started_months_ago < 0:
        started_searching_since = ''
    elif job_search_started_months_ago < 2:
        started_searching_since = 'depuis peu'
    else:
        try:
            num_months = french.try_stringify_number(
                round(job_search_started_months_ago))
            started_searching_since = f'depuis {num_months} mois'
        except NotImplementedError:
            started_searching_since = 'depuis un moment'

    # A city to commute to.
    commute_city = next(
        (city for a in project.advices for city in a.commute_data.cities), '')
    if commute_city:
        commute_city = french.in_city(commute_city)
    commute_advice_url = campaign.get_deep_link_advice(user.user_id, project,
                                                       'commute')
    if not commute_advice_url:
        commute_city = ''

    # A departement to relocate to.
    relocate_departement = next(
        (departement.name for a in project.advices
         for departement in a.relocate_data.departement_scores), '')
    if relocate_departement:
        try:
            departement_id = geo.get_departement_id(database,
                                                    relocate_departement)
            relocate_departement = geo.get_in_a_departement_text(
                database, departement_id)
        except KeyError:
            relocate_departement = ''
    relocate_advice_url = campaign.get_deep_link_advice(
        user.user_id, project, 'relocate')
    if not relocate_advice_url:
        relocate_departement = ''

    # Whether the job may have freelancers.
    job_group_info = jobs.get_group_proto(database,
                                          project.target_job.job_group.rome_id)
    could_freelance = job_group_info and job_group_info.has_freelancers

    return campaign.get_default_coaching_email_vars(user) | {
        'adviceUrlBodyLanguage':
        campaign.get_deep_link_advice(user.user_id, project, 'body-language'),
        'adviceUrlCommute':
        commute_advice_url,
        'adviceUrlCreateYourCompany':
        campaign.get_deep_link_advice(user.user_id, project,
                                      'create-your-company'),
        'adviceUrlExploreOtherJobs':
        campaign.get_deep_link_advice(user.user_id, project,
                                      'explore-other-jobs'),
        'adviceUrlImproveInterview':
        campaign.get_deep_link_advice(user.user_id, project,
                                      'improve-interview'),
        'adviceUrlRelocate':
        relocate_advice_url,
        'adviceUrlVolunteer':
        campaign.get_deep_link_advice(user.user_id, project, 'volunteer'),
        'couldFreelance':
        campaign.as_template_boolean(could_freelance),
        'emailInUrl':
        parse.quote(user.profile.email),
        'inCommuteCity':
        commute_city,
        'inRelocateDepartement':
        relocate_departement,
        'nextYear':
        str(now.year + 1),
        'startedSearchingSince':
        started_searching_since,
        'year':
        str(now.year),
    }
Example #11
0
def network_plus_vars(
        user: user_pb2.User, *, database: mongo.NoPiiMongoDatabase,
        **unused_kwargs: Any) -> dict[str, str]:
    """Compute vars for a given user for the network email.

    Returns:
        a dict with all vars required for the template, or None if no email
        should be sent.
    """

    if not user.projects:
        raise scoring.NotEnoughDataException('No project yet', {'projects.0'})

    project = user.projects[0]

    if project.network_estimate < 2:
        raise campaign.DoNotSend('User does not have a strong network')

    rome_id = project.target_job.job_group.rome_id
    in_target_domain = _get_in_target_domain(rome_id, database)
    job_group_info = jobs.get_group_proto(database, rome_id)
    assert job_group_info
    application_modes = job_group_info.application_modes.values()

    fap_modes = [fap_modes.modes for fap_modes in application_modes if len(fap_modes.modes)]
    if not fap_modes:
        raise scoring.NotEnoughDataException(
            'No information about application modes for the target job',
            {f'data.job_group_info.{rome_id}.application_modes'})
    flat_fap_modes = [mode for modes in fap_modes for mode in modes]
    network_percentages = [mode.percentage for mode in flat_fap_modes if (
        mode.mode == job_pb2.PERSONAL_OR_PROFESSIONAL_CONTACTS)]
    # We want to focus on the users for which network,
    # as an application mode, has a substantial importance.
    if not network_percentages:
        raise campaign.DoNotSend(
            'User is not targeting a job where networking is a main application mode')
    scoring_project = scoring.ScoringProject(project, user, database=database)
    average_network_percentage = sum(network_percentages) / len(network_percentages)
    if average_network_percentage > 55:
        network_application_importance = scoring_project.translate_static_string('que la majorité')
    elif average_network_percentage >= 45:
        network_application_importance = scoring_project.translate_static_string('que la moitié')
    elif average_network_percentage >= 25:
        network_application_importance = scoring_project.translate_static_string("qu'un tiers")
    else:
        raise campaign.DoNotSend(
            'User is not targeting a job where networking is a main application mode')

    worst_frustration = next(
        (f for f in (user_profile_pb2.SELF_CONFIDENCE, user_profile_pb2.MOTIVATION)
         if f in user.profile.frustrations),
        None)
    has_children = user.profile.family_situation in {
        user_profile_pb2.FAMILY_WITH_KIDS, user_profile_pb2.SINGLE_PARENT_SITUATION}

    age = datetime.date.today().year - user.profile.year_of_birth
    max_young = 35

    try:
        in_departement = geo.get_in_a_departement_text(
            database, project.city.departement_id,
            city_hint=project.city, locale=user.profile.locale)
    except KeyError:
        raise scoring.NotEnoughDataException(
            'Need departement info for phrasing',
            {f'data.departements.{project.city.departement_id}'}) from None

    job_group_name = french.lower_first_letter(project.target_job.job_group.name)

    if (user.profile.locale or 'fr').startswith('fr'):
        in_city = french.in_city(project.city.name)
    else:
        # TODO(pascal): Update the English template so that it follows the logic of "in city" and
        # not "city". For now it's phrased as "near {{inCity}}".
        in_city = project.city.name

    return campaign.get_default_coaching_email_vars(user) | {
        'frustration':
        user_profile_pb2.Frustration.Name(worst_frustration) if worst_frustration else '',
        'hasChildren': campaign.as_template_boolean(has_children),
        'hasHighSchoolDegree': campaign.as_template_boolean(
            user.profile.highest_degree >= job_pb2.BAC_BACPRO),
        'hasLargeNetwork': campaign.as_template_boolean(project.network_estimate >= 2),
        'hasWorkedBefore': campaign.as_template_boolean(
            project.kind != project_pb2.FIND_A_FIRST_JOB),
        'inCity': in_city,
        'inTargetDomain': in_target_domain,
        'isAbleBodied': campaign.as_template_boolean(not user.profile.has_handicap),
        'isYoung': campaign.as_template_boolean(age <= max_young),
        'jobGroupInDepartement': f'{job_group_name} {in_departement}',
        'networkApplicationPercentage': network_application_importance,
    }
Example #12
0
def imt_vars(user, database):
    """Compute vars for the "IMT" email."""

    if not user.projects:
        logging.info('User has no project')
        return None
    project = user.projects[0]

    genderized_job_name = french.lower_first_letter(
        french.genderize_job(project.target_job, user.profile.gender))

    departement_id = project.mobility.city.departement_id
    rome_id = project.target_job.job_group.rome_id
    diagnosis_key = '{}:{}'.format(departement_id, rome_id)
    local_diagnosis = _LOCAL_DIAGNOSIS.get_collection(database).get(
        diagnosis_key)
    if not local_diagnosis:
        logging.info('User market does not exist')
        return None
    imt = local_diagnosis.imt
    if not imt:
        logging.info('User market has no IMT data')
        return None

    shown_sections = 0

    market_stress_section = _make_market_stress_section(
        imt.yearly_avg_offers_per_10_candidates)
    if market_stress_section:
        shown_sections += 1

    application_modes_section = _make_application_mode_section(
        campaign.get_application_modes(rome_id, database), project.advices,
        user.user_id)
    if application_modes_section:
        shown_sections += 1

    departements_section = _make_departements_section(
        project.mobility.city.departement_id,
        _get_best_departements_for_job_group(rome_id, database),
        project.mobility.area_type, database)
    if departements_section:
        shown_sections += 1

    employment_types_section = _make_employment_type_section(
        sorted(imt.employment_type_percentages, key=lambda e: e.percentage))
    if employment_types_section:
        shown_sections += 1

    months_section = _make_months_section(imt.active_months)
    if months_section:
        shown_sections += 1

    if shown_sections < 3:
        logging.info('Only %d section(s) to be shown for user.',
                     shown_sections)
        return None

    imt_link = 'http://candidat.pole-emploi.fr/marche-du-travail/statistiques?' + \
        'codeMetier={}&codeZoneGeographique={}&typeZoneGeographique=DEPARTEMENT'.format(
            project.target_job.code_ogr, departement_id)

    job_name_in_departement = '{} {}'.format(
        genderized_job_name,
        geo.get_in_a_departement_text(database,
                                      project.mobility.city.departement_id))

    return dict(
        campaign.get_default_vars(user), **{
            'applicationModes':
            _make_section(application_modes_section),
            'departements':
            _make_section(departements_section),
            'employmentType':
            _make_section(employment_types_section),
            'imtLink':
            imt_link,
            'inCity':
            french.in_city(project.mobility.city.name),
            'jobNameInDepartement':
            job_name_in_departement,
            'loginUrl':
            campaign.create_logged_url(user.user_id),
            'marketStress':
            _make_section(market_stress_section),
            'months':
            _make_section(months_section),
            'ofJobNameInDepartement':
            french.maybe_contract_prefix('de ', "d'", job_name_in_departement),
            'ofJobName':
            french.maybe_contract_prefix('de ', "d'", genderized_job_name),
            'showPs':
            campaign.as_template_boolean(
                _can_go_to_arles_hotellerie_event(rome_id, project.mobility)),
            'statusUpdateUrl':
            campaign.get_status_update_link(user.user_id, user.profile),
        })
Example #13
0
def network_plus_vars(user, database):
    """Compute vars for a given user for the network email.

    Returns:
        a dict with all vars required for the template, or None if no email
        should be sent.
    """

    if not user.projects:
        logging.info('User has no project')
        return None
    project = user.projects[0]

    registered_months_ago = campaign.get_french_months_ago(
        user.registered_at.ToDatetime())
    if not registered_months_ago:
        logging.warning('User registered only recently (%s)',
                        user.registered_at)
        return None

    job_group_info = jobs.get_group_proto(database,
                                          project.target_job.job_group.rome_id)
    in_target_domain = job_group_info.in_domain
    application_modes = job_group_info.application_modes.values()
    if not in_target_domain:
        logging.warning('Could not find a target domain (%s)',
                        project.target_job.job_group)
        return None

    fap_modes = [
        fap_modes.modes for fap_modes in application_modes
        if len(fap_modes.modes)
    ]
    if not fap_modes:
        return None
    flat_fap_modes = [mode for modes in fap_modes for mode in modes]
    network_percentages = [
        mode.percentage for mode in flat_fap_modes
        if (mode.mode == job_pb2.PERSONAL_OR_PROFESSIONAL_CONTACTS)
    ]
    # We want to focus on the user for which network,
    # as an application mode, has a substantial importance.
    if not network_percentages:
        return None
    average_network_percentage = sum(network_percentages) / len(
        network_percentages)
    if average_network_percentage < 55:
        network_application_importance = 'que la majorité'
    if average_network_percentage >= 45 and average_network_percentage <= 55:
        network_application_importance = 'que la moitié'
    if average_network_percentage >= 25 and average_network_percentage < 45:
        network_application_importance = "qu'un tiers"
    else:
        return None

    worst_frustration = next(
        (f for f in (user_pb2.SELF_CONFIDENCE, user_pb2.MOTIVATION)
         if f in user.profile.frustrations), None)
    has_children = user.profile.family_situation in {
        user_pb2.FAMILY_WITH_KIDS, user_pb2.SINGLE_PARENT_SITUATION
    }

    age = datetime.date.today().year - user.profile.year_of_birth
    max_young = 35

    return dict(
        campaign.get_default_vars(user), **{
            'frustration':
            user_pb2.Frustration.Name(worst_frustration)
            if worst_frustration else '',
            'hasChildren':
            campaign.as_template_boolean(has_children),
            'hasHandicap':
            campaign.as_template_boolean(user.profile.has_handicap),
            'hasHighSchoolDegree':
            campaign.as_template_boolean(
                user.profile.highest_degree >= job_pb2.BAC_BACPRO),
            'hasLargeNetwork':
            campaign.as_template_boolean(project.network_estimate >= 2),
            'hasWorkedBefore':
            campaign.as_template_boolean(
                project.kind != project_pb2.FIND_A_FIRST_JOB),
            'inCity':
            french.in_city(project.mobility.city.name),
            'inTargetDomain':
            in_target_domain,
            'isYoung':
            campaign.as_template_boolean(age <= max_young),
            'jobGroupInDepartement':
            '{} {}'.format(
                french.lower_first_letter(project.target_job.job_group.name),
                geo.get_in_a_departement_text(
                    database, project.mobility.city.departement_id)),
            'networkApplicationPercentage':
            network_application_importance,
        })
Example #14
0
def network_plus_vars(user: user_pb2.User,
                      database: Optional[pymongo.database.Database] = None,
                      **unused_kwargs: Any) -> Optional[Dict[str, str]]:
    """Compute vars for a given user for the network email.

    Returns:
        a dict with all vars required for the template, or None if no email
        should be sent.
    """

    project = user.projects[0]

    if project.network_estimate < 2:
        logging.info('User does not have a strong network')
        return None

    assert database
    job_group_info = jobs.get_group_proto(database,
                                          project.target_job.job_group.rome_id)
    if not job_group_info:
        logging.warning('Could not find job group info for "%s"',
                        project.target_job.job_group.rome_id)
        return None
    in_target_domain = job_group_info.in_domain
    application_modes = job_group_info.application_modes.values()
    if not in_target_domain:
        logging.warning('Could not find a target domain (%s)',
                        project.target_job.job_group)
        return None

    fap_modes = [
        fap_modes.modes for fap_modes in application_modes
        if len(fap_modes.modes)
    ]
    if not fap_modes:
        return None
    flat_fap_modes = [mode for modes in fap_modes for mode in modes]
    network_percentages = [
        mode.percentage for mode in flat_fap_modes
        if (mode.mode == job_pb2.PERSONAL_OR_PROFESSIONAL_CONTACTS)
    ]
    # We want to focus on the user for which network,
    # as an application mode, has a substantial importance.
    if not network_percentages:
        return None
    average_network_percentage = sum(network_percentages) / len(
        network_percentages)
    if average_network_percentage > 55:
        network_application_importance = 'que la majorité'
    elif average_network_percentage >= 45:
        network_application_importance = 'que la moitié'
    elif average_network_percentage >= 25:
        network_application_importance = "qu'un tiers"
    else:
        return None

    worst_frustration = next(
        (f for f in (user_pb2.SELF_CONFIDENCE, user_pb2.MOTIVATION)
         if f in user.profile.frustrations), None)
    has_children = user.profile.family_situation in {
        user_pb2.FAMILY_WITH_KIDS, user_pb2.SINGLE_PARENT_SITUATION
    }

    age = datetime.date.today().year - user.profile.year_of_birth
    max_young = 35

    try:
        in_departement = geo.get_in_a_departement_text(
            database, project.city.departement_id)
    except KeyError:
        logging.warning('Could not find departement (%s)',
                        project.city.departement_id)
        return None

    job_group_name = french.lower_first_letter(
        project.target_job.job_group.name)

    return dict(
        campaign.get_default_coaching_email_vars(user), **{
            'frustration':
            user_pb2.Frustration.Name(worst_frustration)
            if worst_frustration else '',
            'hasChildren':
            campaign.as_template_boolean(has_children),
            'hasHighSchoolDegree':
            campaign.as_template_boolean(
                user.profile.highest_degree >= job_pb2.BAC_BACPRO),
            'hasLargeNetwork':
            campaign.as_template_boolean(project.network_estimate >= 2),
            'hasWorkedBefore':
            campaign.as_template_boolean(
                project.kind != project_pb2.FIND_A_FIRST_JOB),
            'inCity':
            french.in_city(project.city.name),
            'inTargetDomain':
            in_target_domain,
            'isAbleBodied':
            campaign.as_template_boolean(not user.profile.has_handicap),
            'isYoung':
            campaign.as_template_boolean(age <= max_young),
            'jobGroupInDepartement':
            f'{job_group_name} {in_departement}',
            'networkApplicationPercentage':
            network_application_importance,
        })