Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 18 additions & 15 deletions api/src/pcapi/core/educational/api/adage.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,9 @@
from pydantic.v1 import parse_obj_as

from pcapi.core.educational import adage_backends as adage_client
from pcapi.core.educational import models as educational_models
from pcapi.core.educational import models
from pcapi.core.educational import schemas
from pcapi.core.educational.api.venue import get_relative_venues_by_siret
from pcapi.core.educational.schemas import AdageCulturalPartner
from pcapi.core.educational.schemas import AdageCulturalPartners
from pcapi.core.history import api as history_api
from pcapi.core.history import models as history_models
from pcapi.core.mails.transactional import send_eac_offerer_activation_email
Expand All @@ -31,7 +30,9 @@
logger = logging.getLogger(__name__)


def get_cultural_partners(*, since_date: datetime | None = None, force_update: bool = False) -> AdageCulturalPartners:
def get_cultural_partners(
*, since_date: datetime | None = None, force_update: bool = False
) -> schemas.AdageCulturalPartners:
CULTURAL_PARTNERS_CACHE_KEY = "api:adage_cultural_partner:cache"
CULTURAL_PARTNERS_CACHE_TIMEOUT = 24 * 60 * 60 # 24h in seconds

Expand All @@ -53,7 +54,7 @@ def _get_cultural_partners() -> str:

cultural_partners_json = typing.cast(str, cultural_partners_json)
cultural_partners = json.loads(cultural_partners_json)
return parse_obj_as(AdageCulturalPartners, {"partners": cultural_partners})
return parse_obj_as(schemas.AdageCulturalPartners, {"partners": cultural_partners})


def get_cultural_partner(siret: str) -> venues_serialize.AdageCulturalPartnerResponseModel:
Expand Down Expand Up @@ -94,7 +95,7 @@ def get_venue_by_id_for_adage_iframe(
return venue, relative


def synchronize_adage_ids_on_offerers(partners_from_adage: list[AdageCulturalPartner]) -> None:
def synchronize_adage_ids_on_offerers(partners_from_adage: list[schemas.AdageCulturalPartner]) -> None:
adage_sirens: set[str] = {p.siret[:9] for p in partners_from_adage if (p.actif == 1 and p.siret)}
existing_sirens: dict[str, bool] = dict(
db.session.query( # type: ignore [arg-type]
Expand Down Expand Up @@ -153,7 +154,9 @@ class CulturalPartner:
active: int | None


def synchronize_adage_ids_on_venues(adage_cultural_partners: AdageCulturalPartners, debug: bool = False) -> None:
def synchronize_adage_ids_on_venues(
adage_cultural_partners: schemas.AdageCulturalPartners, debug: bool = False
) -> None:
from pcapi.core.external.attributes.api import update_external_pro

adage_cps = []
Expand Down Expand Up @@ -320,18 +323,18 @@ def get_redactor_favorites_count(redactor_id: int) -> int:
"""
Note: Non-eligible for search templates are ignored.
"""
redactor: educational_models.EducationalRedactor = (
db.session.query(educational_models.EducationalRedactor)
redactor = (
db.session.query(models.EducationalRedactor)
.filter_by(id=redactor_id)
.options(
sa_orm.joinedload(educational_models.EducationalRedactor.favoriteCollectiveOfferTemplates)
sa_orm.joinedload(models.EducationalRedactor.favoriteCollectiveOfferTemplates)
.load_only(
educational_models.CollectiveOfferTemplate.id,
educational_models.CollectiveOfferTemplate.venueId,
educational_models.CollectiveOfferTemplate.validation,
educational_models.CollectiveOfferTemplate.isActive,
models.CollectiveOfferTemplate.id,
models.CollectiveOfferTemplate.venueId,
models.CollectiveOfferTemplate.validation,
models.CollectiveOfferTemplate.isActive,
)
.joinedload(educational_models.CollectiveOfferTemplate.venue)
.joinedload(models.CollectiveOfferTemplate.venue)
.load_only(
offerers_models.Venue.managingOffererId,
offerers_models.Venue.isVirtual,
Expand Down
54 changes: 27 additions & 27 deletions api/src/pcapi/core/educational/api/playlists.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@

import sqlalchemy as sa

import pcapi.connectors.big_query.queries as big_query
import pcapi.connectors.big_query.queries.adage_playlists as bq_playlists
import pcapi.core.educational.api.institution as institution_api
import pcapi.core.educational.models as educational_models
from pcapi.connectors.big_query import queries as big_query
from pcapi.connectors.big_query.queries import adage_playlists as bq_playlists
from pcapi.connectors.big_query.queries.base import BaseQuery
from pcapi.core.educational import models
from pcapi.core.educational import repository
from pcapi.core.educational.api import institution as institution_api
from pcapi.core.offerers import models as offerers_models
from pcapi.models import db
from pcapi.utils.transaction_manager import atomic
Expand Down Expand Up @@ -38,28 +38,28 @@ def format_collective_offer_id(collective_offer_id: str) -> int:


QUERY_DESC = {
educational_models.PlaylistType.CLASSROOM: QueryCtx(
models.PlaylistType.CLASSROOM: QueryCtx(
query=big_query.ClassroomPlaylistQuery,
bq_attr_name="collective_offer_id",
bq_attr_formatter=format_collective_offer_id,
local_attr_name="collectiveOfferTemplateId",
foreign_class=educational_models.CollectiveOfferTemplate,
foreign_class=models.CollectiveOfferTemplate,
),
educational_models.PlaylistType.NEW_OFFER: QueryCtx(
models.PlaylistType.NEW_OFFER: QueryCtx(
query=big_query.NewTemplateOffersPlaylistQuery,
bq_attr_name="collective_offer_id",
bq_attr_formatter=format_collective_offer_id,
local_attr_name="collectiveOfferTemplateId",
foreign_class=educational_models.CollectiveOfferTemplate,
foreign_class=models.CollectiveOfferTemplate,
),
educational_models.PlaylistType.LOCAL_OFFERER: QueryCtx(
models.PlaylistType.LOCAL_OFFERER: QueryCtx(
query=big_query.LocalOfferersQuery,
bq_attr_name="venue_id",
bq_attr_formatter=int,
local_attr_name="venueId",
foreign_class=offerers_models.Venue,
),
educational_models.PlaylistType.NEW_OFFERER: QueryCtx(
models.PlaylistType.NEW_OFFERER: QueryCtx(
query=big_query.NewOffererQuery,
bq_attr_name="venue_id",
bq_attr_formatter=int,
Expand All @@ -75,18 +75,18 @@ def format_collective_offer_id(collective_offer_id: str) -> int:


def synchronize_institution_playlist(
playlist_type: educational_models.PlaylistType,
institution: educational_models.EducationalInstitution,
playlist_type: models.PlaylistType,
institution: models.EducationalInstitution,
rows: BigQueryPlaylistModels,
) -> None:
ctx = QUERY_DESC[playlist_type]
new_rows = {ctx.bq_attr_formatter(getattr(row, ctx.bq_attr_name)): row.distance_in_km for row in rows}

actual_rows = {
getattr(row, ctx.local_attr_name): row
for row in db.session.query(educational_models.CollectivePlaylist).filter(
educational_models.CollectivePlaylist.type == playlist_type,
educational_models.CollectivePlaylist.institutionId == institution.id,
for row in db.session.query(models.CollectivePlaylist).filter(
models.CollectivePlaylist.type == playlist_type,
models.CollectivePlaylist.institutionId == institution.id,
)
}

Expand Down Expand Up @@ -116,8 +116,8 @@ def synchronize_institution_playlist(
]

if playlist_ids_to_remove:
db.session.query(educational_models.CollectivePlaylist).filter(
educational_models.CollectivePlaylist.id.in_(playlist_ids_to_remove)
db.session.query(models.CollectivePlaylist).filter(
models.CollectivePlaylist.id.in_(playlist_ids_to_remove)
).delete()
if playlist_items_to_add:
# Ensure that objects added to playlist still exist before insertion
Expand All @@ -129,12 +129,12 @@ def synchronize_institution_playlist(
playlist_items_to_really_add = [
item for item in playlist_items_to_add if item[ctx.local_attr_name] in existing_foreign_ids
]
db.session.execute(sa.insert(educational_models.CollectivePlaylist), playlist_items_to_really_add)
db.session.execute(sa.insert(models.CollectivePlaylist), playlist_items_to_really_add)
if playlist_items_to_update:
db.session.execute(sa.update(educational_models.CollectivePlaylist), playlist_items_to_update)
db.session.execute(sa.update(models.CollectivePlaylist), playlist_items_to_update)


def synchronize_collective_playlist(playlist_type: educational_models.PlaylistType) -> None:
def synchronize_collective_playlist(playlist_type: models.PlaylistType) -> None:
ctx = QUERY_DESC[playlist_type]
institution = None
institution_rows: BigQueryPlaylistModels = []
Expand All @@ -143,7 +143,7 @@ def synchronize_collective_playlist(playlist_type: educational_models.PlaylistTy
for row in ctx.query().execute(page_size=BIGQUERY_PLAYLIST_BATCH_SIZE):
current_institution_id = int(getattr(row, "institution_id"))
if institution is None:
institution = db.session.get(educational_models.EducationalInstitution, current_institution_id)
institution = db.session.get(models.EducationalInstitution, current_institution_id)

assert institution # helps mypy

Expand All @@ -164,7 +164,7 @@ def synchronize_collective_playlist(playlist_type: educational_models.PlaylistTy

has_error = True

institution = db.session.get(educational_models.EducationalInstitution, current_institution_id)
institution = db.session.get(models.EducationalInstitution, current_institution_id)
institution_rows = []

institution_rows.append(row)
Expand All @@ -183,17 +183,17 @@ def synchronize_collective_playlist(playlist_type: educational_models.PlaylistTy


def get_playlist_items(
institution: educational_models.EducationalInstitution,
playlist_type: educational_models.PlaylistType,
institution: models.EducationalInstitution,
playlist_type: models.PlaylistType,
min_items: int = 10,
) -> typing.Collection[educational_models.CollectivePlaylist]:
) -> typing.Collection[models.CollectivePlaylist]:
playlist_items = (
repository.get_collective_offer_templates_for_playlist_query(
institution_id=institution.id,
playlist_type=playlist_type,
max_distance=institution_api.get_playlist_max_distance(institution),
)
.distinct(educational_models.CollectivePlaylist.venueId)
.distinct(models.CollectivePlaylist.venueId)
.limit(10)
.all()
)
Expand All @@ -206,7 +206,7 @@ def get_playlist_items(
playlist_type=playlist_type,
min_distance=institution_api.get_playlist_max_distance(institution),
)
.distinct(educational_models.CollectivePlaylist.venueId)
.distinct(models.CollectivePlaylist.venueId)
.limit(missing_count)
.all()
)
Expand Down
33 changes: 15 additions & 18 deletions api/src/pcapi/core/educational/api/shared.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import datetime

from pcapi.core.educational import exceptions as educational_exceptions
from pcapi.core.educational import models as educational_models
from pcapi.core.educational import repository as educational_repository
from pcapi.core.educational import utils as educational_utils
from pcapi.core.educational import exceptions
from pcapi.core.educational import models
from pcapi.core.educational import repository
from pcapi.core.educational import utils
from pcapi.utils import date as date_utils


def update_collective_stock_booking(
stock: educational_models.CollectiveStock,
current_booking: educational_models.CollectiveBooking | None,
stock: models.CollectiveStock,
current_booking: models.CollectiveBooking | None,
start_datetime_has_changed: bool,
) -> None:
"""When a collective stock is updated, we also update some fields of its related booking"""
Expand All @@ -26,7 +26,7 @@ def update_collective_stock_booking(
# the booking to update should either be the expired booking that was set back to PENDING
# or the non-cancelled booking (there should not be one of each at the same time)
if expired_booking_to_update and current_booking:
raise educational_exceptions.MultipleCollectiveBookingFound()
raise exceptions.MultipleCollectiveBookingFound()

booking_to_update = expired_booking_to_update or current_booking
if booking_to_update:
Expand All @@ -38,37 +38,34 @@ def update_collective_stock_booking(


def _update_collective_booking_educational_year_id(
booking: educational_models.CollectiveBooking,
new_start_datetime: datetime.datetime,
booking: models.CollectiveBooking, new_start_datetime: datetime.datetime
) -> None:
educational_year = educational_repository.find_educational_year_by_date(new_start_datetime)
educational_year = repository.find_educational_year_by_date(new_start_datetime)
if educational_year is None:
raise educational_exceptions.EducationalYearNotFound()
raise exceptions.EducationalYearNotFound()

booking.educationalYear = educational_year


def _update_collective_booking_cancellation_limit_date(
booking: educational_models.CollectiveBooking, new_start_datetime: datetime.datetime
booking: models.CollectiveBooking, new_start_datetime: datetime.datetime
) -> None:
# if the input date has a timezone (resp. does not have one), we need to compare it with an aware datetime (resp. a naive datetime)
now = (
date_utils.get_naive_utc_now()
if new_start_datetime.tzinfo is None
else datetime.datetime.now(datetime.timezone.utc)
)
booking.cancellationLimitDate = educational_utils.compute_educational_booking_cancellation_limit_date(
new_start_datetime, now
)
booking.cancellationLimitDate = utils.compute_educational_booking_cancellation_limit_date(new_start_datetime, now)


def _update_collective_booking_pending(expired_booking: educational_models.CollectiveBooking) -> None:
expired_booking.status = educational_models.CollectiveBookingStatus.PENDING
def _update_collective_booking_pending(expired_booking: models.CollectiveBooking) -> None:
expired_booking.status = models.CollectiveBookingStatus.PENDING
expired_booking.cancellationReason = None
expired_booking.cancellationDate = None


def _should_update_collective_booking_pending(
booking: educational_models.CollectiveBooking | None, booking_limit: datetime.datetime
booking: models.CollectiveBooking | None, booking_limit: datetime.datetime
) -> bool:
return booking is not None and booking.is_expired and booking_limit > date_utils.get_naive_utc_now()
Loading
Loading