def should_call_email_service_for_individual_bookings_which_will_expire_in_7_days(
            self, mocked_email_recap, app) -> None:
        # Given
        now = date.today()
        booking_date_23_days_ago = now - timedelta(days=23)
        booking_date_22_days_ago = now - timedelta(days=22)

        dvd = ProductFactory(
            subcategoryId=subcategories.SUPPORT_PHYSIQUE_FILM.id)
        expire_in_7_days_dvd_individual_booking = IndividualBookingFactory(
            stock__offer__product=dvd,
            dateCreated=booking_date_23_days_ago,
            isCancelled=False,
        )
        non_expired_cd = ProductFactory(
            subcategoryId=subcategories.SUPPORT_PHYSIQUE_MUSIQUE.id)
        dont_expire_in_7_days_cd_individual_booking = IndividualBookingFactory(
            stock__offer__product=non_expired_cd,
            dateCreated=booking_date_22_days_ago,
            isCancelled=False,
        )
        repository.save(dont_expire_in_7_days_cd_individual_booking)

        # When
        notify_users_of_soon_to_be_expired_individual_bookings()

        # Then
        mocked_email_recap.assert_called_once_with(
            expire_in_7_days_dvd_individual_booking.individualBooking.user,
            [expire_in_7_days_dvd_individual_booking])
def test_get_user_attributes():
    user = BeneficiaryGrant18Factory(deposit__version=1)
    offer = OfferFactory(product__id=list(TRACKED_PRODUCT_IDS.keys())[0])
    b1 = IndividualBookingFactory(individualBooking__user=user,
                                  amount=10,
                                  stock__offer=offer)
    b2 = IndividualBookingFactory(individualBooking__user=user,
                                  amount=10,
                                  dateUsed=datetime(2021, 5, 6),
                                  stock__offer=offer)
    IndividualBookingFactory(
        individualBooking__user=user,
        amount=100,
        status=BookingStatus.CANCELLED)  # should be ignored

    last_date_created = max(booking.dateCreated for booking in [b1, b2])

    n_query_get_user = 1
    n_query_get_bookings = 1
    n_query_get_deposit = 1
    n_query_is_pro = 1
    n_query_get_last_favorite = 1

    with assert_num_queries(n_query_get_user + n_query_get_bookings +
                            n_query_get_deposit + n_query_is_pro +
                            n_query_get_last_favorite):
        attributes = get_user_attributes(user)

    assert attributes == UserAttributes(
        domains_credit=DomainsCredit(
            all=Credit(initial=Decimal("500"), remaining=Decimal("480.00")),
            digital=Credit(initial=Decimal("200"), remaining=Decimal("200")),
            physical=Credit(initial=200, remaining=Decimal("180.00")),
        ),
        booking_categories=["FILM"],
        date_created=user.dateCreated,
        date_of_birth=user.dateOfBirth,
        departement_code="75",
        deposit_expiration_date=user.deposit_expiration_date,
        eligibility=EligibilityType.AGE18,
        first_name="Jeanne",
        is_beneficiary=True,
        is_pro=False,
        last_booking_date=last_date_created,
        last_name="Doux",
        marketing_push_subscription=True,
        postal_code=None,
        products_use_date={"product_brut_x_use": datetime(2021, 5, 6, 0, 0)},
        booking_count=2,
        booking_subcategories=["SUPPORT_PHYSIQUE_FILM"],
        deposit_activation_date=user.deposit_activation_date,
        has_completed_id_check=None,
        user_id=user.id,
        is_eligible=True,
        is_email_validated=True,
        last_favorite_creation_date=None,
        last_visit_date=None,
        marketing_email_subscription=True,
    )
def test_get_bookings_categories_and_subcategories():
    user = BeneficiaryGrant18Factory()
    offer = OfferFactory(product__id=list(TRACKED_PRODUCT_IDS.keys())[0])

    assert _get_bookings_categories_and_subcategories(
        _get_user_bookings(user)) == ([], [])

    IndividualBookingFactory(individualBooking__user=user, stock__offer=offer)
    IndividualBookingFactory(individualBooking__user=user, stock__offer=offer)
    IndividualBookingFactory(individualBooking__user=user, isCancelled=True)

    assert _get_bookings_categories_and_subcategories(
        _get_user_bookings(user)) == (["FILM"], ["SUPPORT_PHYSIQUE_FILM"])
Exemplo n.º 4
0
    def when_user_has_booked_some_offers(self, app):
        # Given
        user = BeneficiaryGrant18Factory(email="*****@*****.**",
                                         postalCode="93020",
                                         deposit__version=1)

        IndividualBookingFactory(individualBooking__user=user, amount=5)

        # When
        response = (TestClient(app.test_client()).with_session_auth(
            "*****@*****.**").get("/beneficiaries/current"))

        # Then
        assert response.json["wallet_balance"] == 495.0
        assert response.json["domainsCredit"] == {
            "all": {
                "initial": 500.0,
                "remaining": 495.0
            },
            "digital": {
                "initial": 200.0,
                "remaining": 200.0
            },
            "physical": {
                "initial": 200.0,
                "remaining": 195.0
            },
        }
    def when_current_user_has_rights_on_offer(self, app, db_session):
        # given
        offer = offers_factories.OfferFactory()
        offers_factories.UserOffererFactory(
            user__email="*****@*****.**",
            offerer=offer.venue.managingOfferer,
        )
        stock = offers_factories.StockFactory(offer=offer)
        booking = IndividualBookingFactory(stock=stock)

        # when
        client = TestClient(
            app.test_client()).with_session_auth("*****@*****.**")
        response = client.delete(f"/stocks/{humanize(stock.id)}")

        # then
        assert response.status_code == 200
        assert response.json == {"id": humanize(stock.id)}
        assert stock.isSoftDeleted
        assert push_testing.requests[-1] == {
            "group_id": "Cancel_booking",
            "message": {
                "body":
                f"""Ta commande "{offer.name}" a été annulée par l'offreur.""",
                "title": "Commande annulée",
            },
            "user_ids": [booking.individualBooking.userId],
        }
Exemplo n.º 6
0
def test_format_batch_user():
    user = BeneficiaryGrant18Factory(deposit__version=1)
    booking = IndividualBookingFactory(individualBooking__user=user)

    res = format_batch_users([user])

    assert len(res) == 1
    assert res[0].attributes == {
        "date(u.date_created)":
        user.dateCreated.strftime(BATCH_DATETIME_FORMAT),
        "date(u.date_of_birth)":
        user.dateOfBirth.strftime(BATCH_DATETIME_FORMAT),
        "date(u.deposit_expiration_date)":
        user.deposit_expiration_date.strftime(BATCH_DATETIME_FORMAT),
        "date(u.last_booking_date)":
        booking.dateCreated.strftime(BATCH_DATETIME_FORMAT),
        "u.credit":
        49000,
        "u.departement_code":
        "75",
        "u.is_beneficiary":
        True,
        "u.marketing_push_subscription":
        True,
        "u.postal_code":
        None,
        "ut.booking_categories": ["FILM"],
    }
Exemplo n.º 7
0
def test_format_sendinblue_user():
    user = BeneficiaryGrant18Factory(deposit__version=1)
    booking = IndividualBookingFactory(individualBooking__user=user)

    res = format_sendinblue_users([user])

    assert len(res) == 1
    assert res[0].email == user.email
    assert res[0].attributes == {
        "BOOKED_OFFER_CATEGORIES": "FILM",
        "BOOKED_OFFER_SUBCATEGORIES": "SUPPORT_PHYSIQUE_FILM",
        "BOOKING_COUNT": 1,
        "CREDIT": Decimal("490.00"),
        "DATE_CREATED": user.dateCreated,
        "DATE_OF_BIRTH": user.dateOfBirth,
        "DEPARTMENT_CODE": "75",
        "DEPOSIT_ACTIVATION_DATE": user.deposit_activation_date,
        "DEPOSIT_EXPIRATION_DATE": user.deposit_expiration_date,
        "ELIGIBILITY": user.eligibility,
        "FIRSTNAME": "Jeanne",
        "HAS_COMPLETED_ID_CHECK": None,
        "INITIAL_CREDIT": Decimal("500"),
        "IS_BENEFICIARY": True,
        "IS_ELIGIBLE": user.is_eligible,
        "IS_EMAIL_VALIDATED": user.isEmailValidated,
        "IS_PRO": False,
        "LASTNAME": "Doux",
        "LAST_BOOKING_DATE": booking.dateCreated,
        "LAST_FAVORITE_CREATION_DATE": None,
        "LAST_VISIT_DATE": None,
        "MARKETING_EMAIL_SUBSCRIPTION": True,
        "POSTAL_CODE": None,
        "PRODUCT_BRUT_X_USE_DATE": None,
        "USER_ID": user.id,
    }
    def when_user_has_bookings_and_qr_code_feature_is_active(
            self, qr_code_is_active, app):
        # Given
        user1 = BeneficiaryGrant18Factory(email="*****@*****.**")
        user2 = BeneficiaryGrant18Factory(email="*****@*****.**")
        venue = VenueFactory(latitude=None, longitude=None)
        offer = ThingOfferFactory(venue=venue)
        offer2 = ThingOfferFactory()
        stock = ThingStockFactory(offer=offer, price=0, quantity=None)
        stock2 = ThingStockFactory(offer=offer2, price=0)
        IndividualBookingFactory(individualBooking__user=user1,
                                 stock=stock,
                                 token="ABCDEF")
        IndividualBookingFactory(individualBooking__user=user2,
                                 stock=stock,
                                 token="GHIJK")
        IndividualBookingFactory(individualBooking__user=user1,
                                 stock=stock2,
                                 token="BBBBB")

        # When
        response = TestClient(app.test_client()).with_session_auth(
            user1.email).get("/bookings")

        # Then
        all_bookings = response.json
        assert len(all_bookings) == 2
        first_booking = all_bookings[0]
        assert response.status_code == 200
        assert "qrCode" in first_booking
        assert "completedUrl" in first_booking
        assert "isEventExpired" in first_booking
        assert "offer" in first_booking["stock"]
        assert "isEventExpired" in first_booking["stock"]
        assert "isDigital" in first_booking["stock"]["offer"]
        assert "isEvent" in first_booking["stock"]["offer"]
        assert "thumbUrl" in first_booking["stock"]["offer"]
        assert "stocks" in first_booking["stock"]["offer"]
        assert "venue" in first_booking["stock"]["offer"]
        assert "validationToken" not in first_booking["stock"]["offer"][
            "venue"]
def _create_has_booked_some_bookings(bookings_by_name, offers_by_name, user,
                                     user_name):

    for (offer_index, (offer_name,
                       offer)) in enumerate(list(offers_by_name.items())):
        # FIXME (viconnex, 2020-12-22) trying to adapt previous code - not sure of the result and intention
        # FIXME (asaunier, 2021-01-22) UPDATE - We should replace the "ratio" mechanism by a more immutable data
        #  construction. We currently pick among the list of available offers that may change.
        if offer_index % OFFER_WITH_BOOKINGS_RATIO != 0:
            continue
        domains_credit = get_domains_credit(user)
        digital_credit = domains_credit.digital
        all_credit = domains_credit.all

        if digital_credit and digital_credit.remaining < MAX_RATIO_OF_INITIAL_CREDIT * float(
                digital_credit.initial):
            break

        if all_credit.remaining < MAX_RATIO_OF_INITIAL_CREDIT * float(
                all_credit.initial):
            break

        is_activation_offer = offer.product.subcategoryId in (
            subcategories.ACTIVATION_EVENT.id
            or subcategories.ACTIVATION_THING.id)

        stock = choice(offer.stocks)

        if is_activation_offer:
            is_used = True
        else:
            is_used = offer_index % BOOKINGS_USED_REMOVE_MODULO != 0

        if is_used:
            stock.beginningDatetime = datetime.now() - timedelta(days=2)
            stock.bookingLimitDatetime = datetime.now() - timedelta(days=5)
            repository.save(stock)

        booking = IndividualBookingFactory(
            individualBooking__user=user,
            isUsed=is_used,
            status=BookingStatus.USED if is_used else BookingStatus.CONFIRMED,
            stock=stock,
            dateUsed=datetime.now() - timedelta(days=2) if is_used else None,
        )
        booking_name = "{} / {} / {}".format(offer_name, user_name,
                                             booking.token)
        bookings_by_name[booking_name] = booking
def test_update_external_user():
    user = BeneficiaryGrant18Factory()
    IndividualBookingFactory(individualBooking__user=user)

    n_query_get_user = 1
    n_query_get_bookings = 1
    n_query_get_deposit = 1
    n_query_is_pro = 1
    n_query_get_last_favorite = 1

    with assert_num_queries(n_query_get_user + n_query_get_bookings +
                            n_query_get_deposit + n_query_is_pro +
                            n_query_get_last_favorite):
        update_external_user(user)

    assert len(batch_testing.requests) == 1
    assert len(sendinblue_testing.sendinblue_requests) == 1
Exemplo n.º 11
0
def test_pc_send_tomorrow_events_notifications_only_to_individual_bookings_users(
):
    """
    Test that each stock that is linked to an offer that occurs tomorrow and
    creates a job that will send a notification to all of the stock's users
    with a valid (not cancelled) booking, for individual bookings only.
    """
    tomorrow = datetime.now() + timedelta(days=1)
    stock_tomorrow = EventStockFactory(beginningDatetime=tomorrow,
                                       offer__name="my_offer")

    begin = datetime.now() + timedelta(days=7)
    stock_next_week = EventStockFactory(beginningDatetime=begin)

    bookings_tomorrow = IndividualBookingFactory.create_batch(
        2, stock=stock_tomorrow, isCancelled=False)
    BookingFactory.create_batch(2,
                                stock=stock_tomorrow,
                                isCancelled=True,
                                status=BookingStatus.CANCELLED)
    BookingFactory.create_batch(2, stock=stock_next_week, isCancelled=False)
    EducationalBookingFactory.create_batch(2,
                                           stock=stock_tomorrow,
                                           isCancelled=False)

    pc_send_tomorrow_events_notifications()

    assert len(testing.requests) == 1
    assert all(data["message"]["title"] == "my_offer, c'est demain !"
               for data in testing.requests)

    user_ids = set()
    for data in testing.requests:
        for user_id in data["user_ids"]:
            user_ids.add(user_id)

    expected_user_ids = {
        booking.individualBooking.userId
        for booking in bookings_tomorrow
    }
    assert user_ids == expected_user_ids
Exemplo n.º 12
0
def save_bookings_recap_sandbox():
    yesterday = datetime.utcnow() - timedelta(days=1)
    today = datetime.utcnow()

    beneficiary1 = BeneficiaryGrant18Factory(publicName="Riri Duck",
                                             firstName="Riri",
                                             lastName="Duck",
                                             email="*****@*****.**")

    beneficiary2 = BeneficiaryGrant18Factory(
        publicName="Fifi Brindacier",
        firstName="Fifi",
        lastName="Brindacier",
        email="*****@*****.**",
    )
    beneficiary3 = BeneficiaryGrant18Factory(
        publicName="LouLou Duck",
        firstName="Loulou",
        lastName="Duck",
        email="*****@*****.**",
    )

    pro = ProFactory(
        publicName="Balthazar Picsou",
        firstName="Balthazar",
        lastName="Picsou",
        email="*****@*****.**",
    )
    offerer = OffererFactory(siren="645389012")
    UserOffererFactory(user=pro, offerer=offerer)
    venue1 = VenueFactory(managingOfferer=offerer,
                          name="Cinéma Le Monde Perdu",
                          siret="64538901265877")
    venue2 = VenueFactory(managingOfferer=offerer,
                          name="Librairie Atlantis",
                          siret="64538901201379")
    venue3 = VenueFactory(managingOfferer=offerer,
                          name="Théatre Mordor",
                          siret="64538954601379")
    venue4_virtual = VenueFactory(managingOfferer=offerer,
                                  name="Un lieu virtuel",
                                  siret=None,
                                  isVirtual=True)

    product1_venue1 = EventProductFactory(
        name="Jurassic Park", subcategoryId=subcategories.SEANCE_CINE.id)
    offer1_venue1 = EventOfferFactory(product=product1_venue1,
                                      venue=venue1,
                                      isDuo=True)
    stock_1_offer1_venue1 = EventStockFactory(offer=offer1_venue1,
                                              beginningDatetime=yesterday,
                                              quantity=None,
                                              price=12.99)

    product2_venue1 = EventProductFactory(
        name="Matrix", subcategoryId=subcategories.SEANCE_CINE.id)

    offer2_venue1 = EventOfferFactory(product=product2_venue1,
                                      venue=venue1,
                                      isDuo=False)
    stock_2_offer2_venue1 = EventStockFactory(offer=offer2_venue1,
                                              beginningDatetime=today,
                                              quantity=None,
                                              price=0)

    product1_venue2 = ThingProductFactory(
        name="Fondation",
        subcategoryId=subcategories.LIVRE_PAPIER.id,
        extraData={"isbn": "9788804119135"})
    offer1_venue2 = ThingOfferFactory(product=product1_venue2, venue=venue2)
    stock_1_offer1_venue2 = ThingStockFactory(offer=offer1_venue2,
                                              quantity=42,
                                              price=9.99)

    product2_venue2 = ThingProductFactory(
        name="Martine à la playa",
        subcategoryId=subcategories.LIVRE_PAPIER.id,
        extraData={"isbn": "9787605639121"},
    )
    offer2_venue2 = ThingOfferFactory(product=product2_venue2, venue=venue2)
    stock_1_offer2_venue2 = ThingStockFactory(offer=offer2_venue2,
                                              quantity=12,
                                              price=49.99)

    product1_venue3 = EventProductFactory(
        name="Danse des haricots",
        subcategoryId=subcategories.SPECTACLE_REPRESENTATION.id)
    offer1_venue3 = EventOfferFactory(product=product1_venue3, venue=venue3)
    stock_1_offer1_venue3 = EventStockFactory(offer=offer1_venue3,
                                              quantity=44,
                                              price=18.50)

    product1_venue4 = ThingProductFactory(
        name="Le livre des haricots",
        subcategoryId=subcategories.LIVRE_PAPIER.id)
    offer1_venue4 = ThingOfferFactory(product=product1_venue4,
                                      venue=venue4_virtual)
    stock_1_offer1_venue4 = ThingStockFactory(offer=offer1_venue4,
                                              quantity=70,
                                              price=10.99)

    IndividualBookingFactory(
        individualBooking__user=beneficiary1,
        stock=stock_1_offer1_venue1,
        dateCreated=datetime(2020, 3, 18, 14, 56, 12, 0),
        isUsed=True,
        dateUsed=datetime(2020, 3, 22, 17, 00, 10, 0),
        quantity=2,
    )

    IndividualBookingFactory(
        individualBooking__user=beneficiary1,
        stock=stock_2_offer2_venue1,
        dateCreated=datetime(2020, 4, 22, 9, 17, 12, 0),
    )

    IndividualBookingFactory(
        individualBooking__user=beneficiary2,
        stock=stock_1_offer1_venue1,
        dateCreated=datetime(2020, 3, 18, 12, 18, 12, 0),
        isUsed=True,
        dateUsed=datetime(2020, 5, 2),
        quantity=2,
    )

    booking2_beneficiary2 = IndividualBookingFactory(
        individualBooking__user=beneficiary2,
        stock=stock_1_offer1_venue2,
        dateCreated=datetime(2020, 4, 12, 14, 31, 12, 0),
        isCancelled=False,
    )

    booking1_beneficiary3 = IndividualBookingFactory(
        individualBooking__user=beneficiary3,
        stock=stock_2_offer2_venue1,
        dateCreated=datetime(2020, 1, 4, 19, 31, 12, 0),
        isCancelled=False,
        isUsed=True,
        dateUsed=datetime(2020, 1, 4, 23, 00, 10, 0),
        quantity=2,
    )

    booking2_beneficiary3 = IndividualBookingFactory(
        individualBooking__user=beneficiary3,
        stock=stock_1_offer1_venue2,
        dateCreated=datetime(2020, 3, 21, 22, 9, 12, 0),
        isCancelled=False,
    )

    booking3_beneficiary1 = UsedIndividualBookingFactory(
        individualBooking__user=beneficiary1,
        stock=stock_1_offer1_venue3,
        dateCreated=datetime(2020, 4, 12, 14, 31, 12, 0),
    )

    payment_booking3_beneficiary1 = PaymentFactory(
        booking=booking3_beneficiary1)
    PaymentStatusFactory(payment=payment_booking3_beneficiary1,
                         status=TransactionStatus.PENDING)

    booking3_beneficiary2 = UsedIndividualBookingFactory(
        individualBooking__user=beneficiary2,
        stock=stock_1_offer1_venue3,
        dateCreated=datetime(2020, 4, 12, 19, 31, 12, 0),
        dateUsed=datetime(2020, 4, 22, 17, 00, 10, 0),
    )

    PaymentFactory(booking=booking3_beneficiary2)
    PaymentStatusFactory(payment=payment_booking3_beneficiary1,
                         status=TransactionStatus.SENT)

    booking3_beneficiary3 = UsedIndividualBookingFactory(
        individualBooking__user=beneficiary3,
        stock=stock_1_offer1_venue3,
        dateCreated=datetime(2020, 4, 12, 22, 9, 12, 0),
    )

    payment_booking3_beneficiary3 = PaymentFactory(
        booking=booking3_beneficiary3)
    PaymentStatusFactory(payment=payment_booking3_beneficiary3,
                         status=TransactionStatus.ERROR)

    UsedIndividualBookingFactory(
        individualBooking__user=beneficiary3,
        stock=stock_1_offer1_venue2,
        dateCreated=datetime(2020, 3, 21, 22, 9, 12, 0),
    )

    booking5_beneficiary3 = IndividualBookingFactory(
        individualBooking__user=beneficiary3,
        stock=stock_1_offer1_venue4,
        dateCreated=datetime(2020, 3, 21, 22, 9, 12, 0),
        isCancelled=False,
    )

    booking6_beneficiary3 = UsedIndividualBookingFactory(
        individualBooking__user=beneficiary3,
        stock=stock_1_offer2_venue2,
        dateCreated=datetime(2020, 3, 21, 22, 9, 12, 0),
        dateUsed=datetime(2020, 4, 22, 21, 9, 12, 0),
    )

    payment_booking6_beneficiary3 = PaymentFactory(
        booking=booking6_beneficiary3)
    PaymentStatusFactory(payment=payment_booking6_beneficiary3,
                         status=TransactionStatus.SENT)

    booking7_beneficiary2 = UsedIndividualBookingFactory(
        individualBooking__user=beneficiary2,
        stock=stock_1_offer2_venue2,
        dateCreated=datetime(2020, 4, 21, 22, 6, 12, 0),
        dateUsed=datetime(2020, 4, 22, 22, 9, 12, 0),
    )

    payment_booking7_beneficiary2 = PaymentFactory(
        booking=booking7_beneficiary2)
    PaymentStatusFactory(payment=payment_booking7_beneficiary2,
                         status=TransactionStatus.RETRY)

    UsedIndividualBookingFactory(
        individualBooking__user=beneficiary1,
        stock=stock_1_offer2_venue2,
        dateCreated=datetime(2020, 2, 21, 22, 6, 12, 0),
        dateUsed=datetime(2020, 4, 22, 23, 9, 12, 0),
    )

    payment_booking8_beneficiary1 = PaymentFactory(
        booking=booking7_beneficiary2)
    PaymentStatusFactory(payment=payment_booking8_beneficiary1,
                         status=TransactionStatus.PENDING)

    bookings_to_cancel = [
        booking2_beneficiary2,
        booking1_beneficiary3,
        booking2_beneficiary3,
        booking3_beneficiary2,
        booking5_beneficiary3,
    ]

    for booking in bookings_to_cancel:
        try:
            booking.cancel_booking()
        except (BookingIsAlreadyUsed, BookingIsAlreadyCancelled) as e:
            logger.info(str(e), extra={"booking": booking.id})
    repository.save(*bookings_to_cancel)
    def test_when_user_has_bookings_and_qr_code_feature_is_inactive_does_not_return_qr_code(
            self, qr_code_is_active, app):
        # Given
        user1 = BeneficiaryGrant18Factory(email="*****@*****.**")
        user2 = BeneficiaryGrant18Factory(email="*****@*****.**")
        venue = VenueFactory(latitude=None, longitude=None)
        offer = ThingOfferFactory(venue=venue)
        offer2 = ThingOfferFactory()
        stock = ThingStockFactory(offer=offer, price=0, quantity=None)
        stock2 = ThingStockFactory(offer=offer2, price=0)
        booking1 = IndividualBookingFactory(individualBooking__user=user1,
                                            stock=stock,
                                            token="ABCDEF")
        IndividualBookingFactory(individualBooking__user=user2,
                                 stock=stock,
                                 token="GHIJK")
        booking3 = IndividualBookingFactory(individualBooking__user=user1,
                                            stock=stock2,
                                            token="BBBBB")

        # When
        response = TestClient(app.test_client()).with_session_auth(
            user1.email).get("/bookings")

        # Then
        assert response.status_code == 200
        bookings = response.json
        assert len(bookings) == 2
        assert {b["id"]
                for b in bookings
                } == set(humanize(b.id) for b in {booking1, booking3})
        assert "qrCode" not in bookings[0]
        assert "validationToken" not in bookings[0]["stock"]["offer"]["venue"]
        assert bookings[0]["id"] == humanize(booking1.id)
        assert bookings[0] == {
            "activationCode": None,
            "amount": 0.0,
            "cancellationDate": None,
            "completedUrl": None,
            "dateCreated": format_into_utc_date(booking1.dateCreated),
            "dateUsed": None,
            "displayAsEnded": None,
            "id": humanize(booking1.id),
            "isCancelled": False,
            "isEventExpired": False,
            "isUsed": False,
            "quantity": 1,
            "stock": {
                "beginningDatetime": None,
                "id": humanize(stock.id),
                "isEventExpired": False,
                "offer": {
                    "description":
                    offer.description,
                    "durationMinutes":
                    None,
                    "extraData":
                    offer.extraData,
                    "id":
                    humanize(offer.id),
                    "isBookable":
                    True,
                    "isDigital":
                    False,
                    "isDuo":
                    False,
                    "isEvent":
                    False,
                    "isNational":
                    False,
                    "name":
                    offer.product.name,
                    "stocks": [{
                        "beginningDatetime":
                        None,
                        "bookingLimitDatetime":
                        None,
                        "dateCreated":
                        format_into_utc_date(stock.dateCreated),
                        "dateModified":
                        format_into_utc_date(stock.dateModified),
                        "id":
                        humanize(stock.id),
                        "isBookable":
                        True,
                        "offerId":
                        humanize(offer.id),
                        "price":
                        0.0,
                        "quantity":
                        None,
                        "remainingQuantity":
                        "unlimited",
                    }],
                    "thumbUrl":
                    None,
                    "venue": {
                        "address": venue.address,
                        "city": venue.city,
                        "departementCode": venue.departementCode,
                        "id": humanize(venue.id),
                        "latitude": None,
                        "longitude": None,
                        "name": venue.name,
                        "postalCode": venue.postalCode,
                    },
                    "venueId":
                    humanize(venue.id),
                    "withdrawalDetails":
                    None,
                },
                "offerId": humanize(offer.id),
                "price": 0.0,
            },
            "stockId": humanize(stock.id),
            "token": "ABCDEF",
            "userId": humanize(booking1.individualBooking.userId),
        }
def _create_bookings_for_other_beneficiaries(bookings_by_name,
                                             list_of_users_with_no_more_money,
                                             offers_by_name, token: int,
                                             user: User,
                                             user_name: str) -> int:
    user_should_have_no_more_money = "has-no-more-money" in user.email
    for (offer_index, (offer_name,
                       offer)) in enumerate(list(offers_by_name.items())):
        # FIXME (viconnex, 2020-12-22) trying to adapt previous code - not sure of the result and intention
        if offer_index % OFFER_WITH_BOOKINGS_RATIO != 0:
            continue

        user_has_only_activation_booked = (
            "has-booked-activation" in user.email
            or "has-confirmed-activation" in user.email)

        is_activation_offer = offer.product.subcategoryId in (
            subcategories.ACTIVATION_EVENT.id,
            subcategories.ACTIVATION_THING.id,
        )

        if user_has_only_activation_booked and not is_activation_offer:
            continue

        for (index, stock) in enumerate(offer.stocks):
            # every STOCK_MODULO RECO will have several stocks
            if index > 0 and offer_index % (
                    OFFER_WITH_SEVERAL_STOCKS_REMOVE_MODULO + index):
                continue

            booking_name = "{} / {} / {}".format(offer_name, user_name,
                                                 str(token))

            if is_activation_offer:
                is_used = ("has-confirmed-activation" in user.email
                           or "has-booked-some" in user.email
                           or "has-no-more-money" in user.email)
            else:
                is_used = offer_index % BOOKINGS_USED_REMOVE_MODULO != 0

            if is_used:
                stock.beginningDatetime = datetime.now() - timedelta(days=2)
                stock.bookingLimitDatetime = datetime.now() - timedelta(days=5)
                repository.save(stock)

            if user_should_have_no_more_money and user not in list_of_users_with_no_more_money:
                booking_amount = user.deposit.amount
                list_of_users_with_no_more_money.append(user)
            elif user_should_have_no_more_money and user in list_of_users_with_no_more_money:
                booking_amount = 0
            else:
                booking_amount = None

            bookings_by_name[booking_name] = IndividualBookingFactory(
                individualBooking__user=user,
                isUsed=is_used,
                status=BookingStatus.USED
                if is_used else BookingStatus.CONFIRMED,
                stock=stock,
                dateUsed=datetime.now() -
                timedelta(days=2) if is_used else None,
                amount=booking_amount,
                token=str(token),
                offerer=offer.venue.managingOfferer,
                venue=offer.venue,
            )

            token = token + 1

    return token
    def test_expect_booking_to_have_completed_url(self, app):
        # Given
        user = BeneficiaryGrant18Factory(email="*****@*****.**")
        offerer = OffererFactory()
        product = ThingProductFactory()
        offer = ThingOfferFactory(
            url="https://host/path/{token}?offerId={offerId}&email={email}",
            audioDisabilityCompliant=None,
            bookingEmail="*****@*****.**",
            extraData={"author": "Test Author"},
            mediaUrls=["test/urls"],
            mentalDisabilityCompliant=None,
            motorDisabilityCompliant=None,
            name="Test Book",
            venue__managingOfferer=offerer,
            product=product,
        )
        stock = ThingStockFactory(offer=offer, price=0, quantity=None)
        booking = IndividualBookingFactory(individualBooking__user=user,
                                           stock=stock,
                                           token="ABCDEF")

        # When
        response = TestClient(app.test_client()).with_session_auth(
            user.email).get("/bookings/" + humanize(booking.id))

        # Then
        assert response.status_code == 200
        completed_url = "https://host/path/ABCDEF?offerId={}&[email protected]".format(
            humanize(offer.id))

        assert "validationToken" not in response.json["stock"]["offer"]
        assert response.json == {
            "amount": 0.0,
            "cancellationDate": None,
            "cancellationReason": None,
            "completedUrl": completed_url,
            "cancellationLimitDate": None,
            "dateCreated": format_into_utc_date(booking.dateCreated),
            "dateUsed": None,
            "id": humanize(booking.id),
            "isCancelled": False,
            "isEventExpired": False,
            "isUsed": False,
            "mediation": None,
            "offererId": humanize(offer.venue.managingOffererId),
            "quantity": 1,
            "reimbursementDate": None,
            "stock": {
                "beginningDatetime":
                None,
                "bookingLimitDatetime":
                None,
                "dateCreated":
                format_into_utc_date(stock.dateCreated),
                "dateModified":
                format_into_utc_date(stock.dateModified),
                "dateModifiedAtLastProvider":
                format_into_utc_date(stock.dateModifiedAtLastProvider),
                "fieldsUpdated": [],
                "id":
                humanize(stock.id),
                "idAtProviders":
                None,
                "isBookable":
                True,
                "isEventExpired":
                False,
                "isSoftDeleted":
                False,
                "lastProviderId":
                None,
                "offer": {
                    "ageMax":
                    None,
                    "ageMin":
                    None,
                    "audioDisabilityCompliant":
                    None,
                    "bookingEmail":
                    "*****@*****.**",
                    "conditions":
                    None,
                    "dateCreated":
                    format_into_utc_date(offer.dateCreated),
                    "dateModifiedAtLastProvider":
                    format_into_utc_date(offer.dateModifiedAtLastProvider),
                    "description":
                    product.description,
                    "durationMinutes":
                    None,
                    "externalTicketOfficeUrl":
                    None,
                    "extraData": {
                        "author": "Test Author"
                    },
                    "fieldsUpdated": [],
                    "hasBookingLimitDatetimesPassed":
                    False,
                    "id":
                    humanize(offer.id),
                    "idAtProviders":
                    offer.idAtProviders,
                    "isActive":
                    True,
                    "isBookable":
                    True,
                    "isDigital":
                    True,
                    "isDuo":
                    False,
                    "isEducational":
                    False,
                    "isEvent":
                    False,
                    "isNational":
                    False,
                    "lastProviderId":
                    None,
                    "mediaUrls": ["test/urls"],
                    "mentalDisabilityCompliant":
                    None,
                    "motorDisabilityCompliant":
                    None,
                    "name":
                    "Test Book",
                    "productId":
                    humanize(offer.product.id),
                    "stocks": [{
                        "beginningDatetime":
                        None,
                        "bookingLimitDatetime":
                        None,
                        "dateCreated":
                        format_into_utc_date(stock.dateCreated),
                        "dateModified":
                        format_into_utc_date(stock.dateModified),
                        "dateModifiedAtLastProvider":
                        format_into_utc_date(stock.dateModifiedAtLastProvider),
                        "fieldsUpdated": [],
                        "id":
                        humanize(stock.id),
                        "idAtProviders":
                        None,
                        "isBookable":
                        True,
                        "isEventExpired":
                        False,
                        "isSoftDeleted":
                        False,
                        "lastProviderId":
                        None,
                        "offerId":
                        humanize(offer.id),
                        "price":
                        0.0,
                        "quantity":
                        None,
                        "remainingQuantity":
                        "unlimited",
                    }],
                    "subcategoryId":
                    "SUPPORT_PHYSIQUE_FILM",
                    "thumbUrl":
                    None,
                    "url":
                    "https://host/path/{token}?offerId={offerId}&email={email}",
                    "validation":
                    "APPROVED",
                    "venue": {
                        "address":
                        "1 boulevard Poissonnière",
                        "audioDisabilityCompliant":
                        False,
                        "bannerMeta":
                        None,
                        "bannerUrl":
                        None,
                        "bookingEmail":
                        None,
                        "city":
                        "Paris",
                        "comment":
                        None,
                        "dateCreated":
                        format_into_utc_date(offer.venue.dateCreated),
                        "dateModifiedAtLastProvider":
                        format_into_utc_date(
                            offer.venue.dateModifiedAtLastProvider),
                        "departementCode":
                        "75",
                        "description":
                        offer.venue.description,
                        "fieldsUpdated": [],
                        "id":
                        humanize(offer.venue.id),
                        "idAtProviders":
                        None,
                        "isPermanent":
                        False,
                        "isVirtual":
                        False,
                        "lastProviderId":
                        None,
                        "latitude":
                        48.87004,
                        "longitude":
                        2.3785,
                        "managingOffererId":
                        humanize(offer.venue.managingOffererId),
                        "mentalDisabilityCompliant":
                        False,
                        "motorDisabilityCompliant":
                        False,
                        "name":
                        offer.venue.name,
                        "postalCode":
                        "75000",
                        "publicName":
                        offer.venue.publicName,
                        "siret":
                        offer.venue.siret,
                        "thumbCount":
                        0,
                        "venueLabelId":
                        None,
                        "venueTypeId":
                        None,
                        "visualDisabilityCompliant":
                        False,
                        "venueTypeCode":
                        offer.venue.venueTypeCode.value,
                        "withdrawalDetails":
                        None,
                    },
                    "venueId":
                    humanize(offer.venue.id),
                    "visualDisabilityCompliant":
                    False,
                    "withdrawalDetails":
                    None,
                },
                "offerId":
                humanize(offer.id),
                "price":
                0.0,
                "quantity":
                None,
                "remainingQuantity":
                "unlimited",
            },
            "stockId": humanize(stock.id),
            "token": booking.token,
            "userId": humanize(user.id),
            "venueId": humanize(offer.venue.id),
        }