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
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}"
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
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 == {}
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" ]
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" ]
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
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
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
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, }, }