def fill_stock_attributes(self, allocine_stock: Stock): showtime_uuid = _get_showtimes_uuid_by_idAtProvider( allocine_stock.idAtProviders) showtime = _find_showtime_by_showtime_uuid( self.filtered_movie_showtimes, showtime_uuid) parsed_showtimes = retrieve_showtime_information(showtime) diffusion_version = parsed_showtimes["diffusionVersion"] allocine_stock.offerId = (self.last_vo_offer_id if diffusion_version == ORIGINAL_VERSION else self.last_vf_offer_id) local_tz = get_department_timezone(self.venue.departementCode) date_in_utc = _format_date_from_local_timezone_to_utc( parsed_showtimes["startsAt"], local_tz) allocine_stock.beginningDatetime = date_in_utc is_new_stock_to_insert = allocine_stock.id is None if is_new_stock_to_insert: allocine_stock.fieldsUpdated = [] if "bookingLimitDatetime" not in allocine_stock.fieldsUpdated: allocine_stock.bookingLimitDatetime = date_in_utc if "quantity" not in allocine_stock.fieldsUpdated: allocine_stock.quantity = self.quantity if "price" not in allocine_stock.fieldsUpdated: allocine_stock.price = self.apply_allocine_price_rule( allocine_stock)
def _edit_stock( stock: Stock, price: float, quantity: int, beginning: datetime.datetime, booking_limit_datetime: datetime.datetime, ) -> Stock: validation.check_stock_is_updatable(stock) validation.check_required_dates_for_stock(stock.offer, beginning, booking_limit_datetime) validation.check_stock_price(price) validation.check_stock_quantity(quantity, stock.bookingsQuantity) # FIXME (dbaty, 2020-11-25): We need this ugly workaround because # the frontend sends us datetimes like "2020-12-03T14:00:00Z" # (note the "Z" suffix). Pydantic deserializes it as a datetime # *with* a timezone. However, datetimes are stored in the database # as UTC datetimes *without* any timezone. Thus, we wrongly detect # a change for the "beginningDatetime" field for Allocine stocks: # because we do not allow it to be changed, we raise an error when # we should not. def as_utc_without_timezone(d: datetime.datetime) -> datetime.datetime: return d.astimezone(pytz.utc).replace(tzinfo=None) if beginning: beginning = as_utc_without_timezone(beginning) if booking_limit_datetime: booking_limit_datetime = as_utc_without_timezone( booking_limit_datetime) updates = { "price": price, "quantity": quantity, "beginningDatetime": beginning, "bookingLimitDatetime": booking_limit_datetime, } if stock.offer.isFromAllocine: # fmt: off updated_fields = { attr for attr, new_value in updates.items() if new_value != getattr(stock, attr) } # fmt: on validation.check_update_only_allowed_stock_fields_for_allocine_offer( updated_fields) stock.fieldsUpdated = list(updated_fields) for model_attr, value in updates.items(): setattr(stock, model_attr, value) return stock
def edit_stock( stock: Stock, price: int = None, quantity: int = None, beginning: datetime.datetime = None, booking_limit_datetime: datetime.datetime = None, ) -> Stock: validation.check_stock_is_updatable(stock) validation.check_required_dates_for_stock(stock.offer, beginning, booking_limit_datetime) # FIXME (dbaty, 2020-11-25): We need this ugly workaround because # the frontend sends us datetimes like "2020-12-03T14:00:00Z" # (note the "Z" suffix). Pydantic deserializes it as a datetime # *with* a timezone. However, datetimes are stored in the database # as UTC datetimes *without* any timezone. Thus, we wrongly detect # a change for the "beginningDatetime" field for Allocine stocks: # because we do not allow it to be changed, we raise an error when # we should not. def as_utc_without_timezone(d: datetime.datetime) -> datetime.datetime: return d.astimezone(pytz.utc).replace(tzinfo=None) if beginning: beginning = as_utc_without_timezone(beginning) if booking_limit_datetime: booking_limit_datetime = as_utc_without_timezone(booking_limit_datetime) updates = { "price": price, "quantity": quantity, "beginningDatetime": beginning, "bookingLimitDatetime": booking_limit_datetime, } if stock.offer.isFromAllocine: # fmt: off updated_fields = { attr for attr, new_value in updates.items() if new_value != getattr(stock, attr) } # fmt: on validation.check_update_only_allowed_stock_fields_for_allocine_offer(updated_fields) stock.fieldsUpdated = list(updated_fields) previous_beginning = stock.beginningDatetime for model_attr, value in updates.items(): setattr(stock, model_attr, value) repository.save(stock) if beginning != previous_beginning: bookings = bookings_repository.find_not_cancelled_bookings_by_stock(stock) if bookings: bookings = update_confirmation_dates(bookings, beginning) date_in_two_days = datetime.datetime.utcnow() + datetime.timedelta(days=2) check_event_is_in_more_than_48_hours = beginning > date_in_two_days if check_event_is_in_more_than_48_hours: bookings = _invalidate_bookings(bookings) try: user_emails.send_batch_stock_postponement_emails_to_users(bookings, send_email=mailing.send_raw_email) except mailing.MailServiceException as exc: # fmt: off app.logger.exception( "Could not notify beneficiaries about update of stock=%s: %s", stock.id, exc, ) # fmt: on if feature_queries.is_active(FeatureToggle.SYNCHRONIZE_ALGOLIA): redis.add_offer_id(client=app.redis_client, offer_id=stock.offerId) return stock