Skip to content

Commit

Permalink
(PC-30781)[API] feat: add allowed actions to collective offers api
Browse files Browse the repository at this point in the history
  • Loading branch information
jcicurel-pass committed Sep 16, 2024
1 parent b2589fd commit 1e2df26
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 4 deletions.
6 changes: 2 additions & 4 deletions api/src/pcapi/core/educational/api/offer.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@
from pcapi.core.educational.api import adage as educational_api_adage
import pcapi.core.educational.api.national_program as national_program_api
from pcapi.core.educational.exceptions import AdageException
from pcapi.core.educational.models import CollectiveOffer
from pcapi.core.educational.models import HasImageMixin
from pcapi.core.educational.utils import get_image_from_url
from pcapi.core.external.attributes.api import update_external_pro
from pcapi.core.mails import transactional as transactional_mails
Expand Down Expand Up @@ -615,7 +613,7 @@ def publish_collective_offer_template(
return offer_template


def delete_image(obj: HasImageMixin) -> None:
def delete_image(obj: educational_models.HasImageMixin) -> None:
obj.delete_image()
db.session.commit()
return
Expand Down Expand Up @@ -788,4 +786,4 @@ def get_offer_coordinates(offer: AnyCollectiveOffer) -> tuple[float | Decimal, f


def query_has_any_archived(collective_query: BaseQuery) -> bool:
return collective_query.filter(CollectiveOffer.isArchived).count() > 0
return collective_query.filter(educational_models.CollectiveOffer.isArchived).count() > 0
99 changes: 99 additions & 0 deletions api/src/pcapi/core/educational/models.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from datetime import date
from datetime import datetime
from datetime import timedelta
import decimal
from decimal import Decimal
import enum
Expand Down Expand Up @@ -128,6 +129,72 @@ class CollectiveOfferDisplayedStatus(enum.Enum):
DRAFT = "DRAFT"


class CollectiveOfferAllowedAction(enum.Enum):
CAN_EDIT_DETAILS = "CAN_EDIT_DETAILS"
CAN_EDIT_DATES = "CAN_EDIT_DATES"
CAN_EDIT_INSTITUTION = "CAN_EDIT_INSTITUTION"
CAN_EDIT_DISCOUNT = "CAN_EDIT_DISCOUNT"
CAN_DUPLICATE = "CAN_DUPLICATE"
CAN_CANCEL = "CAN_CANCEL"
CAN_ARCHIVE = "CAN_ARCHIVE"


ALLOWED_ACTIONS_BY_DISPLAYED_STATUS: dict[CollectiveOfferDisplayedStatus, tuple[CollectiveOfferAllowedAction, ...]] = {
CollectiveOfferDisplayedStatus.DRAFT: (
CollectiveOfferAllowedAction.CAN_EDIT_DETAILS,
CollectiveOfferAllowedAction.CAN_EDIT_DATES,
CollectiveOfferAllowedAction.CAN_EDIT_INSTITUTION,
CollectiveOfferAllowedAction.CAN_EDIT_DISCOUNT,
CollectiveOfferAllowedAction.CAN_ARCHIVE,
),
CollectiveOfferDisplayedStatus.PENDING: (CollectiveOfferAllowedAction.CAN_DUPLICATE,),
CollectiveOfferDisplayedStatus.ACTIVE: (
CollectiveOfferAllowedAction.CAN_EDIT_DETAILS,
CollectiveOfferAllowedAction.CAN_EDIT_DATES,
CollectiveOfferAllowedAction.CAN_EDIT_DISCOUNT,
CollectiveOfferAllowedAction.CAN_DUPLICATE,
CollectiveOfferAllowedAction.CAN_CANCEL,
CollectiveOfferAllowedAction.CAN_ARCHIVE,
),
CollectiveOfferDisplayedStatus.REJECTED: (
CollectiveOfferAllowedAction.CAN_DUPLICATE,
CollectiveOfferAllowedAction.CAN_ARCHIVE,
),
CollectiveOfferDisplayedStatus.PREBOOKED: (
CollectiveOfferAllowedAction.CAN_EDIT_DETAILS,
CollectiveOfferAllowedAction.CAN_EDIT_DATES,
CollectiveOfferAllowedAction.CAN_EDIT_DISCOUNT,
CollectiveOfferAllowedAction.CAN_DUPLICATE,
CollectiveOfferAllowedAction.CAN_CANCEL,
),
CollectiveOfferDisplayedStatus.BOOKED: (
CollectiveOfferAllowedAction.CAN_EDIT_DISCOUNT,
CollectiveOfferAllowedAction.CAN_DUPLICATE,
CollectiveOfferAllowedAction.CAN_CANCEL,
),
CollectiveOfferDisplayedStatus.EXPIRED: (
CollectiveOfferAllowedAction.CAN_EDIT_DATES,
CollectiveOfferAllowedAction.CAN_ARCHIVE,
),
CollectiveOfferDisplayedStatus.ENDED: ( # after 48h, cannot edit discount or cancel anymore
CollectiveOfferAllowedAction.CAN_EDIT_DISCOUNT,
CollectiveOfferAllowedAction.CAN_DUPLICATE,
CollectiveOfferAllowedAction.CAN_CANCEL,
CollectiveOfferAllowedAction.CAN_ARCHIVE,
),
CollectiveOfferDisplayedStatus.REIMBURSED: (
CollectiveOfferAllowedAction.CAN_DUPLICATE,
CollectiveOfferAllowedAction.CAN_ARCHIVE,
),
CollectiveOfferDisplayedStatus.CANCELLED: (
CollectiveOfferAllowedAction.CAN_DUPLICATE,
CollectiveOfferAllowedAction.CAN_ARCHIVE,
),
CollectiveOfferDisplayedStatus.ARCHIVED: (CollectiveOfferAllowedAction.CAN_DUPLICATE,),
CollectiveOfferDisplayedStatus.INACTIVE: (),
}


class EducationalBookingStatus(enum.Enum):
REFUSED = "REFUSED"

Expand Down Expand Up @@ -564,6 +631,14 @@ def dates(self) -> dict | None:
return None
return {"start": self.start, "end": self.end}

@property
def is_two_days_past_end(self) -> bool:
end = self.end
if end is None:
return False

return end + timedelta(days=2) < datetime.utcnow()

@property
def hasBookingLimitDatetimePassed(self) -> bool:
if self.collectiveStock:
Expand Down Expand Up @@ -694,6 +769,25 @@ def displayedStatus(self) -> CollectiveOfferDisplayedStatus:

return CollectiveOfferDisplayedStatus.ACTIVE

@property
def allowed_actions(self) -> list[CollectiveOfferAllowedAction]:
displayed_status = self.displayedStatus
allowed_actions = ALLOWED_ACTIONS_BY_DISPLAYED_STATUS[displayed_status]

# an offer that has ended more than 48 hours ago cannot be edited or canceled
if displayed_status == CollectiveOfferDisplayedStatus.ENDED and self.is_two_days_past_end:
return list(
action
for action in allowed_actions
if action
not in {
CollectiveOfferAllowedAction.CAN_EDIT_DISCOUNT,
CollectiveOfferAllowedAction.CAN_CANCEL,
}
)

return list(allowed_actions)

@property
def subcategory(self) -> subcategories.Subcategory | None:
if self.subcategoryId not in subcategories.ALL_SUBCATEGORIES_DICT:
Expand Down Expand Up @@ -931,6 +1025,11 @@ def displayedStatus(self) -> CollectiveOfferDisplayedStatus:

return CollectiveOfferDisplayedStatus.ACTIVE

@property
def allowed_actions(self) -> None:
# TODO: this will be implemented once the actions are defined for an OfferTemplate
return None

@property
def start(self) -> datetime | None:
if not self.dateRange:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from pcapi.core.educational.models import CollectiveBooking
from pcapi.core.educational.models import CollectiveBookingStatus
from pcapi.core.educational.models import CollectiveOffer
from pcapi.core.educational.models import CollectiveOfferAllowedAction
from pcapi.core.educational.models import CollectiveOfferDisplayedStatus
from pcapi.core.educational.models import CollectiveOfferTemplate
from pcapi.core.educational.models import CollectiveStock
Expand Down Expand Up @@ -153,6 +154,7 @@ class CollectiveOfferResponseModel(BaseModel):
venue: base_serializers.ListOffersVenueResponseModel
status: CollectiveOfferStatus
displayedStatus: CollectiveOfferDisplayedStatus
allowedActions: list[CollectiveOfferAllowedAction] | None
educationalInstitution: EducationalInstitutionResponseModel | None
interventionArea: list[str]
templateId: str | None
Expand Down Expand Up @@ -207,6 +209,7 @@ def _serialize_offer_paginated(offer: CollectiveOffer | CollectiveOfferTemplate)
venue=_serialize_venue(offer.venue), # type: ignore[arg-type]
status=offer.status.name,
displayedStatus=offer.displayedStatus,
allowedActions=offer.allowed_actions,
isShowcase=is_offer_template,
educationalInstitution=EducationalInstitutionResponseModel.from_orm(institution) if institution else None,
interventionArea=offer.interventionArea,
Expand Down Expand Up @@ -433,11 +436,13 @@ class GetCollectiveOfferResponseModel(GetCollectiveOfferBaseResponseModel):
formats: typing.Sequence[subcategories.EacFormat] | None
isTemplate: bool = False
dates: TemplateDatesModel | None
allowedActions: list[CollectiveOfferAllowedAction] | None

@classmethod
def from_orm(cls, offer: CollectiveOffer) -> "GetCollectiveOfferResponseModel":
result = super().from_orm(offer)
result.formats = offer.get_formats()
result.allowedActions = offer.allowed_actions

if result.status == CollectiveOfferStatus.INACTIVE.name:
result.isActive = False
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,13 @@ def test_duplicate_collective_offer(self, client):
"end": format_into_utc_date(offer.collectiveStock.endDatetime),
"start": format_into_utc_date(offer.collectiveStock.startDatetime),
},
"allowedActions": [
"CAN_EDIT_DETAILS",
"CAN_EDIT_DATES",
"CAN_EDIT_INSTITUTION",
"CAN_EDIT_DISCOUNT",
"CAN_ARCHIVE",
],
}

def test_duplicate_collective_offer_without_subcategoryId(self, client):
Expand Down

0 comments on commit 1e2df26

Please sign in to comment.