def billing_approved_book_order(callback_args, order): from sharing.station_controller import send_ride_in_risk_notification ride_id = callback_args.get("ride_id") ride_data = callback_args.get("ride_data") discount_data = callback_args.get("discount_data") discount_data = DiscountData.load(discount_data) if discount_data else None if not (ride_id is not None and ride_data): logging.error("no ride_id or ride_data for on_billing_trx_approved") return try: if ride_id == NEW_ORDER_ID: ride = create_shared_ride_for_order(ride_data, order) else: ride = SharedRide.by_id(ride_id) if ride and ride.lock(): # try joining existing ride try: update_ride_add_order(ride, ride_data, order) ride.unlock() except Exception, e: #TODO_WB: handle this error in some way - try again, create a new ride logging.error(traceback.format_exc()) ride.unlock() raise Exception(e.message) else:
def get_discounted_offers(request, order_settings, start_ride_algo_data): user = request.user if request.user.is_authenticated() else None discounted_offers = [] earliest_offer_dt = ceil_datetime(max(trim_seconds(default_tz_now()) + datetime.timedelta(minutes=asap_interval()), order_settings.pickup_dt - OFFERS_TIMEDELTA), minutes=booking_interval()) discounts_data = compute_discounts_data(order_settings, earliest_offer_dt, order_settings.pickup_dt + OFFERS_TIMEDELTA, datetime.timedelta(minutes=booking_interval()), user = user ) for discount_data in discounts_data: discount_rule = discount_data.discount_rule discount_dt = discount_data.pickup_dt tariff_for_discount_offer = RuleSet.get_active_set(discount_dt) base_price_for_discount_offer = start_ride_algo_data.order_price(NEW_ORDER_ID, tariff_for_discount_offer) if base_price_for_discount_offer: discount = discount_rule.get_discount(base_price_for_discount_offer) if discount == 0: logging.info(u"skipping %s: grants zero discount" % discount_rule.name) continue offer_key = "%s_%s" % (DISCOUNTED_OFFER_PREFIX, get_uuid()) memcache.set(offer_key, DiscountData.dump(discount_data), namespace=DISCOUNTED_OFFERS_NS) offer_text = _(u"The price includes a discount of %g NIS") % discount if discount_rule.offer_text: offer_text = discount_rule.offer_text if offer_text.find("%g") > -1: # render discount amount offer_text %= discount discount_offer_data = { "ride_id": offer_key, "pickup_time": to_js_date(discount_dt), "discount_picture_url": discount_rule.picture_url, "discount_name": discount_rule.display_name, "passengers": [], "seats_left": MAX_SEATS, "price": base_price_for_discount_offer - discount, "new_ride": True, "comment": offer_text } user_agent = request.META.get("HTTP_USER_AGENT", "") if RE_2_1_AGENT.match(user_agent) is None: # only for client < 1.2.1 discount_offer_data.update({ "seats_left": MAX_SEATS - 1, "passengers": [{'name': discount_rule.display_name, 'picture_url': discount_rule.picture_url}] }) discounted_offers.append(discount_offer_data) return discounted_offers
def create_order(order_settings, passenger, ride=None, discount_data=None): """ Returns a created Order or None @param order_settings: @param passenger: @param ride: @param discount_data: a DiscountData instance @return: """ ride_id = ride.id if ride else NEW_ORDER_ID # get ride data from algo: don't trust the client candidates = [ride] if ride else [] matching_rides = get_matching_rides(candidates, order_settings) ride_data = first(lambda match: match.ride_id == ride_id, matching_rides) if not ride_data: return None order = Order.fromOrderSettings(order_settings, passenger, commit=False) if ride: # if joining a ride, order departure is as shown in offer, not what was submitted in order_settings ride_departure = compute_new_departure(ride, ride_data) new_order_pickup_point = ride_data.order_pickup_point(NEW_ORDER_ID) order.depart_time = ride_departure + datetime.timedelta(seconds=new_order_pickup_point.offset) if order_settings.private: order.type = OrderType.PRIVATE else: order.type = OrderType.SHARED order.price_data = ride_data.order_price_data(NEW_ORDER_ID) if discount_data: order = apply_discount_data(order, order_settings, discount_data) if not order: return None order.save() logging.info("created new %s order [%s]" % (OrderType.get_name(order.type), order.id)) billing_trx = BillingTransaction(order=order, amount=order.get_billing_amount(), debug=order.debug) billing_trx.save() billing_trx.commit(callback_args={ "ride_id": ride_id, "ride_data": ride_data, "discount_data": DiscountData.dump(discount_data) }) return order
def save_search_req_and_offers(passenger, order_settings, offers): sr = SearchRequest.fromOrderSettings(order_settings, passenger) sr.save() for offer in offers: pickup_dt = offer['pickup_time'] / 1000 pickup_dt = datetime.datetime.fromtimestamp(pickup_dt).replace(tzinfo=TZ_INFO["UTC"]).astimezone(TZ_INFO['Asia/Jerusalem']) ride_offer = RideOffer(search_req=sr, ride_key=offer.get('ride_id'), ride=SharedRide.by_id(offer.get('ride_id')), pickup_dt=pickup_dt, seats_left=offer['seats_left'], price=offer['price'], new_ride=offer['new_ride']) if str(offer.get('ride_id')).startswith(DISCOUNTED_OFFER_PREFIX): cached_discount_data = memcache.get(offer.get('ride_id'), namespace=DISCOUNTED_OFFERS_NS) if cached_discount_data: discount_data = DiscountData.load(cached_discount_data) ride_offer.discount_rule = discount_data.discount_rule ride_offer.promotion = discount_data.promotion ride_offer.promo_code = discount_data.promo_code ride_offer.new_ride = True # this is actually a new ride ride_offer.save()
def book_ride(request): return JSONResponse({ 'status': 'failed', 'error': SERVICE_NOT_AVAILABLE_MSG }) passenger = Passenger.from_request(request) request_data = simplejson.loads(request.POST.get('data')) logging.info(u"book ride: %s\n%s" % (passenger, unicode(simplejson.dumps(request_data), "unicode-escape"))) result = { 'status': '', 'order_id': None, 'redirect': '', 'error': '', 'pickup_dt': None } if passenger and passenger.user and hasattr(passenger, "billing_info"): # we have logged-in passenger with billing_info - let's proceed order_settings = OrderSettings.fromRequest(request) ride_id = request_data.get("ride_id") new_ride = (ride_id == NEW_ORDER_ID) discounted_ride = (ride_id and str(ride_id).startswith(DISCOUNTED_OFFER_PREFIX)) join_ride = not (new_ride or discounted_ride) ride_to_join = SharedRide.by_id(ride_id) if join_ride else None order = None if ride_to_join: # check it is indeed a valid candidate if is_valid_candidate(ride_to_join, order_settings): order = create_order(order_settings, passenger, ride=ride_to_join) else: logging.warning("tried booking an invalid ride candidate") result['error'] = _("Sorry, but this ride has been closed for booking") else: # new or discounted ride, check pickup time isn't before ASAP (minus a couple seconds to allow booking to exactly ASAP) if order_settings.pickup_dt <= default_tz_now() + datetime.timedelta(minutes=asap_interval()) - datetime.timedelta(seconds=10): logging.warning("tried booking to expired pickup time %s" % order_settings.pickup_dt) result['error'] = _("Please choose a later pickup time") else: if discounted_ride: cached_discount_data = memcache.get(ride_id, namespace=DISCOUNTED_OFFERS_NS) discount_data = DiscountData.load(cached_discount_data) logging.info("[book_ride] discount_data = %s" % discount_data) order = create_order(order_settings, passenger, discount_data=discount_data) else: order = create_order(order_settings, passenger) if order: result['status'] = 'success' result['order_id'] = order.id result['pickup_formatted'] = order.from_raw result['pickup_dt'] = to_js_date(order.depart_time) result["price"] = order.get_billing_amount() ride_orders = [order] + ( list(ride_to_join.orders.all()) if ride_to_join else [] ) result["passengers"] = [{'name': o.passenger.name, 'picture_url': o.passenger.picture_url, 'is_you': o==order} for o in ride_orders for seat in range(o.num_seats)] result["seats_left"] = MAX_SEATS - sum([o.num_seats for o in ride_orders]) deferred.defer(join_offer_and_order, order, request_data) else: result['status'] = 'failed' else: # not authorized for booking, save current booking state in session set_current_booking_data(request) if passenger and not hasattr(passenger, "billing_info"): result['status'] = 'billing_failed' result['redirect'] = get_token_url(request) # go to billing else: result['status'] = 'auth_failed' logging.info("book ride result: %s" % result) return JSONResponse(result)
def compute_discounts_data(order_settings, start_dt, end_dt, delta, user=None): """ @param order_settings: @param start_dt: @param end_dt: @param delta: @param user: @return: a list of DiscountData objects """ passenger = None user_email_domain = None if user: user_email_domain = user.email.split("@")[1] passenger = user.passenger logging.info("get discounts @%s" % user_email_domain) discounts_data = [] for discount_rule in DiscountRule.objects.filter(open_to_all=True): if discount_rule.email_domains and ( user_email_domain not in discount_rule.email_domains): logging.info( u"skipping: %s - only for %s" % (discount_rule.name, ", ".join(discount_rule.email_domains))) continue active_dt = get_active_dt(discount_rule, order_settings, start_dt, end_dt, delta) if active_dt: discounts_data.append(DiscountData(active_dt, discount_rule)) if passenger: promo_activations = PromoCodeActivation.objects.filter( passenger=passenger, consumed=False) seen_promo_discounts = [] for promo_code in [ activation.promo_code for activation in promo_activations ]: promotion = promo_code.promotion promo_discount_rule = promotion.discount_rule if promo_discount_rule in seen_promo_discounts: continue seen_promo_discounts.append(promo_discount_rule) if passenger and not promotion.applies_to(passenger): continue active_dt = get_active_dt(promo_discount_rule, order_settings, start_dt, end_dt, delta) if active_dt: discounts_data.append( DiscountData(active_dt, promo_discount_rule, promotion=promotion, promo_code=promo_code)) logging.info("active discounts: %s" % discounts_data) return discounts_data