def test_get_enabled_providers_for_pro(self, app): # Given Provider.query.delete() # remove automatically added providers provider1 = offerers_factories.AllocineProviderFactory( localClass="Truc", isActive=True, enabledForPro=True) offerers_factories.APIProviderFactory(name="NotEnabledAPIProvider", isActive=True, enabledForPro=False) offerers_factories.APIProviderFactory(name="InactiveAPIProvider", isActive=False, enabledForPro=True) offerers_factories.APIProviderFactory(name="InactiveAPIProvider2", isActive=False, enabledForPro=False) provider2 = offerers_factories.APIProviderFactory(name="Provider2", isActive=True, enabledForPro=True) # When enabled_providers = get_enabled_providers_for_pro() # Then assert len(enabled_providers) == 2 assert provider1 in enabled_providers assert provider2 in enabled_providers
def test_synchronize_venue_providers(self, mocked_synchronize_venue_provider, app): # Given api_provider_1 = offerers_factories.APIProviderFactory() api_provider_2 = offerers_factories.APIProviderFactory() specific_provider = offerers_factories.AllocineProviderFactory() inactive_provider = offerers_factories.APIProviderFactory( isActive=False) correct_venue_providers = [ VenueProviderFactory(isActive=True, provider=api_provider_1), VenueProviderFactory(isActive=True, provider=api_provider_1), VenueProviderFactory(isActive=True, provider=api_provider_2), ] VenueProviderFactory(isActive=True, provider=specific_provider) VenueProviderFactory(isActive=False, provider=api_provider_1) VenueProviderFactory(isActive=True, provider=inactive_provider) # When synchronize_stocks() # Then assert mocked_synchronize_venue_provider.call_count == len( correct_venue_providers) mocked_synchronize_venue_provider.assert_has_calls( call(v) for v in correct_venue_providers)
def when_venue_provider_is_successfully_created( self, mock_siret_can_be_synchronized, mock_synchronize_venue_provider, app): # Given user = user_factories.AdminFactory() venue = offer_factories.VenueFactory(siret="12345678912345") provider = offerers_factories.APIProviderFactory() venue_provider_data = { "providerId": humanize(provider.id), "venueId": humanize(venue.id), } mock_siret_can_be_synchronized.return_value = True auth_request = TestClient( app.test_client()).with_session_auth(email=user.email) # When response = auth_request.post("/venueProviders", json=venue_provider_data) # Then assert response.status_code == 201 venue_provider = VenueProvider.query.one() assert venue_provider.venueId == venue.id assert venue_provider.providerId == provider.id assert venue_provider.venueIdAtOfferProvider == "12345678912345" assert "id" in response.json venue_provider_id = response.json["id"] mock_synchronize_venue_provider.assert_called_once_with( dehumanize(venue_provider_id))
def when_provider_api_not_available(self, mock_siret_can_be_synchronized, app): # Given user = user_factories.AdminFactory() venue = offer_factories.VenueFactory(siret="12345678912345") provider = offerers_factories.APIProviderFactory() venue_provider_data = { "providerId": humanize(provider.id), "venueId": humanize(venue.id), } auth_request = TestClient( app.test_client()).with_session_auth(email=user.email) errors = ApiErrors() errors.status_code = 422 errors.add_error( "provider", "L’importation d’offres avec LesLibraires n’est pas disponible " "pour le SIRET 12345678912345", ) mock_siret_can_be_synchronized.side_effect = [errors] # When response = auth_request.post("/venueProviders", json=venue_provider_data) # Then assert response.status_code == 422 assert response.json["provider"] == [ "L’importation d’offres avec LesLibraires n’est pas disponible pour le SIRET 12345678912345" ] assert VenueProvider.query.count() == 0
def test_when_add_same_provider(self, mock_siret_can_be_synchronized, mock_synchronize_venue_provider, app): # Given user = user_factories.AdminFactory() venue = offer_factories.VenueFactory(siret="12345678912345") provider = offerers_factories.APIProviderFactory() venue_provider = create_venue_provider( venue, provider, venue_id_at_offer_provider="12345678912345") repository.save(venue_provider) auth_request = TestClient( app.test_client()).with_session_auth(email=user.email) venue_provider_data = { "providerId": humanize(provider.id), "venueId": humanize(venue.id), } mock_siret_can_be_synchronized.return_value = True # When response = auth_request.post("/venueProviders", json=venue_provider_data) # Then assert response.status_code == 400 assert response.json == { "global": ["Votre lieu est déjà lié à cette source"] } assert venue.venueProviders[0].provider.id == provider.id
def test_change_venue_provider(): api_url = "https://example.com/provider/api" provider = offerers_factories.APIProviderFactory() venue_provider = offerers_factories.VenueProviderFactory(provider=provider) venue = venue_provider.venue stock = StockFactory(quantity=10, offer__venue=venue, offer__idAtProviders="1") BookingFactory(stock=stock) new_provider = offerers_factories.APIProviderFactory(apiUrl=api_url) api.change_venue_provider(venue_provider, new_provider.id) # Check venue_provider has change provider and sync date reset assert len(venue.venueProviders) == 1 assert venue.venueProviders[0].providerId == new_provider.id assert venue.venueProviders[0].lastSyncDate == None # Check that the quantity of existing stocks has been reset. assert stock.quantity == 1 assert stock.offer.lastProviderId == new_provider.id
def test_non_allocine_provider_offer(self): offerer = offerers_factories.APIProviderFactory() provider_offer = offers_factories.OfferFactory(lastProvider=offerer, idAtProviders="1") with pytest.raises(ApiErrors) as error: validation.check_offer_existing_stocks_are_editable(provider_offer) assert error.value.errors["global"] == [ "Les offres importées ne sont pas modifiables" ]
def test_offer_from_non_allocine_provider(self): provider = offerers_factories.APIProviderFactory() offer = offers_factories.OfferFactory(lastProvider=provider, idAtProviders="1") stock = offers_factories.StockFactory(offer=offer) with pytest.raises(ApiErrors) as error: validation.check_stock_is_updatable(stock) assert error.value.errors["global"] == [ "Les offres importées ne sont pas modifiables" ]
def test_use_siret_as_default(can_be_synchronized, app): # Given venue = VenueFactory(siret="12345678912345") provider = offerers_factories.APIProviderFactory() # When connect_venue_to_provider(venue, provider, None) # Then venue_provider = VenueProvider.query.one() assert venue_provider.venueIdAtOfferProvider == "12345678912345" can_be_synchronized.assert_called_once_with("12345678912345")
def test_should_get_actives_and_enabled_providers_for_pro(self, app): # Given Provider.query.delete() # remove automatically added providers offerers_factories.AllocineProviderFactory(name="Provider1", isActive=True, enabledForPro=True) offerers_factories.APIProviderFactory(name="NotEnabledAPIProvider", isActive=True, enabledForPro=False) offerers_factories.APIProviderFactory(name="InactiveAPIProvider", isActive=False, enabledForPro=True) provider = offerers_factories.APIProviderFactory(name="Provider2", isActive=True, enabledForPro=True) # When providers = get_providers_enabled_for_pro_excluding_specific_provider( "AllocineStocks") # Then assert providers == [provider]
def test_when_venue_id_at_offer_provider_is_given(can_be_synchronized, app): # Given venue_id_at_offer_provider = "id_for_remote_system" venue = VenueFactory(siret="12345678912345") provider = offerers_factories.APIProviderFactory() # When connect_venue_to_provider(venue, provider, venue_id_at_offer_provider) # Then venue_provider = VenueProvider.query.one() assert venue_provider.venueIdAtOfferProvider == venue_id_at_offer_provider can_be_synchronized.assert_called_once_with("id_for_remote_system")
def when_no_regression_on_format(self, mock_siret_can_be_synchronized, mock_synchronize_venue_provider, app): # Given user = user_factories.AdminFactory() venue = offer_factories.VenueFactory(siret="12345678912345") provider = offerers_factories.APIProviderFactory() venue_provider_data = { "providerId": humanize(provider.id), "venueId": humanize(venue.id), } auth_request = TestClient( app.test_client()).with_session_auth(email=user.email) mock_siret_can_be_synchronized.return_value = True # When response = auth_request.post("/venueProviders", json=venue_provider_data) # Then assert response.status_code == 201 assert set(response.json.keys()) == { "dateModifiedAtLastProvider", "fieldsUpdated", "id", "idAtProviders", "isActive", "isDuo", "isFromAllocineProvider", "lastProviderId", "lastSyncDate", "nOffers", "price", "provider", "providerId", "quantity", "venueId", "venueIdAtOfferProvider", } assert set(response.json["provider"].keys()) == { "enabledForPro", "id", "isActive", "localClass", "name", }
def should_not_connect_venue_when_venue_has_no_siret(self, app): # Given offerer = create_offerer() venue = create_venue(offerer, siret=None, is_virtual=True) provider = offerers_factories.APIProviderFactory(name="FNAC") repository.save(venue) self.find_by_id.return_value = venue # when with pytest.raises(NoSiretSpecified): connect_venue_to_provider(venue, provider) # then assert not VenueProvider.query.first()
def should_not_connect_venue_when_synchronization_is_not_allowed( self, app): # Given offerer = create_offerer() venue = create_venue(offerer, siret="12345678912345") provider = offerers_factories.APIProviderFactory(name="FNAC") repository.save(venue) self.find_by_id.return_value = venue stock_repository = MagicMock() stock_repository.can_be_synchronized.return_value = False # when with pytest.raises(VenueSiretNotRegistered): connect_venue_to_provider(venue, provider) # then assert not VenueProvider.query.first()
def should_connect_venue_when_synchronization_is_allowed(self, app): # Given offerer = create_offerer() venue = create_venue(offerer) provider = offerers_factories.APIProviderFactory() repository.save(venue) self.find_by_id.return_value = venue stock_repository = MagicMock() stock_repository.can_be_synchronized.return_value = True # When connect_venue_to_provider(venue, provider) # Then fnac_venue_provider = VenueProvider.query.one() assert fnac_venue_provider.venue == venue
def when_venue_does_not_exist(self, app): # Given user = user_factories.AdminFactory() provider = offerers_factories.APIProviderFactory() venue_provider_data = { "providerId": humanize(provider.id), "venueId": "AZERT", } auth_request = TestClient( app.test_client()).with_session_auth(email=user.email) # When response = auth_request.post("/venueProviders", json=venue_provider_data) # Then assert response.status_code == 404
def test_fully_sync_venue(): api_url = "https://example.com/provider/api" provider = offerers_factories.APIProviderFactory(apiUrl=api_url) venue_provider = offerers_factories.VenueProviderFactory(provider=provider) venue = venue_provider.venue stock = offers_factories.StockFactory(quantity=10, offer__venue=venue, offer__idAtProviders="1") bookings_factories.BookingFactory(stock=stock) product2 = offers_factories.ProductFactory( idAtProviders="1234", extraData={"prix_livre": 10}, subcategoryId=subcategories.LIVRE_PAPIER.id, ) with requests_mock.Mocker() as mock: response = { "total": 1, "stocks": [{ "ref": "1234", "available": 5 }], } mock.get(f"{api_url}/{venue_provider.venueIdAtOfferProvider}", [{ "json": response }, { "json": { "stocks": [] } }]) fully_sync_venue.fully_sync_venue(venue) # Check that the quantity of existing stocks has been reset. assert stock.quantity == 1 # Check that offers and stocks have been created or updated. offer2 = offers_models.Offer.query.filter_by(product=product2).one() assert offer2.stocks[0].quantity == 5
def should_inject_the_appropriate_repository_to_the_usecase( self, mocked_connect_venue_to_provider, mock_siret_can_be_synchronized, app): # Given user = user_factories.AdminFactory() venue = offer_factories.VenueFactory(siret="12345678912345") provider = offerers_factories.APIProviderFactory() venue_provider_data = { "providerId": humanize(provider.id), "venueId": humanize(venue.id), } auth_request = TestClient( app.test_client()).with_session_auth(email=user.email) mock_siret_can_be_synchronized.return_value = True # When auth_request.post("/venueProviders", json=venue_provider_data) # Then mocked_connect_venue_to_provider.assert_called_once_with( venue, provider, None)
def test_execution(self, mock_async_index_offer_ids): # Given spec = [ {"ref": "3010000101789", "available": 6}, {"ref": "3010000101797", "available": 4}, {"ref": "3010000103769", "available": 18}, {"ref": "3010000107163", "available": 12}, {"ref": "3010000108123", "available": 17}, {"ref": "3010000108124", "available": 17}, {"ref": "3010000108125", "available": 17}, {"ref": "3010000101790", "available": 1}, {"ref": "3010000102735", "available": 1}, ] offerers_factories.APIProviderFactory(apiUrl="https://provider_url", authToken="fake_token") venue = VenueFactory() siret = venue.siret provider = offerers_factories.ProviderFactory() stock_details = synchronize_provider_api._build_stock_details_from_raw_stocks(spec, siret, provider, venue.id) stock = create_stock( spec[0]["ref"], siret, quantity=20, ) offer = create_offer(spec[1]["ref"], siret) product = create_product(spec[2]["ref"]) create_product(spec[4]["ref"]) create_product(spec[6]["ref"], isGcuCompatible=False) create_product(spec[8]["ref"], isSynchronizationCompatible=False) stock_with_booking = create_stock(spec[5]["ref"], siret, quantity=20) BookingFactory(stock=stock_with_booking) BookingFactory(stock=stock_with_booking, quantity=2) create_product(spec[7]["ref"]) OfferFactory(venue=venue, idAtProviders="out-of-date-id-at-p", idAtProvider=spec[7]["ref"]) # When api.synchronize_stocks(stock_details, venue, provider_id=provider.id) # Then # Test updates stock if already exists assert stock.quantity == 6 assert stock.rawProviderQuantity == 6 # Test creates stock if does not exist assert len(offer.stocks) == 1 created_stock = offer.stocks[0] assert created_stock.quantity == 4 assert created_stock.rawProviderQuantity == 4 # Test creates offer if does not exist created_offer = Offer.query.filter_by(idAtProviders=f"{spec[2]['ref']}@{siret}").one() assert created_offer.stocks[0].quantity == 18 # Test doesn't create offer if product does not exist or not gcu compatible or not synchronization compatible assert Offer.query.filter_by(idAtProviders=f"{spec[3]['ref']}@{siret}").count() == 0 assert Offer.query.filter_by(idAtProviders=f"{spec[6]['ref']}@{siret}").count() == 0 assert Offer.query.filter_by(idAtProviders=f"{spec[8]['ref']}@{siret}").count() == 0 # Test second page is actually processed second_created_offer = Offer.query.filter_by(idAtProviders=f"{spec[4]['ref']}@{siret}").one() assert second_created_offer.stocks[0].quantity == 17 # Test existing bookings are added to quantity assert stock_with_booking.quantity == 17 + 1 + 2 assert stock_with_booking.rawProviderQuantity == 17 # Test fill stock attributes assert created_stock.price == Decimal("12.00") assert created_stock.idAtProviders == f"{spec[1]['ref']}@{siret}" # Test fill offers attributes assert created_offer.bookingEmail == venue.bookingEmail assert created_offer.description == product.description assert created_offer.extraData == product.extraData assert created_offer.name == product.name assert created_offer.productId == product.id assert created_offer.venueId == venue.id assert created_offer.idAtProviders == f"{spec[2]['ref']}@{siret}" assert created_offer.lastProviderId == provider.id # Test offer reindexation mock_async_index_offer_ids.assert_called_with( {stock.offer.id, offer.id, stock_with_booking.offer.id, created_offer.id, second_created_offer.id} )
def test_build_new_offers_from_stock_details(self, db_session): # Given spec = [ StockDetail( # known offer, must be ignored available_quantity=1, offers_provider_reference="offer_ref1", venue_reference="venue_ref1", products_provider_reference="isbn_product_ref", stocks_provider_reference="stock_ref", price=28.989, ), StockDetail( # new one, will be created available_quantity=17, offers_provider_reference="offer_ref_2", price=28.989, products_provider_reference="isbn_product_ref", stocks_provider_reference="stock_ref", venue_reference="venue_ref2", ), # no quantity, must be ignored StockDetail( available_quantity=0, offers_provider_reference="offer_ref_3", price=28.989, products_provider_reference="isbn_product_ref", stocks_provider_reference="stock_ref", venue_reference="venue_ref3", ), ] existing_offers_by_provider_reference = {"offer_ref1": 1} existing_offers_by_venue_reference = {"venue_ref1": 1} provider = offerers_factories.APIProviderFactory(apiUrl="https://provider_url", authToken="fake_token") venue = VenueFactory(bookingEmail="booking_email", withdrawalDetails="My withdrawal details") product = Product( id=456, name="product_name", description="product_desc", extraData="extra", subcategoryId=subcategories.LIVRE_PAPIER.id, ) products_by_provider_reference = {"isbn_product_ref": product} # When new_offers = api._build_new_offers_from_stock_details( spec, existing_offers_by_provider_reference, products_by_provider_reference, existing_offers_by_venue_reference, venue, provider_id=provider.id, ) # Then assert new_offers == [ Offer( bookingEmail="booking_email", description="product_desc", extraData="extra", idAtProviders="offer_ref_2", lastProviderId=provider.id, name="product_name", productId=456, venueId=venue.id, subcategoryId=subcategories.LIVRE_PAPIER.id, withdrawalDetails=venue.withdrawalDetails, ), ] new_offer = new_offers[0] assert new_offer.bookingEmail == "booking_email" assert new_offer.description == "product_desc" assert new_offer.extraData == "extra" assert new_offer.idAtProviders == "offer_ref_2" assert new_offer.idAtProvider == "isbn_product_ref" assert new_offer.lastProviderId == provider.id assert new_offer.name == "product_name" assert new_offer.productId == 456 assert new_offer.venueId == venue.id assert new_offer.subcategoryId == subcategories.LIVRE_PAPIER.id assert new_offer.withdrawalDetails == venue.withdrawalDetails