# -*- coding: utf-8 -*-

from __future__ import unicode_literals

import ast
import datetime
import json
from collections import defaultdict

from django.conf import settings
from django.db.models import Q, F, Prefetch
from gm_types.plutus.rm_type import RM_STATUS
from gm_types.gaia import RESERVATION_STATUS, DOCTOR_TYPE, REFUND_STATUS, \
    BALANCE_PAYMENT_TYPE
from gm_types.pay import SUFPAY_STATUS
from api.models import Doctor, Service, Order, COUPON_TYPES, get_timestamp, User, Special, ServiceItem, ServiceItemPrice
from api.models.types import ORDER_STATUS, ORDER_OPERATION_TYPE
from api.tool.user_tool import get_user_from_context, get_doctor_from_context
from gaia.routers import thread_local
from pay.models import ServiceSnapshot
from rpc.tool.error_code import CODES, gen
from rpc.tool.dict_mixin import to_dict
from rpc.decorators import bind_context, list_interface
from rpc.tool.log_tool import logging_exception
from rpc.tool.time_tool import get_timestamp_epoch
from services.notify import notify
from doctor.tool.order_tool import gen_order_data
from talos.models.topic import Activity
from weikuan.models import HospitalPay
from api.manager.service_info_manager import get_sku_id_to_sku_name_info


@bind_context("api/doctor/order/detail", login_required=True)
@bind_context("doctor/order/detail", login_required=True)
def order_manage_detail(ctx, order_id):
    """
        订单详情
    """
    doctor = get_doctor_from_context(ctx)
    if not doctor:
        return gen(CODES.DOCTOR_NOT_FOUND)

    try:
        order = Order.objects.get(pk=order_id)
    except Order.DoesNotExist:
        return gen(CODES.ORDER_NOT_FOUND)
    if not doctor.is_merchant and doctor.allow_hospital_agent:
        officer = Doctor.objects.get(hospital=doctor.hospital, doctor_type=DOCTOR_TYPE.OFFICER, is_merchant=True)
    else:
        officer = doctor
    if doctor != order.service.doctor and doctor != officer:
        return gen(CODES.NO_PERMISSION)

    data = order.data()
    data['coupon_data'] = order.order_coupon_data()

    # 判断该订单有没有任买尾款分期
    installments = ctx.rpc_remote['plutus/installment/installment/status'](
        person_id=get_user_from_context(ctx).person.id.hex,
        order_list=[order.id]
    ).unwrap()
    if installments and installments[0]['status'] in [RM_STATUS.REPAY, RM_STATUS.GRANT] and not (
                    order.status == ORDER_STATUS.USED and installments[0]['status'] == RM_STATUS.GRANT):
        data['hospital_payment'] = 0

    # 判断该订单有没有在线支付尾款
    try:
        if order.hospital_pay.status == SUFPAY_STATUS.PAID:
            data['hospital_payment'] = 0
    except:
        pass
    data.update({
        'is_doctor_see': order.is_doctor_see,
        'customer_phone': None,
    })
    if order.is_doctor_see:
        data['customer_phone'] = order.phone
    return data


@bind_context("doctor/order/detail_v2", login_required=True)
def doctor_order_detail_v2(ctx, order_ids):
    """医生后台获取订单相信信息

    :param List[int] order_id: 订单ID

    更美价: 即订单金额。如果涉及活动则为活动折后价格

    更美佣金抽成：即佣金，为订单金额的10%

    应付预付款：用户应该支付的预付款金额，对应app前端的预付款小计

    应付尾款：用户应该支付的尾款金额，对应app前端的尾款小计

    活动名称：该美购项目涉及的活动名称（如不涉及活动则不显示）

    美券抵扣预付：使用的预付款券抵扣的预付款金额

    商家分摊抵扣（预付）：预付款券抵扣金额中，由商家承担的金额（如不涉及预付款券则不显示）

    更美分摊抵扣（预付）：预付款券抵扣金额中，由更美承担的金额（如不涉及预付款券则不显示）

    美券名称（预付）：所使用的预付款券的名称（如不涉及预付款券则不显示）

    美分抵扣预付：使用的美分抵扣的预付款金额，该部分金额由更美承担

    实收预付款：用户应付预付金额减去预付款券，实际支付的预付款金额，即最终线上从用户收到的金额。

    应结预付款：最终线上从用户收到的金额，需要结算给商家的部分。应结预付款=预付款金额-更美抽成-医生承担美劵抵扣金额

    更美抽成实收款：最终线上从用户收到的金额，由更美抽走的部分。更美抽成实收款=更美抽成-更美分摊抵扣（预付）-美分抵扣预付

    美券抵扣尾款：使用的尾款券（医生美券）抵扣的尾款金额，该部分金额由商家承担

    美券名称（尾款）：所使用的尾款券的名称（如不涉及尾款券则不显示）

    分期支付尾款：用户应付尾款金额减去预付款券，实际通过分期支付的尾款金额

    到院支付尾款：即用户到院支付金额
    """
    doctor = get_doctor_from_context(ctx)
    if not doctor:
        gen(CODES.DOCTOR_NOT_FOUND)

    order_ids = list(set(order_ids))

    orders = Order.objects.defer('service_snapshot').filter(id__in=order_ids).prefetch_related(
        Prefetch('hospital_pay', queryset=HospitalPay.objects.only('status', 'order_id').all()),
        Prefetch('servicesnapshot', queryset=ServiceSnapshot.objects.only(
            'name', 'items', 'service_type', 'gengmei_price', 'pre_payment_price', 'order_id'
        ).all()),
        Prefetch('service', queryset=Service.objects.only('doctor_id').all()),
        Prefetch('user', queryset=User.objects.all().only('id', 'last_name')),
        Prefetch('service__doctor', queryset=Doctor.objects.only('id', 'name', 'user_id').all())
    ).all()

    if len(orders) != len(order_ids):
        gen(CODES.ORDER_NOT_FOUND)

    if not doctor.is_merchant and doctor.allow_hospital_agent:
        officer = Doctor.objects.get(hospital=doctor.hospital, doctor_type=DOCTOR_TYPE.OFFICER, is_merchant=True)
    else:
        officer = doctor

    # 将所有活动ID找到并且预处理
    activity_ids = [order.activity_id for order in orders if order.activity_id]
    specials = Special.objects.filter(id__in=activity_ids).only('id', 'title')
    special_id_to_special_title = {str(special.id): special.title for special in specials}

    # 订单优惠券信息预处理
    order_id_to_coupon_infos = Order.get_order_id_to_coupon_infos(order_ids)

    # 获取所有订单的任买尾款分期数据
    installments = ctx.rpc_remote['plutus/installment/installment/status'](
        person_id=get_user_from_context(ctx).person.id.hex,
        order_list=order_ids
    ).unwrap()
    order_id_to_installment = {installment['order_id']: installment for installment in installments}

    order_data_list = list()

    #获取订单service_item_id，获取sku数据
    all_service_item_id=[o.service_item_id for o in orders]
    service_item_id_to_sku_name_info = get_sku_id_to_sku_name_info(all_service_item_id,is_toc=False)

    for order in orders:
        if order.activity_type is None:
            activity_title = ""
        else:
            activity_title = special_id_to_special_title.get(order.activity_id, "未找到对应活动")

        if doctor != order.service.doctor and doctor != officer:
            return gen(CODES.NO_PERMISSION)

        coupon_info = {x['coupon_type']: x for x in order_id_to_coupon_infos.get(order.id, [])}
        pre_payment_coupon_info = coupon_info.get(COUPON_TYPES.PLATFORM, defaultdict(lambda: 0))
        final_payment_coupon_info = coupon_info.get(COUPON_TYPES.DOCTOR, defaultdict(lambda: 0))

        final_payment_price = order.servicesnapshot.gengmei_price - order.servicesnapshot.pre_payment_price
        gengmei_real_discount = (
            order.discount - order.points_deduction - pre_payment_coupon_info['coupon_gengmei_value']
        )  # 更美抽成实收款

        hospital_payment = installment_payment = order.hospital_payment

        # 判断该订单有没有任买尾款分期
        installment = order_id_to_installment.get(order.id)
        if installment and installment['status'] in [RM_STATUS.REPAY, RM_STATUS.GRANT] and not (
                        order.status == ORDER_STATUS.USED and installment['status'] == RM_STATUS.GRANT):
            hospital_payment = 0

        # 判断该订单有没有在线花呗支付尾款
        try:
            if order.hospital_pay.status == SUFPAY_STATUS.PAID:
                hospital_payment = 0
        except:
            pass

        # 对美购items做特殊处理
        service_items=service_item_id_to_sku_name_info.get(str(order.service_item_id),{}).get("name","")

        # 美券多单合并判断
        if pre_payment_coupon_info['platform_coupon_deduction'] != pre_payment_coupon_info['coupon_value']:
            pre_payment_coupon_name = pre_payment_coupon_info.get('coupon_name', '') + "（多美购合并使用）"
        else:
            pre_payment_coupon_name = pre_payment_coupon_info.get('coupon_name', '')

        if final_payment_coupon_info['doctor_coupon_deduction'] != final_payment_coupon_info['coupon_value']:
            final_payment_coupon_name = final_payment_coupon_info.get('coupon_name', '') + "（多美购合并使用）"
        else:
            final_payment_coupon_name = final_payment_coupon_info.get('coupon_name', '')
        service_item_id = order.service_item_id
        is_multibuy = True if ServiceItem.objects.get(id=service_item_id).parent_id else False
        service_item_price_id = order.service_item_price_id
        obj = ServiceItemPrice.objects.get(id=service_item_price_id)
        multibuy_amount = obj.selling_rule.more_buy_count if obj and obj.selling_rule else ''
        data={
            "order_id": order.id,
            "service_name": order.servicesnapshot.name,  # 美购名称
            "service_items": str(multibuy_amount) + '次 '+ service_items if is_multibuy else service_items,  # 实际购买属性
            "service_type": order.servicesnapshot.service_type,  # 美购类型
            "doctor": to_dict(order.service.doctor, fields=['id', 'name', 'user_id']),  # 医生相关信息
            "user": to_dict(order.user, fields=['id', 'last_name']),  # 用户相关信息
            "created_at": get_timestamp(order.created_time),  # 下单时间
            "validate_at": get_timestamp(order.validate_time),  # 验证时间
            'validated': order.validated,  # 是否验证
            "status": order.status,  # 订单状态
            "gengmei_price": order.servicesnapshot.gengmei_price,  # 更美价
            "gengmei_discount": order.discount,  # 更美佣金抽成
            "gengmei_real_discount": gengmei_real_discount,  # 更美抽成实收款
            "pre_payment_price": order.servicesnapshot.pre_payment_price,  # 预付款
            "real_pre_payment_price": order.real_payment,  # 应付预付款
            "final_payment_price": final_payment_price,  # 尾款
            "real_finnal_payment_price": final_payment_price - final_payment_coupon_info['doctor_coupon_deduction'],  # 应付尾款
            "activity_title": activity_title,  # 活动名称
            "pre_payment_coupon_deduction": pre_payment_coupon_info['platform_coupon_deduction'],  # 使用的预付款券抵扣的预付款金额
            "pre_payment_coupon_info": {
                "coupon_value": pre_payment_coupon_info['coupon_value'],  # 美券总金额
                "coupon_gengmei_value": pre_payment_coupon_info['coupon_gengmei_value'],  # 更美分摊抵扣（预付）
                "coupon_doctor_value": pre_payment_coupon_info['coupon_doctor_value'],  # 商家分摊抵扣（预付）
                "coupon_name": pre_payment_coupon_name,  # 美券名称（预付）
            },
            "final_payment_coupon_deduction": final_payment_coupon_info['doctor_coupon_deduction'],  # 使用的尾款券（医生美券）抵扣的金额
            "final_payment_coupon_info": {
                "coupon_value": final_payment_coupon_info['coupon_value'],  # 美券总金额
                "coupon_gengmei_value": 0,  # 更美分摊抵扣（尾款）
                "coupon_doctor_value": 0,  # 商家分摊抵扣（尾款）
                "coupon_name": final_payment_coupon_name,  # 美券名称（尾款）
            },
            "points_deduction": order.points_deduction,  # 美分抵扣预付
            "doctor_real_pre_payment_price": order.real_payment - gengmei_real_discount if order.real_payment > 0 else 0,  # 应结预付款 霸王餐 应结预付款为0
            'is_doctor_see': order.is_doctor_see,
            'customer_phone': order.phone,
            "installment_payment": installment_payment if hospital_payment == 0 else 0,  # 分期支付尾款
            "hospital_payment": hospital_payment,  # 到院支付尾款
            "cancel_time": order.get_cancel_timespan(), # 取消时间
            'is_multibuy': is_multibuy, #多买优惠需求新增字段，是否多买
        }
        try:
            if order.servicesnapshot.service_type == 3:
                city_name = ServiceItem.objects.get(id=order.service_item_id).city.name
                data.update(city_name=city_name)
        except:
            pass
        order_data_list.append(data)
    return order_data_list


@bind_context('doctor/order/related_list', login_required=True)
@list_interface(offset_name='start_num', limit_name='count', element_model=Order)
def get_conversation_related(ctx, p_uid, start_num=0, count=10):
    """
        p_uid: 患者用户id
    """
    exclude_status = [ORDER_STATUS.NOT_PAID, ORDER_STATUS.CANCEL, ORDER_STATUS.OTHER]
    user = get_user_from_context(ctx)
    try:
        user.doctor
    except Doctor.DoesNotExist:
        return gen(CODES.DOCTOR_NOT_FOUND)
    result = []
    orders = Order.objects.filter(user_id=p_uid, service__doctor=user.doctor).exclude(
        status__in=exclude_status).order_by('-last_modified')[start_num: start_num + count]

    orders_data = gen_order_data(orders)
    for order, order_data in zip(orders, orders_data):
        reservation = order.reservation.filter(
            status__in=[RESERVATION_STATUS.RESERVING, RESERVATION_STATUS.ACCEPTED,
                        RESERVATION_STATUS.CANCELED]).order_by('-created_time').first()
        operation = order.orderoperation_set.filter(
            optype__in=[ORDER_OPERATION_TYPE.APPLY_REFUND, ORDER_OPERATION_TYPE.CANCEL_REFUND,
                        ORDER_OPERATION_TYPE.REFUNDED, ORDER_OPERATION_TYPE.DOCTOR_APPROVE,
                        ORDER_OPERATION_TYPE.DOCTOR_REJECT, ORDER_OPERATION_TYPE.REFUND_TIMEOUT]).order_by(
            '-operate_at').first()
        data = {
            'reservation': to_dict(reservation) if reservation else None,
            'order': order_data,
            'operation': to_dict(operation) if operation else None,
        }
        if data['operation']:
            data['operation'].pop('operator')
        if data['reservation']:
            data['reservation']['address'] = reservation.schedule.address.desc
        result.append(data)
    return result


@bind_context('doctor/order/list', login_required=True)
@list_interface(offset_name='start_num', limit_name='count', element_model=Order)
@thread_local(DB_FOR_READ_OVERRIDE=settings.SLAVE_DB_NAME)
def doctor_order_list(ctx, start_num=0, count=10, status=None):
    """
        医生的订单列表
        status: 可以是单个，也可以传递数组
    """
    doctor = get_doctor_from_context(ctx)
    if not doctor:
        return gen(CODES.DOCTOR_NOT_FOUND)

    service_ids = Service.objects.filter(doctor=doctor).values_list('id', flat=True)
    if not service_ids:
        return {
            'total_count': 0,
            'orders': [],
        }

    orders = Order.objects.filter(service_id__in=service_ids)
    if status is None:
        pass
    elif isinstance(status, list):
        orders = orders.filter(status__in=status).order_by('-last_modified')
    else:
        orders = orders.filter(status=status)
        if status == ORDER_STATUS.PAID:
            orders = orders.order_by('-pay_time')
        elif status == ORDER_STATUS.USED:
            orders = orders.order_by('-validate_time')
        elif status == ORDER_STATUS.REFUNDED:
            orders = orders.order_by('-refund_time')

    # add 医生版小红点数量
    notify("order/clear", doctor_id=doctor.id)

    return {
        'total_count': orders.count(),
        'orders': [o.data() for o in orders[start_num:start_num + count]],
    }


@bind_context('doctor/order/status_amount', login_required=True)
def status_amount(ctx, status_list=[]):
    """
        医生的订单不同状态下数目统计
        status: 传递数组
    """
    doctor = get_doctor_from_context(ctx)
    if not doctor:
        return gen(CODES.DOCTOR_NOT_FOUND)

    service_ids = Service.objects.filter(doctor=doctor).values_list('id', flat=True)
    if not service_ids:
        return [0 for s in status_list]
    result = []
    orders = Order.objects.filter(service_id__in=service_ids)
    for status in status_list:
        result.append(orders.filter(status=status).count())
    return result


@bind_context('doctor/order/validate_orders')
@list_interface(offset_name='start_num', limit_name='count', element_model=Order)
def api_doctor_order_validate(ctx, start_num=0, count=10, ids=None):
    orders = []

    user = get_user_from_context(ctx)
    validated_orders = Order.objects.filter(operate_user=user).order_by('-validate_time')
    if ids:
        if isinstance(ids, list):
            q = Q(id__in=ids)
        else:
            q = Q(id__contains=ids)
        validated_orders = validated_orders.filter(q)
    num = len(validated_orders)
    validated_orders = validated_orders[start_num:start_num + count]

    for validated_order in validated_orders:
        orders.append(validated_order.data())
    return {
        'orders': orders,
        'total': num,
    }


@bind_context('doctor/order/sale_info', login_required=True)
@list_interface(offset_name='start_num', limit_name='count')
def sale_info(ctx, doctor_id, count=10, start_num=0, begin_date=None, end_date=None):
    """
        销售详情, 按美购统计
    """
    # TODO Deprecated since 1.9.1, see sale_detail(销售相关都用成单量了)
    # TODO Deprecated【sale_detail----bind('doctor/order/sale_detail')】 since 2.0.0 see doctor/stats/sale_detail
    DATE_FMT = '%Y-%m-%d'
    orders = Order.objects.select_related('service').filter(service__doctor=doctor_id)
    if begin_date is not None:
        begin_date = datetime.datetime.strptime(begin_date, DATE_FMT)
        orders = orders.filter(last_modified__gte=begin_date)
    if end_date is not None:
        end_date = datetime.datetime.strptime(end_date, DATE_FMT)
        orders = orders.filter(last_modified__lt=end_date)

    result = {
        'order_total': {},
        'services': [],
    }
    #  销售单量状态集合
    sale_status_set = [
        ORDER_STATUS.PAID,
        ORDER_STATUS.USED,
        ORDER_STATUS.SETTLED,
        ORDER_STATUS.AUDITING,
        ORDER_STATUS.SETTLING,
    ]
    if start_num == 0:
        result['order_total']['sale_total'] = orders.filter(status__in=sale_status_set).count()
        result['order_total']['used_total'] = orders.filter(status=ORDER_STATUS.USED).count()
        result['order_total']['refunded_total'] = orders.filter(status=ORDER_STATUS.REFUNDED).count()

    service_ids = []
    status = sale_status_set + [ORDER_STATUS.REFUNDED]
    orders_ids = orders.filter(status__in=status).order_by('-last_modified')
    for order in orders_ids:
        service_id = order.service.id
        if service_id not in service_ids:
            service_ids.append(service_id)
    for service_id in service_ids[start_num:start_num + count]:
        service_order = orders.filter(service_id=service_id)
        service_info = {
            'service_name': service_order[0].service.name,
            'sale_total': service_order.filter(status__in=sale_status_set).count(),
            'used_total': service_order.filter(status=ORDER_STATUS.USED).count(),
            'refunded_total': service_order.filter(status=ORDER_STATUS.REFUNDED).count(),
        }
        result['services'].append(service_info)
    return result


@bind_context('doctor/order/sale_detail', login_required=True)
@list_interface(offset_name='start_num', limit_name='count')
def sale_detail(ctx, doctor_id, count=10, start_num=0, begin_date=None, end_date=None):
    # TODO Deprecated since 2.0.0 see doctor/stats/sale_detail， 下个版本可以删除
    """
        1.9.1销售相关都用成单量，定义改变了
        销售详情, 按美购统计
    """
    DATE_FMT = '%Y-%m-%d'
    orders = Order.objects.select_related('service').filter(service__doctor=doctor_id)
    if begin_date is not None:
        begin_date = datetime.datetime.strptime(begin_date, DATE_FMT)
        orders = orders.filter(last_modified__gte=begin_date)
    if end_date is not None:
        end_date = datetime.datetime.strptime(end_date, DATE_FMT)
        orders = orders.filter(last_modified__lt=end_date)

    result = {
        'order_total': {},
        'services': [],
    }
    #  成单量状态集合
    sale_status_set = [
        ORDER_STATUS.PAID,
        ORDER_STATUS.USED,
        ORDER_STATUS.SETTLED,
        ORDER_STATUS.AUDITING,
        ORDER_STATUS.SETTLING,
        ORDER_STATUS.REFUNDED,
        ORDER_STATUS.WAIT_REFUNDED,
    ]
    orders_ids = orders.filter(status__in=sale_status_set).order_by('-last_modified')

    if start_num == 0:
        result['order_total']['real_order_amount'] = orders_ids.count()
        result['order_total']['used_total'] = orders.filter(status=ORDER_STATUS.USED).count()
        result['order_total']['refunded_total'] = orders.filter(status=ORDER_STATUS.REFUNDED).count()

    service_ids = []
    for order in orders_ids:
        service_id = order.service.id
        if service_id not in service_ids:
            service_ids.append(service_id)
    for service_id in service_ids[start_num:start_num + count]:
        service_order = orders.filter(service_id=service_id)
        service_info = {
            'service_name': service_order[0].service.name,
            'real_order_amount': service_order.filter(status__in=sale_status_set).count(),  # 成单量
            'used_total': service_order.filter(status=ORDER_STATUS.USED).count(),
            'refunded_total': service_order.filter(status=ORDER_STATUS.REFUNDED).count(),
        }
        result['services'].append(service_info)
    return result


@bind_context('doctor/order/query')
@thread_local(DB_FOR_READ_OVERRIDE=settings.SLAVE_DB_NAME)
def order_list(ctx, start_num=0, count=10, query={}, global_field=[], global_key='', order_by=[]):
    """
        只用于 医生后台 订单列表，涉及小红点的控制
    """
    doctor = get_doctor_from_context(ctx)

    doctor_ids = query.pop('doctor_ids', [])
    service_ids = Service.objects.filter(
        doctor_id__in=doctor_ids
    ).values_list('id', flat=True)
    if not service_ids:
        return {
            'total': 0,
            'orders': [],
        }

    created_time_start = query.pop('created_time_start', 0)
    created_time_end = query.pop('created_time_end', 0)
    validate_time_start = query.pop('validate_time_start', 0)
    validate_time_end = query.pop('validate_time_end', 0)
    pay_time_start = query.pop('pay_time_start', 0)
    pay_time_end = query.pop('pay_time_end', 0)
    status__in_list = query.pop('status__in', [])
    balance_payment = query.pop('balance_payment', BALANCE_PAYMENT_TYPE.ALL)

    q = Q(**query)

    def get_timestamp(time):
        return datetime.datetime.fromtimestamp(time)

    if created_time_start and created_time_end:
        q &= Q(created_time__range=(get_timestamp(created_time_start), get_timestamp(created_time_end)))
    elif created_time_start:
        q &= Q(created_time__gt=get_timestamp(created_time_start))
    elif created_time_end:
        q &= Q(created_time__lt=get_timestamp(created_time_end))

    if validate_time_start and validate_time_end:
        q &= Q(validate_time__range=(get_timestamp(validate_time_start), get_timestamp(validate_time_end)))
    elif validate_time_start:
        q &= Q(validate_time__gt=get_timestamp(validate_time_start))
    elif validate_time_end:
        q &= Q(validate_time__lt=get_timestamp(validate_time_end))

    if pay_time_start and pay_time_end:
        q &= Q(pay_time__range=(get_timestamp(pay_time_start), get_timestamp(pay_time_end)))
    elif pay_time_start:
        q &= Q(pay_time__gt=get_timestamp(pay_time_start))
    elif pay_time_end:
        q &= Q(pay_time__lt=get_timestamp(pay_time_end))

    q = q & Q(service_id__in=service_ids)
    if global_key:
        global_q = Q()
        for field in global_field:
            global_q |= Q(**{field: global_key})
        q &= global_q

    queryset = Order.objects

    if balance_payment == BALANCE_PAYMENT_TYPE.ALL:
        pass
    elif balance_payment == BALANCE_PAYMENT_TYPE.INSTALLMENT:
        q &= Q(payment__lt=F('service_price'))
        q &= Q(hospital_pay__period__isnull=False,
               hospital_pay__paid_time__isnull=False,
               hospital_pay__refund_time__isnull=True)
        queryset = queryset.select_related('hospital_pay')
    elif balance_payment == BALANCE_PAYMENT_TYPE.NOT_INSTALLMENT:
        q &= Q(payment__lt=F('service_price'))
        q &= Q(hospital_pay__period__isnull=True) | \
             Q(hospital_pay__paid_time__isnull=True) | \
             Q(hospital_pay__refund_time__isnull=False)
        queryset = queryset.select_related('hospital_pay')

    if not status__in_list:
        pass
    elif ORDER_STATUS.REFUNDING not in status__in_list:
        q &= Q(status__in=status__in_list)
    elif len(status__in_list) == 1:
        q &= Q(refund__status__in=[REFUND_STATUS.REFUND_APPLY_SELLER_TIMEOUT,
                                   REFUND_STATUS.DOCTOR_APPROVE,
                                   REFUND_STATUS.REFUNDING])
        queryset = queryset.select_related('refund')
    else:
        # 多个状态同时查, 其中一个状态是REFUNDING
        status__in_list.remove(ORDER_STATUS.REFUNDING)
        q &= (
                Q(status__in=status__in_list) | \
                Q(refund__status__in=[REFUND_STATUS.REFUND_APPLY_SELLER_TIMEOUT,
                                      REFUND_STATUS.DOCTOR_APPROVE,
                                      REFUND_STATUS.REFUNDING])
        )
        queryset = queryset.select_related('refund')

    orders = queryset.filter(q)

    if 'settleprice' in order_by or '-settleprice' in order_by:
        orders = orders.annotate(settleprice=F('servicesnapshot__pre_payment_price') - F('discount'))

    orders = orders.order_by(*order_by)
    total = orders.count()

    orders = orders[start_num: start_num + count]

    installments = ctx.rpc_remote['plutus/installment/installment/status'](
        person_id=get_user_from_context(ctx).person.id.hex,
        order_list=[order.id for order in orders]
    ).unwrap()
    renmai_dic = {}
    for installment in installments:
        # if installment['status'] in [RM_STATUS.REPAY, RM_STATUS.AUDITING, RM_STATUS.GRANT]:
        if installment['status'] in [RM_STATUS.REPAY, RM_STATUS.GRANT]:
            renmai_dic[installment['order_id']] = installment['status']
     # 获取订单service_item_id，获取sku数据
    all_service_item_id=[o.service_item_id for o in orders]
    service_item_id_to_sku_name_info = get_sku_id_to_sku_name_info(all_service_item_id,is_toc=False)

    def obj_data(obj):
        if obj.id in renmai_dic and not (obj.status == ORDER_STATUS.USED and renmai_dic[obj.id] == RM_STATUS.GRANT):
            renmai = True

            # 尾款分期到医院支付为0
            hospital_payment = 0
        else:
            renmai = False
            hospital_payment = obj.hospital_payment
        # 花呗尾款分期 判断是否在线支付了尾款
        huabei = False
        if getattr(order, 'hospital_pay', None):
            if order.hospital_pay.status == SUFPAY_STATUS.PAID:
                hospital_payment = 0
                huabei = True
        settle_price = obj.settle_data()['settle_payment']
        service_items = service_item_id_to_sku_name_info.get(str(obj.service_item_id),{}).get("name","")
        refund = getattr(obj, 'refund', object())
        refund_status = getattr(refund, 'status', None)
        refund_id = getattr(refund, 'id', None)
        data= {
            'id': obj.id,
            'status': obj.status,
            'name': obj.servicesnapshot.name,
            'service_item_name': service_items,
            'item': obj.order_multiattribute,
            'gengmei_price': obj.servicesnapshot.gengmei_price,
            'service_type': obj.servicesnapshot.service_type,
            'pre_payment_price': obj.servicesnapshot.pre_payment_price,
            'hospital_payment': hospital_payment,
            'created_time': get_timestamp_epoch(obj.created_time),
            'validate_time': get_timestamp_epoch(obj.validate_time),
            'user_id': obj.user.id,
            'user_name': obj.user.last_name,
            'settle_price': settle_price,
            'renmai': renmai or huabei,
            'doctor_name': obj.service.doctor.name,
            'doctor_user_id': obj.service.doctor.user_id,
            'is_doctor_see': obj.is_doctor_see,
            'customer_phone': obj.phone,
            'refund_status': refund_status,
            'refund_id': refund_id,
        }
        if obj.servicesnapshot.service_type == 3:
            city_name = ServiceItem.objects.get(id=obj.service_item_id).city.name
            data.update(city_name=city_name)
        return data

    # add 医生版小红点数量
    notify("order/clear", doctor_id=doctor.id)

    return {
        'total': total,
        'orders': [obj_data(order) for order in orders],
    }


@bind_context('doctor/order/user_paid')
def get_orders_user_paid(ctx, user_id):
    """
        医生查找 用户 在自己购买的订单数目
    """
    doctor = get_doctor_from_context(ctx)
    if not doctor:
        return gen(CODES.DOCTOR_NOT_FOUND)

    service_ids = Service.objects.filter(doctor=doctor).values_list('id', flat=True)
    data = {'total': 0}
    if service_ids:
        orders = Order.objects.filter(user_id=user_id, service_id__in=service_ids)
        data['total'] = orders.count()
    return data


@bind_context('doctor/order/user_paid_v2')
def get_orders_user_paid(ctx, doctor_id, user_id):
    """
        医生查找 用户 在自己购买的订单数目
    """
    doctor = Doctor.objects.get(id=doctor_id)
    if not doctor:
        return gen(CODES.DOCTOR_NOT_FOUND)

    service_ids = Service.objects.filter(doctor=doctor).values_list('id', flat=True)
    data = {'total': 0}
    if service_ids:
        orders = Order.objects.filter(user_id=user_id, service_id__in=service_ids)
        data['total'] = orders.count()
    return data


@bind_context('store/child/order/query')
@thread_local(DB_FOR_READ_OVERRIDE=settings.SLAVE_DB_NAME)
def order_list(ctx, start_num=0, count=10, query={}, global_field=[], global_key='', order_by=[], is_store_classification_child=False):
    """
        只用于 医生后台 订单列表，涉及小红点的控制
    """
    doctor = get_doctor_from_context(ctx)
    """
    获取医生所在机构的城市
    """
    doctor_city = doctor.hospital.city
    doctor_ids = query.pop('doctor_ids', [])
    service_item_ids = list(ServiceItem.objects.filter(parent_id=0, city_id=doctor_city.id).values_list('id', flat=True))
    service_ids = Service.objects.filter(
        doctor_id__in=doctor_ids
    ).values_list('id', flat=True)
    if not service_ids:
        return {
            'total': 0,
            'orders': [],
        }

    created_time_start = query.pop('created_time_start', 0)
    created_time_end = query.pop('created_time_end', 0)
    validate_time_start = query.pop('validate_time_start', 0)
    validate_time_end = query.pop('validate_time_end', 0)
    pay_time_start = query.pop('pay_time_start', 0)
    pay_time_end = query.pop('pay_time_end', 0)
    q = Q(**query)

    def get_timestamp(time):
        return datetime.datetime.fromtimestamp(time)

    if created_time_start and created_time_end:
        q &= Q(created_time__range=(get_timestamp(created_time_start), get_timestamp(created_time_end)))
    elif created_time_start:
        q &= Q(created_time__gt=get_timestamp(created_time_start))
    elif created_time_end:
        q &= Q(created_time__lt=get_timestamp(created_time_end))

    if validate_time_start and validate_time_end:
        q &= Q(validate_time__range=(get_timestamp(validate_time_start), get_timestamp(validate_time_end)))
    elif validate_time_start:
        q &= Q(validate_time__gt=get_timestamp(validate_time_start))
    elif validate_time_end:
        q &= Q(validate_time__lt=get_timestamp(validate_time_end))

    if pay_time_start and pay_time_end:
        q &= Q(pay_time__range=(get_timestamp(pay_time_start), get_timestamp(pay_time_end)))
    elif pay_time_start:
        q &= Q(pay_time__gt=get_timestamp(pay_time_start))
    elif pay_time_end:
        q &= Q(pay_time__lt=get_timestamp(pay_time_end))

    q = q & Q(service_id__in=service_ids)
    if global_key:
        global_q = Q()
        for field in global_field:
            global_q |= Q(**{field: global_key})
        q &= global_q

    orders = Order.objects.filter(q, service_item_id__in=service_item_ids)

    if 'settleprice' in order_by or '-settleprice' in order_by:
        orders = orders.annotate(settleprice=F('servicesnapshot__pre_payment_price') - F('discount'))

    orders = orders.order_by(*order_by)
    total = orders.count()

    orders = orders[start_num: start_num + count]

    installments = ctx.rpc_remote['plutus/installment/installment/status'](
        person_id=get_user_from_context(ctx).person.id.hex,
        order_list=[order.id for order in orders]
    ).unwrap()
    renmai_dic = {}
    for installment in installments:
        # if installment['status'] in [RM_STATUS.REPAY, RM_STATUS.AUDITING, RM_STATUS.GRANT]:
        if installment['status'] in [RM_STATUS.REPAY, RM_STATUS.GRANT]:
            renmai_dic[installment['order_id']] = installment['status']

    def obj_data(obj):
        if obj.id in renmai_dic and not (obj.status == ORDER_STATUS.USED and renmai_dic[obj.id] == RM_STATUS.GRANT):
            renmai = True

            # 尾款分期到医院支付为0
            hospital_payment = 0
        else:
            renmai = False
            hospital_payment = obj.hospital_payment
        # 花呗尾款分期 判断是否在线支付了尾款
        huabei = False
        if getattr(order, 'hospital_pay', None):
            if order.hospital_pay.status == SUFPAY_STATUS.PAID:
                hospital_payment = 0
                huabei = True
        settle_price = obj.settle_data()['settle_payment']
        if not obj.servicesnapshot.items:
            service_items = ""
        else:
            try:
                service_items = "".join(json.loads(obj.servicesnapshot.items))
            except:
                logging_exception()
                service_items = ""
        return {
            'id': obj.id,
            'status': obj.status,
            'name': obj.servicesnapshot.name,
            'service_item_name': service_items,
            'city_name':doctor_city.name,
            'item': obj.order_multiattribute,
            'gengmei_price': obj.servicesnapshot.gengmei_price,
            'service_type': obj.servicesnapshot.service_type,
            'pre_payment_price': obj.servicesnapshot.pre_payment_price,
            'hospital_payment': hospital_payment,
            'created_time': get_timestamp_epoch(obj.created_time),
            'validate_time': get_timestamp_epoch(obj.validate_time),
            'user_id': obj.user.id,
            'user_name': obj.user.last_name,
            'settle_price': settle_price,
            'renmai': renmai or huabei,
            'doctor_name': obj.service.doctor.name,
            'doctor_user_id': obj.service.doctor.user_id,
            'is_doctor_see': obj.is_doctor_see,
            'customer_phone': obj.phone,
        }

    # add 医生版小红点数量
    notify("order/clear", doctor_id=doctor.id)

    return {
        'total': total,
        'orders': [obj_data(order) for order in orders],
    }