def test_compute_first_thumb_dominant_color_even_if_not_first_file(
            self, get_thumbs_zip_file_from_ftp, get_ordered_thumbs_zip_files,
            app):
        # given
        product1 = create_product_with_thing_subcategory(
            id_at_providers="9780847858903", thumb_count=0)
        product2 = create_product_with_thing_subcategory(
            id_at_providers="9782016261903", thumb_count=0)
        repository.save(product1, product2)
        zip_thumb_file = get_zip_with_2_usable_thumb_files()
        get_ordered_thumbs_zip_files.return_value = [zip_thumb_file]
        get_thumbs_zip_file_from_ftp.side_effect = [
            get_zip_file_from_sandbox(zip_thumb_file)
        ]

        # Import thumbs for existing things
        provider_test(
            app,
            TiteLiveThingThumbs,
            None,
            checkedObjects=2,
            createdObjects=0,
            updatedObjects=2,
            erroredObjects=0,
            checkedThumbs=2,
            createdThumbs=5,
            updatedThumbs=0,
            erroredThumbs=0,
            Product=0,
        )
def test_filter_query_where_user_is_user_offerer_and_is_validated(app):
    # Given
    pro = users_factories.ProFactory(email="*****@*****.**")
    offerer1 = create_offerer(siren="123456789")
    offerer2 = create_offerer(siren="987654321")
    offerer3 = create_offerer(siren="123456780")
    user_offerer1 = create_user_offerer(pro, offerer1)
    user_offerer2 = create_user_offerer(pro, offerer2)

    event1 = create_product_with_event_subcategory(event_name="Rencontre avec Jacques Martin")
    event2 = create_product_with_event_subcategory(event_name="Concert de contrebasse")
    thing1 = create_product_with_thing_subcategory(thing_name="Jacques la fripouille")
    thing2 = create_product_with_thing_subcategory(thing_name="Belle du Seigneur")
    venue1 = create_venue(offerer1, name="Bataclan", city="Paris", siret=offerer1.siren + "12345")
    venue2 = create_venue(offerer2, name="Librairie la Rencontre", city="Saint Denis", siret=offerer2.siren + "54321")
    venue3 = create_venue(
        offerer3, name="Une librairie du méchant concurrent gripsou", city="Saint Denis", siret=offerer3.siren + "54321"
    )
    offer1 = create_offer_with_event_product(venue=venue1, product=event1)
    offer2 = create_offer_with_event_product(venue=venue1, product=event2)
    offer3 = create_offer_with_thing_product(venue=venue2, product=thing1)
    offer4 = create_offer_with_thing_product(venue=venue3, product=thing2)

    repository.save(user_offerer1, user_offerer2, offerer3, offer1, offer2, offer3, offer4)

    # When
    offers = filter_query_where_user_is_user_offerer_and_is_validated(Offer.query.join(Venue).join(Offerer), pro).all()

    # Then
    offer_ids = [offer.id for offer in offers]
    assert offer1.id in offer_ids
    assert offer2.id in offer_ids
    assert offer3.id in offer_ids
    assert offer4.id not in offer_ids
    def test_save_chunks_insert_1_offer_and_1_stock_in_chunk(self, app):
        # Given
        offerer = create_offerer()
        venue = create_venue(offerer)
        product = create_product_with_thing_subcategory()
        repository.save(venue, product)

        offer = create_offer_with_thing_product(
            venue, product=product, id_at_providers="1%12345678912345")
        offer.venueId = venue.id
        offer_id = db.session.execute(Sequence("offer_id_seq"))
        offer.id = offer_id

        stock = create_stock(offer=offer)
        stock.offerId = offer_id

        chunk_to_insert = {
            "1|Offer": offer,
            "1|Stock": stock,
        }
        db.session.expunge(offer)
        db.session.expunge(stock)

        chunk_to_update = {}

        # When
        save_chunks(chunk_to_insert, chunk_to_update)

        # Then
        assert Offer.query.count() == 1
        assert Stock.query.count() == 1
Beispiel #4
0
    def test_should_delete_product_when_related_offer_is_on_user_favorite_list(
            self, app):
        # Given
        isbn = "1111111111111"
        beneficiary = users_factories.BeneficiaryGrant18Factory()
        offerer = create_offerer(siren="775671464")
        venue = create_venue(offerer,
                             name="Librairie Titelive",
                             siret="77567146400110")
        product = create_product_with_thing_subcategory(id_at_providers=isbn)
        offer = create_offer_with_thing_product(venue, product=product)
        stock = create_stock(offer=offer, price=0)
        mediation = create_mediation(offer=offer)
        favorite = create_favorite(mediation=mediation,
                                   offer=offer,
                                   user=beneficiary)

        repository.save(venue, product, offer, stock, mediation, favorite)

        # When
        delete_unwanted_existing_product("1111111111111")

        # Then
        assert Product.query.count() == 0
        assert Offer.query.count() == 0
        assert Stock.query.count() == 0
        assert Mediation.query.count() == 0
        assert Favorite.query.count() == 0
    def test_update_1_thing_from_one_data_line_in_one_file(
        self, get_lines_from_thing_file, get_files_to_process_from_titelive_ftp, app
    ):
        # Given
        files_list = list()
        files_list.append("Quotidien30.tit")

        get_files_to_process_from_titelive_ftp.return_value = files_list

        data_line = "~".join(BASE_DATA_LINE_PARTS)

        get_lines_from_thing_file.return_value = iter([data_line])

        titelive_things_provider = get_provider_by_local_class("TiteLiveThings")

        product = create_product_with_thing_subcategory(
            id_at_providers="9782895026310",
            thing_name="Toto à la playa",
            date_modified_at_last_provider=datetime(2001, 1, 1),
            last_provider_id=titelive_things_provider.id,
        )
        activate_provider("TiteLiveThings")
        repository.save(product)
        titelive_things = TiteLiveThings()

        # When
        titelive_things.updateObjects()

        # Then
        updated_product = Product.query.first()
        assert updated_product.name == "nouvelles du Chili"
        assert updated_product.extraData.get("bookFormat") == BookFormat.BEAUX_LIVRES.value
    def test_should_delete_product_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)
        product = create_product_with_thing_subcategory(
            id_at_providers="9782895026310",
            thing_name="Presse papier",
            date_modified_at_last_provider=datetime(2001, 1, 1),
            last_provider_id=titelive_provider.id,
        )
        repository.save(product)

        titelive_things = TiteLiveThings()

        # When
        titelive_things.updateObjects()

        # Then
        assert Product.query.count() == 0
def test_should_return_errors_when_valid_product():
    # Given
    product = create_product_with_thing_subcategory()

    # When
    api_errors = validate(product)

    # Then
    assert api_errors.errors == {}
def when_product_has_no_thumb(app):
    # Given
    product = create_product_with_thing_subcategory(thumb_count=0)
    repository.save(product)

    # When
    thumb_url = product.thumbUrl

    # Then
    assert thumb_url is None
def when_product_has_one_thumb(app):
    # Given
    product = create_product_with_thing_subcategory(thumb_count=1)
    repository.save(product)
    product_id = humanize(product.id)

    # When
    thumb_url = product.thumbUrl

    # Then
    assert thumb_url == f"http://localhost/storage/thumbs/products/{product_id}"
Beispiel #10
0
    def test_should_not_delete_product_when_isbn_not_found(self, app):
        # Given
        isbn = "1111111111111"
        product = create_product_with_thing_subcategory(id_at_providers=isbn)
        repository.save(product)

        # When
        delete_unwanted_existing_product("2222222222222")

        # Then
        assert Product.query.count() == 1
Beispiel #11
0
def test_should_not_return_error_message_when_product_is_online():
    # Given
    product = create_product_with_thing_subcategory(is_offline_only=False,
                                                    is_digital=False)
    api_errors = ApiErrors()

    # When
    api_error = validate(product, api_errors)

    # Then
    assert api_error.errors == {}
Beispiel #12
0
def test_should_return_error_message_when_product_is_digital_and_offline():
    # Given
    product = create_product_with_thing_subcategory(is_offline_only=True,
                                                    is_digital=True)
    api_errors = ApiErrors()

    # When
    api_error = validate(product, api_errors)

    # Then
    assert api_error.errors["url"] == [
        "Un produit de sous-catégorie CARTE_CINE_MULTISEANCES ne peut pas être numérique"
    ]
Beispiel #13
0
    def test_should_not_return_not_gcu_compatible_product(self, app):
        # Given
        valid_isbn = "1111111111111"
        product = create_product_with_thing_subcategory(
            id_at_providers=valid_isbn,
            thing_subcategory_id=subcategories.LIVRE_PAPIER.id,
            is_gcu_compatible=False)
        repository.save(product)

        # When
        existing_product = find_active_book_product_by_isbn(valid_isbn)

        # Then
        assert existing_product is None
def test_should_return_errors_when_invalid_product():
    # Given
    product = create_product_with_thing_subcategory(is_offline_only=True,
                                                    is_digital=True)

    # When
    api_errors = validate(product)

    # Then
    assert api_errors.errors == {
        "url": [
            "Un produit de sous-catégorie CARTE_CINE_MULTISEANCES ne peut pas être numérique"
        ]
    }
def test_thing_error_when_thing_type_is_offlineOnly_but_has_url(app):
    # Given
    thing_product = create_product_with_thing_subcategory(
        thing_subcategory_id=subcategories.MATERIEL_ART_CREATIF.id,
        url="http://mygame.fr/offre")

    # When
    with pytest.raises(ApiErrors) as errors:
        repository.save(thing_product)

    # Then
    assert errors.value.errors["url"] == [
        "Un produit de sous-catégorie MATERIEL_ART_CREATIF ne peut pas être numérique"
    ]
Beispiel #16
0
    def test_get_offers_by_venue_id_returns_offers_matching_venue_id(self, app):
        # Given
        product = create_product_with_thing_subcategory(thing_name="Lire un livre", is_national=True)
        offerer = create_offerer()
        venue = create_venue(offerer, postal_code="34000", departement_code="34")
        offer = create_offer_with_thing_product(venue=venue, product=product)
        repository.save(offer)

        # When
        offers = get_offers_by_venue_id(venue.id)

        # Then
        assert len(offers) == 1
        assert offers[0].venueId == venue.id
Beispiel #17
0
    def test_should_return_nothing_when_non_existing_isbn_is_given(self, app):
        # Given
        invalid_isbn = "99999999999"
        valid_isbn = "1111111111111"
        product = create_product_with_thing_subcategory(
            id_at_providers=valid_isbn,
            thing_subcategory_id=subcategories.LIVRE_PAPIER.id,
        )
        repository.save(product)

        # When
        existing_product = find_active_book_product_by_isbn(invalid_isbn)

        # Then
        assert existing_product is None
    def test_should_not_return_payload_when_offer_is_not_bookable(self, app):
        # Given
        offerer = create_offerer(validation_token="validation_token")
        venue = create_venue(offerer)
        product = create_product_with_thing_subcategory()
        offer = create_offer_with_thing_product(venue, product=product)
        stock = create_stock(offer=offer)
        mediation = create_mediation(offer)
        repository.save(mediation, stock)

        # When
        offer_json_response = get_non_free_thing_offer_with_active_mediation()

        # Then
        assert offer_json_response == {}
    def test_should_log_error_when_trying_to_delete_product_with_associated_bookings(
        self, get_lines_from_thing_file, get_files_to_process_from_titelive_ftp, app
    ):
        # Given
        files_list = list()
        files_list.append("Quotidien30.tit")

        get_files_to_process_from_titelive_ftp.return_value = files_list

        DATA_LINE_PARTS = BASE_DATA_LINE_PARTS[:]
        DATA_LINE_PARTS[2] = "jeux de société"
        DATA_LINE_PARTS[4] = "1234"
        DATA_LINE_PARTS[13] = "O"
        DATA_LINE_PARTS[27] = "Littérature scolaire"
        DATA_LINE_PARTS[40] = ""

        data_line = "~".join(DATA_LINE_PARTS)

        get_lines_from_thing_file.return_value = iter([data_line])

        beneficiary = users_factories.BeneficiaryGrant18Factory()
        offerer = create_offerer(siren="775671464")
        venue = create_venue(offerer, name="Librairie Titelive", siret="77567146400110")
        titelive_provider = activate_provider("TiteLiveThings")
        repository.save(venue)
        product = create_product_with_thing_subcategory(
            id_at_providers="9782895026310",
            thing_name="Toto à la playa",
            date_modified_at_last_provider=datetime(2001, 1, 1),
            last_provider_id=titelive_provider.id,
        )
        offer = create_offer_with_thing_product(venue, product=product)
        stock = create_stock(offer=offer, price=0)
        booking = create_booking(user=beneficiary, stock=stock)
        repository.save(product, offer, stock, booking)

        titelive_things = TiteLiveThings()

        # When
        titelive_things.updateObjects()

        # Then
        assert Product.query.count() == 1
        provider_log_error = LocalProviderEvent.query.filter_by(type=LocalProviderEventType.SyncError).one()
        assert provider_log_error.payload == "Error deleting product with ISBN: 9782895026310"
    def test_save_chunks_insert_1_offer_in_chunk(self, app):
        # Given
        offerer = create_offerer()
        venue = create_venue(offerer)
        product = create_product_with_thing_subcategory()
        repository.save(venue, product)

        offer = create_offer_with_thing_product(
            venue, product=product, id_at_providers="1%12345678912345")
        offer.venueId = venue.id
        chunk_to_insert = {"1|Offer": offer}
        db.session.expunge(offer)

        chunk_to_update = {}

        # When
        save_chunks(chunk_to_insert, chunk_to_update)

        # Then
        assert Offer.query.count() == 1
Beispiel #21
0
    def test_should_delete_product_when_it_has_offer_and_stock_but_not_booked(
            self, app):
        # Given
        isbn = "1111111111111"
        offerer = create_offerer(siren="775671464")
        venue = create_venue(offerer,
                             name="Librairie Titelive",
                             siret="77567146400110")
        product = create_product_with_thing_subcategory(id_at_providers=isbn)
        offer = create_offer_with_thing_product(venue, product=product)
        stock = create_stock(offer=offer, price=0)
        repository.save(venue, product, offer, stock)

        # When
        delete_unwanted_existing_product("1111111111111")

        # Then
        assert Product.query.count() == 0
        assert Offer.query.count() == 0
        assert Stock.query.count() == 0
Beispiel #22
0
    def test_should_return_1_offer_when_there_are_one_full_stock_and_one_empty_stock(self):
        # Given
        product = create_product_with_thing_subcategory(thing_name="Lire un livre", is_national=True)
        offerer = create_offerer()
        venue = create_venue(offerer, postal_code="34000", departement_code="34")
        offer = create_offer_with_thing_product(venue=venue, product=product)
        stock1 = create_stock_from_offer(offer, price=0, quantity=2)
        stock2 = create_stock_from_offer(offer, price=0, quantity=2)
        beneficiary = users_factories.BeneficiaryGrant18Factory()
        booking1 = create_booking(user=beneficiary, stock=stock1, quantity=2, venue=venue)
        repository.save(booking1, stock2)
        bookings_quantity = _build_bookings_quantity_subquery()

        # When
        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
    def test_save_chunks_update_2_offers_and_1_stock_in_chunk(self, app):
        # Given
        offerer = create_offerer()
        venue = create_venue(offerer)
        product = create_product_with_thing_subcategory()
        offer1 = create_offer_with_thing_product(
            venue, product=product, id_at_providers="1%12345678912345")
        offer2 = create_offer_with_thing_product(
            venue, product=product, id_at_providers="2%12345678912345")
        stock = create_stock(offer=offer1)
        repository.save(venue, product, offer1, offer2, stock)

        db.session.refresh(offer1)
        db.session.refresh(offer2)
        db.session.refresh(stock)
        offer1.isDuo = True
        offer2.isDuo = True
        stock.quantity = 2
        chunk_to_update = {
            "1|Offer": offer1,
            "1|Stock": stock,
            "2|Offer": offer2,
        }
        db.session.expunge(offer1)
        db.session.expunge(offer2)
        db.session.expunge(stock)

        chunk_to_insert = {}

        # When
        save_chunks(chunk_to_insert, chunk_to_update)

        # Then
        offers = Offer.query.all()
        assert len(offers) == 2
        assert any(offer.isDuo for offer in offers)
        assert Stock.query.count() == 1
    def test_updates_thumb_count_for_product_when_new_thumbs_added(
            self, get_thumbs_zip_file_from_ftp, get_ordered_thumbs_zip_files,
            app):
        # Given
        product1 = create_product_with_thing_subcategory(
            id_at_providers="9780847858903", thumb_count=0)
        repository.save(product1)
        zip_thumb_file = get_zip_with_1_usable_thumb_file()
        get_ordered_thumbs_zip_files.return_value = [zip_thumb_file]
        get_thumbs_zip_file_from_ftp.side_effect = [
            get_zip_file_from_sandbox(zip_thumb_file)
        ]

        provider_object = TiteLiveThingThumbs()
        provider_object.provider.isActive = True
        repository.save(provider_object.provider)

        # When
        provider_object.updateObjects()

        # Then
        new_product = Product.query.one()
        assert new_product.name == "Test Book"
        assert new_product.thumbCount == 1
    def test_should_delete_product_when_non_valid_product_type(
        self, get_lines_from_thing_file, get_files_to_process_from_titelive_ftp, app
    ):
        # Given
        files_list = list()
        files_list.append("Quotidien30.tit")

        get_files_to_process_from_titelive_ftp.return_value = files_list

        DATA_LINE_PARTS = BASE_DATA_LINE_PARTS[:]
        DATA_LINE_PARTS[2] = "jeux de société"
        DATA_LINE_PARTS[4] = "1234"
        DATA_LINE_PARTS[13] = "O"
        DATA_LINE_PARTS[27] = "Littérature scolaire"
        DATA_LINE_PARTS[40] = ""

        data_line = "~".join(DATA_LINE_PARTS)

        get_lines_from_thing_file.return_value = iter([data_line])
        get_lines_from_thing_file.return_value = iter([data_line])

        titelive_provider = activate_provider("TiteLiveThings")
        product = create_product_with_thing_subcategory(
            id_at_providers="9782895026310",
            thing_name="Toto à la playa",
            date_modified_at_last_provider=datetime(2001, 1, 1),
            last_provider_id=titelive_provider.id,
        )
        repository.save(product)
        titelive_things = TiteLiveThings()

        # When
        titelive_things.updateObjects()

        # Then
        assert Product.query.count() == 0
def create_industrial_thing_products():
    logger.info("create_industrial_thing_products")

    thing_products_by_name = {}

    thing_subcategories = [s for s in subcategories.ALL_SUBCATEGORIES if not s.is_event]

    id_at_providers = 1234

    for product_creation_counter in range(0, THINGS_PER_SUBCATEGORY):

        for (thing_subcategories_list_index, thing_subcategory) in enumerate(thing_subcategories):

            mock_index = (product_creation_counter + thing_subcategories_list_index) % len(MOCK_NAMES)

            name = "{} / {}".format(thing_subcategory.id, MOCK_NAMES[mock_index])
            is_online_only = (
                thing_subcategory.online_offline_platform == subcategories.OnlineOfflinePlatformChoices.ONLINE.value
            )
            url = "https://ilestencoretemps.fr/" if is_online_only else None

            thing_product = create_product_with_thing_subcategory(
                author_name=MOCK_AUTHOR_NAMES[mock_index],
                description=MOCK_DESCRIPTIONS[mock_index],
                id_at_providers=str(id_at_providers),
                is_national=is_online_only,
                thing_name=MOCK_NAMES[mock_index],
                thing_subcategory_id=thing_subcategory.id,
                thumb_count=0,
                url=url,
            )

            extraData = {}
            extra_data_index = 0
            for conditionalField in thing_product.subcategory.conditional_fields:
                conditional_index = product_creation_counter + thing_subcategories_list_index + extra_data_index
                if conditionalField in ["author", "performer", "speaker", "stageDirector"]:
                    mock_first_name_index = (
                        product_creation_counter + thing_subcategories_list_index + extra_data_index
                    ) % len(MOCK_FIRST_NAMES)
                    mock_first_name = MOCK_FIRST_NAMES[mock_first_name_index]
                    mock_last_name_index = (
                        product_creation_counter + thing_subcategories_list_index + extra_data_index
                    ) % len(MOCK_LAST_NAMES)
                    mock_last_name = MOCK_LAST_NAMES[mock_last_name_index]
                    mock_name = "{} {}".format(mock_first_name, mock_last_name)
                    extraData[conditionalField] = mock_name
                elif conditionalField == "musicType":
                    music_type_index = conditional_index % len(music_types)
                    music_type = music_types[music_type_index]
                    extraData[conditionalField] = str(music_type["code"])
                    music_sub_type_index = conditional_index % len(music_type["children"])
                    music_sub_type = music_type["children"][music_sub_type_index]
                    extraData["musicSubType"] = str(music_sub_type["code"])
                elif conditionalField == "isbn":
                    extraData[conditionalField] = random_token(13)
                extra_data_index += 1
            thing_product.extraData = extraData
            thing_products_by_name[name] = thing_product
            id_at_providers += 1

        product_creation_counter += len(thing_subcategories)

    repository.save(*thing_products_by_name.values())

    logger.info("created %d thing products", len(thing_products_by_name))

    return thing_products_by_name
    def test_should_return_expected_payload_for_bookable_offer(self, app):
        # Given
        offerer = create_offerer()
        venue = create_venue(offerer)
        product = create_product_with_thing_subcategory()
        offer = create_offer_with_thing_product(venue, product=product)
        stock = create_stock(offer=offer)
        mediation = create_mediation(offer)
        repository.save(mediation, stock)

        # When
        offer_json_response = get_non_free_thing_offer_with_active_mediation()

        # Then
        assert offer_json_response == {
            "mediationId": humanize(mediation.id),
            "offer": {
                "ageMax":
                None,
                "ageMin":
                None,
                "authorId":
                None,
                "audioDisabilityCompliant":
                None,
                "bookingEmail":
                "*****@*****.**",
                "conditions":
                None,
                "dateCreated":
                format_into_utc_date(offer.dateCreated),
                "dateModifiedAtLastProvider":
                format_into_utc_date(offer.dateModifiedAtLastProvider),
                "description":
                None,
                "durationMinutes":
                None,
                "externalTicketOfficeUrl":
                None,
                "extraData": {
                    "author": "Test Author"
                },
                "fieldsUpdated": [],
                "id":
                humanize(offer.id),
                "idAtProvider":
                offer.idAtProvider,
                "idAtProviders":
                offer.idAtProviders,
                "isActive":
                True,
                "isDuo":
                False,
                "isEducational":
                False,
                "isNational":
                False,
                "dateUpdated":
                format_into_utc_date(offer.dateUpdated),
                "lastProviderId":
                None,
                "lastValidationDate":
                None,
                "mediaUrls": ["test/urls"],
                "mentalDisabilityCompliant":
                None,
                "motorDisabilityCompliant":
                None,
                "name":
                "Test Book",
                "productId":
                humanize(product.id),
                "rankingWeight":
                None,
                "status":
                "ACTIVE",
                "subcategoryId":
                "LIVRE_PAPIER",
                "thingName":
                "Test Book",
                "url":
                None,
                "validation":
                "APPROVED",
                "venueCity":
                "Montreuil",
                "venueId":
                humanize(venue.id),
                "venueName":
                "La petite librairie",
                "visualDisabilityCompliant":
                None,
                "withdrawalDetails":
                None,
            },
        }