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)
Example #6
0
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