def test_venue_with_draft_bank_information(self): offerer = offerers_factories.OffererFactory() offers_factories.VirtualVenueFactory(managingOfferer=offerer) venue = offers_factories.VenueFactory(managingOfferer=offerer) offers_factories.BankInformationFactory(venue=venue, status=BankInformationStatus.DRAFT) assert not has_physical_venue_without_draft_or_accepted_bank_information(offerer_id=offerer.id)
def when_creating_new_thing_offer(self, app): # Given venue = offers_factories.VirtualVenueFactory() offerer = venue.managingOfferer offers_factories.UserOffererFactory(offerer=offerer, user__email="*****@*****.**") # When client = TestClient(app.test_client()).with_auth("*****@*****.**") data = { "venueId": humanize(venue.id), "bookingEmail": "*****@*****.**", "mediaUrls": ["http://example.com/media"], "name": "Les lièvres pas malins", "type": "ThingType.JEUX_VIDEO", "url": "http://example.com/offer", } response = client.post("/offers", json=data) # Then assert response.status_code == 201 offer_id = dehumanize(response.json["id"]) offer = Offer.query.get(offer_id) assert offer.bookingEmail == "*****@*****.**" assert offer.type == str(ThingType.JEUX_VIDEO) assert offer.venue == venue assert offer.product.name == "Les lièvres pas malins" assert offer.product.url == "http://example.com/offer" assert offer.url == "http://example.com/offer" assert offer.isDigital assert offer.isNational assert offer.product.isNational assert offer.product.owningOfferer == offerer
def test_fail_when_offer_type_does_not_allow_virtual_offer_and_venue_is_virtuel( self, app): # Given venue = offers_factories.VirtualVenueFactory() offerer = venue.managingOfferer offers_factories.UserOffererFactory(offerer=offerer, user__email="*****@*****.**") # When data = { "type": "ThingType.JEUX", "name": "Le grand jeu", "url": "http://legrandj.eu", "mediaUrls": ["http://media.url"], "venueId": humanize(venue.id), "audioDisabilityCompliant": True, "mentalDisabilityCompliant": False, "motorDisabilityCompliant": False, "visualDisabilityCompliant": False, } client = TestClient(app.test_client()).with_auth("*****@*****.**") response = client.post("/offers", json=data) # Then assert response.status_code == 400 assert response.json["url"] == [ "Une offre de type Jeux (support physique) ne peut pas être numérique" ]
def get_existing_pro_validated_user_with_validated_offerer_validated_user_offerer_no_physical_venue(): user_offerer = offers_factories.UserOffererFactory( validationToken=None, offerer__validationToken=None, user__validationToken=None, ) offers_factories.VirtualVenueFactory(managingOfferer=user_offerer.offerer) return {"offerer": get_offerer_helper(user_offerer.offerer), "user": get_pro_helper(user_offerer.user)}
def test_venues_with_missing_and_accepted_bank_information(self): offerer = offerers_factories.OffererFactory() offers_factories.VirtualVenueFactory(managingOfferer=offerer) offers_factories.VenueFactory(managingOfferer=offerer) venue_with_rejected_bank_information = offers_factories.VenueFactory(managingOfferer=offerer) offers_factories.BankInformationFactory( venue=venue_with_rejected_bank_information, status=BankInformationStatus.ACCEPTED ) assert has_physical_venue_without_draft_or_accepted_bank_information(offerer_id=offerer.id)
def test_success_if_digital_product_and_virtual_venue(self): venue = factories.VirtualVenueFactory() user_offerer = factories.UserOffererFactory(offerer=venue.managingOfferer) product = factories.DigitalProductFactory() data = offers_serialize.PostOfferBodyModel( venueId=humanize(venue.id), productId=humanize(product.id), ) api.create_offer(data, user_offerer.user) # should not fail
def test_should_return_numerique_when_venue_is_virtual( self, mock_is_offer_active, mock_build_pc_pro_offer_link): # Given virtual_venue = offers_factories.VirtualVenueFactory() stock = offers_factories.ThingStockFactory(offer__venue=virtual_venue) booking1 = bookings_factories.CancelledIndividualBookingFactory( stock=stock, quantity=2) booking2 = bookings_factories.IndividualBookingFactory(stock=stock) # When mailjet_data = retrieve_offerer_booking_recap_email_data_after_user_cancellation( booking1) # Then assert mailjet_data == { "MJ-TemplateID": 780015, "MJ-TemplateLanguage": True, "Vars": { "departement": "numérique", "nom_offre": stock.offer.name, "lien_offre_pcpro": "http://pc_pro.com/offer_link", "nom_lieu": virtual_venue.name, "prix": f"{stock.price}", "is_event": 0, "date": "", "heure": "", "quantite": booking1.quantity, "user_name": booking1.publicName, "user_email": booking1.email, "is_active": 0, "nombre_resa": 1, "users": [{ "contremarque": booking2.token, "email": booking2.email, "firstName": booking2.firstName, "lastName": booking2.lastName, }], }, }
def test_fail_if_physical_product_and_virtual_venue(self): venue = factories.VirtualVenueFactory() user_offerer = factories.UserOffererFactory(offerer=venue.managingOfferer) product = factories.ProductFactory() data = offers_serialize.PostOfferBodyModel( venueId=humanize(venue.id), productId=humanize(product.id), ) with pytest.raises(api_errors.ApiErrors) as error: api.create_offer(data, user_offerer.user) err = 'Une offre physique ne peut être associée au lieu "Offre numérique"' assert error.value.errors["venue"] == [err]
def get_existing_pro_validated_user_with_at_least_one_visible_activated_offer( ): user_offerer = offers_factories.UserOffererFactory( validationToken=None, offerer__validationToken=None, user__validationToken=None, ) venue = offers_factories.VirtualVenueFactory( managingOfferer=user_offerer.offerer) offer = offers_factories.OfferFactory(venue=venue, isActive=True) return { "offer": get_offer_helper(offer), "user": get_pro_helper(user_offerer.user) }
def test_with_virtual_offer(self): # Given author = users_factories.ProFactory() offer = offers_factories.EventOfferFactory( author=author, product=offers_factories.DigitalProductFactory( name="Les lièvres pas malins"), venue=offers_factories.VirtualVenueFactory(), ) # When email = make_offer_creation_notification_email(offer) # Then assert email[ "Subject"] == "[Création d’offre - numérique] Les lièvres pas malins"
def when_user_is_not_attached_to_offerer(self, app): # Given users_factories.UserFactory(email="*****@*****.**") venue = offers_factories.VirtualVenueFactory() # When client = TestClient(app.test_client()).with_auth("*****@*****.**") data = { "venueId": humanize(venue.id), } response = client.post("/offers", json=data) # Then assert response.status_code == 403 assert response.json["global"] == [ "Vous n'avez pas les droits d'accès suffisant pour accéder à cette information." ]
def get_existing_pro_validated_user_with_validated_offerer_with_iban_validated_user_offerer_with_event_offer_with_no_stock( ): user_offerer = offers_factories.UserOffererFactory( validationToken=None, offerer__validationToken=None, user__validationToken=None, ) offers_factories.BankInformationFactory(offerer=user_offerer.offerer) venue = offers_factories.VirtualVenueFactory( managingOfferer=user_offerer.offerer) offer = offers_factories.EventOfferFactory(venue=venue, isActive=True) return { "offer": get_offer_helper(offer), "offerer": get_offerer_helper(user_offerer.offerer), "user": get_pro_helper(user_offerer.user), "venue": get_venue_helper(venue), }
def should_fail_when_externalTicketOfficeUrl_has_no_host(self, app): # Given venue = offers_factories.VirtualVenueFactory() offerer = venue.managingOfferer offers_factories.UserOffererFactory(offerer=offerer, user__email="*****@*****.**") # When client = TestClient(app.test_client()).with_session_auth("*****@*****.**") data = { "venueId": humanize(venue.id), "name": "Les lièvres pas malins", "subcategoryId": subcategories.JEU_EN_LIGNE.id, "externalTicketOfficeUrl": "https://missing", } response = client.post("/offers", json=data) # Then assert response.status_code == 400 assert response.json["externalTicketOfficeUrl"] == ['L\'URL doit terminer par une extension (ex. ".fr")']
def should_fail_when_url_has_no_scheme(self, app): # Given venue = offers_factories.VirtualVenueFactory() offerer = venue.managingOfferer offers_factories.UserOffererFactory(offerer=offerer, user__email="*****@*****.**") # When client = TestClient(app.test_client()).with_session_auth("*****@*****.**") data = { "venueId": humanize(venue.id), "name": "Les lièvres pas malins", "subcategoryId": subcategories.JEU_EN_LIGNE.id, "url": "missing.something", } response = client.post("/offers", json=data) # Then assert response.status_code == 400 assert response.json["url"] == ['L\'URL doit commencer par "http://" ou "https://"']
def when_creating_new_thing_offer(self, app): # Given venue = offers_factories.VirtualVenueFactory() offerer = venue.managingOfferer offers_factories.UserOffererFactory(offerer=offerer, user__email="*****@*****.**") # When client = TestClient(app.test_client()).with_session_auth("*****@*****.**") data = { "venueId": humanize(venue.id), "bookingEmail": "*****@*****.**", "mediaUrls": ["http://example.com/media"], "name": "Les lièvres pas malins", "subcategoryId": subcategories.JEU_EN_LIGNE.id, "url": "http://example.com/offer", "externalTicketOfficeUrl": "http://example.net", "audioDisabilityCompliant": True, "mentalDisabilityCompliant": False, "motorDisabilityCompliant": False, "visualDisabilityCompliant": False, } response = client.post("/offers", json=data) # Then assert response.status_code == 201 offer_id = dehumanize(response.json["id"]) offer = Offer.query.get(offer_id) assert offer.bookingEmail == "*****@*****.**" assert offer.subcategoryId == subcategories.JEU_EN_LIGNE.id assert offer.venue == venue assert offer.product.name == "Les lièvres pas malins" assert offer.product.url == "http://example.com/offer" assert offer.externalTicketOfficeUrl == "http://example.net" assert offer.url == "http://example.com/offer" assert offer.isDigital assert offer.isNational assert offer.product.isNational assert offer.product.owningOfferer == offerer assert offer.motorDisabilityCompliant == False assert offer.visualDisabilityCompliant == False assert offer.audioDisabilityCompliant == True assert offer.mentalDisabilityCompliant == False
def test_fail_if_incoherent_input(self, app): # Given venue = offers_factories.VirtualVenueFactory() offerer = venue.managingOfferer offers_factories.UserOffererFactory(offerer=offerer, user__email="*****@*****.**") # When data = { "type": "ThingType.JEUX", "name": "Le grand jeu", "url": "http://legrandj.eu", "mediaUrls": ["http://media.url"], "venueId": humanize(venue.id), } client = TestClient(app.test_client()).with_auth("*****@*****.**") response = client.post("/offers", json=data) # Then assert response.status_code == 400 assert response.json["url"] == ["Une offre de type Jeux (support physique) ne peut pas être numérique"]
def should_fail_when_url_has_no_scheme(self, app): # Given virtual_venue = offers_factories.VirtualVenueFactory() offer = offers_factories.OfferFactory(venue=virtual_venue) offers_factories.UserOffererFactory( user__email="*****@*****.**", offerer=offer.venue.managingOfferer, ) # When data = { "name": "Les lièvres pas malins", "url": "missing.something", } client = TestClient(app.test_client()).with_auth("*****@*****.**") response = client.patch(f"offers/{humanize(offer.id)}", json=data) # Then assert response.status_code == 400 assert response.json["url"] == ['L\'URL doit commencer par "http://" ou "https://"']
def should_fail_when_externalTicketOfficeUrl_has_no_host(self, app): # Given virtual_venue = offers_factories.VirtualVenueFactory() offer = offers_factories.OfferFactory(venue=virtual_venue) offers_factories.UserOffererFactory( user__email="*****@*****.**", offerer=offer.venue.managingOfferer, ) # When data = { "name": "Les lièvres pas malins", "externalTicketOfficeUrl": "https://missing", } client = TestClient(app.test_client()).with_auth("*****@*****.**") response = client.patch(f"offers/{humanize(offer.id)}", json=data) # Then assert response.status_code == 400 assert response.json["externalTicketOfficeUrl"] == ['L\'URL doit terminer par une extension (ex. ".fr")']
def test_fail_when_offer_subcategory_is_offline_only_and_venue_is_virtuel(self, app): # Given venue = offers_factories.VirtualVenueFactory() offerer = venue.managingOfferer offers_factories.UserOffererFactory(offerer=offerer, user__email="*****@*****.**") # When data = { "subcategoryId": subcategories.ACHAT_INSTRUMENT.id, "name": "Le grand jeu", "url": "http://legrandj.eu", "mediaUrls": ["http://media.url"], "venueId": humanize(venue.id), "audioDisabilityCompliant": True, "mentalDisabilityCompliant": False, "motorDisabilityCompliant": False, "visualDisabilityCompliant": False, } client = TestClient(app.test_client()).with_session_auth("*****@*****.**") response = client.post("/offers", json=data) # Then assert response.status_code == 400 assert response.json["url"] == ["Une offre de sous-catégorie Achat instrument ne peut pas être numérique"]
def test_digital_venue_without_offer(self): offerer = offerers_factories.OffererFactory() offers_factories.VirtualVenueFactory(managingOfferer=offerer) assert not has_digital_venue_with_at_least_one_offer(offerer.id)
def test_return_managing_offerer_timezone_when_venue_is_virtual(self): offers_factories.VirtualVenueFactory(managingOfferer__postalCode="97300") query_result = Venue.query.filter(Venue.timezone == "America/Cayenne").all() assert len(query_result) == 1
def test_generate_and_send_payments(): # Comments below indicate what `generate_and_send_payments()` will # do, no what the setup does. cutoff = datetime.datetime.now() before_cutoff = cutoff - datetime.timedelta(days=1) # 1 new payment + 1 retried payment for venue 1 venue1 = offers_factories.VenueFactory(name="venue1") offers_factories.BankInformationFactory(venue=venue1) booking11 = bookings_factories.UsedBookingFactory( dateUsed=before_cutoff, stock__offer__venue=venue1) booking12 = bookings_factories.UsedBookingFactory( dateUsed=before_cutoff, stock__offer__venue=venue1) payment12 = payments_factories.PaymentFactory(booking=booking12) payments_factories.PaymentStatusFactory(payment=payment12, status=TransactionStatus.ERROR) payment13 = payments_factories.PaymentFactory( booking__stock__offer__venue=venue1) payments_factories.PaymentStatusFactory(payment=payment13, status=TransactionStatus.SENT) bookings_factories.BookingFactory(stock__offer__venue=venue1) # 1 new payment for venue 2 venue2 = offers_factories.VenueFactory(name="venue2") offers_factories.BankInformationFactory(offerer=venue2.managingOfferer) booking2 = bookings_factories.UsedBookingFactory( dateUsed=before_cutoff, stock__offer__venue=venue2) # 0 payment for venue 3 (existing booking has already been reimbursed) payment3 = payments_factories.PaymentFactory() payments_factories.PaymentStatusFactory(payment=payment3, status=TransactionStatus.SENT) # 1 new payment (not processable) for venue 4 (no IBAN nor BIC) venue4 = offers_factories.VenueFactory() booking4 = bookings_factories.UsedBookingFactory( dateUsed=before_cutoff, stock__offer__venue=venue4) # 0 payment for venue 5 (booking is not used) venue5 = offers_factories.VenueFactory() bookings_factories.BookingFactory(stock__offer__venue=venue5) # 0 payment for venue 6 (booking has been used after cutoff) venue6 = offers_factories.VenueFactory(name="venue2") offers_factories.BankInformationFactory(offerer=venue6.managingOfferer) bookings_factories.UsedBookingFactory(dateUsed=cutoff, stock__offer__venue=venue2) # 1 new payment for digital venue virtual_venue = offers_factories.VirtualVenueFactory() offers_factories.BankInformationFactory( offerer=virtual_venue.managingOfferer) digital_reimbursable_offer = offers_factories.DigitalOfferFactory( venue=virtual_venue, subcategoryId=subcategories.CINE_VENTE_DISTANCE.id) digital_booking = bookings_factories.UsedBookingFactory( dateUsed=before_cutoff, stock__offer=digital_reimbursable_offer) last_payment_id = Payment.query.with_entities(func.max( Payment.id)).scalar() last_status_id = PaymentStatus.query.with_entities( func.max(PaymentStatus.id)).scalar() generate_and_send_payments(cutoff) # Check new payments and statuses new_payments = Payment.query.filter(Payment.id > last_payment_id).all() assert set(p.booking for p in new_payments) == { booking11, booking2, booking4, digital_booking } new_statuses = (PaymentStatus.query.filter( PaymentStatus.id > last_status_id).join( PaymentStatus.payment).order_by(Payment.bookingId)) assert set((s.payment.booking, s.status) for s in new_statuses) == { (booking11, TransactionStatus.PENDING), (booking11, TransactionStatus.UNDER_REVIEW), (booking12, TransactionStatus.UNDER_REVIEW), (booking2, TransactionStatus.PENDING), (booking2, TransactionStatus.UNDER_REVIEW), (booking4, TransactionStatus.NOT_PROCESSABLE), (digital_booking, TransactionStatus.PENDING), (digital_booking, TransactionStatus.UNDER_REVIEW), } # Check "transaction" e-mail email = mails_testing.outbox[0] subject = email.sent_data["Subject"].split("-")[0].strip() # ignore date assert subject == "Virements XML pass Culture Pro" xml = base64.b64decode( email.sent_data["Attachments"][0]["Content"]).decode("utf-8") assert "<NbOfTxs>4</NbOfTxs>" in xml assert "<CtrlSum>40.00</CtrlSum>" in xml assert xml.count("<EndToEndId>") == 4 # Check "report" e-mail email = mails_testing.outbox[1] subject = email.sent_data["Subject"].split("-")[0].strip() # ignore date assert subject == "Récapitulatif des paiements pass Culture Pro" html = email.sent_data["Html-part"] assert "Nombre total de paiements : 5" in html assert "NOT_PROCESSABLE : 1" in html assert "UNDER_REVIEW : 4" in html # Check "details" e-mail email = mails_testing.outbox[2] subject = email.sent_data["Subject"].split("-")[0].strip() # ignore date assert subject == "Détails des paiements pass Culture Pro" zip_data = base64.b64decode(email.sent_data["Attachments"][0]["Content"]) with zipfile.ZipFile(io.BytesIO(zip_data)) as zf: csv = zf.open(zf.namelist()[0]).read().decode("utf-8") rows = csv.splitlines() assert len(rows) == 5 # header + 4 payments # Check "wallet balance" e-mail email = mails_testing.outbox[3] subject = email.sent_data["Subject"].split("-")[0].strip() # ignore date assert subject == "Soldes des utilisateurs pass Culture" zip_data = base64.b64decode(email.sent_data["Attachments"][0]["Content"]) with zipfile.ZipFile(io.BytesIO(zip_data)) as zf: csv = zf.open(zf.namelist()[0]).read().decode("utf-8") rows = csv.splitlines() assert len(rows) == users_models.User.query.count() + 1 # + header
def test_return_managing_offerer_timezone_when_venue_is_virtual(self): venue = offers_factories.VirtualVenueFactory(managingOfferer__postalCode="97300") assert venue.timezone == "America/Cayenne"