# coding: utf-8
import sys
import json
import time
import redis

from hippo.models import MerchantRelevance, MerchantContract
from themis.views.team import recursive_users
from datetime import datetime, date,timedelta
from django.conf import settings
from django.contrib.auth.models import User
from django.db.models import F
from django_bulk_update.helper import bulk_update
from gm_types.error import ERROR
from gm_types.gaia import BDTRANSFER_OBJECT_STATE, SINGLE_TYPE, TRANSFER_SOURCE, USER_GENDER, REPEAT_TYPE, AssistStatus, BUDAN_STATUS, VISIT_METHOD,BD_SERVICE_TYPE,USERACTIVE_STATUS,TEAM_TYPE,BD_SERVICE_TYPE
from gm_types.doctor import BDTRANSFER_APPLY_STATUS, BDTRANSFER_PIC_TYPE
from api.models import BDTransfer, Q, GaiaRPCFaultException, transaction, City, BDTransferClueTag, OPERATION_ACTION, \
    BDTransferCommunicationRecord, BDTransferSingleRecord, BuDan, Tag, BDTransferWillingProject, \
    BDTransferHistoryProject, Doctor, BDTransferWebKefu, BDTransferMonth, BDTransferMonthToBudan, BDTransferApplyRecord, \
    BDTransferApplyPic, BDTransferCommunicationRecordImg, Province, User, BDTransferAssist, BDTransferVisitRecord, \
    Service, ServiceItem
from api.models import BDTransferSingleRecordLog, City, Person, BDTransferOperationRecord, UserInnerInfo
from api.tool.datetime_tool import get_timestamp_epoch
from api.tool.user_tool import get_user_from_context, get_user_by_id
from api.tool.buryiny_point_tool import bdtransfer_record
from hera.models import Config
from hera.queries.bdtransfer import BDTransferSingleRecordDQ
from rpc.cache import req_data_cache
from hera.views.transfer.bdtransfer_auto_assign import auto_assign_single_bdtransfer,send_notify
from rpc.context import get_rpc_remote_invoker,logging_exception
from rpc.decorators import bind, bind_context
from rpc.tool.dict_mixin import to_dict
from rpc.tool.error_code import CODES, gen
from api.tasks.referral_data_task import (
    export_referral_data_excel_task,
    export_clue_data_excel_task,
    export_connection_data_excel_task,
    export_order_settlement_excel_task,
    return_export_data_excel_task
)
from rpc.tool.queryset_tool import queryset_dec
from hera.models import BDTransferAssignRecord
from rpc.tool.log_tool import logging_exception,info_logger


reload(sys)
sys.setdefaultencoding("utf8")

uri_pre = 'hera/bdtransfer/'


@bind(uri_pre + 'get')
def get_bdtransfer_info(bdtransfer_id):
    """获取商务转诊完整信息用户渲染

    :param bdtransfer_id: 商务转诊ID
    :rtype: Dict[str, List[Dict]]
    """
    try:
        bdtransfer = BDTransfer.objects.prefetch_related(
            'operation_records', 'communication_records', 'willing_projects', 'history_projects', 'single_records'
        ).get(id=bdtransfer_id)
    except BDTransfer.DoesNotExist:
        gen(CODES.BDTRANSFER_NOT_EXIST)
    bdtransfer_creator = get_user_by_id(bdtransfer.creator)
    bdtransfer_formatted = dict(to_dict(bdtransfer, expands={'current_follow_up_consultant': ['username', 'first_name', 'last_name']}))
    bdtransfer_formatted['creator_info'] = to_dict(bdtransfer_creator, fields=['username', 'first_name', 'last_name'])
    bdtransfer_communicationrecord = [to_dict(_, expands={"user": ["id", 'username']})
                                           for _ in bdtransfer.communication_records.order_by('-communication_time', '-id').all()]
    for i in bdtransfer_communicationrecord:
        img_urls = BDTransferCommunicationRecordImg.objects.filter(bdtransfercommunicationrecord_id=i['id']).values_list('image_url', flat=True)
        i['img_urls'] = list(img_urls)

    visit_record_object_list = bdtransfer.visit_records.all()
    visit_record_list = []
    for visit in visit_record_object_list:
        # status = 1
        # if visit.is_delete:
        #     status = 4
        # elif visit.visit_at:
        #     if visit.visit_at > visit.plan_at:
        #         status = 3
        #     else:
        #         status = 2
        visit_dict = {
            'id':visit.id,
            'method':VISIT_METHOD.getDesc(visit.method),
            'status':BD_SERVICE_TYPE.getDesc(visit.status),
            'plan_at':visit.plan_at.strftime('%Y-%m-%d %H:%M:%S'),
            'visit_at':visit.visit_at.strftime('%Y-%m-%d %H:%M:%S') if visit.visit_at else '',
            'state':USERACTIVE_STATUS.getDesc(visit.state) if visit.state else '',
            'remark':visit.remark,
            'creator':visit.creator.username,
            'create_at':visit.create_at.strftime('%Y-%m-%d %H:%M:%S')
        }
        visit_record_list.append(visit_dict)
    return {
        "bdtransfer": bdtransfer_formatted,
        "bdtransfer_assistors": [to_dict(_.assistor)
                                 for _ in bdtransfer.bdtransfer_assist.filter(status=AssistStatus.PASSED,
                                                                              is_delete=False).all()],
        "bdtransfer_operationrecord": [to_dict(_, expands={"operate_user": ["id", "username"]})
                                       for _ in bdtransfer.operation_records.all()],
        "bdtransfer_communicationrecord": bdtransfer_communicationrecord,
        "bdtransfer_willing_projects": [to_dict(_) for _ in bdtransfer.willing_projects.all()],
        "bdtransfer_history_projects": [to_dict(_) for _ in bdtransfer.history_projects.all()],
        "bdtransfer_single_records": [
            to_dict(_, expands={"user": ["id", 'username'], "doctor": ["id", "name"], "project": ["id", "name"]})
            for _ in bdtransfer.single_records.all()
        ],
        "visit_record_list":visit_record_list
    }


@bind_context(uri_pre + 'edit')
def edit_bdtransfer_info(ctx, bdtransfer_info, bdtransfer_id=None, is_from=True):
    """更新和创建商务转诊信息

    :param bdtransfer_info: 商务转诊信息
    :param bdtransfer_id: 商务转诊ID, 如果存在则为更新，否则为创建
    :param is_from: 如果is_from为true, 表示创建信息来自个人池，否则为公池
    :return:
    """
    # TODO 是否创建过后分配的人才能修改改信息
    operate_user = get_user_from_context(ctx)
    # todo del
    # operate_user = User.objects.get(pk=20296583)
    willing_projects = bdtransfer_info.pop('willing_projects', [])
    user_city = bdtransfer_info.get('user_city', '')
    user_provice = bdtransfer_info.get('user_provice', '')
    if user_city and not user_provice:
        user_provice = City.objects.get(id=user_city).province_id
    if bdtransfer_id:
        bdtransfer_obj = BDTransfer.get_by_id(id=bdtransfer_id)
    check_contact_bd_query = Q()
    if bdtransfer_info['qq'] != '':
        check_contact_bd_query |= Q(qq=bdtransfer_info['qq'])
    if bdtransfer_info['weibo'] != '':
        check_contact_bd_query |= Q(weibo=bdtransfer_info['weibo'])
    if bdtransfer_info['wechat'] != '':
        check_contact_bd_query |= Q(wechat=bdtransfer_info['wechat'])
    if bdtransfer_info['user_phone'] != '':
        check_contact_bd_query |= Q(user_phone=bdtransfer_info['user_phone'])
    check_contact_bd_obj = BDTransfer.objects.filter(check_contact_bd_query)
    if bdtransfer_id:
        check_contact_bd_obj = check_contact_bd_obj.exclude(id=int(bdtransfer_id))
    check_contact_bd_obj = check_contact_bd_obj.first()
    if check_contact_bd_obj:
        repeat_type = None
        assist_count = BDTransferAssist.objects.filter(bdtransfer=check_contact_bd_obj, status__in=(AssistStatus.PASSED, AssistStatus.PENDING), is_delete=False).count()
        is_ordered = BDTransferSingleRecord.objects.filter(dbtransfer=check_contact_bd_obj,
                                                           budan__isnull=False).exists()
        if is_from and check_contact_bd_obj.is_assign and assist_count < 4 and not is_ordered:
            is_singled = BDTransferSingleRecord.objects.filter(dbtransfer=check_contact_bd_obj,
                                                               status=SINGLE_TYPE.NO_ORDER_FORM).exists()
            # 是否已派单
            if is_singled:
                date_30days_before = datetime.now() - timedelta(days=30)
                is_communicate = BDTransferCommunicationRecord.objects.filter(bdtransfer=check_contact_bd_obj,
                                                                              communication_time__range=(date_30days_before, datetime.now()),
                                                                              user=check_contact_bd_obj.current_follow_up_consultant).exists()
                if is_communicate:
                    repeat_type = REPEAT_TYPE.APPLY
                else:
                    repeat_type = REPEAT_TYPE.CREATE
            else:
                repeat_type = REPEAT_TYPE.CREATE
        if check_contact_bd_obj.qq != '' and check_contact_bd_obj.qq == bdtransfer_info['qq']:
            bdtransfer_exist_field = u'QQ号'
        elif check_contact_bd_obj.weibo != '' and check_contact_bd_obj.weibo == bdtransfer_info['weibo']:
            bdtransfer_exist_field = u'微博账号'
        elif check_contact_bd_obj.wechat != '' and check_contact_bd_obj.wechat == bdtransfer_info['wechat']:
            bdtransfer_exist_field = u'微信号'
        else:
            bdtransfer_exist_field = u'手机号'
        raise GaiaRPCFaultException(
            error=ERROR.UNKNOWN_ERROR, message=u'已存在相同 {} 的转诊对象, 重复数据信息为:'
                                               u'【姓名】{user};【手机号码】{user_phone};【微信号码】{wechat};'
                                               u'【跟进顾问】{current_follower};【对象状态】{state}'.format(
                bdtransfer_exist_field, user=check_contact_bd_obj.user if check_contact_bd_obj.user else u'无',
                user_phone=check_contact_bd_obj.user_phone if check_contact_bd_obj.user_phone else u'无',
                wechat=check_contact_bd_obj.wechat if check_contact_bd_obj else u'无',
                current_follower=check_contact_bd_obj.current_follow_up_consultant if check_contact_bd_obj.current_follow_up_consultant else u"无",
                state=BDTRANSFER_OBJECT_STATE.getDesc(check_contact_bd_obj.object_state)), data={'repeat_type': repeat_type, 'repeat_id': check_contact_bd_obj.pk}
        )
    with transaction.atomic():
        """
            创建或者更新商务转诊信息
            如果转诊信息为新增，则创建操作记录
            创建或者更新意向城市
            创建或者更新线索标签
        """
        update_or_create_bdtransfer_data = {
            "user": bdtransfer_info['user'],
            "user_phone": bdtransfer_info['user_phone'],
            "qq": bdtransfer_info['qq'],
            "wechat": bdtransfer_info['wechat'],
            "weibo": bdtransfer_info['weibo'],
            "consume_potential_min": bdtransfer_info["consume_potential_min"],
            "consume_potential_max": bdtransfer_info["consume_potential_max"],
            "intention": bdtransfer_info["intention"],
            "source": bdtransfer_info["source"],
            "potential_assess": bdtransfer_info["potential_assess"],
            'wechat_nickname': bdtransfer_info["wechat_nickname"],
            "email": bdtransfer_info['email'],
            "gender": bdtransfer_info['gender'],
            "call_phone": bdtransfer_info['call_phone'],
            "user_province": user_provice,
            "user_city": user_city,
            "comments": bdtransfer_info['comments'],
            "age": bdtransfer_info.get('age'),
            "old_phone":bdtransfer_info.get('old_phone','') if bdtransfer_info['source'] == u'58' else '',
            "old_datetime":bdtransfer_info.get('old_datetime') if bdtransfer_info['source'] == u'58' and bdtransfer_info.get('old_datetime') else None
        }
        if bdtransfer_id:
            for attr, value in update_or_create_bdtransfer_data.items():
                setattr(bdtransfer_obj, attr, value)
            bdtransfer_obj.save(update_fields=update_or_create_bdtransfer_data.keys())

        else:
            import random, string
            client_id = None
            #多次尝试获取不重复的client_id
            for i in range(10):
                client_id = ''.join(random.sample(string.digits + string.ascii_uppercase, 6))
                if not BDTransfer.objects.filter(client_id=client_id):
                    break
            update_or_create_bdtransfer_data.update({
                'creator': bdtransfer_info.get('creator', ''),
                'is_assign': True if bdtransfer_info.get('current_follow_up_consultant', None) else False,
                'object_state': BDTRANSFER_OBJECT_STATE.HAS_PASSED_INFOMATION if is_from else BDTRANSFER_OBJECT_STATE.NOT_THROUGH_INFOMATION,
                'current_follow_up_consultant_id': bdtransfer_info.get('current_follow_up_consultant', None),
                'assigned_time': bdtransfer_info.get('current_follow_up_consultant', None) and datetime.now() or None,
                'client_id': client_id,
                "pooled_time": bdtransfer_info.get('current_follow_up_consultant', None) and datetime.now() or None,
            })

            # if bool(is_from):
            update_or_create_bdtransfer_data.update({'assigner': bdtransfer_info.get('current_follow_up_consultant', None)})

            bdtransfer_obj = BDTransfer.objects.create(**update_or_create_bdtransfer_data)
            bdtransfer_obj.operation_records.create(
                operate_user=operate_user, action=OPERATION_ACTION.CREATE, content=u"转诊信息创建"
            )
            if update_or_create_bdtransfer_data.get('current_follow_up_consultant_id', None):
                record = BDTransferAssignRecord.objects.filter(
                    user_id=update_or_create_bdtransfer_data['current_follow_up_consultant_id'],
                    date=datetime.today()).first()
                if not record:
                    BDTransferAssignRecord.objects.create(
                        user_id=update_or_create_bdtransfer_data['current_follow_up_consultant_id'],
                        count=1, date=datetime.today())
                else:
                    record.count += 1
                    record.save()

        willing_cities_obj = list(City.objects.filter(id__in=bdtransfer_info['willing_cities']))
        # django 1.9 m2m can use set
        bdtransfer_obj.willing_cities.clear()
        bdtransfer_obj.willing_cities.add(*willing_cities_obj)

        clue_tags = list(BDTransferClueTag.objects.filter(id__in=bdtransfer_info['clue_tags']))
        bdtransfer_obj.clue_tags.clear()
        bdtransfer_obj.clue_tags.add(*clue_tags)

        bdtransfer_willing_project_handler.func(ctx, bdtransfer_obj.id, willing_projects)

        return bdtransfer_obj.id



@bind_context(uri_pre + 'assistor_apply')
@transaction.atomic
def follower_apply(ctx, bdtransfer_id, repeat_type):
    repeat_type = int(repeat_type)
    opuser = get_user_from_context(ctx)
    bdtransfer = BDTransfer.objects.filter(pk=bdtransfer_id).first()
    if not bdtransfer:
        raise GaiaRPCFaultException(
            error=ERROR.UNKNOWN_ERROR, message='转诊单不存在', data=None
        )
    # 判断是否有相同的协助请求
    is_repeat = BDTransferAssist.objects.filter(bdtransfer=bdtransfer, assistor=opuser).count()
    if is_repeat:
        raise GaiaRPCFaultException(
            error=ERROR.UNKNOWN_ERROR, message='重复申请', data=None
        )
    # 直接创建
    if repeat_type == REPEAT_TYPE.CREATE:
        BDTransferAssist.objects.create(
            bdtransfer=bdtransfer,
            assistor=opuser,
            status=AssistStatus.PASSED
        )
        # 添加操作记录
        BDTransferOperationRecord.objects.create(
            bdtransfer=bdtransfer,
            operate_user=opuser,
            action=OPERATION_ACTION.ADD_ASSISTOR,
            content='申请成功，自动添加协助顾问：{}'.format(opuser.username)
        )
    else:
        BDTransferAssist.objects.create(
            bdtransfer=bdtransfer,
            assistor=opuser,
            is_apply=True,
        )
    return {'repeat_type': repeat_type, 'transfer_id': bdtransfer.pk}


@bind_context(uri_pre + 'assistor_modify')
@transaction.atomic
def apply_confirm(ctx, id, status, content):
    opuser = get_user_from_context(ctx)
    bdtransferassist = BDTransferAssist.objects.filter(pk=id).select_for_update().first()
    if not bdtransferassist:
        raise GaiaRPCFaultException(
            error=ERROR.UNKNOWN_ERROR, message='申请单不存在', data=None
        )
    if bdtransferassist.status != AssistStatus.PENDING:
        raise GaiaRPCFaultException(
            error=ERROR.UNKNOWN_ERROR, message='申请单状态异常,不允许操作', data=None
        )

    BDTransferAssist.objects.filter(pk=id).update(status=status)
    if int(status) == AssistStatus.PASSED:
        if BDTransferAssist.objects.filter(bdtransfer=bdtransferassist.bdtransfer, is_delete=False,
                                           status=AssistStatus.PASSED).count() >= 4:
            raise GaiaRPCFaultException(
                error=ERROR.UNKNOWN_ERROR, message='协助顾问数量已达上限', data=None
            )
        BDTransferOperationRecord.objects.create(
            bdtransfer=bdtransferassist.bdtransfer,
            operate_user=opuser,
            action=OPERATION_ACTION.PASS,
            content='{}审批通过，自动添加协助顾问：{}'.format(opuser.username, bdtransferassist.assistor.username)
        )
    else:
        BDTransferOperationRecord.objects.create(
            bdtransfer=bdtransferassist.bdtransfer,
            operate_user=opuser,
            action=OPERATION_ACTION.REJECT,
            content=content
        )
    return {}


@bind_context(uri_pre + 'assistor_del')
def apply_confirm(ctx, assistor_id, bdtransfer_id):
    opuser = get_user_from_context(ctx)
    assistor = User.objects.filter(id=assistor_id).first()
    BDTransferAssist.objects.filter(assistor=assistor, bdtransfer__pk=bdtransfer_id).update(is_delete=True)
    BDTransferOperationRecord.objects.create(
        bdtransfer_id=bdtransfer_id,
        operate_user=opuser,
        action=OPERATION_ACTION.DEL_ASSISTOR,
        content='{}删除协助顾问：{}'.format(opuser.username, assistor.username)
    )
    return {}


@bind_context(uri_pre + 'assistor_batch_create')
def assistor_batch_create(ctx, assistor_ids, bdtransfer_id):
    opuser = get_user_from_context(ctx)
    assistor_list = assistor_ids.split(',')
    for assistor_id in assistor_list:
        assistor = User.objects.filter(id=assistor_id).first()
        BDTransferAssist.objects.create(assistor=assistor, bdtransfer_id=bdtransfer_id, status=AssistStatus.PASSED)
        BDTransferOperationRecord.objects.create(
            bdtransfer_id=bdtransfer_id,
            operate_user=opuser,
            action=OPERATION_ACTION.ADD_ASSISTOR,
            content='{}添加协助顾问：{}'.format(opuser.username, assistor.username)
        )
    return {}


@transaction.atomic
@bind_context(uri_pre + 'communication_record')
def bdtransfer_operation_communication_record_handler(ctx, record_id=None, bdtransfer_id=None, content=None, images='', email_addr=None, communication_time=None,
                                                      visit_id=None):
    """商务转诊沟通记录Handler

    :param int record_id: 沟通记录ID
    :param int bdtransfer_id: 商务转诊ID
    :param unicode content: 沟通内容
    :return:
    """
    # TODO 权限控制
    def update_bd_last_follow_time(bdtransfer):
        try:
            bdtransfer.last_follow_time = bdtransfer.communication_records.order_by('-communication_time'). \
                only('communication_time').first().communication_time
        except BaseException:
            bdtransfer.last_follow_time = None
        bdtransfer.save()
    operate_user = get_user_from_context(ctx)
    if bdtransfer_id:
        bdtransfer = BDTransfer.get_by_id(id=bdtransfer_id)
    if record_id:
        communication_record = BDTransferCommunicationRecord.get_by_id(id=record_id)
    if record_id and content:  # 修改
        BDTransferCommunicationRecordImg.objects.filter(bdtransfercommunicationrecord_id=record_id).delete()
        if images:
            for i in json.loads(images):
                image = i.replace("'", '')
                BDTransferCommunicationRecordImg.objects.create(bdtransfercommunicationrecord_id=record_id, image_url=image)
        communication_record.content = content
        communication_record.save()
    elif bdtransfer_id and content:  # 新建
        if not operate_user and email_addr:
            operate_user = UserInnerInfo.objects.filter(wx_email=email_addr).first().user

        bdtransfercommunicationrecord_id = bdtransfer.communication_records.create(user=operate_user, content=content, visit_record_id=visit_id).id
        if communication_time:
            bdtransfer.communication_records.filter(id=bdtransfercommunicationrecord_id).update(communication_time=communication_time)
        if images:
            for i in json.loads(images):
                BDTransferCommunicationRecordImg.objects.create(bdtransfercommunicationrecord_id=bdtransfercommunicationrecord_id, image_url=i)
        update_bd_last_follow_time(bdtransfer)
    elif record_id:  # 删除
        communication_record.delete()
        BDTransferCommunicationRecordImg.objects.filter(bdtransfercommunicationrecord_id=record_id).delete()
        update_bd_last_follow_time(communication_record.bdtransfer)
    else:
        raise GaiaRPCFaultException(ERROR.UNIVERSAL, u'无效的操作', data=None)

@bind(uri_pre + 'get_images')
def get_bdtransfer_info(communicationrecord_id):
    """获取沟通记录的图片

    :param communicationrecord_id: 沟通记录ID
    :rtype:
    """
    try:
        img_urls = BDTransferCommunicationRecordImg.objects.filter(bdtransfercommunicationrecord_id=communicationrecord_id).values_list('image_url', flat=True)
    except BDTransfer.DoesNotExist:
        gen(CODES.BDTRANSFER_NOT_EXIST)

    return list(img_urls)


@bind_context(uri_pre + 'single_record')
def bdtransfer_single_record_handler(ctx, bdtransfer_id=None, doctor_id=None, project_ids=None,
                                     record_id=None, budan_id=None, consultation_time=None, appointment_time=None, is_terminate=False, operation_time=None):
    """商务转诊派单记录Handler

    :param bdtransfer_id: 商务转诊ID
    :param doctor_id: 医生ID
    :param project_ids: 项目对应的二级标签TAGS
    :param record_id: 派单记录ID
    :param budan_id: 补单ID
    :param is_terminate: 是否终止派单记录
    :return:
    """

    def _adjustment_assistor(bdtransfer, operate_user, is_order=False):
        # 调整一下顾问和协助顾问关系
        follower = bdtransfer.current_follow_up_consultant
        if operate_user != follower:
            date_30days_before = datetime.now() - timedelta(days=30)
            has_communicate = BDTransferCommunicationRecord.objects.filter(bdtransfer=bdtransfer, user=follower,
                                                                           communication_time__range=(
                                                                               date_30days_before,
                                                                               datetime.now())).exists()
            has_single = BDTransferSingleRecord.objects.filter(dbtransfer=bdtransfer, user=follower).exists()
            has_budan = BDTransferSingleRecord.objects.filter(dbtransfer=bdtransfer, budan__isnull=False).exists()
            if (not has_single) or (not has_communicate and not is_order) or (not has_budan and is_order):
                res = BDTransferAssist.objects.filter(bdtransfer=bdtransfer, assistor=operate_user).update(assistor=follower)
                if not res:
                    BDTransferAssist.objects.create(bdtransfer=bdtransfer, assistor=follower, status=AssistStatus.PASSED)
                bdtransfer.current_follow_up_consultant = operate_user
                bdtransfer.assigner = operate_user.id
                bdtransfer.save()
                BDTransferOperationRecord.objects.create(
                    bdtransfer=bdtransfer,
                    operate_user=operate_user,
                    action=OPERATION_ACTION.REASSIGN,
                    content='顾问{}调整成为跟进顾问，顾问{}调整成为协助顾问'.format(operate_user.username, follower.username)
                )

        if is_order:
            ordered_user_ids = BDTransferSingleRecord.objects.filter(dbtransfer=bdtransfer).values_list("user").all()
            has_budan = BDTransferSingleRecord.objects.filter(dbtransfer=bdtransfer, budan__isnull=False).exists()
            if not has_budan:
                ordered_user_ids = [i for i, in ordered_user_ids]
                assists = BDTransferAssist.objects.filter(bdtransfer=bdtransfer, is_delete=False).exclude(assistor_id__in=ordered_user_ids).all()
                for assist in assists:
                    BDTransferOperationRecord.objects.create(
                        bdtransfer=bdtransfer,
                        operate_user=operate_user,
                        action=OPERATION_ACTION.DEL_ASSISTOR,
                        content='自动删除协助顾问{}'.format(assist.assistor.username)
                    )
                BDTransferAssist.objects.filter(bdtransfer=bdtransfer, is_delete=False).exclude(assistor_id__in=ordered_user_ids).update(is_delete=True)

    rpc = get_rpc_remote_invoker()
    operate_user = get_user_from_context(ctx)
    if consultation_time is not None:
        consultation_time = datetime.strptime(consultation_time, '%Y-%m-%d %H:%M:%S')
    if appointment_time is not None:
        appointment_time = datetime.strptime(appointment_time, '%Y-%m-%d %H:%M:%S')
    if operation_time is not None:
        operation_time = datetime.strptime(operation_time, '%Y-%m-%d %H:%M:%S')
    # 修改single status 状态
    status = SINGLE_TYPE.NO_ORDER_FORM
    if appointment_time:
        status = SINGLE_TYPE.HAS_APPOINTMENT
    if consultation_time:
        status = SINGLE_TYPE.HAS_CONSULTATION

    if bdtransfer_id:
        bdtransfer = BDTransfer.get_by_id(bdtransfer_id)
    if record_id:
        bdtransfer_single_record = BDTransferSingleRecord.get_by_id(id=record_id)
    try:
        if doctor_id:
            doctor = Doctor.objects.get(id=doctor_id)
        if budan_id:
            budan = BuDan.objects.get(id=budan_id)
    except Doctor.DoesNotExist:
        gen(CODES.DOCTOR_NOT_FOUND)
    except BuDan.DoesNotExist:
        gen(CODES.BUDAN_NOT_FOUND)
    if project_ids:
        tag_objs = Tag.objects.filter(id__in=project_ids).all()
        assert len(tag_objs) == len(project_ids)
    bdtransfer_record_cache = redis.StrictRedis(**settings.REDIS['bdtransfer_record'])
    key = "transfer_treatment_"
    current_time = datetime.now().strftime('%Y-%m-%d')
    redis_key = key + current_time
    #向上取整
    expire_time = int(time.mktime(time.strptime(current_time, '%Y-%m-%d')) + 3600 * 24 - time.time()) + 1
    with transaction.atomic():
        if record_id and doctor_id and project_ids:  # 修改
            old_merchant_id = bdtransfer_single_record.doctor.merchant.id
            #原商户的派单数减一
            bdtransfer_record_cache.hincrby(redis_key, old_merchant_id, -1)
            if bdtransfer_record_cache.hget(redis, old_merchant_id) and int(
                    bdtransfer_record_cache.hget(redis, old_merchant_id)) < 0:
                bdtransfer_record_cache.hset(redis_key, old_merchant_id, 0)
            #新商户的派单数加一
            bdtransfer_record_cache.hincrby(redis_key, doctor.merchant.id)
            #过期时间更新
            bdtransfer_record_cache.expire(redis_key, expire_time)
            bdtransfer_single_record.doctor = doctor
            bdtransfer_single_record.project.clear()
            bdtransfer_single_record.appointment_time = appointment_time
            bdtransfer_single_record.consultation_time = consultation_time
            bdtransfer_single_record.operation_time = operation_time
            bdtransfer_single_record.status = status
            bdtransfer_single_record.add(*tag_objs)
            bdtransfer_single_record.save()
        elif bdtransfer_id and doctor_id and project_ids:  # 新增
            #hera后台只要把单派出去，就是“已接单”
            status=SINGLE_TYPE.HAS_ACCEPT
            bdtransfer_single_record = bdtransfer.single_records.create(
                user=operate_user, doctor=doctor, consultation_time=consultation_time,
                appointment_time=appointment_time, status=status, operation_time=operation_time
            )
            bdtransfer_single_record.project.add(*tag_objs)
            #派单扣费
            rpc['artemis/bdtransfer/deduct'](
                id=bdtransfer_single_record.id,
                doctor_id=doctor_id, 
                merchant_id=bdtransfer_single_record.doctor.merchant.id).unwrap()
            #派单数自增
            bdtransfer_record_cache.hincrby(redis_key, doctor.merchant.id)
            #过期时间更新
            bdtransfer_record_cache.expire(redis_key, expire_time)
        elif record_id and budan_id:  # 关联补单信息
            bdtransfer_single_record.budan = budan
            bdtransfer_single_record.status = SINGLE_TYPE.HAS_ORDER_FORM
            bdtransfer_single_record.confirm_user = operate_user
            bdtransfer_single_record.save()
        elif record_id and not is_terminate:  # 删除
            bdtransfer_single_record.delete()
        elif record_id and is_terminate:  # 终止派单, 但不删除
            bdtransfer_single_record.status = SINGLE_TYPE.HAS_TERMINATE
            bdtransfer_single_record.save()
            merchant_id = bdtransfer_single_record.doctor.merchant.id
            #原商户的派单数减一
            bdtransfer_record_cache.hincrby(redis_key, merchant_id, -1)
            if bdtransfer_record_cache.hget(redis, merchant_id) and int(
                    bdtransfer_record_cache.hget(redis, merchant_id)) < 0:
                bdtransfer_record_cache.hset(redis_key, merchant_id, 0)
            #过期时间更新
            bdtransfer_record_cache.expire(redis_key, expire_time)
        else:
            raise GaiaRPCFaultException(ERROR.UNKNOWN_ERROR, u'无效的操作', data=None)


@bind_context(uri_pre + 'willing_project')
def bdtransfer_willing_project_handler(ctx, bdtransfer_id, data):
    """商务转诊意向项目处理Handler

    :param int bdtransfer_id: 商务转诊ID
    :param List[Dict] data: 项目数据
    :return:
    """
    # TODO 权限控制
    bdtransfer = BDTransfer.get_by_id(bdtransfer_id)
    tag_objs = Tag.objects.filter(id__in=[_['opt'] for _ in data]).all()
    tag_obj_dict = {tag.id: tag for tag in tag_objs}
    create_willing_project = list()
    new_tags = []
    for project_info in data:
        if project_info['opt'] is None:
            continue
        willing_project = BDTransferWillingProject(
            tag=tag_obj_dict[int(project_info['opt'])], bdtransfer=bdtransfer
        )
        if project_info['start_time'] != "":
            willing_project.start_time = project_info['start_time']
        if project_info['end_time'] != "":
            willing_project.end_time = project_info['end_time']
        if project_info['comment'] != "":
            willing_project.comment = project_info['comment']

        new_tags.append(int(project_info['opt']))
        create_willing_project.append(willing_project)
    with transaction.atomic():
        bdtransfer.willing_projects.all().delete()
        BDTransferWillingProject.objects.bulk_create(create_willing_project)

    if bdtransfer.user_phone:
        try:
            p = Person.objects.get(phone=bdtransfer.user_phone)
            user_id = p.user_id
        except Person.DoesNotExist:
            user_id = None
        if new_tags and user_id:
            ctx.logger.app(**bdtransfer_record(user_id=user_id, tags=json.dumps(new_tags)))


@bind_context(uri_pre + 'history_project')
def bdtransfer_history_project_handler(ctx, bdtransfer_id, data):
    """商务转诊历史项目处理Handler

    :param int bdtransfer_id: 商务转诊ID
    :param List[Dict] data: 项目数据
    :return:
    """
    bdtransfer = BDTransfer.get_by_id(bdtransfer_id)
    tag_objs = Tag.objects.filter(id__in=[_['opt'] for _ in data]).all()
    tag_obj_dict = {tag.id: tag for tag in tag_objs}
    create_history_project = list()
    for project_info in data:
        history_project = BDTransferHistoryProject(
            tag=tag_obj_dict[int(project_info['opt'])], bdtransfer=bdtransfer
        )
        if project_info['time'] != "":
            history_project.know_time = project_info['time']
        create_history_project.append(history_project)
    with transaction.atomic():
        bdtransfer.history_projects.all().delete()
        BDTransferHistoryProject.objects.bulk_create(create_history_project)


@bind(uri_pre + 'confirm_infomation')
def bdtransfer_confirm_infomation(bdtransfer_id):
    bdtransfer = BDTransfer.get_by_id(bdtransfer_id)
    bdtransfer.object_state = BDTRANSFER_OBJECT_STATE.HAS_PASSED_INFOMATION
    bdtransfer.save(update_fields=['object_state'])


@bind(uri_pre+'statistics_detail_list')
def bdtransfer_record_detail_list(ids=None, start_time=None, end_time=None, status=None, list_stats=None, source=None):
    q_list = Q()

    if start_time and len(start_time) > 0:
        format_start_time = datetime.strptime('{} {}'.format(start_time, '00:00:00'), "%Y-%m-%d %H:%M:%S")
        q_list.add(Q(create_time__gte=format_start_time), Q.AND)
    if end_time and len(end_time) > 0:
        format_end_time = datetime.strptime('{} {}'.format(end_time, '23:59:59'), "%Y-%m-%d %H:%M:%S")
        q_list.add(Q(create_time__lte=format_end_time), Q.AND)
    if status:
        q_list.add(Q(object_state=status), Q.AND)
    if list_stats and len(list_stats):
        q_list.add(Q(object_state__in=list_stats), Q.AND)
    if ids and len(ids) > 0:
        q_list.add(Q(id__in=ids), Q.AND)
    if source:
        q_list.add(Q(source=source), Q.AND)

    query_filter = BDTransfer.objects \
        .annotate(status=F('object_state'),
                  citys=F('willing_cities__name'),
                  consultant_username=F('current_follow_up_consultant__username'),
                  consultant_last_name=F('current_follow_up_consultant__last_name'))\
        .values('id', 'user', 'citys', 'user_phone', 'wechat', 'status', 'create_time',
                'source', 'last_follow_time','consultant_username', 'consultant_last_name','creator')\
        .filter(q_list)
    data = []
    for each in list(query_filter):
        u = User.objects.get(id=each.get('creator'))
        creator_name = u.username if u.username else u.last_name
        if not creator_name:
            creator_name = ""
        follow_name = each.get('consultant_username') if each.get('consultant_username') else each.get('consultant_last_name')
        if not follow_name:
            follow_name = ''
        data.append({
            'bdtransfer_id': each.get('id'),
            'user': each.get('user'),
            'user_phone': each.get('user_phone'),
            'wechat': each.get('wechat'),
            'status': each.get('status'),
            'city': each.get('citys'),
            'create_time':
                each.get('create_time').strftime("%Y-%m-%d %H:%M:%S") if each.get('create_time') else '',
            'source': each.get('source'),
            'last_follow_time':
                each.get('last_follow_time').strftime("%Y-%m-%d %H:%M:%S") if each.get('last_follow_time') else '',
            'follow_up_consultant': follow_name,
            'creator': creator_name
        })

    return data


@bind(uri_pre+'statistics_record_list')
def get_data_from_record_log(start_time=None, end_time=None, source=None,
                           creator=None, current_consultant_id=None,
                           doctor_id=None, **kwargs):
    q_list = Q()
    data = list()
    if start_time and len(start_time) > 0:
        format_start_time = datetime.strptime('{} {}'.format(start_time, '00:00:00'), "%Y-%m-%d %H:%M:%S")
        q_list.add(Q(created_time__gte=format_start_time), Q.AND)
    if end_time and len(end_time) > 0:
        format_end_time = datetime.strptime('{} {}'.format(end_time, '23:59:59'), "%Y-%m-%d %H:%M:%S")
        q_list.add(Q(created_time__lte=format_end_time), Q.AND)
    if source and len(source) > 0:
        q_list.add(Q(singlerecord__dbtransfer__source=source), Q.AND)
    if creator and len(creator) > 0:
        q_list.add(Q(singlerecord__dbtransfer__creator=creator), Q.AND)
    if current_consultant_id and len(current_consultant_id) > 0:
        q_list.add(Q(singlerecord__dbtransfer__current_follow_up_consultant_id=current_consultant_id), Q.AND)
    if doctor_id and len(doctor_id) > 0:
        q_list.add(Q(singlerecord__doctor__id=doctor_id), Q.AND)

    if len(q_list) > 0:
        query_filter = BDTransferSingleRecordLog.objects \
            .annotate(record_id=F('singlerecord__id'),
                      record_status=F('status'),
                      bdtransfer_id=F('singlerecord__dbtransfer__id'),
                      budan_id=F('singlerecord__budan__id'),
                      budan_status=F('singlerecord__budan__status'),
                      consume_total_money=F('singlerecord__budan__extra_consume'),
                      commission=F('singlerecord__budan__payment'),
                      user_id=F('singlerecord__user_id'),
                      bdtransfer_status=F('singlerecord__dbtransfer__object_state'),
                      ) \
            .values('record_id', 'record_status',
                    'bdtransfer_id', 'budan_id',
                    'budan_status', 'consume_total_money',
                    'commission', 'user_id',
                    'bdtransfer_status') \
            .filter(q_list)
        data = list(query_filter)
    return data


@bind(uri_pre+'user_info')
def get_cache_user_info(role):

    """
    :param role:
           role value contains: creator, consultant
    :return:
    """
    data = list()
    if role == 'creator':
        query_filter = User.objects.\
            annotate(name=F('username'))\
            .filter(id__in=BDTransfer.objects.
                    exclude(Q(creator__isnull=False) & Q(creator='')).
                    values_list('creator', flat=True).distinct()).values('id', 'name')
        data = list(query_filter)
    elif role == 'consultant':
        query_filter = User.objects\
            .annotate(name=F('username'))\
            .filter(id__in=BDTransfer.objects
                    .filter(current_follow_up_consultant__id__isnull=False)
                    .values_list('current_follow_up_consultant__id', flat=True).distinct()
                    ).values('id', 'name')
        data = list(query_filter)
    return data


@bind(uri_pre+'doctor_info')
def get_bdtransfer_record_doctor():
    query_filter = Doctor.objects.filter(
        id__in=BDTransferSingleRecord.objects.
            exclude(Q(doctor__id__isnull=False) & Q(doctor__id='')).
            values_list('doctor__id', flat=True).distinct()).values('id', 'name')
    data = list(query_filter)
    return data


@bind(uri_pre + 'web_kefu/get')
def get_bdtransfer_web_kefu_info(kefu_id):
    kefu_info = BDTransferWebKefu.objects.filter(id=kefu_id).first()
    return to_dict(kefu_info)


@bind_context(uri_pre + 'web_kefu/edit')
def edit_bdtransfer_web_kefu_info(ctx, kefu_info, kefu_id):
    if kefu_id:
        kefu_instance = BDTransferWebKefu.objects.filter(id=kefu_id).first()
        if not kefu_instance:
            raise gen(CODES.UNIVERSAL)
        kefu_instance.nickname = kefu_info['nickname']
        kefu_instance.qr_code = kefu_info['qr_code']
        kefu_instance.is_online = kefu_info['is_online']
        kefu_instance.save()
    else:
        kefu_instance = BDTransferWebKefu.objects.create(nickname=kefu_info['nickname'],
                                                         qr_code=kefu_info['qr_code'],
                                                         is_online=kefu_info['is_online'])
    return to_dict(kefu_instance)


@bind(uri_pre + 'web_kefu_image/get')
def get_bdtransfer_web_kefu_image():
    c = Config.objects.filter(key='bdtransfer_web_kefu_image').first()
    return c.value if c else ""


@bind(uri_pre + 'web_kefu_image/update')
def update_bdtransfer_web_kefu_image(image_url):
    Config.objects.update_or_create(key='bdtransfer_web_kefu_image', defaults={"value": image_url})
    return


@bind(uri_pre + 'commission_edit')
def commission_edit(record_id=None, data=None):
    ret = {}
    budan_data = []
    if record_id is None:
        pass

    else:
        bd = BDTransferApplyRecord.objects.get(id=record_id)

        for _bdtransfermonth in bd.record_budans.all():
            budan_data.append({
                'budan_id': _bdtransfermonth.budan.id,
                'total_amount': _bdtransfermonth.budan.extra_consume,
                'should_pay': _bdtransfermonth.budan.payment
            })

        ret = {
            'record_id': bd.id,
            'date': datetime.strftime(bd.bdtransfermonth.month_at, '%Y-%m') if bd.bdtransfermonth.month_at else '',
            'merchant_name': bd.doctor.name,
            'related_budan': budan_data,
            'pay_money': bd.should_pay,
            'apply_time': datetime.strftime(bd.created_time, '%Y-%m-%d %H:%M:%S') if bd.created_time else '',
            'success_time': datetime.strftime(bd.pass_time, '%Y-%m-%d %H:%M:%S') if bd.pass_time else '',
            'status': bd.status,
            'status_desc': BDTRANSFER_APPLY_STATUS.getDesc(bd.status),
            'pay_images': bd.get_pics(BDTRANSFER_PIC_TYPE.PROOF_OF_PAYMENT),
            'gathering_images': bd.get_pics(BDTRANSFER_PIC_TYPE.COLLECTION_OF_PAYMENTS),
            'authorization_images': bd.get_pics(BDTRANSFER_PIC_TYPE.AUTHORIZATION_VOUCHER),
            'reason': bd.reason,
        }
    return ret


@bind(uri_pre + 'commission_confirm')
def bdtransfer_commission_confirm(record_id, is_pass, reason=None, images=[]):
    if not record_id:
        return False

    bd_apply_imgs = []
    bd = BDTransferApplyRecord.objects.get(id=record_id)

    with transaction.atomic():
        if is_pass:  # 审核通过
            bd.status = BDTRANSFER_APPLY_STATUS.SUCCESS
            bd.bdtransfermonth.already_pay += bd.should_pay
            bd.pass_time = datetime.now()
            bd.bdtransfermonth.save()
            bd.save()

            if bd.bdtransfermonth.already_pay == bd.bdtransfermonth.should_pay:
                bd.bdtransfermonth.is_finished = True
                bd.bdtransfermonth.save()

            for img in images:
                bd_apply_imgs.append(BDTransferApplyPic(
                    bdtransferapplyrecord=bd,
                    content=img,
                    image_type=BDTRANSFER_PIC_TYPE.COLLECTION_OF_PAYMENTS
                ))
            BDTransferApplyPic.objects.bulk_create(bd_apply_imgs)

            BDTransferMonthToBudan.objects.filter(
                budan_id__in=list(bd.record_budans.values_list('budan_id', flat=True)),
                bdtransfermonth=bd.bdtransfermonth
            ).update(has_paid=True)
        else:
            # 审核失败
            bd.status = BDTRANSFER_APPLY_STATUS.REJECT
            bd.reason = reason
            bd.save()

    return True


@bind(uri_pre + 'analyze')
def bdtransfer_data_analyze(source, single_start_time=None, single_end_time=None, single_creator_id=None,
                            single_doctor_id=None, budan_start_time=None, budan_end_time=None,
                            bdtransfer_start_time=None, bdtransfer_end_time=None, confirm_single_user_id=None):
    query_q = ~Q(status=SINGLE_TYPE.HAS_CANCEL)
    if source is not None:
        query_q &= Q(dbtransfer__source=source)
    if single_start_time:
        format_single_start_time = datetime.strptime('{} {}'.format(single_start_time, '00:00:00'), "%Y-%m-%d %H:%M:%S")
        query_q &= Q(single_time__gte=format_single_start_time)
    if single_end_time:
        format_single_end_time = datetime.strptime('{} {}'.format(single_end_time, '23:59:59'), "%Y-%m-%d %H:%M:%S")
        query_q &= Q(single_time__lte=format_single_end_time)
    if single_creator_id:
        query_q &= Q(user_id=single_creator_id)
    if single_doctor_id:
        query_q &= Q(doctor_id=single_doctor_id)
    if budan_start_time:
        format_budan_start_time = datetime.strptime('{} {}'.format(budan_start_time, '00:00:00'), "%Y-%m-%d %H:%M:%S")
        query_q &= Q(budan__happen_time__gte=format_budan_start_time)
    if budan_end_time:
        format_budan_end_time = datetime.strptime('{} {}'.format(budan_end_time, '23:59:59'), "%Y-%m-%d %H:%M:%S")
        query_q &= Q(budan__happen_time__lte=format_budan_end_time)
    if bdtransfer_start_time:
        format_bdtransfer_start_time = datetime.strptime('{} {}'.format(bdtransfer_start_time, '00:00:00'), "%Y-%m-%d %H:%M:%S")
        query_q &= Q(dbtransfer__create_time__gte=format_bdtransfer_start_time)
    if bdtransfer_end_time:
        format_bdtransfer_end_time = datetime.strptime('{} {}'.format(bdtransfer_end_time, '23:59:59'), "%Y-%m-%d %H:%M:%S")
        query_q &= Q(dbtransfer__create_time__lte=format_bdtransfer_end_time)
    if confirm_single_user_id:
        query_q &= Q(confirm_user_id=confirm_single_user_id)
    res = BDTransferSingleRecord.objects.using(settings.SLAVE_DB_NAME).filter(query_q).prefetch_related(
        'dbtransfer', 'budan', 'user', 'doctor', 'budan__doctor', 'confirm_user'
    )
    return [format_bdtransfer_analyze(_) for _ in res]


@bind(uri_pre + 'order/rate')
def order_rate(time_range='60_120', user_name_cn=None, user_name=None):
    _source_list_score_two = [TRANSFER_SOURCE.NEITOU_PC, TRANSFER_SOURCE.NEITOU_M, TRANSFER_SOURCE.NEITOU_APP, TRANSFER_SOURCE.NEITOU_APP_OLD, TRANSFER_SOURCE.NEITOU_APP_NEW, TRANSFER_SOURCE.NEITOU_APP_SERVICE, TRANSFER_SOURCE.NEITOU_APP_KEFU, TRANSFER_SOURCE.NEITOU_APP_BLOCK, TRANSFER_SOURCE.NEITOU_WEIBO]

    def _get_time_range(time_range):
        if time_range == '60_120':
            now = datetime.now()
            zeroToday = now - timedelta(hours=now.hour, minutes=now.minute, seconds=now.second,
                                        microseconds=now.microsecond)
            date_60 = zeroToday - timedelta(days=60)
            date_120 = now - timedelta(days=120)
            date_360 = now - timedelta(days=360)
            return zeroToday, date_60, date_120, date_360

    def _get_clue_num_by_user_id(user_id, zero_today, date_high):
        # 用户个人池看到所有线索 + 120天内回抛的所有线索
        # 当前协助顾问
        bdtransfer_ids_assist = BDTransferAssist.objects.filter(assistor_id=user_id, status=AssistStatus.PASSED, is_delete=False, create_time__lte=zero_today).values_list('bdtransfer_id')
        # 回抛的线索(协助顾问)
        bdtransfer_ids_throwd_assist = BDTransferAssist.objects.filter(assistor_id=user_id,
                                                            create_time__range=(date_high, zero_today),
                                                            is_delete=True).values_list('bdtransfer_id')
        # 回抛的线索(跟进顾问)
        bdtransfer_ids_throwed_follow = BDTransferOperationRecord.objects.filter(operate_user_id=user_id,
                                                                     action__in=(OPERATION_ACTION.RETURN, OPERATION_ACTION.ASSIGN),
                                                                     operate_time__gte=date_high).values_list('bdtransfer_id')
        bdtransfer_ids = list(set(bdtransfer_ids_assist) | set(bdtransfer_ids_throwd_assist) | set(bdtransfer_ids_throwed_follow))
        bdtransfer_ids = [i for i, in bdtransfer_ids]
        bdtransfer_ids_throwed_follow = [i for i, in bdtransfer_ids_throwed_follow]
        query_bd = Q(assigner=user_id) & Q(assigned_time__lte=zero_today) | Q(pk__in=bdtransfer_ids)
        query_bd &= Q(wechat__isnull=False)
        bds = BDTransfer.objects.filter(query_bd).exclude(wechat='').all()
        clue_num = 0.0
        for bd in bds:
            assigner_id = bd.assigner and int(bd.assigner) or None

            # 根据该顾问的最最终状态
            if assigner_id == user_id:
                score = 1
            elif bd.id in bdtransfer_ids_throwed_follow:
                bd_assitor = BDTransferAssist.objects.filter(assistor_id=user_id, bdtransfer=bd).last()
                record = BDTransferOperationRecord.objects.filter(operate_user_id=user_id,
                                                         action__in=(OPERATION_ACTION.RETURN, OPERATION_ACTION.ASSIGN),
                                                         bdtransfer_id=bd.id).last()
                score = 1
                if record and bd_assitor and bd_assitor.create_time > record.operate_time:
                    score = 0.2
            else:
                score = 0.2

            if bd.source in _source_list_score_two:
                score = score + score
            clue_num += score
        return round(clue_num, 2)

    def _get_budan_all_payment(user_id, zero_today, date_low):
        bdtransfer_singlerecords = BDTransferSingleRecord.objects.filter(user_id=user_id,
                                                                         budan__isnull=False).all()
        all_payment = 0
        for bdtransfer_singlerecord in bdtransfer_singlerecords:
            bdtransferapplyrecord = bdtransfer_singlerecord.budan.record_budans.first()
            if bdtransferapplyrecord and bdtransferapplyrecord.bdtransferapplyrecord.pass_time and bdtransferapplyrecord.bdtransferapplyrecord.pass_time >= date_low and bdtransferapplyrecord.bdtransferapplyrecord.pass_time <= zero_today:
                all_payment += bdtransfer_singlerecord.budan.payment
        return all_payment

    zero_today, date_low, date_high, date_360 = _get_time_range(time_range)
    query_q = ~Q(status=SINGLE_TYPE.HAS_CANCEL)
    query_q &= Q(budan__create_time__lte=zero_today)
    query_q &= Q(budan__create_time__gte=date_low)

    query_user = None
    if user_name or user_name_cn:
        if user_name:
            query_user = User.objects.filter(username=user_name).first()
        if user_name_cn:
            inner_user = UserInnerInfo.objects.filter(name=user_name_cn).first()
            query_user = inner_user and inner_user.user or None
        if not query_user:
            return []
        query_q &= Q(user=query_user)

    single_records = BDTransferSingleRecord.objects.using(settings.SLAVE_DB_NAME).filter(query_q).prefetch_related(
        'dbtransfer', 'budan', 'user', 'confirm_user'
    )
    single_records = [{"budan_payment": bdtransfer_singlerecord.budan.payment if bdtransfer_singlerecord.budan and bdtransfer_singlerecord.budan.status != BUDAN_STATUS.CANCEL else 0,
                       #"budan_already_payment": bdtransfer_singlerecord.budan.payment if bdtransfer_singlerecord and bdtransfer_singlerecord.budan and bdtransfer_singlerecord.budan.record_budans.first() and bdtransfer_singlerecord.budan.record_budans.first().bdtransferapplyrecord.status == BDTRANSFER_APPLY_STATUS.SUCCESS else 0,
                       "single_creator_id": bdtransfer_singlerecord.budan.create_user_id,
                       }
                       for bdtransfer_singlerecord in single_records]

    single_data = {}
    for single_record in single_records:
        user_static_info = single_data.get(single_record["single_creator_id"])
        if not user_static_info:
            single_data[single_record['single_creator_id']] = single_record
            continue
        user_static_info["budan_payment"] += single_record["budan_payment"]

    if query_user:
        consultants = [{'id': query_user.id, "name": query_user.username}]
    else:
        query_filter = User.objects \
            .annotate(name=F('username')) \
            .filter(id__in=BDTransfer.objects
                    .filter(current_follow_up_consultant__id__isnull=False)
                    .filter(create_time__gte=date_360)
                    .values_list('current_follow_up_consultant__id', flat=True).distinct()
                    ).values('id', 'name')
        consultants = list(query_filter)

    for consultant in consultants:
        inner_user = UserInnerInfo.objects.filter(user_id=consultant['id']).first()
        consultant["single_creator_name"] = inner_user.user.username if inner_user and inner_user.user else consultant['name'],
        consultant['single_creator_id'] = consultant['id']
        consultant.update({"single_creator_name_cn": inner_user and inner_user.name or ''})
        consultant.update({"clue_num": _get_clue_num_by_user_id(consultant['single_creator_id'], zero_today, date_high)})
        consultant_dict = single_data.get(consultant['id'])
        # "budan_already_payment": bdtransfer_singlerecord.budan.payment if bdtransfer_singlerecord and bdtransfer_singlerecord.budan and bdtransfer_singlerecord.budan.record_budans.first() and bdtransfer_singlerecord.budan.record_budans.first().bdtransferapplyrecord.status == BDTRANSFER_APPLY_STATUS.SUCCESS else 0,
        budan_already_payment = _get_budan_all_payment(consultant['id'], zero_today, date_low)
        consultant.update({"budan_already_payment": budan_already_payment})
        if consultant_dict:
            consultant.update(consultant_dict)
        else:
            consultant['budan_payment'] = 0

        consultant.update({"gmv": (consultant['budan_payment'] + consultant['budan_already_payment']) / 2})
        consultant.update({"order_rate": consultant['clue_num'] and consultant['gmv'] / consultant['clue_num'] or 0})
    return consultants


def format_bdtransfer_analyze(bdtransfer_singlerecord):
    return {
        "single_id": bdtransfer_singlerecord.id,
        "single_time": get_timestamp_epoch(bdtransfer_singlerecord.single_time),
        "single_creator_id": bdtransfer_singlerecord.user_id,
        "single_creator_name": bdtransfer_singlerecord.user.username,
        "single_doctor_id": bdtransfer_singlerecord.doctor_id,
        "single_doctor_name": bdtransfer_singlerecord.doctor.name,
        "status": bdtransfer_singlerecord.status,  # 派单状态
        "status_desc": SINGLE_TYPE.getDesc(bdtransfer_singlerecord.status),
        "budan_id": bdtransfer_singlerecord.budan_id,
        "bdtransfer_id": bdtransfer_singlerecord.dbtransfer_id,
        "appointment_time":
            get_timestamp_epoch(bdtransfer_singlerecord.appointment_time) if bdtransfer_singlerecord.appointment_time else '',
        "consultation_time":
            get_timestamp_epoch(bdtransfer_singlerecord.consultation_time) if bdtransfer_singlerecord.consultation_time else '',
        "single_confirm_user_id": bdtransfer_singlerecord.confirm_user_id,
        "single_confirm_user_name": bdtransfer_singlerecord.confirm_user.username if bdtransfer_singlerecord.confirm_user else '',
        "budan_payment": bdtransfer_singlerecord.budan.payment if bdtransfer_singlerecord.budan else 0,
        "budan_already_payment": bdtransfer_singlerecord.budan.payment if bdtransfer_singlerecord and bdtransfer_singlerecord.budan and bdtransfer_singlerecord.budan.status == BUDAN_STATUS.CREATE_SETTLEMENT else 0,
        "budan_projects_payment": bdtransfer_singlerecord.budan.total_project_amount() if bdtransfer_singlerecord.budan else 0,
        "bdtransfer_user": bdtransfer_singlerecord.dbtransfer.user,
        "bdtransfer_userphone": bdtransfer_singlerecord.dbtransfer.user_phone,
        "bdtransfer_wechat": bdtransfer_singlerecord.dbtransfer.wechat,  # 微信
        "bdtransfer_source": bdtransfer_singlerecord.dbtransfer.source,
        "bdtransfer_source_desc": TRANSFER_SOURCE.getDesc(bdtransfer_singlerecord.dbtransfer.source),
        "budan_happen_time": get_timestamp_epoch(bdtransfer_singlerecord.budan.happen_time) if bdtransfer_singlerecord.budan else '' ,
        "budan_doctor_id": bdtransfer_singlerecord.budan.doctor_id if bdtransfer_singlerecord.budan else '',
        "budan_doctor_name": bdtransfer_singlerecord.budan.doctor.name if bdtransfer_singlerecord.budan else '',
    }


@bind_context(uri_pre + 'bdtransfer_excel_export')
def bdtransfer_excel_export(ctx, single_and_hostipal_data=None, budan_data=None, source_data=None):
    data1=bdtransfer_data_analyze.func(**single_and_hostipal_data)
    data2=bdtransfer_data_analyze.func(**budan_data)
    data3=bdtransfer_data_analyze.func(**source_data)
    send_list, order_list, hospital_list, channel_list = [], [], [], []

    single_creator_name_list, single_hostipal_list, single_order_list, single_channel_list = [], [], [], []
    for s in data1:
        if s['single_creator_name'] not in single_creator_name_list:
            single_creator_name_list.append(s['single_creator_name'])

        if s['single_doctor_name'] not in single_hostipal_list:
            single_hostipal_list.append(s['single_doctor_name'])
    for s in data2:
        if s['single_creator_name'] not in single_order_list:
            single_order_list.append(s['single_creator_name'])

    for s in data3:
        if s['bdtransfer_source'] not in single_channel_list:
            single_channel_list.append(s['bdtransfer_source'])

    for c in single_creator_name_list:
        send_data = filter(lambda x: x['single_creator_name']== c, data1)

        send_list.append({
            "single_creator_name": c,
            "send_num": len(send_data),
            "send_person": len(set(map(lambda x:x['bdtransfer_userphone'], send_data))),
            "send_hospital":len(set(map(lambda x:x['single_doctor_id'], send_data)))
        })

    for h in single_hostipal_list:
        hospital_data = filter(lambda x: x['single_doctor_name']== h, data1)
        order_num = len(filter(lambda x: x['status_desc']== u'已成单', hospital_data))
        budan_payment = sum(map(lambda x:x['budan_payment'], hospital_data))
        send_achievement = budan_payment / (len(hospital_data) - order_num) if len(hospital_data) - order_num else 0

        hospital_list.append({
            "single_doctor_name": h,
            "send_num": len(hospital_data),
            "order_num": order_num,
            "budan_projects_payment": round(sum(map(lambda x:x['budan_projects_payment'], hospital_data)),2),
            'budan_payment': round(budan_payment,2),
            'send_achievement': round(send_achievement,2),
            'order_achievement': round(budan_payment / order_num,2)
        })

    for c in single_order_list:
        order_data = filter(lambda x: x['single_creator_name']== c, data2)

        order_list.append({
            "single_creator_name": c,
            'budan_projects_payment': round(sum(map(lambda x:x['budan_projects_payment'], order_data)),2),
            'budan_payment': round(sum(map(lambda x:x['budan_payment'], order_data)),2),
            "send_num": len(order_data),
            "order_num": len(set(map(lambda x:x['bdtransfer_userphone'], order_data)))
        })

    for c in single_channel_list:
        channel_data = filter(lambda x: x['bdtransfer_source']== c, data3)

        channel_list.append({
            "channel": TRANSFER_SOURCE.getDesc(c),
            'clue_num': len(set(map(lambda x:x['bdtransfer_id'], channel_data))),
            "send_num": len(channel_data),
            "order_num": len(filter(lambda x: x['status_desc']== u'已成单', channel_data)),
            'budan_projects_payment': round(sum(map(lambda x:x['budan_projects_payment'], channel_data)),2),
            'budan_payment': round(sum(map(lambda x:x['budan_payment'], channel_data)),2),

        })

    user = ctx.session.user
    export_referral_data_excel_task.delay(user.email, send_list, order_list, hospital_list, channel_list)

@bind(uri_pre + 'analyze_clue')
def bdtransfer_data_analyze_clue(single_start_time=None, single_end_time=None, single_creator_id=None):
    query_q = Q()
    if single_start_time:
        format_single_start_time = datetime.strptime('{} {}'.format(single_start_time, '00:00:00'), "%Y-%m-%d %H:%M:%S")
        query_q &= Q(create_time__gte=format_single_start_time)
    if single_end_time:
        format_single_end_time = datetime.strptime('{} {}'.format(single_end_time, '23:59:59'), "%Y-%m-%d %H:%M:%S")
        query_q &= Q(create_time__lte=format_single_end_time)
    if single_creator_id:
        query_q &= Q(creator=single_creator_id)
    res = BDTransfer.objects.using(settings.SLAVE_DB_NAME).filter(query_q)
    return [format_bdtransfer_analyze_clue(_) for _ in res]

def format_bdtransfer_analyze_clue(bdtransfer):
    try:
        bdtransfersinglerecord=BDTransferSingleRecord.objects.get(dbtransfer_id=bdtransfer.id)
    except:
        bdtransfersinglerecord = ''
    return {
        "bdtransfer_id": bdtransfer.id,
        "bdtransfer_user": bdtransfer.user,
        "bdtransfer_userphone": bdtransfer.user_phone,
        "bdtransfer_wechat": bdtransfer.wechat,  # 微信
        "bdtransfer_creator_id": bdtransfer.creator,  # 创建人
        "bdtransfer_creator_name": User.objects.get(id=bdtransfer.creator).username,
        'bdtransfer_object_state': bdtransfer.object_state,
        "single_creator_name": bdtransfersinglerecord.user.username if bdtransfersinglerecord and bdtransfersinglerecord.user else '',
        "single_confirm_user_name": bdtransfersinglerecord.confirm_user.username if bdtransfersinglerecord and bdtransfersinglerecord.confirm_user else '',
        "single_doctor_name": bdtransfersinglerecord.doctor.name if bdtransfersinglerecord and bdtransfersinglerecord.doctor else '',
        "budan_doctor_name": bdtransfersinglerecord.budan.doctor.name if bdtransfersinglerecord and bdtransfersinglerecord.budan else '',
        "budan_projects_payment": bdtransfersinglerecord.budan.total_project_amount() if bdtransfersinglerecord and bdtransfersinglerecord.budan else 0,
        "budan_payment": bdtransfersinglerecord.budan.payment if bdtransfersinglerecord and bdtransfersinglerecord.budan else 0,
        "bdtransfer_source_desc": TRANSFER_SOURCE.getDesc(bdtransfersinglerecord.dbtransfer.source) if bdtransfersinglerecord and bdtransfersinglerecord.dbtransfer else '',
        "status_desc": SINGLE_TYPE.getDesc(bdtransfersinglerecord.status) if bdtransfersinglerecord and bdtransfersinglerecord.status else '',
        "appointment_time":
            get_timestamp_epoch(bdtransfersinglerecord.appointment_time) if bdtransfersinglerecord and bdtransfersinglerecord.appointment_time else '',
        "consultation_time":
            get_timestamp_epoch(bdtransfersinglerecord.consultation_time) if bdtransfersinglerecord and bdtransfersinglerecord.consultation_time else '',
        "budan_happen_time": get_timestamp_epoch(bdtransfersinglerecord.budan.happen_time) if bdtransfersinglerecord and bdtransfersinglerecord.budan else '',
        #个人线索新增字段
        "created_time": get_timestamp_epoch(bdtransfer.create_time),
        "current_follow_up_consultant": bdtransfer.current_follow_up_consultant.username if bdtransfer.current_follow_up_consultant else '',
        "status": BDTRANSFER_OBJECT_STATE.getDesc(bdtransfer.object_state),
        "source": TRANSFER_SOURCE.getDesc(bdtransfer.source)
    }

@bind_context(uri_pre + 'bdtransfer_clue_excel_export')
def bdtransfer_clue_excel_export(ctx, single_start_time=None, single_end_time=None, single_creator_id=None):
    data=bdtransfer_data_analyze_clue.func(single_start_time=single_start_time, single_end_time=single_end_time, single_creator_id=single_creator_id)
    send_list, single_creator_name_list = [], []
    for s in data:
        if s['bdtransfer_creator_name'] not in single_creator_name_list:
            single_creator_name_list.append(s['bdtransfer_creator_name'])

    for c in single_creator_name_list:
        send_data = filter(lambda x: x['bdtransfer_creator_name']== c, data)
        notadopted = len(filter(lambda x: x['bdtransfer_object_state']== 1, send_data))
        send_list.append({
            "bdtransfer_creator_name": c,
            "clue_num": len(send_data),
            "adopted": len(send_data)-notadopted,
            "notadopted": notadopted,
        })

    user = ctx.session.user
    export_clue_data_excel_task.delay(user.email, send_list)

@bind_context(uri_pre + 'redistribution')
@transaction.atomic
def bdtransfer_redistribution(ctx, id=None, updates=None):
    opuser_id = updates['operate_user_id']
    operation_type = int(updates['type'])

    assigner_id = updates.get('assigner_id')
    assigner = get_user_by_id(assigner_id)
    opuser = get_user_by_id(opuser_id)
    if opuser is None:
        raise GaiaRPCFaultException(ERROR.USER_NOT_FOUND, u"对象商务人员不存在", data=None)

    bdtransfer = BDTransfer.objects.filter(id=id).first()
    if not bdtransfer:
        raise GaiaRPCFaultException(ERROR.UNIVERSAL, u"转诊对象未找到", data=None)
    if operation_type == OPERATION_ACTION.ASSIGN:
        content = u"分配给 {}".format(assigner.username)
    else:
        raise GaiaRPCFaultException(ERROR.UNIVERSAL, u"操作类型错误", data=None)
    if bdtransfer.assigner != assigner_id:
        bdtransfer.visit_records.filter(status__in=[BD_SERVICE_TYPE.TOBEDONE, BD_SERVICE_TYPE.OVERDUE]).update(
            status=BD_SERVICE_TYPE.INVALID)
    bdtransfer.is_assign = True
    bdtransfer.assigner = assigner_id
    bdtransfer.assigned_time = datetime.now()
    bdtransfer.current_follow_up_consultant_id = assigner
    bdtransfer.save()
    BDTransferOperationRecord.objects.create(
        bdtransfer=bdtransfer,
        operate_user=opuser,
        action=operation_type,
        content=content
    )
    return id

@bind(uri_pre+'province_info')
def get_bdtransfer_record_province():
    query_filter = Province.objects.filter(
        id__in=BDTransferMonth.objects.
            exclude(Q(doctor__hospital__city__province__id__isnull=False) & Q(doctor__hospital__city__province__id='')).
            values_list('doctor__hospital__city__province__id', flat=True).distinct()).values('id', 'name')
    data = list(query_filter)
    return data

@bind(uri_pre+'city_info')
def get_bdtransfer_record_city():
    query_filter = City.objects.filter(
        id__in=BDTransferMonth.objects.
            exclude(Q(doctor__hospital__city__id__isnull=False) & Q(doctor__hospital__city__id='')).
            values_list('doctor__hospital__city__id', flat=True).distinct()).values('id', 'name')
    data = list(query_filter)
    return data

@bind(uri_pre+'business_partener_info')
def get_bdtransfer_record_business_partener():
    query_filter = User.objects \
        .annotate(name=F('username')) \
        .filter(id__in=BDTransferMonth.objects
                .filter(doctor__business_partener__id__isnull=False)
                .values_list('doctor__business_partener__id', flat=True).distinct()
                ).values('id', 'name')
    data = list(query_filter)
    return data

@bind(uri_pre + 'analyze_schedule')
def bdtransfer_data_analyze_schedule(search_data=None):
    province_id = search_data.get('province_id','')
    city_id = search_data.get('city_id','')
    business_partener_id = search_data.get('business_partener_id','')

    query_q = Q()
    if province_id:
        query_q &= Q(doctor__hospital__city__province__id=province_id)
    if city_id:
        query_q &= Q(doctor__hospital__city__id=city_id)
    if business_partener_id:
        query_q &= Q(doctor__business_partener__id=business_partener_id)

    res = BDTransferMonth.objects.using(settings.SLAVE_DB_NAME).filter(query_q).prefetch_related(
        'doctor', 'doctor__business_partener', 'doctor__hospital', 'doctor__hospital__city', 'doctor__hospital__city__province'
    )
    return [format_bdtransfer_analyze_schedule(_) for _ in res]

def format_bdtransfer_analyze_schedule(bdtransfermonth):

    return {
        "bdtransfermonth_id": bdtransfermonth.id,
        "doctor__d_merchant__id": bdtransfermonth.doctor.id,
        "doctor__name": bdtransfermonth.doctor.name,
        "business_partener_name": bdtransfermonth.doctor.business_partener.username if bdtransfermonth.doctor.business_partener else '' ,
        "doctor__hospital__city__province": bdtransfermonth.doctor.hospital.city.province.name if bdtransfermonth.doctor.hospital else '',
        "doctor__hospital__city": bdtransfermonth.doctor.hospital.city.name if bdtransfermonth.doctor.hospital else '',
        'month_at': '.'.join(str(bdtransfermonth.month_at).split('-')[:2]), #将日期从2019-09-01转化成2019.09
        "is_finished": u'是' if bdtransfermonth.is_finished else u'否',
        "budan_amount": bdtransfermonth.month_budans.count(),
        "total_amount": bdtransfermonth.total_amount,
        "should_pay": bdtransfermonth.should_pay,
        "already_pay": bdtransfermonth.already_pay,
    }


@bind(uri_pre + 'dispatch_query')
def dispatch_query(user_id, options):
    req_data_cache.set(str(user_id) + 'dispatch', json.dumps(options))
    dqobj = BDTransferSingleRecordDQ()
    return dqobj.process(**options)


@bind(uri_pre + 'dispatch_export_excel')
def dispatch_export_excel(user_id):
    """
    拍单记录导出
    :param user_id:
    :return:
    """
    dqobj = BDTransferSingleRecordDQ()
    options = json.loads(req_data_cache.get(str(user_id) + 'dispatch'))
    options.pop('paging')
    options.pop('columns')
    datas = dqobj.build_queryset(**options)
    user = User.objects.get(id=user_id)
    from api.tasks.export_excel_task import export_bdtransfer_dispatch_excel
    export_bdtransfer_dispatch_excel.delay(queryset_dec(datas, need_instant_data=True), user)


@bind(uri_pre + 'dispatch_detail')
def dispatch_detail(dispatch_id, doctor_id=None, refer='hera'):
    """
    :param dispatch_id:
    :param doctor_id:
    :param refer: hera:请求从hera来，ascle:请求从ascle来
    :return:
    """
    data = {}
    obj = BDTransferSingleRecord.objects.get(id=dispatch_id)
    if refer == 'ascle':
        obj = BDTransferSingleRecord.objects.get(id=dispatch_id, doctor_id=doctor_id)
    #基本信息构建
    user_name = obj.dbtransfer.user
    gender = USER_GENDER.getDesc(obj.dbtransfer.gender)
    gender = gender if gender else '未知'
    age = obj.dbtransfer.age
    if not isinstance(age, long):
        age = '年龄未知'
    #用户城市省份id与name转换
    user_province = Province.objects.get(id=obj.dbtransfer.user_province).name if obj.dbtransfer.user_province else ''
    user_city = City.objects.get(id=obj.dbtransfer.user_city).name if obj.dbtransfer.user_city else ''
    #基本信息
    base_info = {
        'dbtransfer_client_id': obj.dbtransfer.client_id,
        'dbtransfer_user_name': '{}({}/{})'.format(user_name, gender, age),
        'dbtransfer_address': '{} {}'.format(user_province, user_city),
        'dbtransfer_wechat': obj.dbtransfer.wechat,
        'dbtransfer_user_phone': obj.dbtransfer.user_phone,
        'single_time': obj.single_time.strftime('%Y-%m-%d %H:%M:%S') if obj.single_time else '',
        'project_name': '; '.join(obj.project.all().values_list('name', flat=True)),
        'dbtransfer_consume_potential': '{}-{}'.format(obj.dbtransfer.consume_potential_min, obj.dbtransfer.consume_potential_max),
        'operation_time': obj.operation_time.strftime('%Y-%m-%d %H:%M:%S') if obj.operation_time else '',
        'dbtransfer_comments': obj.dbtransfer.comments,
        'dbtransfer_current_follow_up_consultant': obj.dbtransfer.current_follow_up_consultant.id if obj.dbtransfer.current_follow_up_consultant else None,
        'dbtransfer_id': obj.dbtransfer.id
    }
    #消费信息
    consume_info = {
        'consume_image': obj.consume_image,
        'consume_projects': obj.consume_projects if obj.consume_projects else [],
        'appointment_time': obj.appointment_time.strftime('%Y-%m-%d %H:%M:%S') if obj.appointment_time else '',
        'consultation_time': obj.consultation_time.strftime('%Y-%m-%d %H:%M:%S') if obj.consultation_time else '',
        'comment': obj.comment
    }
    #状态信息
    budan_id = None
    confirm_dispatch = None
    #已预约，已接单，已面诊,已派单
    if obj.status in {SINGLE_TYPE.HAS_APPOINTMENT, SINGLE_TYPE.HAS_CONSULTATION, SINGLE_TYPE.HAS_ACCEPT, SINGLE_TYPE.NO_ORDER_FORM}:
        confirm_dispatch = '0'
    #已成单
    elif obj.status == SINGLE_TYPE.HAS_ORDER_FORM:
        confirm_dispatch = '1'
        budan_id = obj.budan.id
    #已重单
    elif obj.status == SINGLE_TYPE.DUPICATE_DISPATCH:
        confirm_dispatch = '2'
    #已撤销
    elif obj.status ==SINGLE_TYPE.HAS_CANCEL:
        confirm_dispatch = '3'
        budan_id = obj.budan.id
    status_info = {
        'confirm_dispatch': confirm_dispatch,
        'budan_id': budan_id,
    }
    #重单信息
    duplicate_info = {
        'duplicate_comment': obj.duplicate_comment,
        'duplicate_image': obj.duplicate_image
    }
    if refer == 'ascle':
        base_info.pop('dbtransfer_current_follow_up_consultant')
        base_info.pop('dbtransfer_id')
        if obj.is_new:
            consume_info = {}
            if obj.status == SINGLE_TYPE.HAS_ORDER_FORM:
                budan_obj = obj.budan
                projects = []
                dev_projects = json.loads(budan_obj.dev_projects)
                for project in dev_projects:
                    item = {}
                    service_id = project['service_id'] if project['service_id'] else None
                    sku_id = project['sku_id'] if project['sku_id'] else None
                    second_tag_id = project['second_tag_id'] if project['second_tag_id'] else None
                    third_tag_id = project['third_tag_id'] if project['third_tag_id'] else None
                    second_tag = Tag.objects.filter(id=second_tag_id).first()
                    third_tag = Tag.objects.filter(id=third_tag_id).first()
                    service = Service.objects.filter(id=service_id).first()
                    service_item = ServiceItem.objects.filter(id=sku_id).first()
                    second_tag_name = second_tag.name if second_tag else ''
                    third_tag_name = third_tag.name if third_tag else ''
                    service_name = service.name if service else ''
                    service_item_name = ''.join(service_item.items_name) if service_item else ''
                    item.update(name=project['name'], money=project['money'], time=project.get('time', ''),
                                project_type=[second_tag_name, third_tag_name],
                                related_project=[service_name, service_item_name])
                    projects.append(item)
                consume_info.update(dev_projects=projects)
        merchant_id = MerchantRelevance.objects.filter(doctor_id=doctor_id).first().merchant_id
        is_fixed_ratio = not MerchantContract.objects.filter(merchant_id=merchant_id).exists()
        data.update(base_info=base_info, consume_info=consume_info, status=obj.status, budan_id=obj.budan_id,
                    is_new=obj.is_new, is_fixed_ratio=is_fixed_ratio)
        return data
    data.update(base_info=base_info, consume_info=consume_info, status_info=status_info, duplicate_info=duplicate_info)
    return data


@bind(uri_pre + 'dispatch_edit')
def dispatch_edit(consume_data=None, duplicate_data=None, status=None, id=None, merchant_id=None):
    rpc = get_rpc_remote_invoker()
    obj = BDTransferSingleRecord.objects.get(id=id)
    if duplicate_data:
        obj.duplicate_comment = duplicate_data.get('duplicate_comment')
        obj.duplicate_image = duplicate_data.get('duplicate_image')
        obj.status = SINGLE_TYPE.DUPICATE_DISPATCH
    #重单接单状态流转:接单、重单、终止派单
    elif status:
        if int(status) in {SINGLE_TYPE.DUPICATE_DISPATCH, SINGLE_TYPE.HAS_TERMINATE}:
            obj.status = int(status)
            bdtransfer_record_cache = redis.StrictRedis(**settings.REDIS['bdtransfer_record'])
            key = "transfer_treatment_"
            current_time = datetime.now().strftime('%Y-%m-%d')
            redis_key = key + current_time
            merchant_id = obj.doctor.merchant.id
            bdtransfer_record_cache.hincrby(redis_key, merchant_id, -1)
            # 向上取整
            expire_time = int(time.mktime(time.strptime(current_time, '%Y-%m-%d')) + 3600 * 24 - time.time()) + 1
            if bdtransfer_record_cache.hget(redis, merchant_id) and int(
                    bdtransfer_record_cache.hget(redis, merchant_id)) < 0:
                bdtransfer_record_cache.hset(redis_key, merchant_id, 0)
            #过期时间更新
            bdtransfer_record_cache.expire(redis_key, expire_time)
        elif int(status) == SINGLE_TYPE.HAS_ACCEPT:
            if obj.consultation_time:
                obj.status = SINGLE_TYPE.HAS_CONSULTATION
            elif obj.appointment_time:
                obj.status = SINGLE_TYPE.HAS_APPOINTMENT
            else:
                obj.status = SINGLE_TYPE.HAS_ACCEPT
    elif consume_data:
        obj.comment = consume_data.get('comment')
        obj.consume_projects = consume_data.get('consume_projects')
        obj.consume_image = consume_data.get('consume_image')
        if consume_data.get('appointment_time'):
            obj.appointment_time = consume_data.get('appointment_time')
            obj.status = SINGLE_TYPE.HAS_APPOINTMENT
        if consume_data.get('consultation_time'):
            obj.consultation_time = consume_data.get('consultation_time')
            obj.status = SINGLE_TYPE.HAS_CONSULTATION
        if obj.consume_projects:
            obj.is_consume = True
        else:
            obj.is_consume = False
    obj.save()
    return {'message': 'ok'}

@bind(uri_pre + 'dispatch_filter')
def dispatch_query(page, options, size=10):
    data = []
    if options.get('dbtransfer__user_name__contains'):
        user = options.pop('dbtransfer__user_name__contains')
        dbtransfer_ids = BDTransfer.objects.filter(user__contains=user).values_list('id', flat=True)
        options.update(dbtransfer_id__in=list(dbtransfer_ids))
    objs = BDTransferSingleRecord.objects.filter(**options).exclude(Q(status=SINGLE_TYPE.HAS_TERMINATE)& Q(is_new=0)).order_by('-single_time')
    for obj in objs[size*(page - 1): size*page]:
        projects_name = '; '.join(obj.project.all().values_list('name', flat=True))
        user_name = obj.dbtransfer.user
        gender = USER_GENDER.getDesc(obj.dbtransfer.gender)
        gender = gender if gender else '未知'
        age = obj.dbtransfer.age
        if not isinstance(age, long):
            age = '年龄未知'
        #用户城市省份id与name转换
        user_province = Province.objects.get(id=obj.dbtransfer.user_province).name if obj.dbtransfer.user_province else ''
        user_city = City.objects.get(id=obj.dbtransfer.user_city).name if obj.dbtransfer.user_city else ''
        result = {
            'id': obj.id,
            'dbtransfer_client_id': obj.dbtransfer.client_id,
            'dbtransfer_user_name': '{}({}/{})'.format(user_name, gender, age),
            'project_name': projects_name if projects_name else '/',
            'dbtransfer_address': '{} {}'.format(user_province,
                                                    user_city) if obj.status != SINGLE_TYPE.NO_ORDER_FORM and obj.status != SINGLE_TYPE.DUPICATE_DISPATCH else '***',
            'single_time': obj.single_time.strftime('%Y-%m-%d %H:%M:%S') if obj.single_time else '',
            'status': obj.status,
            'is_consume': obj.is_consume,
            'dbtransfer_user_phone': obj.dbtransfer.user_phone,
            'is_new': True if obj.is_new else False,
            'is_fixed_ratio': not MerchantContract.objects.filter(merchant=obj.doctor.merchant).exists()
        }
        data.append(result)
    return {"dispatch_info": data, 'total': objs.count()}


@bind_context('hera/bdtransfer/connection')
def connection_history_excel_export(ctx, id, user_id, counsellor_doctor_id,
                                    counsellor__consultant__id, counsellor_type,
                                    type, counsellor_is_assistant, status, create_time):
    rpc = get_rpc_remote_invoker()
    try:
        res = rpc['diagnosis/consultation/excel_export'](id=id, user_id=user_id, counsellor_doctor_id=counsellor_doctor_id,
                                                         counsellor__consultant__id=counsellor__consultant__id, type=type,
                                                         counsellor_type=counsellor_type, counsellor_is_assistant=counsellor_is_assistant,
                                                         status=status, create_time=create_time).unwrap()
    except Exception as e:
        print e
        return {}

    consul = res['send_list']
    dict2 = res['dict2']
    hospital_id_list = res['hospital_id_list']

    user = ctx.session.user
    export_connection_data_excel_task.delay(user.email, consul, dict2, hospital_id_list)



@bind_context('hera/bdtransfer/order_settlement_export')
def order_settlement_export(ctx, id, consultant_id, doctor_id, status, create_time_begin, create_time_end):
    """ 订单结算账单导出 """
    rpc = get_rpc_remote_invoker()
    try:
        data = rpc['diagnosis/consultation/order_settlement/excel_export'](id=id,
                                                                           consultant_id=consultant_id,
                                                                           doctor_id=doctor_id,
                                                                           status=status,
                                                                           create_time_begin=create_time_begin,
                                                                           create_time_end=create_time_end).unwrap()
    except:
        logging_exception()
        return {}

    user = ctx.session.user
    export_order_settlement_excel_task.delay(user.email, data)


@bind_context('hera/bdtransfer/return_excel_export')
def return_excel_export(ctx, bdtransfer__id, bdtransfer__user, type,
                        state, bdtransfer__object_state,
                        plan_at, visit_at, create_at, is_all, status,
                        bdtransfer__user_phone,bdtransfer__wechat):
    a = plan_at.split(',')
    b = visit_at.split(',')
    c = create_at.split(',')
    cur_user = get_user_from_context(ctx)
    user_ids = recursive_users.func(user_id=cur_user.id)
    q = Q(assignor__in=user_ids)
    if bdtransfer__id:
        q &= Q(bdtransfer__id=bdtransfer__id)
    if bdtransfer__user:
        q &= Q(bdtransfer__user=bdtransfer__user)
    if bdtransfer__user_phone:
        q &= Q(bdtransfer__user_phone=bdtransfer__user_phone)
    if bdtransfer__wechat:
        q &= Q(bdtransfer__wechat=bdtransfer__wechat)
    if type:
        q &= Q(type=type)
    if state:
        q &= Q(state=state)
    if bdtransfer__object_state:
        q &= Q(bdtransfer__object_state=bdtransfer__object_state)
    if plan_at:
        q &= Q(plan_at__lte=(datetime.strptime(a[1],'%Y-%m-%d').date() + timedelta(days=1)),plan_at__gte=a[0])
    if visit_at:
        q &= Q(visit_at__lte=(datetime.strptime(b[1],'%Y-%m-%d').date() + timedelta(days=1)),visit_at__gte=b[0])
    if create_at:
        q &= Q(create_at__lte=(datetime.strptime(c[1],'%Y-%m-%d').date() + timedelta(days=1)),create_at__gte=c[0])
    if status:
        q &= Q(status=status)
    if is_all == '':
        today = date.today()
        tomorrow = today + timedelta(days=1)
        q &= Q(plan_at__lte=tomorrow,plan_at__gte=today)


    consul = BDTransferVisitRecord.objects.select_related().filter(q).all()
    send_list = []
    for item in consul:
        send_list.append({
            'id': item.id,
            'bdtransfer__id': item.bdtransfer.id,
            'status': BD_SERVICE_TYPE.getDesc(item.status),
            'bdtransfer__object_state': BDTRANSFER_OBJECT_STATE.getDesc(item.bdtransfer.object_state),
            'bdtransfer__user': item.bdtransfer.user,
            'assignor': item.assignor.username,
            'plan_at': item.plan_at if item.plan_at else '',
            'visit_at': item.visit_at if item.visit_at else '',
            'method': VISIT_METHOD.getDesc(item.method),
            'state': USERACTIVE_STATUS.getDesc(item.state) if item.state else '暂无',
            'creator': item.creator,
            'create_at': item.create_at.strftime("%Y-%m-%d %H:%M:%S")
        })


    user = ctx.session.user
    return_export_data_excel_task.delay(user.email, send_list)


@bind_context('hera/bdtransfer/return_statistics')
def return_statistics(ctx,list_type=None):
    cur_user = ctx.session.user
    business_partener_list = recursive_users.func(user_id=cur_user.id)

    q = Q(assignor__in=business_partener_list,status=BD_SERVICE_TYPE.FINISHED)
    q1 = Q(assignor__in=business_partener_list,status=BD_SERVICE_TYPE.TOBEDONE)
    q2 = Q(assignor__in=business_partener_list,status=BD_SERVICE_TYPE.OVERDUE)
    q3 = Q(assignor__in=business_partener_list)
    if not list_type:
        q &= Q(plan_at__gte=date.today(), plan_at__lte=date.today()+timedelta(days=1))
        q1 &= Q(plan_at__gte=date.today(), plan_at__lte=date.today()+timedelta(days=1))
        q2 &= Q(plan_at__gte=date.today(), plan_at__lte=date.today()+timedelta(days=1))
        q3 &= Q(plan_at__gte=date.today(), plan_at__lte=date.today()+timedelta(days=1), status__in=[BD_SERVICE_TYPE.TOBEDONE,BD_SERVICE_TYPE.FINISHED])
    todo = BDTransferVisitRecord.objects.filter(q1).count()
    finished = BDTransferVisitRecord.objects.filter(q).count()
    overdue_tasks = BDTransferVisitRecord.objects.filter(q2).count()
    total = BDTransferVisitRecord.objects.filter(q3).count()
    return {'total':total,'finished':finished,'todo':todo,'overdue':overdue_tasks}


@bind('get/bdtransfer_singlerecord/num')
def bdtransfer_singlerecord_num(doctor_id, date):
    objs = BDTransferSingleRecord.objects.filter(doctor_id=doctor_id, single_time__gte=date)
    return {"num": objs.count()}