示例#1
0
 def get_for_time_period(cls, service_user, service_identity, first_day,
                         last_day):
     service_identity_user = create_service_identity_user_wo_default(
         service_user, service_identity)
     return cls.all() \
         .ancestor(parent_key_unsafe(service_identity_user, SOLUTION_COMMON)) \
         .filter('redeemed_timestamp >=', first_day) \
         .filter('redeemed_timestamp <', last_day)
示例#2
0
 def get_by_service_user(cls, service_user, service_identity):
     service_identity_user = create_service_identity_user_wo_default(
         service_user, service_identity)
     return cls.all().ancestor(
         parent_key_unsafe(service_identity_user, SOLUTION_COMMON)).filter(
             "processed =",
             False).filter("timestamp >",
                           now() - (60 * 60 * 24)).order("timestamp")
示例#3
0
 def create_key(cls, service_user, service_identity, app_user,
                timestamp_day):
     service_identity_user = create_service_identity_user_wo_default(
         service_user, service_identity)
     return db.Key.from_path(cls.kind(),
                             "%s|%s" % (timestamp_day, app_user.email()),
                             parent=parent_key_unsafe(
                                 service_identity_user, SOLUTION_COMMON))
示例#4
0
 def load(cls, service_user, service_identity):
     service_identity_user = create_service_identity_user_wo_default(
         service_user, service_identity)
     qry = cls.all().ancestor(
         parent_key_unsafe(service_identity_user, SOLUTION_COMMON))
     qry.filter('redeemed', False)
     qry.order('-timestamp')
     return qry
示例#5
0
def get_broken_reservations(service_user, service_identity):
    service_identity_user = create_service_identity_user_wo_default(
        service_user, service_identity)
    filter_ = RestaurantReservation.all().filter("service_user =",
                                                 service_identity_user)
    return generator(
        filter_.filter('status >=',
                       RestaurantReservation.STATUS_SHIFT_REMOVED))
示例#6
0
def get_planned_reservations_by_user(service_user, service_identity, user,
                                     from_):
    service_identity_user = create_service_identity_user_wo_default(
        service_user, service_identity)
    return generator(RestaurantReservation.all().filter(
        "service_user =", service_identity_user).filter('user', user).filter(
            'status', RestaurantReservation.STATUS_PLANNED).filter(
                'shift_start >=', from_))
示例#7
0
def get_solution_loyalty_visits_for_lottery(service_user, service_identity,
                                            app_user):
    service_identity_user = create_service_identity_user_wo_default(
        service_user, service_identity)
    qry = SolutionLoyaltyVisitLottery.all().ancestor(
        parent_key_unsafe(service_identity_user, SOLUTION_COMMON)).filter(
            'redeemed =', False).filter('app_user =', app_user)
    return generator(qry.run())
示例#8
0
 def load_active(cls, service_user, service_identity):
     service_identity_user = create_service_identity_user_wo_default(
         service_user, service_identity)
     qry = cls.all().ancestor(
         parent_key_unsafe(service_identity_user, SOLUTION_COMMON))
     qry.filter('deleted =', False)
     qry.filter('redeemed =', False)
     return qry
示例#9
0
def _repair_order_received(service_user, message_flow_run_id, member, steps, end_id, end_message_flow_id, parent_message_key,
                   tag, result_key, flush_id, flush_message_flow_id, service_identity, user_details):
    from solutions.common.bizz.messaging import send_inbox_forwarders_message


    logging.info("_flow_member_result_repair_order: \n %s" % steps)

    remarks = _get_value(steps[0], u'message_remarks')
    if steps[1].answer_id == u"positive":
        picture_url = _get_value(steps[1], u'message_picture')
    else:
        picture_url = None

    sln_settings = get_solution_settings(service_user)

    logging.info("Saving repair order from %s" % user_details[0].email)
    service_identity_user = create_service_identity_user_wo_default(service_user, service_identity)
    o = SolutionRepairOrder(parent=parent_key_unsafe(service_identity_user, sln_settings.solution))
    o.description = remarks
    o.sender = SolutionUser.fromTO(user_details[0])
    o.timestamp = steps[1].received_timestamp
    o.status = SolutionRepairOrder.STATUS_RECEIVED
    o.picture_url = picture_url
    o.user = user_details[0].toAppUser() if user_details else None

    msg = common_translate(sln_settings.main_language, SOLUTION_COMMON, 'if-repair-order-received',
                           remarks=remarks)

    message = create_solution_inbox_message(service_user, service_identity, SolutionInboxMessage.CATEGORY_REPAIR, None, False, user_details, steps[1].received_timestamp, msg, True, [picture_url] if picture_url else [])
    o.solution_inbox_message_key = message.solution_inbox_message_key
    o.put()
    message.category_key = unicode(o.key())
    message.put()

    sln_i_settings = get_solution_settings_or_identity_settings(sln_settings, service_identity)

    sm_data = []
    sm_data.append({u"type": u"solutions.common.repair_orders.update"})
    sm_data.append({u"type": u"solutions.common.messaging.update",
                 u"message": serialize_complex_value(SolutionInboxMessageTO.fromModel(message, sln_settings, sln_i_settings, True), SolutionInboxMessageTO, False)})

    send_message(service_user, sm_data, service_identity=service_identity)

    attachments = []
    if picture_url:
        att = AttachmentTO()
        att.content_type = AttachmentTO.CONTENT_TYPE_IMG_JPG
        att.download_url = picture_url
        att.name = common_translate(sln_settings.main_language, SOLUTION_COMMON, u'picture')
        att.size = 0
        attachments = [att]

    app_user = user_details[0].toAppUser()

    send_inbox_forwarders_message(service_user, service_identity, app_user, msg, {
            'if_name': user_details[0].name,
            'if_email':user_details[0].email
        }, message_key=message.solution_inbox_message_key, attachments=attachments, reply_enabled=message.reply_enabled)
示例#10
0
 def load_pending(cls, service_user, service_identity):
     service_identity_user = create_service_identity_user_wo_default(
         service_user, service_identity)
     qry = cls.all().ancestor(
         parent_key_unsafe(service_identity_user, SOLUTION_COMMON))
     qry.filter('deleted =', False)
     qry.filter('pending =', True)
     qry.order("end_timestamp")
     return qry.get()
示例#11
0
 def get_all_by_service(cls, service_user, service_identity, start_date):
     service_identity_user = create_service_identity_user_wo_default(
         service_user, service_identity)
     ancestor = parent_key_unsafe(service_identity_user, SOLUTION_COMMON)
     return cls.all().ancestor(ancestor) \
         .filter('parent_message_key', None) \
         .filter('deleted =', False) \
         .filter('last_timestamp >', start_date) \
         .order('-last_timestamp')
示例#12
0
def get_solution_loyalty_slides(service_user, service_identity):
    service_identity_user = create_service_identity_user_wo_default(
        service_user, service_identity)
    qry = SolutionLoyaltySlide.gql(
        "WHERE ANCESTOR IS :ancestor AND deleted=False ORDER BY timestamp DESC"
    )
    qry.bind(
        ancestor=parent_key_unsafe(service_identity_user, SOLUTION_COMMON))
    return generator(qry.run())
示例#13
0
 def get_for_time_period(cls, service_user, service_identity, first_day,
                         last_day):
     service_identity_user = create_service_identity_user_wo_default(
         service_user, service_identity)
     return cls.all() \
         .ancestor(parent_key_unsafe(service_identity_user, SOLUTION_COMMON)) \
         .filter('winner_timestamp >', first_day) \
         .filter('winner_timestamp <', last_day) \
         .filter('deleted =', False) \
         .filter('claimed', True)
示例#14
0
def get_solution_pharmacy_orders(service_user, service_identity):
    service_identity_user = create_service_identity_user_wo_default(
        service_user, service_identity)
    qry = SolutionPharmacyOrder.gql(
        "WHERE ANCESTOR IS :ancestor AND deleted = :deleted ORDER BY timestamp DESC"
    )
    qry.bind(ancestor=parent_key_unsafe(service_identity_user,
                                        SOLUTION_COMMON),
             deleted=False)
    return generator(qry.run())
示例#15
0
def get_reservations(service_user, service_identity, from_=None, until=None):
    service_identity_user = create_service_identity_user_wo_default(
        service_user, service_identity)
    filter_ = RestaurantReservation.all().filter("service_user =",
                                                 service_identity_user)
    if from_:
        filter_ = filter_.filter('shift_start >=', from_)
    if until:
        filter_ = filter_.filter('shift_start <', until)
    return generator(filter_)
示例#16
0
def get_upcoming_planned_reservations_by_table(service_user, service_identity,
                                               table_id, from_):
    service_identity_user = create_service_identity_user_wo_default(
        service_user, service_identity)
    qry = RestaurantReservation.all().filter("service_user =",
                                             service_identity_user)
    qry.filter('tables =', table_id)
    qry.filter('status', RestaurantReservation.STATUS_PLANNED)
    qry.filter('shift_start >=', from_)
    return generator(qry)
示例#17
0
def clear_table_id_in_reservations(service_user, service_identity, table_id):
    service_identity_user = create_service_identity_user_wo_default(
        service_user, service_identity)
    qry = RestaurantReservation.all().filter("service_user =",
                                             service_identity_user)
    qry.filter('tables =', table_id)
    reservations = qry.fetch(None)
    for r in reservations:
        r.tables.remove(table_id)
    put_and_invalidate_cache(*reservations)
示例#18
0
    def post(self):
        service_user = users.get_current_user()
        session_ = users.get_current_session()
        service_identity = session_.service_identity
        slide_id = self.request.get("slide_id", "")
        if slide_id == "":
            slide_id = None
        else:
            slide_id = long(slide_id)
        slide_name = self.request.get("slide_name", "")

        try:
            slide_time = long(self.request.get("slide_time", 10))
        except:
            self.response.out.write(broadcast_via_iframe_result(u"solutions.common.loyalty.slide.post_result",
                                                                    error=u"Please fill in valid time!"))
            return

        uploaded_file = self.request.POST.get('slide_file')  # type: FieldStorage
        if not slide_id and not isinstance(uploaded_file, FieldStorage):
            self.response.out.write(broadcast_via_iframe_result(u"solutions.common.loyalty.slide.post_result",
                                                                    error=u"Please select a picture!"))
            return

        if not slide_id:
            sln_settings = get_solution_settings(service_user)
            if SolutionModule.HIDDEN_CITY_WIDE_LOTTERY in sln_settings.modules:
                service_identity_user = create_service_identity_user_wo_default(service_user, service_identity)
                p = parent_key_unsafe(service_identity_user, SOLUTION_COMMON)
                sli = SolutionLoyaltySlide.all(keys_only=True).ancestor(p).get()
                if sli:
                    self.response.out.write(broadcast_via_iframe_result(u"solutions.common.loyalty.slide.post_result",
                                                                    error=u"A city can only have 1 active slide at a time!"))
                    return

        gcs_filename = None
        content_type = None
        if isinstance(uploaded_file, FieldStorage):
            content_type = uploaded_file.type
            if not content_type.startswith("image/"):
                self.response.out.write(broadcast_via_iframe_result(u"solutions.common.loyalty.slide.post_result",
                                                                        error=u"The uploaded file is not an image!"))
                return

            date = datetime.datetime.now().strftime('%Y-%m-%d_%H:%M:%S')
            gcs_filename = '%s/oca/loyalty_slides/%s/%s_%s.%s' % (ROGERTHAT_ATTACHMENTS_BUCKET,
                                                               service_user.email(),
                                                               date,
                                                               uploaded_file.filename,
                                                               get_extension_for_content_type(content_type))
            upload_to_gcs(uploaded_file.value, content_type, gcs_filename)

        put_loyalty_slide(service_user, service_identity, slide_id, slide_name, slide_time, gcs_filename, content_type)

        self.response.out.write(broadcast_via_iframe_result(u"solutions.common.loyalty.slide.post_result"))
示例#19
0
def count_unread_solution_inbox_messages(service_user, service_identity):
    service_identity_user = create_service_identity_user_wo_default(
        service_user, service_identity)
    ancestor = parent_key_unsafe(service_identity_user, SOLUTION_COMMON)
    qry = SolutionInboxMessage.all(keys_only=True).ancestor(ancestor).filter(
        'parent_message_key =', None)
    qry.filter('deleted =', False)
    qry.filter('trashed =', False)
    qry.filter('read =', False)
    qry.filter('starred =', False)
    return qry.count(None)
示例#20
0
 def create_parent_key(cls, app_id, service_user, service_identity,
                       app_user):
     service_identity_user = create_service_identity_user_wo_default(
         service_user, service_identity)
     city_ancestor_key = cls.create_city_parent_key(app_id)
     service_ancestor_key = db.Key.from_path(SOLUTION_COMMON,
                                             service_identity_user.email(),
                                             parent=city_ancestor_key)
     return db.Key.from_path(cls.kind(),
                             app_user.email(),
                             parent=service_ancestor_key)
示例#21
0
def get_solution_repair_orders(service_user,
                               service_identity,
                               solution,
                               cursor=None):
    service_identity_user = create_service_identity_user_wo_default(
        service_user, service_identity)
    qry = SolutionRepairOrder.gql(
        "WHERE ANCESTOR IS :ancestor AND deleted=False ORDER BY timestamp DESC"
    )
    qry.with_cursor(cursor)
    qry.bind(ancestor=parent_key_unsafe(service_identity_user, solution))
    return generator(qry.run())
示例#22
0
def get_reservations_keys_qry(service_user,
                              service_identity,
                              from_=None,
                              until=None):
    service_identity_user = create_service_identity_user_wo_default(
        service_user, service_identity)
    filter_ = RestaurantReservation.all(keys_only=True).filter(
        "service_user =", service_identity_user)
    if from_:
        filter_ = filter_.filter('shift_start >=', from_)
    if until:
        filter_ = filter_.filter('shift_start <', until)
    return filter_
示例#23
0
def get_solution_loyalty_visits_for_revenue_discount(service_user,
                                                     service_identity,
                                                     app_user,
                                                     max_visits=None):
    service_identity_user = create_service_identity_user_wo_default(
        service_user, service_identity)
    qry = SolutionLoyaltyVisitRevenueDiscount.all() \
        .ancestor(parent_key_unsafe(service_identity_user, SOLUTION_COMMON)) \
        .filter('redeemed =', False) \
        .filter('app_user ='******'timestamp')
        return qry.fetch(max_visits)
    else:
        qry.order('-timestamp')
        return generator(qry.run())
示例#24
0
def solution_voucher_redeem(service_user, email, method, params, tag,
                            service_identity, user_details):
    logging.debug("Received voucher redeem call with params: %s", params)
    sln_settings = get_solution_settings(service_user)
    r = SendApiCallCallbackResultTO()
    r.result = None
    r.error = None
    try:
        jsondata = json.loads(params)

        ancestor_key = SolutionCityVoucher.create_parent_key(
            jsondata["app_id"])
        sln_city_voucher = SolutionCityVoucher.get_by_id(
            jsondata["voucher_id"], ancestor_key)
        if not sln_city_voucher:
            raise Exception(u"sln_city_voucher was None")

        value = long(jsondata["value"])
        if (sln_city_voucher.value - sln_city_voucher.redeemed_value) < value:
            raise Exception(u"insufficient funds")

        service_identity_user = create_service_identity_user_wo_default(
            service_user, service_identity)
        sln_city_voucher_rt = SolutionCityVoucherRedeemTransaction(
            parent=parent_key_unsafe(service_identity_user, SOLUTION_COMMON))
        sln_city_voucher_rt.created = now()
        sln_city_voucher_rt.confirmed = False
        sln_city_voucher_rt.value = value
        sln_city_voucher_rt.voucher_key = unicode(sln_city_voucher.key())
        sln_city_voucher_rt.signature = sln_city_voucher.signature()
        sln_city_voucher_rt.put()

        r_dict = dict()
        r_dict["uid"] = sln_city_voucher.uid
        r_dict["voucher_redeem_key"] = unicode(sln_city_voucher_rt.key())
        r_dict["value"] = sln_city_voucher_rt.value

        result = json.dumps(r_dict)
        r.result = result if isinstance(result,
                                        unicode) else result.decode("utf8")
    except:
        logging.error("solutions.voucher.redeem exception occurred",
                      exc_info=True)
        r.error = common_translate(sln_settings.main_language, SOLUTION_COMMON,
                                   'error-occured-unknown')
    return r
示例#25
0
def get_solution_loyalty_visits_for_stamps(service_user,
                                           service_identity,
                                           app_user,
                                           max_stamps=None,
                                           return_qry=False):
    service_identity_user = create_service_identity_user_wo_default(
        service_user, service_identity)
    qry = SolutionLoyaltyVisitStamps.all() \
        .ancestor(parent_key_unsafe(service_identity_user, SOLUTION_COMMON)) \
        .filter('redeemed =', False) \
        .filter('app_user ='******'timestamp')
        if return_qry:
            return qry
        return qry.fetch(max_stamps)
    else:
        return generator(qry.run())
示例#26
0
def delete_group_purchase(service_user, service_identity, group_purchase_id):
    service_identity_user = create_service_identity_user_wo_default(
        service_user, service_identity)

    def txn():
        sln_settings = get_solution_settings(service_user)
        m = SolutionGroupPurchase.get_by_id(
            group_purchase_id,
            parent_key_unsafe(service_identity_user, sln_settings.solution))
        azzert(service_user == m.service_user)
        m.deleted = True
        m.put()

    xg_on = db.create_transaction_options(xg=True)
    db.run_in_transaction_options(xg_on, txn)

    send_message(service_user,
                 u"solutions.common.group_purchase.update",
                 service_identity=service_identity)
示例#27
0
def add_loyalty_lottery_info(winnings, date):
    service_user = users.get_current_user()
    session_ = users.get_current_session()
    service_identity = session_.service_identity
    sln_settings = get_solution_settings(service_user)
    try:
        now_ = now()
        end_timestamp = date.toEpoch()
        if end_timestamp <= (now_ + 24 * 3600):
            raise BusinessException("end-date-24h-in-future")

        ll_info = SolutionLoyaltyLottery.load_pending(service_user, service_identity)
        if ll_info:
            if end_timestamp <= ll_info.end_timestamp:
                raise BusinessException("lottery-time-bigger-first-upcoming")

        service_identity_user = create_service_identity_user_wo_default(service_user, service_identity)
        ll_info = SolutionLoyaltyLottery(parent=parent_key_unsafe(service_identity_user, SOLUTION_COMMON))
        ll_info.timestamp = now_
        ll_info.end_timestamp = end_timestamp
        ll_info.schedule_loot_time = ll_info.end_timestamp - 24 * 3600
        ll_info.winnings = winnings
        ll_info.winner = None
        ll_info.winner_info = None
        ll_info.winner_timestamp = 0
        ll_info.skip_winners = []
        ll_info.pending = True
        ll_info.redeemed = False
        ll_info.claimed = False
        ll_info.put()

        sln_settings.updates_pending = True
        put_and_invalidate_cache(sln_settings)
        broadcast_updates_pending(sln_settings)

        send_message(service_user, u"solutions.common.loyalty.lottery.update", service_identity=service_identity)

        return RETURNSTATUS_TO_SUCCESS
    except BusinessException, e:
        return ReturnStatusTO.create(False, common_translate(sln_settings.main_language, SOLUTION_COMMON, e.message))
示例#28
0
    def trans():
        service_identity_user = create_service_identity_user_wo_default(
            service_user, service_identity)
        sgp = SolutionGroupPurchase.get_by_id(
            group_purchase_id,
            parent_key_unsafe(service_identity_user, sln_settings.solution))
        units_user = 0
        if user_detail:
            for subscription in sgp.subscriptions_for_user(app_user):
                units_user += subscription.units
        if sgp.max_units_pp and units_user >= sgp.max_units_pp:
            raise BusinessException(
                translate(sln_settings.main_language, SOLUTION_COMMON,
                          'new-group-subscription-failure-reached-maximum'))
        if sgp.max_units_pp and (units_user + units) > sgp.max_units_pp:
            raise BusinessException(
                translate(sln_settings.main_language,
                          SOLUTION_COMMON,
                          'new-group-subscription-failure-exceeded-maximum',
                          max_units=sgp.max_units_pp - units_user))
        if (sgp.units_available - units) >= 0:
            sgpe = SolutionGroupPurchaseSubscription(parent=sgp)
            sgpe.sender = SolutionUser.fromTO(
                user_detail) if user_detail else None
            sgpe.name = name
            sgpe.units = units
            sgpe.timestamp = now()
            sgpe.app_user = app_user
            sgpe.put()

            units_user += units
        else:
            raise BusinessException(
                translate(sln_settings.main_language, SOLUTION_COMMON,
                          'new-group-subscription-failure-insufficient-units'))
        return sln_settings, sgp, units_user
示例#29
0
def get_solution_inbox_messages(service_user,
                                service_identity,
                                count,
                                name,
                                cursor=None):
    service_identity_user = create_service_identity_user_wo_default(
        service_user, service_identity)
    ancestor = parent_key_unsafe(service_identity_user, SOLUTION_COMMON)
    qry = SolutionInboxMessage.all().with_cursor(cursor).ancestor(
        ancestor).filter('parent_message_key =', None)
    qry.filter('deleted =', False)
    if name == SolutionInboxMessage.INBOX_NAME_UNREAD:
        qry.filter('trashed =', False)
        qry.filter('read =', False)
        qry.filter('starred =', False)
    elif name == SolutionInboxMessage.INBOX_NAME_STARRED:
        qry.filter('trashed =', False)
        qry.filter('starred =', True)
    elif name == SolutionInboxMessage.INBOX_NAME_READ:
        qry.filter('trashed =', False)
        qry.filter('read =', True)
        qry.filter('starred =', False)
    elif name == SolutionInboxMessage.INBOX_NAME_TRASH:
        qry.filter('trashed =', True)
    else:
        return None
    qry.order('-last_timestamp')
    messages = qry.fetch(count)
    cursor_ = qry.cursor()
    has_more = False
    if len(messages) != 0:
        qry.with_cursor(cursor_)
        if len(qry.fetch(1)) > 0:
            has_more = True

    return unicode(cursor_), messages, has_more
示例#30
0
    def trans():
        sln_settings = get_solution_settings(service_user)
        order_settings = get_solution_order_settings(sln_settings)
        lang = sln_settings.main_language
        comment = None
        phone = None
        takeaway_time = None
        if order_type == ORDER_TYPE_SIMPLE:
            details = get_extended_details_from_tag(
                _get_value(steps[0], u'message_details'))
            if steps[1].answer_id == u"positive":
                picture_url = _get_value(steps[1], u'message_picture')
                att = AttachmentTO()
                att.content_type = AttachmentTO.CONTENT_TYPE_IMG_JPG
                att.download_url = picture_url
                att.name = translate(lang, SOLUTION_COMMON, u'picture')
                att.size = 0
                attachments = [att]
            else:
                picture_url = None
                attachments = []
            phone = _get_value(steps[2], u'message_phone')
            msg = common_translate(lang, SOLUTION_COMMON,
                                   'if-order-received') % {
                                       'remarks': details,
                                       'phone_number': phone
                                   }

        elif order_type == ORDER_TYPE_ADVANCED:
            with closing(StringIO()) as order:
                timezone_offset = datetime.datetime.now(
                    pytz.timezone(
                        sln_settings.timezone)).utcoffset().total_seconds()
                has_order_items = False
                for step in steps:
                    if step.step_id == u'message_phone':
                        phone = step.get_value()
                    elif step.step_id == u'message_comment':
                        comment = step.get_value()
                    elif step.step_id == u'message_advanced_order':
                        step_value = step.display_value.encode('utf-8')
                        if step_value:
                            has_order_items = True
                        order.write(step_value)
                    elif step.step_id == u'message_takeaway_time':
                        takeaway_time = int(step.get_value() - timezone_offset)
                picture_url = None
                attachments = []
                if comment:
                    if has_order_items:
                        order.write('\n\n')
                    c = '%s: %s' % (common_translate(
                        lang, SOLUTION_COMMON, 'reservation-comment'), comment)
                    order.write(
                        c.encode('utf-8') if isinstance(c, unicode) else c)
                details = get_extended_details_from_tag(
                    order.getvalue().decode('utf-8'))
                takeaway_datetime = datetime.datetime.fromtimestamp(
                    takeaway_time, tz=get_timezone(sln_settings.timezone))
                takeaway_time_str = format_datetime(takeaway_datetime,
                                                    locale=lang,
                                                    format='d/M/yyyy H:mm')

                msg = '%s:\n%s\n%s: %s\n%s: %s' % (
                    common_translate(lang, SOLUTION_COMMON,
                                     'order_received'), details,
                    common_translate(lang, SOLUTION_COMMON,
                                     'phone_number'), phone,
                    common_translate(lang, SOLUTION_COMMON,
                                     'takeaway_time'), takeaway_time_str)
        else:
            raise BusinessException('Unsupported order type %s', order_type)

        if not order_settings.manual_confirmation:
            # Waiting for follow-up message
            deferred.defer(_send_order_confirmation,
                           service_user,
                           lang,
                           message_flow_run_id,
                           member,
                           steps,
                           end_id,
                           end_message_flow_id,
                           parent_message_key,
                           tag,
                           result_key,
                           flush_id,
                           flush_message_flow_id,
                           service_identity,
                           user_details,
                           details,
                           _transactional=db.is_in_transaction())

        service_identity_user = create_service_identity_user_wo_default(
            service_user, service_identity)
        o = SolutionOrder(
            parent=parent_key_unsafe(service_identity_user, SOLUTION_COMMON))
        o.description = details
        o.phone_number = phone
        o.sender = SolutionUser.fromTO(user_details[0])
        o.timestamp = now()
        o.status = SolutionOrder.STATUS_RECEIVED
        o.picture_url = picture_url
        o.takeaway_time = takeaway_time
        o.user = user_details[0].toAppUser() if user_details else None

        message = create_solution_inbox_message(
            service_user, service_identity,
            SolutionInboxMessage.CATEGORY_ORDER, None, False, user_details,
            steps[2].received_timestamp, msg, True,
            [picture_url] if picture_url else [])
        o.solution_inbox_message_key = message.solution_inbox_message_key
        o.put()
        message.category_key = unicode(o.key())
        message.put()

        sln_i_settings = get_solution_settings_or_identity_settings(
            sln_settings, service_identity)
        sm_data = [{
            u"type": u"solutions.common.orders.update"
        }, {
            u"type":
            u"solutions.common.messaging.update",
            u"message":
            serialize_complex_value(
                SolutionInboxMessageTO.fromModel(message, sln_settings,
                                                 sln_i_settings, True),
                SolutionInboxMessageTO, False)
        }]
        send_message(service_user, sm_data, service_identity=service_identity)

        app_user = user_details[0].toAppUser()

        send_inbox_forwarders_message(
            service_user,
            service_identity,
            app_user,
            msg,
            dict(if_name=user_details[0].name, if_email=user_details[0].email),
            message_key=message.solution_inbox_message_key,
            attachments=attachments,
            reply_enabled=message.reply_enabled)