Beispiel #1
0
    def test_should_return_0_offer_when_there_is_no_stock(self, app):
        # Given
        ThingOfferFactory()

        # When
        offers_count = Offer.query.join(Stock).count()

        # Then
        assert offers_count == 0
    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"]
Beispiel #3
0
    def test_should_return_get_stocks_information(self, app):
        # Given
        offer = ThingOfferFactory(url="http://url.com")
        stock1 = ThingStockFactory(
            beginningDatetime=datetime(2020, 3, 5),
            bookingLimitDatetime=datetime(2020, 1, 6),
            dateCreated=datetime(2020, 1, 4),
            dateModified=datetime(2020, 1, 7),
            offer=offer,
            price=0,
        )
        stock2 = ThingStockFactory(
            beginningDatetime=datetime(2020, 4, 5),
            bookingLimitDatetime=datetime(2020, 2, 6),
            dateCreated=datetime(2020, 2, 4),
            dateModified=datetime(2020, 2, 7),
            offer=offer,
            price=12,
        )

        # When
        results = _get_stocks_information(offers_ids=[offer.id])

        # Then
        assert set(results) == {
            (
                datetime(2020, 1, 4, 0, 0),
                datetime(2020, 3, 5, 0, 0),
                datetime(2020, 1, 6, 0, 0),
                datetime(2020, 1, 7, 0, 0),
                offer.id,
                1000,
                0.00,
                stock1.id,
                False,
                True,
            ),
            (
                datetime(2020, 2, 4, 0, 0),
                datetime(2020, 4, 5, 0, 0),
                datetime(2020, 2, 6, 0, 0),
                datetime(2020, 2, 7, 0, 0),
                offer.id,
                1000,
                12.00,
                stock2.id,
                False,
                True,
            ),
        }
Beispiel #4
0
    def test_should_return_0_offer_when_all_available_stock_is_booked(self, app):
        # Given
        beneficiary = users_factories.BeneficiaryGrant18Factory()
        offer = ThingOfferFactory()
        stock = ThingStockFactory(offer=offer, price=0, quantity=3)
        BookingFactory(user=beneficiary, stock=stock, quantity=2)
        BookingFactory(user=beneficiary, stock=stock, quantity=1)

        # When
        bookings_quantity = _build_bookings_quantity_subquery()
        offers_count = (
            Offer.query.join(Stock)
            .outerjoin(bookings_quantity, Stock.id == bookings_quantity.c.stockId)
            .filter((Stock.quantity == None) | ((Stock.quantity - func.coalesce(bookings_quantity.c.quantity, 0)) > 0))
            .count()
        )

        # Then
        assert offers_count == 0
    def test_should_not_delete_product_and_deactivate_associated_offer_when_it_changes_to_paper_press_product(
        self, get_lines_from_thing_file, get_files_to_process_from_titelive_ftp, app
    ):
        # Given
        files_list = list()
        files_list.append("Quotidien30.tit")

        DATA_LINE_PARTS = BASE_DATA_LINE_PARTS[:]
        DATA_LINE_PARTS[13] = "R"
        DATA_LINE_PARTS[26] = "2,10"

        data_line = "~".join(DATA_LINE_PARTS)

        get_files_to_process_from_titelive_ftp.return_value = files_list

        get_lines_from_thing_file.return_value = iter([data_line])

        titelive_provider = activate_provider("TiteLiveThings")
        repository.save(titelive_provider)

        beneficiary = users_factories.BeneficiaryGrant18Factory(email="*****@*****.**")
        offerer = OffererFactory(siren="123456789")
        venue = VenueFactory(managingOfferer=offerer)
        product = ThingProductFactory(
            idAtProviders="9782895026310",
            name="Presse papier",
            subcategoryId=subcategories.LIVRE_PAPIER.id,
            dateModifiedAtLastProvider=datetime(2001, 1, 1),
            lastProviderId=titelive_provider.id,
        )
        offer = ThingOfferFactory(product=product, venue=venue, isActive=True)
        stock = ThingStockFactory(offer=offer, price=0)
        BookingFactory(user=beneficiary, stock=stock)

        titelive_things = TiteLiveThings()

        # When
        titelive_things.updateObjects()

        # Then
        offer = Offer.query.one()
        assert offer.isActive is False
        assert Product.query.count() == 1
Beispiel #6
0
    def test_should_return_beneficiary_bookings_with_expected_information(self, app):
        # Given
        beneficiary = BeneficiaryGrant18Factory()
        offer = ThingOfferFactory(isActive=True, url="http://url.com", product__thumbCount=1)
        stock = ThingStockFactory(offer=offer, price=0, quantity=10)
        booking = booking_factories.UsedIndividualBookingFactory(
            individualBooking__user=beneficiary,
            stock=stock,
            token="ABCDEF",
            dateCreated=datetime(2020, 4, 22, 0, 0),
            dateUsed=datetime(2020, 5, 5, 0, 0),
            quantity=2,
        )

        # When
        result = BeneficiaryBookingsSQLRepository().get_beneficiary_bookings(beneficiary_id=beneficiary.id)

        # Then
        assert isinstance(result, BeneficiaryBookingsWithStocks)
        assert len(result.bookings) == 1
        expected_booking = result.bookings[0]
        assert expected_booking.amount == 0.0
        assert expected_booking.cancellationDate is None
        assert expected_booking.dateCreated == datetime(2020, 4, 22, 0, 0)
        assert expected_booking.dateUsed == datetime(2020, 5, 5, 0, 0)
        assert expected_booking.id == booking.id
        assert expected_booking.isCancelled is False
        assert expected_booking.isUsed is True
        assert expected_booking.quantity == 2
        assert expected_booking.stockId == stock.id
        assert expected_booking.token == booking.token
        assert expected_booking.userId == beneficiary.id
        assert expected_booking.offerId == stock.offer.id
        assert expected_booking.name == stock.offer.name
        assert expected_booking.url == stock.offer.url
        assert expected_booking.email == beneficiary.email
        assert expected_booking.beginningDatetime == stock.beginningDatetime
        assert expected_booking.venueId == stock.offer.venue.id
        assert expected_booking.departementCode == stock.offer.venue.departementCode
        assert (
            expected_booking.thumb_url == f"http://localhost/storage/thumbs/products/{humanize(stock.offer.productId)}"
        )
Beispiel #7
0
    def test_should_return_1_offer_when_booking_was_cancelled(self, app):
        # Given
        beneficiary = users_factories.BeneficiaryGrant18Factory()
        product = ThingProductFactory(name="Lire un livre", isNational=True)
        venue = VenueFactory(postalCode="34000", departementCode="34")
        offer = ThingOfferFactory(product=product, venue=venue)
        stock = ThingStockFactory(offer=offer, price=0, quantity=2)
        CancelledBookingFactory(user=beneficiary, stock=stock, quantity=2)

        # When
        bookings_quantity = _build_bookings_quantity_subquery()
        offers_count = (
            Offer.query.join(Stock)
            .outerjoin(bookings_quantity, Stock.id == bookings_quantity.c.stockId)
            .filter((Stock.quantity == None) | ((Stock.quantity - func.coalesce(bookings_quantity.c.quantity, 0)) > 0))
            .count()
        )

        # Then
        assert offers_count == 1
Beispiel #8
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 test_cancel_bookings_of_offers_from_rows(self):
        beneficiary = users_factories.BeneficiaryGrant18Factory(email="*****@*****.**")

        offerer_to_cancel = OffererFactory(name="Librairie les petits parapluies gris", siren="123456789")
        offerer_to_not_cancel = OffererFactory(name="L'amicale du club de combat", siren="987654321")

        venue_to_cancel = VenueFactory(managingOfferer=offerer_to_cancel, siret="12345678912345")
        venue_to_not_cancel = VenueFactory(managingOfferer=offerer_to_not_cancel, siret="54321987654321")

        offer_to_cancel = ThingOfferFactory(venue=venue_to_cancel)
        offer_to_not_cancel = ThingOfferFactory(venue=venue_to_not_cancel)

        stock_to_cancel = ThingStockFactory(offer=offer_to_cancel)
        stock_to_not_cancel = ThingStockFactory(offer=offer_to_not_cancel)

        self.booking_to_cancel = BookingFactory(user=beneficiary, stock=stock_to_cancel, isUsed=False, dateUsed=None)
        self.booking_to_not_cancel = BookingFactory(user=beneficiary, stock=stock_to_not_cancel)

        self.booking_2QLYYA_not_to_cancel = BookingFactory(user=beneficiary, stock=stock_to_cancel, token="2QLYYA")
        self.booking_BMTUME_not_to_cancel = BookingFactory(user=beneficiary, stock=stock_to_cancel, token="BMTUME")
        self.booking_LUJ9AM_not_to_cancel = BookingFactory(user=beneficiary, stock=stock_to_cancel, token="LUJ9AM")
        self.booking_DA8YLU_not_to_cancel = BookingFactory(user=beneficiary, stock=stock_to_cancel, token="DA8YLU")
        self.booking_Q46YHM_not_to_cancel = BookingFactory(user=beneficiary, stock=stock_to_cancel, token="Q46YHM")

        self.csv_rows = [
            [
                "id offre",
                "Structure",
                "Département",
                "Offre",
                "Date de l'évènement",
                "Nb Réservations",
                "A annuler ?",
                "Commentaire",
            ],
            [
                offer_to_cancel.id,
                offer_to_cancel.name,
                "75000",
                offer_to_cancel.name,
                "2020-06-19 18:00:48",
                1,
                "Oui",
                "",
            ],
            [
                offer_to_not_cancel.id,
                offerer_to_not_cancel.name,
                offer_to_not_cancel.name,
                "93000",
                "2020-06-20 18:00:12",
                1,
                "Non",
                "",
            ],
        ]

        _cancel_bookings_of_offers_from_rows(self.csv_rows, BookingCancellationReasons.OFFERER)

        # Then
        saved_booking = Booking.query.get(self.booking_to_cancel.id)
        assert saved_booking.isCancelled is True
        assert saved_booking.status is BookingStatus.CANCELLED
        assert saved_booking.cancellationReason == BookingCancellationReasons.OFFERER
        assert saved_booking.cancellationDate is not None
        assert saved_booking.isUsed is False
        assert saved_booking.status is not BookingStatus.USED
        assert saved_booking.dateUsed is None

        saved_booking = Booking.query.get(self.booking_to_not_cancel.id)
        assert saved_booking.isCancelled is False
        assert saved_booking.status is not BookingStatus.CANCELLED
        assert saved_booking.cancellationDate is None

        saved_2QLYYA_booking = Booking.query.get(self.booking_2QLYYA_not_to_cancel.id)
        assert saved_2QLYYA_booking.isCancelled is False
        assert saved_2QLYYA_booking.status is not BookingStatus.CANCELLED
        assert saved_2QLYYA_booking.cancellationDate is None

        saved_BMTUME_booking = Booking.query.get(self.booking_BMTUME_not_to_cancel.id)
        assert saved_BMTUME_booking.isCancelled is False
        assert saved_BMTUME_booking.status is not BookingStatus.CANCELLED
        assert saved_BMTUME_booking.cancellationDate is None

        saved_LUJ9AM_booking = Booking.query.get(self.booking_LUJ9AM_not_to_cancel.id)
        assert saved_LUJ9AM_booking.isCancelled is False
        assert saved_LUJ9AM_booking.status is not BookingStatus.CANCELLED
        assert saved_LUJ9AM_booking.cancellationDate is None

        saved_DA8YLU_booking = Booking.query.get(self.booking_DA8YLU_not_to_cancel.id)
        assert saved_DA8YLU_booking.isCancelled is False
        assert saved_DA8YLU_booking.status is not BookingStatus.CANCELLED
        assert saved_DA8YLU_booking.cancellationDate is None

        saved_Q46YHM_booking = Booking.query.get(self.booking_Q46YHM_not_to_cancel.id)
        assert saved_Q46YHM_booking.isCancelled is False
        assert saved_Q46YHM_booking.status is not BookingStatus.CANCELLED
        assert saved_Q46YHM_booking.cancellationDate is None
    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),
        }