def test_should_register_new_venue(app):
    # given
    user = ProFactory()
    auth_request = TestClient(app.test_client()).with_session_auth(email=user.email)
    venue_data = create_valid_venue_data(user)

    # when
    response = auth_request.post("/venues", json=venue_data)

    # then
    assert response.status_code == 201
    idx = response.json["id"]

    venue = Venue.query.filter_by(id=dehumanize(idx)).one()

    assert venue.name == venue_data["name"]
    assert venue.publicName == venue_data["publicName"]
    assert venue.siret == venue_data["siret"]
    assert venue.venueTypeId == dehumanize(venue_data["venueTypeId"])
    assert venue.venueLabelId == dehumanize(venue_data["venueLabelId"])
    assert venue.description == venue_data["description"]
    assert venue.audioDisabilityCompliant == venue_data["audioDisabilityCompliant"]
    assert venue.mentalDisabilityCompliant == venue_data["mentalDisabilityCompliant"]
    assert venue.motorDisabilityCompliant == venue_data["motorDisabilityCompliant"]
    assert venue.visualDisabilityCompliant == venue_data["visualDisabilityCompliant"]
    assert venue.contact.email == venue_data["contact"]["email"]

    assert venue.isValidated
    assert not venue.isPermanent
    assert not venue.contact.phone_number
    assert not venue.contact.social_medias
Esempio n. 2
0
def get_stocks(offer_id: str) -> StocksResponseModel:
    offerer = offerer_queries.get_by_offer_id(dehumanize(offer_id))
    check_user_has_access_to_offerer(current_user, offerer.id)

    stocks = get_stocks_for_offer(dehumanize(offer_id))
    return StocksResponseModel(
        stocks=[StockResponseModel.from_orm(stock) for stock in stocks],
    )
Esempio n. 3
0
def get_stocks(offer_id: str) -> StocksResponseModel:
    try:
        offerer = pcapi.core.offerers.repository.get_by_offer_id(dehumanize(offer_id))
    except offerers_exceptions.CannotFindOffererForOfferId:
        raise ApiErrors({"offerer": ["Aucune structure trouvée à partir de cette offre"]}, status_code=404)
    check_user_has_access_to_offerer(current_user, offerer.id)
    stocks = get_stocks_for_offer(dehumanize(offer_id))
    return StocksResponseModel(
        stocks=[StockResponseModel.from_orm(stock) for stock in stocks],
    )
Esempio n. 4
0
    def when_creating_new_thing_offer(self, app):
        # Given
        venue = offers_factories.VirtualVenueFactory()
        offerer = venue.managingOfferer
        offers_factories.UserOffererFactory(offerer=offerer, user__email="*****@*****.**")

        # When
        client = TestClient(app.test_client()).with_auth("*****@*****.**")
        data = {
            "venueId": humanize(venue.id),
            "bookingEmail": "*****@*****.**",
            "mediaUrls": ["http://example.com/media"],
            "name": "Les lièvres pas malins",
            "type": "ThingType.JEUX_VIDEO",
            "url": "http://example.com/offer",
        }
        response = client.post("/offers", json=data)

        # Then
        assert response.status_code == 201
        offer_id = dehumanize(response.json["id"])
        offer = Offer.query.get(offer_id)
        assert offer.bookingEmail == "*****@*****.**"
        assert offer.type == str(ThingType.JEUX_VIDEO)
        assert offer.venue == venue
        assert offer.product.name == "Les lièvres pas malins"
        assert offer.product.url == "http://example.com/offer"
        assert offer.url == "http://example.com/offer"
        assert offer.isDigital
        assert offer.isNational
        assert offer.product.isNational
        assert offer.product.owningOfferer == offerer
Esempio n. 5
0
    def test_create_event_offer(self, app):
        # Given
        venue = offers_factories.VenueFactory()
        offerer = venue.managingOfferer
        offers_factories.UserOffererFactory(offerer=offerer, user__email="*****@*****.**")

        # When
        data = {
            "venueId": humanize(venue.id),
            "bookingEmail": "*****@*****.**",
            "durationMinutes": 60,
            "name": "La pièce de théâtre",
            "type": str(EventType.SPECTACLE_VIVANT),
            "extraData": {"toto": "text"},
        }
        client = TestClient(app.test_client()).with_auth("*****@*****.**")
        response = client.post("/offers", json=data)

        # Then
        assert response.status_code == 201
        offer_id = dehumanize(response.json["id"])
        offer = Offer.query.get(offer_id)
        assert offer.bookingEmail == "*****@*****.**"
        assert offer.type == str(EventType.SPECTACLE_VIVANT)
        assert offer.extraData == {"toto": "text"}
        assert offer.venue == venue
        assert offer.product.durationMinutes == 60
        assert offer.product.owningOfferer == offerer
    def when_venue_provider_is_successfully_created(
            self, mock_siret_can_be_synchronized,
            mock_synchronize_venue_provider, app):
        # Given
        user = user_factories.AdminFactory()
        venue = offer_factories.VenueFactory(siret="12345678912345")

        provider = offerers_factories.APIProviderFactory()

        venue_provider_data = {
            "providerId": humanize(provider.id),
            "venueId": humanize(venue.id),
        }
        mock_siret_can_be_synchronized.return_value = True

        auth_request = TestClient(
            app.test_client()).with_session_auth(email=user.email)
        # When
        response = auth_request.post("/venueProviders",
                                     json=venue_provider_data)

        # Then
        assert response.status_code == 201
        venue_provider = VenueProvider.query.one()
        assert venue_provider.venueId == venue.id
        assert venue_provider.providerId == provider.id
        assert venue_provider.venueIdAtOfferProvider == "12345678912345"
        assert "id" in response.json

        venue_provider_id = response.json["id"]
        mock_synchronize_venue_provider.assert_called_once_with(
            dehumanize(venue_provider_id))
Esempio n. 7
0
    def test_create_valid_educational_offer(self, app):
        # Given
        venue = offers_factories.VenueFactory()
        offerer = venue.managingOfferer
        offers_factories.UserOffererFactory(offerer=offerer, user__email="*****@*****.**")

        # When
        data = {
            "venueId": humanize(venue.id),
            "bookingEmail": "*****@*****.**",
            "durationMinutes": 60,
            "name": "La pièce de théâtre",
            "subcategoryId": subcategories.SPECTACLE_REPRESENTATION.id,
            "extraData": {"toto": "text"},
            "externalTicketOfficeUrl": "http://example.net",
            "audioDisabilityCompliant": False,
            "mentalDisabilityCompliant": True,
            "motorDisabilityCompliant": False,
            "visualDisabilityCompliant": False,
            "isEducational": True,
        }
        client = TestClient(app.test_client()).with_session_auth("*****@*****.**")
        response = client.post("/offers", json=data)

        # Then
        assert response.status_code == 201
        offer_id = dehumanize(response.json["id"])
        offer = Offer.query.get(offer_id)
        assert offer.isEducational
Esempio n. 8
0
 def search(self, description, criteria):
     filters = self._build_filters(criteria)
     start = time.perf_counter()
     results = self.index.search(criteria.get("text", ""), filters)
     elapsed = time.perf_counter() - start
     # XXX: apparently, the Algolia index still contains offers
     # whose 'objectID' are a humanized id. This should not happen
     # anymore and those offers should be reindexed under their
     # numeric id instead. Example: CUUEE.
     for result in results["hits"]:
         if not result["objectID"].isdigit():
             print(
                 f'[Algolia] Found offer indexed with its humanized id: {result["objectID"]}'
             )
             result["objectID"] = human_ids.dehumanize(result["objectID"])
     return ResultSet(
         elapsed=elapsed,
         query=
         filters,  # searched text is missing but we don't need it for Algolia
         results=[
             Result(
                 id=int(result["objectID"]),
                 score=None,  # not useful for Algolia results
                 name=result["offer"]["name"],
                 full=result,
             ) for result in results["hits"]
         ],
     )
        def when_venue_provider_is_successfully_created(
            self, stubbed_find_by_id, stubbed_check, mock_synchronize_venue_provider, app
        ):
            # Given
            user = create_user(is_admin=True, is_beneficiary=False)
            offerer = create_offerer()
            venue = create_venue(offerer, siret="12345678912345")
            repository.save(venue, user)

            stubbed_find_by_id.return_value = venue

            provider = activate_provider("LibrairesStocks")

            venue_provider_data = {
                "providerId": humanize(provider.id),
                "venueId": humanize(venue.id),
            }

            auth_request = TestClient(app.test_client()).with_auth(email=user.email)
            stubbed_check.return_value = True

            # When
            response = auth_request.post("/venueProviders", json=venue_provider_data)

            # Then
            assert response.status_code == 201
            venue_provider = VenueProvider.query.one()
            assert venue_provider.venueId == venue.id
            assert venue_provider.providerId == provider.id
            assert venue_provider.venueIdAtOfferProvider == "12345678912345"
            assert "id" in response.json
            venue_provider_id = response.json["id"]
            mock_synchronize_venue_provider.assert_called_once_with(dehumanize(venue_provider_id))
Esempio n. 10
0
def get_booking(booking_id: int) -> Any:
    booking = (
        Booking.query.filter_by(id=dehumanize(booking_id)).options(joinedload(Booking.individualBooking)).first_or_404()
    )
    booking.userId = booking.individualBooking.userId

    return jsonify(as_dict(booking, includes=WEBAPP_GET_BOOKING_INCLUDES)), 200
Esempio n. 11
0
def get_user_offerer(offerer_id):
    user_offerers = UserOfferer.query.filter_by(
        user=current_user, offererId=dehumanize(offerer_id)).all()
    return jsonify([
        as_dict(user_offerer, includes=USER_OFFERER_INCLUDES)
        for user_offerer in user_offerers
    ]), 200
    def test_edit_one_stock(self, app):
        # Given
        offer = offers_factories.ThingOfferFactory()
        existing_stock = offers_factories.StockFactory(offer=offer, price=10)
        offers_factories.UserOffererFactory(
            user__email="*****@*****.**",
            offerer=offer.venue.managingOfferer,
        )

        # When
        stock_data = {
            "offerId": humanize(offer.id),
            "stocks": [{
                "id": humanize(existing_stock.id),
                "price": 20
            }],
        }
        response = TestClient(
            app.test_client()).with_auth("*****@*****.**").post(
                "/stocks/bulk/", json=stock_data)

        # Then
        assert response.status_code == 201

        response_dict = response.json
        assert len(response_dict["stockIds"]) == len(stock_data["stocks"])

        edited_stock = Stock.query.get(
            dehumanize(response_dict["stockIds"][0]["id"]))
        assert edited_stock.price == 20
Esempio n. 13
0
def _connect_stock_providers_to_venue(venue: VenueSQLEntity, venue_provider_payload: Dict) -> VenueProvider:
    venue_provider = VenueProvider()
    venue_provider.venue = venue
    venue_provider.providerId = dehumanize(venue_provider_payload["providerId"])
    venue_provider.venueIdAtOfferProvider = venue.siret

    repository.save(venue_provider)
    return venue_provider
Esempio n. 14
0
def delete_favorite(offer_id):
    dehumanized_offer_id = dehumanize(offer_id)

    favorite = find_favorite_for_offer_and_user(dehumanized_offer_id, current_user.id).first_or_404()

    repository.delete(favorite)

    return jsonify(as_dict(favorite)), 200
def update_from_csv_file(csv_file):
    # XXX: We don't look at CustomReimbursementRule.timespan here,
    # since we currently don't have multiple rules for the same offer,
    # and this script does not support that for simplicity's sake.
    existing_rules = {
        rule.offerId: rule
        for rule in CustomReimbursementRule.query.all()
    }

    results = {"errors": [], "warnings": [], "created": []}
    reader = csv.DictReader(csv_file, fieldnames=FIELD_NAMES)
    for line_nb, row in enumerate(reader, 1):
        if line_nb == 1:
            continue  # ignore header
        offer_id = dehumanize(row["humanized_offer_id"])
        reimbursed_amount = _get_amount(row["reimbursed_amount"])
        file_offer_amount = _get_amount(row["offer_amount"])

        offer = Offer.query.options(joinedload(
            Offer.stocks)).filter_by(id=offer_id).one_or_none()
        if not offer:
            results["errors"].append(
                f"line {line_nb}: File references unknown offer {row['humanized_offer_id']} ({offer_id})"
            )
            continue

        rule = existing_rules.get(offer_id)
        if rule:
            if rule.amount != reimbursed_amount:
                results["errors"].append(
                    f"line {line_nb}: Existing rule on offer {row['humanized_offer_id']} ({offer_id}) reimburses {rule.amount}, file says {reimbursed_amount}"
                )
            continue

        prices = {stock.price for stock in offer.stocks}
        if len(prices) > 1:
            results["warnings"].append(
                f"line {line_nb}: Found multiple prices for offer {row['humanized_offer_id']} ({offer_id}): {prices}"
            )
        if not prices:
            results["warnings"].append(
                f"line {line_nb}: No stock found in database for offer {row['humanized_offer_id']} ({offer_id}), but reimbursement rule has been added nevertheless"
            )
        else:
            db_offer_amount = prices.pop()
            if file_offer_amount != db_offer_amount:
                results["warnings"].append(
                    f"line {line_nb}: Price in database for offer {row['humanized_offer_id']} ({offer_id}) is {db_offer_amount}, file says {file_offer_amount}"
                )

        rule = CustomReimbursementRule(offerId=offer_id,
                                       amount=reimbursed_amount,
                                       timespan=DEFAULT_TIMESPAN)
        repository.save(rule)
        existing_rules[offer_id] = rule
        results["created"].append(rule)

    return results
Esempio n. 16
0
def _ensure_current_user_has_rights(user_id):
    if current_user.id != dehumanize(user_id):
        errors = ApiErrors()
        errors.add_error(
            "global",
            "Vous n'avez pas les droits d'accès suffisant pour effectuer cette modificaiton."
        )
        errors.status_code = 403
        raise errors
Esempio n. 17
0
def dehumanize_id(id_to_dehumanize: Optional[Union[int, str]]) -> Optional[int]:
    if id_to_dehumanize is None:
        return None

    # This is because dehumanize_id will be called on a str the first time
    # and then on ids already dehumanized. dehumanize can't work with int
    if isinstance(id_to_dehumanize, str):
        return dehumanize(id_to_dehumanize)

    return int(id_to_dehumanize)
Esempio n. 18
0
def create_booking(body: PostBookingBodyModel) -> PostBookingResponseModel:
    stock = Stock.query.filter_by(id=dehumanize(body.stock_id)).first_or_404() if body.stock_id else None

    booking = bookings_api.book_offer(
        beneficiary=current_user,
        stock=stock,
        quantity=body.quantity,
    )

    return PostBookingResponseModel(**serialize_booking_minimal(booking))
Esempio n. 19
0
def _create_allocine_venue_provider(
    allocine_theater_id: str, venue_provider_payload: Dict, venue: Venue
) -> AllocineVenueProvider:
    allocine_venue_provider = AllocineVenueProvider()
    allocine_venue_provider.venue = venue
    allocine_venue_provider.providerId = dehumanize(venue_provider_payload["providerId"])
    allocine_venue_provider.venueIdAtOfferProvider = allocine_theater_id
    allocine_venue_provider.isDuo = venue_provider_payload.get("isDuo")
    allocine_venue_provider.quantity = venue_provider_payload.get("quantity")

    return allocine_venue_provider
Esempio n. 20
0
def generate_api_key_route(offerer_id: str) -> GenerateOffererApiKeyResponse:
    check_user_has_access_to_offerer(current_user, dehumanize(offerer_id))
    offerer = load_or_404(Offerer, offerer_id)
    try:
        clear_key = api.generate_and_save_api_key(offerer.id)
    except ApiKeyCountMaxReached:
        raise ApiErrors({"api_key_count_max": "Le nombre de clés maximal a été atteint"})
    except ApiKeyPrefixGenerationError:
        raise ApiErrors({"api_key": "Could not generate api key"})

    return GenerateOffererApiKeyResponse(apiKey=clear_key)
Esempio n. 21
0
    def test_on_pc_object_for_valid_sql_humanize_id_value_with_key_finishing_by_Id(self):
        # Given
        test_pc_object = TestPcObject()
        humanized_entity_id = "AE"
        data = {"entityId": humanized_entity_id}

        # When
        test_pc_object.populate_from_dict(data)

        # Then
        assert test_pc_object.entityId == dehumanize(humanized_entity_id)
Esempio n. 22
0
def load_or_raise_error(obj_class, human_id):
    data = obj_class.query.filter_by(id=dehumanize(human_id)).first()
    if data is None:
        errors = ApiErrors()
        errors.add_error(
            "global",
            "Aucun objet ne correspond à cet identifiant dans notre base de données"
        )
        errors.status_code = 400
        raise errors

    return data
Esempio n. 23
0
def delete_stock(stock_id: str) -> StockResponseIdModel:
    # fmt: off
    stock = (Stock.queryNotSoftDeleted().filter_by(
        id=dehumanize(stock_id)).join(Offer, VenueSQLEntity).first_or_404())
    # fmt: on

    offerer_id = stock.offer.venue.managingOffererId
    ensure_current_user_has_rights(RightsType.editor, offerer_id)

    offers_api.delete_stock(stock)

    return StockResponseIdModel.from_orm(stock)
Esempio n. 24
0
def list_venue_providers():
    venue_id = request.args.get("venueId")
    if venue_id is None:
        e = ApiErrors()
        e.add_error("venueId",
                    "Vous devez obligatoirement fournir le paramètre venueId")
        return jsonify(e.errors), 400

    vp_query = VenueProvider.query.filter_by(venueId=dehumanize(venue_id))
    return jsonify([
        as_dict(venue_provider, includes=VENUE_PROVIDER_INCLUDES)
        for venue_provider in vp_query.all()
    ])
Esempio n. 25
0
def load_or_raise_error(obj_class: Model, human_id: str) -> Model:
    try:
        data = obj_class.query.filter_by(id=dehumanize(human_id)).one()
    except NoResultFound:
        raise ApiErrors(
            errors={
                "global": [
                    "Aucun objet ne correspond à cet identifiant dans notre base de données"
                ],
            },
            status_code=404,
        )
    return data
Esempio n. 26
0
def patch_booking_by_token(token: str) -> tuple[str, int]:
    email: Optional[str] = request.args.get("email", None)
    humanized_offer_id: Optional[str] = request.args.get("offer_id")
    offer_id: Optional[int] = dehumanize(humanized_offer_id)
    booking = booking_repository.find_by(token, email, offer_id)

    if current_user.is_authenticated:
        check_user_has_access_to_offerer(current_user, booking.offererId)
    else:
        check_email_and_offer_id_for_anonymous_user(email, offer_id)

    bookings_api.mark_as_used(booking)

    return "", 204
Esempio n. 27
0
def get_booking_by_token(token: str) -> tuple[str, int]:
    email: Optional[str] = request.args.get("email", None)
    offer_id = dehumanize(request.args.get("offer_id", None))

    check_user_is_logged_in_or_email_is_provided(current_user, email)

    booking = booking_repository.find_by(token, email, offer_id)
    bookings_validation.check_is_usable(booking)

    if check_user_can_validate_bookings(current_user, booking.offererId):
        response = _create_response_to_get_booking_by_token(booking)
        return jsonify(response), 200

    return "", 204
Esempio n. 28
0
def create_booking(body: PostBookingBodyModel) -> PostBookingResponseModel:
    if not body.stock_id:
        abort(404)

    try:
        booking = bookings_api.book_offer(
            beneficiary=current_user,
            stock_id=dehumanize(body.stock_id),
            quantity=body.quantity,
        )
    except StockDoesNotExist:
        abort(404)

    return PostBookingResponseModel(**serialize_booking_minimal(booking))
Esempio n. 29
0
def update_mediation(
        mediation_id: str,
        body: UpdateMediationBodyModel) -> UpdateMediationResponseModel:

    mediation = Mediation.query.filter_by(
        id=dehumanize(mediation_id)).first_or_404()

    ensure_current_user_has_rights(RightsType.editor,
                                   mediation.offer.venue.managingOffererId)

    mediation = offers_api.update_mediation(mediation=mediation,
                                            is_active=body.isActive)

    return UpdateMediationResponseModel.from_orm(mediation)
Esempio n. 30
0
def delete_venue_and_offers_for_venue_id(humanized_venue_id: str):
    dehumanized_venue_id = dehumanize(humanized_venue_id)
    offers = get_offers_by_venue_id(dehumanized_venue_id)
    venue = find_by_id(dehumanized_venue_id)

    if any(offer.stocks for offer in offers):
        raise AttributeError(
            "Offres non supprimables car au moins une contient des stocks")

    for offer in offers:
        repository.delete(offer)

    if venue:
        repository.delete(venue)