#!/usr/bin/env python
# coding=utf-8

from datetime import datetime
from collections import defaultdict
import math
import json
from django.db.models import Sum, Case, When, IntegerField, F, Q
from django.db import transaction
from django.conf import settings
from django.db.models import Min
from helios import create_default_invoker

from hippo.utils import get_doctors, build_edit_status_from_sign_up_data
from ..tool.service_tool import Cleaner, count_pre_payment

from gm_types.gaia import SERVICE_REVIEW_TYPE, SERVICE_SELL_TYPE, DOCTOR_TYPE, VIDEO_CODE_STATUS, OPERTOR_REVIEW_TYPE, CommodityCategoryProperty, TAG_TYPE
from gm_types.gaia import SERVICE_REVIEW_STATUS as REVIEW
from gm_types.ascle import SERVICE_REVIEW_LIST_TYPES
from gm_types.gaia import ORDER_STATUS, DOCTOR_SECKILL_APPLY_STATUS, TAG_TYPE
from gm_types.ascle.types import SERVICE_ORDER_TYPE
from gm_upload.upload import get_video_upload_token

from api.models import Person, City, AuditAttrOptions, ServiceRegisterTag
from api.models import Tag, AttrOptions, PeriodHospital
from api.models import (ServiceRegisterItem, CommodityCategory,
                        CommodityCategoryRelation, CommodityCategoryPropertyRelation)
from api.models import ServiceRegister, ServiceRegisterItemKey, ServiceRegisterVideo
from api.models import Service, IMAGE_TYPE, UploadButton, ServiceItem, ServiceItemPrice, ServiceItemKey
from api.models import ServiceRegisterItem, ServiceNewTag, ServiceTag
from api.models.special import SpecialSeckillButton, DoctorSeckillApply, Special
from api.models import add_reviewrecord

from api.tool.user_tool import get_doctor_from_context
from hippo.models import Doctor, MasterMerchant
from search.utils.service import filter_service
from rpc.decorators import bind, bind_context
from rpc.decorators import list_interface
from rpc.tool.error_code import gen, CODES
from rpc.tool.dict_mixin import to_dict
from api.tool.datetime_tool import get_timestamp, get_timestamp_epoch
from api.tool.coupon_tool import skus_for_coupon
from api.tasks.service_task import set_water_mark_to_video_service

# TODO zhangyunyu
# from api.models import TopicImage
from talos.models.topic import TopicImage

html_cleaner = Cleaner(safe_attrs_only=False)


@bind('api/doctor/service/my')
@list_interface(offset_name='start_num', limit_name='count',
                element_model=Service)
def get_services_my(count=10, start_num=0, doctor_id=None):
    # TODO Deprecated since 1.5.0
    """
        @Deprecated, see 'doctor/service/list'
    """
    result = []

    filters = {}
    if doctor_id:
        filters['doctor_id'] = doctor_id
    service_ids = filter_service(offset=start_num, size=count, filters=filters)
    ids = service_ids['service_ids']
    services = Service.objects.filter(id__in=ids)

    for service in services:
        result.append({
            'id': service.id,
            'name': service.name,
            'gengmei_price': service.gengmei_price_display,
            'pre_payment_price': service.lowest_pre_payment_price,
            'sell_amount': service.real_sell_amount,
            'is_multiattribute': service.is_multiattribute,
        })
    return result


@bind_context('doctor/service/my', login_required=True)
@list_interface(offset_name='start_num', limit_name='count',
                element_model=Service)
def get_my_services(ctx, count=10, start_num=0):
    # TODO Deprecated since 1.6.0
    """
        ##获取医生美购
        Deprecated 1.6.0, see 'doctor/service/list'
    """
    doctor = get_doctor_from_context(ctx)
    if not doctor:
        return gen(CODES.DOCTOR_NOT_FOUND)
    result = {
        'data': [],
        'total_count': 0,  # 总数
    }
    services = Service.objects.filter(doctor_id=doctor.id, is_online=True)
    services = services.order_by('end_time', '-start_time', 'ordering')
    result['total_count'] = services.count()
    for service in services[start_num:start_num + count]:
        result['data'].append({
            'id': service.id,
            'name': service.name,
            'image': service.image_header,
            'gengmei_price': service.gengmei_price_display,
            'pre_payment_price': service.lowest_pre_payment_price,
            'sell_amount': service.real_sell_amount,
            'is_multiattribute': service.is_multiattribute,
        })
    return result


@bind_context('doctor/service/case_list', login_required=True)
def get_service_cases(ctx, count=10, start_num=0):
    # TODO Deprecated since 1.6.0
    # todo 已废弃，不再维护 180314
    # todo 已废弃，不再维护 180314
    # todo 已废弃，不再维护 180314
    """
        ##获取医生 案例
    """
    doctor = get_doctor_from_context(ctx)
    if not doctor:
        return gen(CODES.DOCTOR_NOT_FOUND)
    result = {
        'data': [],
        'total_count': 0,  # 总数
    }
    services = Service.objects.filter(doctor_id=doctor.id, is_online=True)
    services = services.order_by('end_time', '-start_time', 'ordering')

    num = 0
    for service in services:
        pre_images_count = TopicImage.objects.filter(
            topic__diary__service_id=service.id, topic__is_online=True,
            image_type=IMAGE_TYPE.PRE_OPERATION_IMAGE).count()
        post_images_count = TopicImage.objects.filter(
            topic__diary__service_id=service.id, topic__is_online=True,
            image_type=IMAGE_TYPE.POST_OPERATION_IMAGE).count()
        if pre_images_count and post_images_count:
            num += 1
            if start_num < num:
                result['data'].append({
                    'id': service.id,
                    'name': service.name,
                    'image': service.image_header,
                })
            if len(result['data']) == count:
                break
    return result


@bind('doctors/service_id/list')
def get_services_ids_by_doctor_ids(doctor_ids):
    """
        批量获取医生美购id
    """
    if not doctor_ids:
        return gen(CODES.DOCTOR_NOT_FOUND)
    services_ids = list(Service.objects.filter(doctor_id__in=doctor_ids).values_list('id', flat=True))
    return services_ids


@bind_context('doctor/service/list', login_required=True)
# @list_interface(offset_name='start_num', limit_name='count',
#                 element_model=Service)
def get_doctor_services(ctx, doctor_id, count=10, start_num=0, is_online=None,
                        order_by=SERVICE_ORDER_TYPE.DEFAULT):
    COUNT_LIMIT = 300
    if count > COUNT_LIMIT:
        count = COUNT_LIMIT

    if start_num > settings.OFFSET_LIMIT:
        start_num = settings.OFFSET_LIMIT

    """
        获取医生美购
        is_online: True or False
    """
    if not doctor_id:
        return gen(CODES.DOCTOR_NOT_FOUND)
    result = {
        'data': [],
        'total_count': 0,  # 总数
    }
    if isinstance(doctor_id,list):
        services=Service.objects.filter(doctor_id__in=doctor_id)
    else:
        services = Service.objects.filter(doctor_id=doctor_id)
    if is_online is not None:
        services = services.filter(is_online=is_online)

    if order_by == SERVICE_ORDER_TYPE.ONLIENE_TIME_ASC:
        services = services.order_by('start_time')
    elif order_by == SERVICE_ORDER_TYPE.ONLINE_TIME_DESC:
        services = services.order_by('-start_time')
    elif order_by == SERVICE_ORDER_TYPE.IS_ONLINE_ASC:
        services = services.order_by('is_online')
    elif order_by == SERVICE_ORDER_TYPE.IS_ONLINE_DESC:
        services = services.order_by('-is_online')
    elif order_by in [SERVICE_ORDER_TYPE.ORDER_NUM_ASC,
                      SERVICE_ORDER_TYPE.ORDER_NUM_DESC]:
        # 按 成单量排序
        services = services.annotate(
            real_sell_amount_for_doctor=Sum(
                Case(
                    When(order__status__in=Service.order_amount_status_set,
                         then=1),
                    default=0,
                    output_field=IntegerField(),
                )
            )
        )
        if order_by == SERVICE_ORDER_TYPE.ORDER_NUM_ASC:
            services = services.order_by('real_sell_amount_for_doctor')
        else:
            services = services.order_by('-real_sell_amount_for_doctor')
    elif order_by in [SERVICE_ORDER_TYPE.USED_NUM_ASC,
                      SERVICE_ORDER_TYPE.USED_NUM_DESC]:
        # 按 验证单量排序
        services = services.annotate(
            used_amount_for_doctor=Sum(
                Case(
                    When(order__status__in=ORDER_STATUS.USED, then=1),
                    default=0,
                    output_field=IntegerField(),
                )
            )
        )
        if order_by == SERVICE_ORDER_TYPE.USED_NUM_ASC:
            services = services.order_by('used_amount_for_doctor')
        else:
            services = services.order_by('-used_amount_for_doctor')
    elif order_by in [SERVICE_ORDER_TYPE.REFUNDED_NUM_ASC,
                      SERVICE_ORDER_TYPE.REFUNDED_NUM_DESC]:
        # 按 退款单量排序
        services = services.annotate(
            refunded_amount_for_doctor=Sum(
                Case(
                    When(order__status__in=ORDER_STATUS.REFUNDED, then=1),
                    default=0,
                    output_field=IntegerField(),
                )
            )
        )
        if order_by == SERVICE_ORDER_TYPE.REFUNDED_NUM_ASC:
            services = services.order_by('refunded_amount_for_doctor')
        else:
            services = services.order_by('-refunded_amount_for_doctor')
    else:
        # 默认排序
        services = services.order_by('end_time', '-start_time', 'ordering')

    result['total_count'] = services.count()
    for service in services[start_num:start_num + count]:
        # for service in services:
        real_order_amount = service.real_order_amount_v2  # 成单量

        sk_info = service.get_lowest_price_seckill_info()
        item = {
            'id': service.id,
            'name': service.name,
            'image': service.image_header,
            'short_description': service.short_description,
            'gengmei_price': service.gengmei_price_display,
            'pre_payment_price': service.lowest_pre_payment_price,
            'real_order_amount': real_order_amount,
            'sell_amount': service.real_sell_amount_v2,
            'sell_amount_display': service.sell_amount_display,
            'used_amount': service.used_amount,
            'refunded_amount': service.refunded_amount,
            'is_multiattribute': service.is_multiattribute,
            'original_price': service.original_price,
            'is_seckill': True if sk_info else False,
            'is_online': service.is_online,
            'online_time': get_timestamp(service.start_time),
            'refunded_rate': u'0%',
            'service_type': service.service_type,
            'upgrade':service.upgrade
        }
        # 退款率＝退款数量／成单量
        if real_order_amount:
            item['refunded_rate'] = u'{}%'.format(
                service.refunded_amount * 100 // real_order_amount)

        result['data'].append(item)

    return result


# 临时使用，等gm-im的流表好了就弃用了
@bind_context('doctor/service/search', login_required=True)
def get_doctor_services(ctx, count=20, start_num=0, doctor_id=None, city_id=None, service_name=None):
    if count > settings.OFFSET_LIMIT:
        count = settings.OFFSET_LIMIT

    result = {
        'data': [],
        'total_count': 0,  # 总数
    }

    q = Q(is_online=True)

    if doctor_id:
        q &= Q(doctor_id=doctor_id)
    if city_id:
        q &= Q(doctor__hospital__city_id=city_id)
    if service_name:
        q &= Q(name__contains=service_name)

    services = Service.objects.filter(q).order_by('end_time', '-start_time', 'ordering')

    result['total_count'] = services.count()
    for service in services[start_num:start_num + count]:

        real_order_amount = service.real_order_amount_v2  # 成单量

        sk_info = service.get_lowest_price_seckill_info()

        item = {
            'id': service.id,
            'name': service.name,
            'image': service.image_header,
            'short_description': service.short_description,
            'gengmei_price': service.gengmei_price_display,
            'pre_payment_price': service.lowest_pre_payment_price,
            'real_order_amount': real_order_amount,
            'sell_amount': service.real_sell_amount_v2,
            'sell_amount_display': service.sell_amount_display,
            'used_amount': service.used_amount,
            'refunded_amount': service.refunded_amount,
            'is_multiattribute': service.is_multiattribute,
            'original_price': service.original_price,
            'is_seckill': True if sk_info else False,
            'is_online': service.is_online,
            'online_time': get_timestamp(service.start_time),
            'refunded_rate': u'0%',
            'service_type': service.service_type,
            "city_name": service.city_name,
            "doctor_name": service.doctor.name,
            "merchant_name": service.doctor and service.doctor.merchant and service.doctor.merchant.name or '',
        }

        result['data'].append(item)
    import pprint
    pprint.pprint(result)
    return result


@bind_context('doctor/service/service_index', login_required=True)
def service_index(ctx, doctor_id):
    """
    首页美购销量
    :param ctx:
    :param doctor_id:
    :return:
    """
    services = Service.objects.filter(doctor_id=doctor_id, is_online=True)
    services = services.annotate(
        real_sell_amount_for_doctor=Sum(
            Case(
                When(order__status__in=Service.order_amount_status_set,
                     then=1),
                default=0,
                output_field=IntegerField(),
            )
        )
    ).order_by('-real_sell_amount_for_doctor')
    result = []
    for s in services:
        item = {}
        item['service_name'] = s.name
        item['sales'] = s.real_sell_amount_for_doctor
        result.append(item)
    return result


def get_tag_template(tag):
    result = []
    for attr in tag.tagattr_set.filter(is_online=True):
        options = list(
            attr.attroptions_set.filter(is_online=True).values('name', 'id',
                                                               'is_online'))
        if len(options) != 0:
            result.append({
                'id': attr.id,
                'name': attr.name,
                'is_online': attr.is_online,
                'options': options
            })
    return {'attr_options': result, 'name': tag.name, 'video_token': get_video_upload_token()}


@bind_context('doctor/service/settings', login_required=True)
def service_settings(ctx, service_type=SERVICE_SELL_TYPE.NORMAL):
    if service_type == SERVICE_SELL_TYPE.FENGXIANGGOU:
        setting = settings.SERVICE_FENGXIANGGOU_SETTING.copy()
    else:
        setting = settings.SERVICE_SETTING.copy()
    setting['default_tag_attr_id'] = settings.DEFAULT_TAG_ATTR_ID
    return setting


@bind_context('api/service/template', login_required=True)
def get_doctor_service_template(ctx, tag_id):
    """
        获取tag对应的模板
    """
    if not tag_id:
        return gen(CODES.PARAMS_INCOMPLETE)

    doctor = get_doctor_from_context(ctx)
    if not doctor:
        return gen(CODES.DOCTOR_NOT_FOUND)
    tag = Tag.objects.get(id=tag_id, is_online=True)
    return get_tag_template(tag)


def __gen_service_register_detail(service_registers):
    """私有方法,service_registers中特殊的计算字段(最新更新时间)."""

    result = []
    register_ids = []
    for service_register in service_registers:
        result.append({
            'id': service_register.id,
            'short_description': service_register.short_description,
            'status': REVIEW.UNDER_REVIEW if service_register.is_register and \
                                             service_register.review_status == REVIEW.PASS else \
                service_register.review_status,
            'is_special': service_register.is_specialreview,
            'service_id': service_register.service.id if service_register.service else None,
            'is_online': service_register.service.is_online if service_register.service else None,
            'service_name': service_register.name,
            'service_type': service_register.service_type,
            'lastest_time': get_timestamp(service_register.lastest_time),
            'gengmei_price': 0,
            'pre_payment_price': 0,
            # 'locked': service_register.service.is_lock if service_register.service else False,
            'locked': False,  # 维度降低到SKU，换个字段
            'has_sku_lock': service_register.service.has_sku_lock if service_register.service else False,
            'is_draft': service_register.is_draft,
            'doctor_id': service_register.doctor.id,
            'doctor_name': service_register.doctor.name,
            'activity_status': service_register.get_activity_status()
        })
        register_ids.append(service_register.id)

    # 为了一次性查出每一个美购的最小价
    min_prices = ServiceRegisterItem.objects.filter(service_register__in=register_ids,
                                                    is_online=True,
                                                    is_delete=False).annotate(min_gengmei_price=Min('gengmei_price'),
                                                                              min_pre_payment_price=Min(
                                                                                  'pre_payment_price_int')).values(
        'service_register_id', 'min_gengmei_price', 'min_pre_payment_price')
    for register in result:
        for min_price in min_prices:
            if register['id'] == min_price['service_register_id']:
                register['gengmei_price'] = min_price['min_gengmei_price']
                register['pre_payment_price'] = min_price['min_pre_payment_price']
                break
    return result


@bind_context('doctor/service/review', login_required=True)
@list_interface(offset_name='start_num', limit_name='count', element_model=ServiceRegister)
def get_doctor_service_register(ctx, review_type, ask_all_counts=False,
                                keyword=None, doctor_ids=None,
                                count=10, start_num=0, service_type=None, service_id=None, service_register_id=None):
    """
    通过type确定 filter,处理是否需要所有总数,是否需要关键词过滤
    :type
    """
    doctor = get_doctor_from_context(ctx)
    if not doctor:
        return gen(CODES.DOCTOR_NOT_FOUND)
    # 确定filter
    type2filters = {
        SERVICE_REVIEW_LIST_TYPES.ALL: {
            "service__is_delete" : False,
        },
        SERVICE_REVIEW_LIST_TYPES.UNDER_PASS: {
            'is_register': True,
            # "service__is_delete": False,
        },
        SERVICE_REVIEW_LIST_TYPES.ONLINE: {
            'is_register': False,
            'service__is_online': True,
            "service__is_delete": False,
        },
        SERVICE_REVIEW_LIST_TYPES.OFFLINE: {
            'is_register': False,
            'service__is_online': False,
            "service__is_delete": False,
        },
    }

    # 获得总数
    def get_counts(types, keyword, service_type=None):
        """获取总数的辅助方法"""
        result = []
        for t in types:
            c = get_register_query(t, keyword, service_type).count()
            result.append(c)
        return result

    def get_register_query(review_type, keyword, service_type=None):
        if review_type == SERVICE_REVIEW_LIST_TYPES.ALL:
            filters = {}
        else:
            filters = type2filters[review_type]
        if service_type or service_type in [0, '0']:
            filters['service_type'] = service_type
        # 过滤关键字
        if keyword is not None:
            filters['short_description__contains'] = keyword
        services = ServiceRegister.objects.filter(doctor__in=doctor_ids or doctor, doctor_can_see=True, **filters)
        if review_type == SERVICE_REVIEW_LIST_TYPES.ALL:
            query = Q(Q(service__isnull=True) | Q(service__is_delete=False))
            services = services.filter(query)

        if service_id:
            services = services.filter(service_id=service_id)
        if service_register_id:
            services = services.filter(id=service_register_id)
        return services

    result = {}
    if ask_all_counts:
        result['counts'] = get_counts(
            sorted([i for i, _ in SERVICE_REVIEW_LIST_TYPES]), keyword, service_type)
    else:
        result['counts'] = get_counts((review_type,), keyword, service_type)

    services = get_register_query(review_type, keyword, service_type=service_type)
    services = services.annotate(
        lastest_time=Case(When(Q(last_submit_time__gte=F('last_review_time')) | Q(last_review_time__isnull=True),
                               then=F('last_submit_time')),
                          When(Q(last_review_time__gt=F('last_submit_time')) | Q(last_submit_time__isnull=True),
                               then=F('last_review_time'))),
    ).select_related("service").order_by("-lastest_time")
    # 格式化返回
    result['services'] = __gen_service_register_detail(services[start_num:start_num + count])
    return result


@bind_context('doctor/service/offline', login_required=True)
def doctor_service_offline(ctx, doctor_ids, service_register_id):
    """
        让一个美购下线,先更改service_register 状态,
        然后add_reviewrecord对比service和service_register给出描述.
    """
    doctor = get_doctor_from_context(ctx)
    if not doctor:
        return gen(CODES.DOCTOR_NOT_FOUND)

    register = ServiceRegister.objects.get(id=service_register_id, doctor_id__in=doctor_ids,
                                           service__is_online=True)
    if register.review_status in (
            # REVIEW.UNDER_REVIEW,
            REVIEW.UNDER_OFFLINE,
            # REVIEW.SPECIAL_UNDER_REVIEW
    ):
        return gen(CODES.NO_OFFLINE)

    # 在线美购被锁不能下线
    if register.service and register.service.has_sku_lock:
        return gen(CODES.NO_OFFLINE)

    register.review_status = REVIEW.UNDER_OFFLINE
    register.last_submit_time = datetime.now()
    register.save()

    person_id = register.user.person.id
    add_reviewrecord(register, person_id, review_type=SERVICE_REVIEW_TYPE.OFFLINE)


def add_item_data(items, is_seckill, register):
    # 区别 纷享购 取不同的配置
    if register.service_type == SERVICE_SELL_TYPE.FENGXIANGGOU:
        s_setting = settings.SERVICE_FENGXIANGGOU_SETTING.copy()
    else:
        s_setting = settings.SERVICE_SETTING.copy()

    seckill_default_discount = s_setting['seckill_default_discount']
    discount = s_setting['discount']
    pre_payment_price = s_setting['pre_payment_price']
    flag = False
    # 与产品确认，这部分逻辑废弃
    # if is_seckill:
    #     seckill = register.upload_button
    #     discount = seckill.discount if seckill else seckill_default_discount
    for item in items:
        item['stock_add_num'] = item.get('stock_add_num', register.add_num)  # 兼容先上gaia后上ascle,上线删除
        if item.get('id'):
            ritem = ServiceRegisterItem.objects.get(id=item.get('id'))
            if ritem.serviceitem:
                info = ritem.serviceitem.get_current_price_info()
                if ritem.serviceitem.can_modify_price:
                    # 无活动时改大需要审核
                    if not info.get('selling_rule', None):
                        if info['gengmei_price'] < item['gengmei_price']:
                            flag = True
                    # 任何情况改小需要审核
                    if info['gengmei_price'] > item['gengmei_price']:
                        flag = True
                if ritem.gengmei_price == item['gengmei_price']:
                    # 更美价相同则不对这条数据操作
                    continue
        if register.service_type == SERVICE_SELL_TYPE.FENGXIANGGOU:
            item['discount'] = int(math.ceil(item['gengmei_price'] * discount / 100.00))
            item['pre_payment_price'] = pre_payment_price
            # 产品确认过 向下取整
            pre_price = int(item['gengmei_price'] * pre_payment_price / 100)
            item['pre_payment_price_int'] = pre_price
        else:
            price_data = count_pre_payment(item['gengmei_price'])
            item['discount'] = price_data['discount']
            item['pre_payment_price'] = price_data['pre_payment_price']
            item['pre_payment_price_int'] = price_data['pre_payment_price_int']
    return items, flag


@bind_context('doctor/service/register', login_required=True)
def register_detail(ctx, register_id):

    doctor = get_doctor_from_context(ctx)
    try:
        register = ServiceRegister.objects.get(id=register_id)
    except ServiceRegister.DoesNotExist:
        return gen(CODES.NO_SERVICE_REGISTER)

    if register.project_type:
        project_type = register.project_type.id
        project_name = register.project_type.name
        tag_attr = get_tag_template(register.project_type)
    else:
        project_type, project_name, tag_attr = '', '', {'attr_options': []}

    def item_info(item):
        item_dict = to_dict(item)
        opt = ServiceRegisterItemKey.objects.filter(serviceregisteritem=item)
        item_dict['option_ids'] = [to_dict(x.serviceregisterattroption) for x in opt]
        item_dict['sku_stock'] = item.serviceitem.sku_stock if item.serviceitem else 0
        item_dict['is_lock'] = item.serviceitem.is_lock if item.serviceitem else False

        item_dict['option_ids'] = []
        for x in opt:
            serviceregisterattroption = to_dict(x.serviceregisterattroption)
            auditattroptions = AuditAttrOptions.objects.filter(serviceregisteritem=x.serviceregisteritem).order_by('created_time').first()
            if auditattroptions:
                serviceregisterattroption['name'] = auditattroptions.name
            item_dict['option_ids'].append(serviceregisterattroption)

        if item.serviceitem:
            info = item.serviceitem.get_current_price_info()
            item_dict['show_dialog'] = False if info['gengmei_price'] == item.gengmei_price else True
            item_dict['now_price'] = info['gengmei_price']
            item_dict['now_pre_payment'] = info['pre_payment_price']
            item_dict['price_start_time'] = get_timestamp_epoch(info['selling_rule']['start_time']) \
                if info.get('selling_rule') else ''
            item_dict['price_end_time'] = get_timestamp_epoch(info['selling_rule']['end_time']) \
                if info.get('selling_rule') else ''
            item_dict['activity_name'] = info['selling_rule']['name'] \
                if info.get('selling_rule') else ''
            item_dict['now_stock'] = info['sale_limit']
        else:
            item_dict['show_dialog'] = False
            item_dict['now_price'] = 0
            item_dict['now_pre_payment'] = 0
            item_dict['price_start_time'] = ''
            item_dict['price_end_time'] = ''
            item_dict['activity_name'] = ''
            item_dict['now_stock'] = 0
        try:
            city_id = item_dict.pop('city')
            if city_id:
                item_dict['city_name'] = item.city.name
                item_dict['city_id'] = item.city_id
        except:
            pass
        item_dict['sku_description'] = item.sku_description

        #组装类目信息
        category_relation = CommodityCategoryRelation.objects.filter(commodity_register_id=item.id).first()
        category_property_relations = CommodityCategoryPropertyRelation.objects.filter(commodity_register_id=item.id)

        item_dict['commodity_category_info'] = category_relation.category_info() if category_relation else []
        item_dict['category_roperty'] = {c_p_r.property_type: c_p_r.property_name for c_p_r in category_property_relations}
        return item_dict

    def get_register_header():
        item = register.items.filter(is_delete=False).first()
        if not item:
            return None
        keys = ServiceRegisterItemKey.objects.filter(serviceregisteritem=item)
        return [to_dict(x.serviceregisterattroption.tag_attr) for x in keys]

    def is_seckill():
        if register.service:
            return not register.service.is_multiattribute
        return bool(register.upload_button)

    try:
        reason = register.servicereviewrecord_set.latest('created_time').reason
    except:
        # 美购老数据可能没有 record
        reason = ''
    if register.upload_button:
        seckill_discount = register.upload_button.discount
    else:
        if is_seckill():
            seckill_discount = settings.SERVICE_SETTING['seckill_default_discount']
        else:
            seckill_discount = None

    if register.service_type == SERVICE_SELL_TYPE.FENGXIANGGOU:
        pre_payment_price = settings.SERVICE_FENGXIANGGOU_SETTING['pre_payment_price']
    else:
        pre_payment_price = settings.SERVICE_SETTING['pre_payment_price']
    hasvideo = ServiceRegisterVideo.objects.filter(serviceregister_id=register.id).exists()
    if hasvideo:
        video_info = ServiceRegisterVideo.objects.get(serviceregister_id=register.id).get_video_info()
    items_ = [item_info(x) for x in register.items.filter(is_delete=False)]
    service_tags_info = ctx.rpc_remote['pims/catalog/servicesregister/move_check'](registers=[register.id]).unwrap()
    result = {
        'id': register.id,
        'service_name': register.name,
        'short_description': register.short_description,
        'service_id': register.service.id if register.service else None,
        'start_time': get_timestamp_epoch(register.start_time),
        'end_time': get_timestamp_epoch(register.end_time),
        'reservation': register.reservation,
        'total_num': register.total_num,  # 废弃, 上线后可删除, @张晓林
        'add_num': register.add_num,  # 废弃,上线后可删除, @张晓林
        'image_header': register.image_header,
        'photo_details': register.photo_details,
        'project_type': project_type,
        'project_name': project_name,
        'tag_attr': tag_attr,
        'seckill_discount': seckill_discount,
        'pre_payment_price': pre_payment_price,
        'attr_header': get_register_header(),
        'is_seckill': is_seckill(),
        'is_specialreview': register.is_specialreview,
        'review_status': REVIEW.UNDER_REVIEW if register.is_register and \
                                                register.review_status == REVIEW.PASS else \
            register.review_status,
        'turn_down_reason': reason,
        'items': items_,
        'record_info': register.record_info(with_operator_name=False),
        'have_extra_pay': register.have_extra_pay,
        'extra_pay_info': register.extra_pay_info,
        'image_bigpic': register.image_bigpic,
        'supplement_images': register.get_supplement_images(),
        'recommend_services': register.get_recommend_services(),
        'service_type': register.service_type,
        'video_token': get_video_upload_token(),
        'video_pic': video_info['video_pic'] if hasvideo else '',
        'video_url': video_info['video_url'] if hasvideo else '',
        'doctor_name': register.doctor.name,
        'doctor_id': register.doctor.id,
        'reject_reason': register.servicereviewrecord_set.order_by('-created_time')[0].reason if register.servicereviewrecord_set.order_by('-created_time') else None,
        'is_move': service_tags_info['result'].get(str(register.id), False),
        'upgrade': register.upgrade
    }
    try:
        if register.service_type == 3:
            cities = []
            item_names = []
            for item in items_:
                city = {}
                city['city_id'] = item['city_id']
                city['city_name'] = item['city_name']
                cities.append(city)
            #     option_ids = item.get('option_ids', None)
            #     if option_ids:
            #         item_names.append(option_ids.get('name', None))
            result.update(cities=cities)
            return result
    except:
        pass
    return result


@bind_context('doctor/service/seckill_info')
def get_seckill_info(ctx):
    """
        获取秒杀相关配置信息
    """
    now = datetime.now()
    seckill = UploadButton.objects.filter(start_show_time__lt=now,
                                          end_show_time__gt=now).first()
    if seckill:
        data = to_dict(seckill)
        t = ['start_sell_time', 'end_sell_time']
        data.update({x: get_timestamp_epoch(getattr(seckill, x)) for x in t})
        return data


@bind_context('doctor/service/register/create', login_required=True)
def register_create(ctx, data, applier, explanation=None):
    with transaction.atomic():

        # doctor = get_doctor_from_context(ctx)
        doctor = Doctor.objects.get(id=data.pop('doctor_id'))
        if doctor.is_online == False:
            raise gen(CODES.CONSElLOR_DOCTOR_IS_OFFLINE)
        tag = Tag.objects.get(id=data['project_type'])
        if tag.tag_type != TAG_TYPE.ITEM_WIKI:
            return -1
        is_seckill = data['is_seckill']
        is_draft = data.get('is_draft', False)

        is_specialreview = True if data.get('is_specialreview') else False
        if is_draft:
            review_status = REVIEW.DRAFT
        elif is_specialreview:
            review_status = REVIEW.SPECIAL_UNDER_REVIEW
        else:
            review_status = REVIEW.UNDER_REVIEW

        if applier:
            applier = Person.objects.get(id=applier)
        else:
            applier = doctor.user.person

        now = datetime.now()
        # 创建美购申请
        if data.get('service_type', SERVICE_SELL_TYPE.NORMAL) == 3:
            name = u'【{}】{}'.format(doctor.name, tag.name)
        else:
            name = u'【{}@{}】{}'.format(doctor.hospital.city.name, doctor.name, tag.name)
        kwargs = {
            'name': name,
            'user': applier.user,
            'doctor': doctor,
            'reservation': data['reservation'],
            'start_time': datetime.fromtimestamp(data['start_time']),
            'end_time': datetime.fromtimestamp(data['end_time']),
            'photo_details': html_cleaner.clean_html(data['photo_details']) if data['photo_details'] else '',
            'project_type': tag,
            'short_description': data['short_description'],
            'image_header': data['image_header'],
            'is_specialreview': is_specialreview,
            'review_status': review_status,
            'last_submit_time': now,
            'total_num': 0,
            'is_draft': is_draft,
            'is_stage': PeriodHospital.objects.filter(hospital=doctor.hospital, default_online=True).exists(),
            'add_num': data.get('add_num', 0),  # TODO: 上线之后删掉
            'have_extra_pay': data.get('have_extra_pay', False),
            'extra_pay_info': data.get('extra_pay_info'),
            'image_bigpic': data.get('image_bigpic'),
            'service_type': data.get('service_type', SERVICE_SELL_TYPE.NORMAL),
            'merchant_id': data.get('merchant_id')
        }
        if is_seckill:
            kwargs['upload_button'] = UploadButton.objects.filter(
                start_show_time__lt=now, end_show_time__gt=now).first()
            kwargs['name'] = kwargs['upload_button'].button_prefix + kwargs['name']

        register = ServiceRegister.objects.create(**kwargs)

        # 保存关联图片和推荐美购
        register.update_supplement_images(data.pop('supplement_images', []))
        register.update_recommend_services(data.pop('recommend_services', []))

        items, flag = add_item_data(data['items'], is_seckill, register)
        # 创建多属性
        if is_seckill:
            # 秒杀美购
            item = items[0]
            item['key'] = ''  # 秒杀没有标识符 @lipeng
            item['service_register'] = register
            item.pop('option_ids', None)
            commodity_category_id = item.pop('commodity_category_id', None)
            category_roperty = item.pop('category_roperty', None)
            ritem = ServiceRegisterItem.objects.create(**item)
            opt = AttrOptions.objects.create(
                tag_attr_id=settings.DEFAULT_TAG_ATTR_ID,
                name=tag.name, is_online=True)
            ServiceRegisterItemKey.objects.create(
                serviceregisteritem=ritem, serviceregisterattroption=opt)

            #创建类目信息
            if commodity_category_id:
                CommodityCategoryRelation.objects.create(commodity_register_id=ritem.id,
                                                         category_id=commodity_category_id)
            if category_roperty:
                CommodityCategoryPropertyRelation.objects.bulk_create([CommodityCategoryPropertyRelation(
                    commodity_register_id=ritem.id, property_name=property_name, property_type=property_type) for
                                                                       property_type, property_name in
                                                                       category_roperty.items() if property_name])

        else:
            if tag.tagattr_set.filter(is_online=True).exists():
                # 标准美购
                for item in items:
                    option_ids = item.pop('option_ids')
                    commodity_category_id = item.pop('commodity_category_id', None)
                    category_roperty = item.pop('category_roperty', None)

                    item['service_register'] = register
                    item['key'] = '-'.join(map(str, option_ids))
                    ritem = ServiceRegisterItem.objects.create(**item)
                    for opt in option_ids:
                        ServiceRegisterItemKey.objects.create(
                            serviceregisteritem=ritem,
                            serviceregisterattroption_id=opt)

                    # 创建类目信息
                    if commodity_category_id:
                        CommodityCategoryRelation.objects.create(commodity_register_id=ritem.id,
                                                                 category_id=commodity_category_id)
                    if category_roperty:
                        CommodityCategoryPropertyRelation.objects.bulk_create([CommodityCategoryPropertyRelation(
                            commodity_register_id=ritem.id, property_name=property_name,
                            property_type=property_type) for
                            property_type, property_name in
                            category_roperty.items() if property_name])
            else:
                # 非标准美购
                for item in items:
                    name = item.pop('project_name')
                    commodity_category_id = item.pop('commodity_category_id', None)
                    category_roperty = item.pop('category_roperty', None)

                    opt = AttrOptions.objects.create(
                        tag_attr_id=settings.DEFAULT_TAG_ATTR_ID,
                        name=name, is_online=True)
                    item['service_register'] = register
                    item['key'] = str(opt.id)
                    ritem = ServiceRegisterItem.objects.create(**item)
                    ServiceRegisterItemKey.objects.create(
                        serviceregisteritem=ritem, serviceregisterattroption=opt)

                    # 创建类目信息
                    if commodity_category_id:
                        CommodityCategoryRelation.objects.create(commodity_register_id=ritem.id,
                                                                 category_id=commodity_category_id)
                    if category_roperty:
                        for property_type, property_name in category_roperty.items():
                            if not property_name:
                                continue
                            CommodityCategoryPropertyRelation.objects.create(commodity_register_id=ritem.id,
                                                                             property_name=property_name,
                                                                             property_type=property_type)
    video_url = data['video_url'] if data.get('video_url') else ''
    video_pic = data['video_pic'] if data.get('video_pic') else ''
    if video_url != '' or video_pic != '':
        if video_url != '':
            video_url = ServiceRegisterVideo.cleaned_video_url(video_url)
        video = ServiceRegisterVideo()
        video.serviceregister_id = register.id
        video.video_url = video_url
        video.video_pic = video_pic
        video.save()
        set_water_mark_to_video_service.delay(video.id)
    if is_draft:
        return None

    review_type = SERVICE_REVIEW_TYPE.ORDINARY
    if data['is_specialreview']:
        review_type = SERVICE_REVIEW_TYPE.SPECIAL
    return add_reviewrecord(register, applier.id, review_type=review_type, explanation=explanation)


@bind_context('doctor/service/register/edit', login_required=True)
def register_edit(ctx, register_id, data, applier, explanation=None, service_id=None):
    with transaction.atomic():
        # doctor = get_doctor_from_context(ctx)
        doctor = Doctor.objects.get(id=data['doctor_id'])
        if doctor.is_online == False:
            raise gen(CODES.CONSElLOR_DOCTOR_IS_OFFLINE)
        register = ServiceRegister.objects.get(id=register_id)
        tag = Tag.objects.get(id=data['project_type'])

        if tag.tag_type != TAG_TYPE.ITEM_WIKI:
            return -1
        # tag = register.project_type
        is_seckill = data['is_seckill']

        # if register.review_status in (
        #         REVIEW.UNDER_OFFLINE):
        #     return gen(CODES.NO_EDIT)
        # 通过特批审核 不能进行更改
        if register.review_status == REVIEW.UNDER_REVIEW and register.is_specialreview:
            return gen(CODES.NO_EDIT)

        # 美购被锁不能编辑
        # if register.service and register.service.is_lock:
        #    return gen(CODES.NO_EDIT)

        if applier:
            applier = Person.objects.get(id=applier)
        else:
            applier = doctor.user.person

        # 更改register 数值
        modify_items = [
            'short_description', 'start_time', 'end_time', 'reservation',
            'image_header', 'photo_details', 'is_specialreview', 'is_draft',
            'have_extra_pay', 'extra_pay_info', 'image_bigpic', 'doctor_id',
        ]
        for name in modify_items:
            pre = getattr(register, name)
            new = data.get(name)
            if name in {'start_time', 'end_time'}:
                new = datetime.fromtimestamp(new)
            elif name in {'photo_details'}:
                new = html_cleaner.clean_html(new) if new else ''
            if new != pre:
                setattr(register, name, new)
        if register.service_type == 3:
            setattr(register, 'name', u'【{}】{}'.format(doctor.name, tag.name))
        else:
            setattr(register, 'name', u'【{}@{}】{}'.format(doctor.hospital.city.name, doctor.name, tag.name))
        # TODO, 上线后删掉
        register.add_num = data.get('add_num', 0)

        # 编辑后, 若不是保存草稿 状态是要改的
        if not data.get('is_draft'):
            if data['is_specialreview']:
                register.review_status = REVIEW.SPECIAL_UNDER_REVIEW
            else:
                register.review_status = REVIEW.UNDER_REVIEW
        else:
            if not register.is_register:
                register.review_status = REVIEW.PASS
            else:
                register.review_status = REVIEW.DRAFT

        register.last_submit_time = datetime.now()

        # 保存关联图片和推荐美购
        image_urls = data.pop('supplement_images', [])
        register.update_supplement_images(image_urls)
        register.update_supplement_images_order(image_urls)
        register.update_recommend_services(data.pop('recommend_services', []))

        items, flag = add_item_data(data['items'], is_seckill, register)
        if flag:
            register.operator_review_type = OPERTOR_REVIEW_TYPE.WATI_REVIEW
        register.project_type = tag
        register.upgrade = False
        register.save()

        if is_seckill:
            # 秒杀更改
            item = items[0]
            item['key'] = ''  # 秒杀没有标识符 @lipeng
            item_id = item.pop('id')
            item.pop('is_online')
            # 重置类目信息
            commodity_category_id = item.pop('commodity_category_id', None)
            category_roperty = item.pop('category_roperty', None)
            CommodityCategoryRelation.objects.filter(commodity_register_id=item_id).delete()
            CommodityCategoryPropertyRelation.objects.filter(commodity_register_id=item_id).delete()
            ritem = ServiceRegisterItem.objects.filter(id=item_id).first()
            commodity_id = ritem.serviceitem_id if ritem and ritem.serviceitem_id else 0

            if commodity_category_id:
                CommodityCategoryRelation.objects.create(commodity_register_id=item_id,
                                                         commodity_id=ritem.serviceitem_id,
                                                         category_id=commodity_category_id)
            if category_roperty:
                CommodityCategoryPropertyRelation.objects.bulk_create([CommodityCategoryPropertyRelation(
                    commodity_register_id=item_id, property_name=property_name, commodity_id=commodity_id,
                    property_type=property_type) for
                    property_type, property_name in
                    category_roperty.items() if property_name])

            sitem = ServiceRegisterItem.objects.filter(id=item_id)
            sitem.update(**item)


        else:
            # 这次编辑保留了哪些item
            saved_items = []
            if tag.tagattr_set.filter(is_online=True).exists():
                # 标准美购
                for item in items:
                    # 重置类目信息
                    item_id = item.pop('id', None)
                    commodity_category_id = item.pop('commodity_category_id', None)
                    category_roperty = item.pop('category_roperty', None)

                    commodity_id = 0
                    if item_id is None:
                        # 新增数据
                        option_ids = item.pop('option_ids')

                        item['key'] = '-'.join(map(str, option_ids))
                        item['service_register'] = register
                        ritem = ServiceRegisterItem.objects.create(**item)
                        saved_items.append(ritem)
                        item_id = ritem.id

                        # 新建价格数据，添加维度属性
                        for opt in option_ids:
                            ServiceRegisterItemKey.objects.create(
                                serviceregisteritem=ritem,
                                serviceregisterattroption_id=opt)
                    else:
                        # 修改价格维度属性不变
                        ritem = ServiceRegisterItem.objects.filter(id=item_id)
                        ritem_obj = ritem.first()
                        commodity_id = ritem_obj.serviceitem_id if ritem_obj and ritem_obj.serviceitem_id else 0
                        saved_items.append(ritem_obj)
                        ritem.update(**item)
                        ritem = ServiceRegisterItem.objects.filter(id=item_id).first()

                    CommodityCategoryRelation.objects.filter(commodity_register_id=item_id).delete()
                    CommodityCategoryPropertyRelation.objects.filter(commodity_register_id=item_id).delete()

                    if commodity_category_id:
                        CommodityCategoryRelation.objects.create(commodity_register_id=item_id,
                                                                 commodity_id=commodity_id,
                                                                 category_id=commodity_category_id)
                    if category_roperty:
                        CommodityCategoryPropertyRelation.objects.bulk_create([CommodityCategoryPropertyRelation(
                            commodity_register_id=item_id, property_name=property_name,
                            commodity_id=commodity_id,
                            property_type=property_type) for
                            property_type, property_name in
                            category_roperty.items()if property_name])

            else:
                for item in items:
                    # 重置类目信息
                    item_id = item.pop('id', None)
                    name = item.pop('project_name')
                    commodity_category_id = item.pop('commodity_category_id', None)
                    category_roperty = item.pop('category_roperty', None)
                    commodity_id = 0

                    if item_id is None:
                        opt = AttrOptions.objects.create(
                            tag_attr_id=settings.DEFAULT_TAG_ATTR_ID,
                            name=name, is_online=True)
                        item['service_register'] = register
                        item['key'] = str(opt.id)
                        ritem = ServiceRegisterItem.objects.create(**item)
                        saved_items.append(ritem)
                        ServiceRegisterItemKey.objects.create(
                            serviceregisteritem=ritem,
                            serviceregisterattroption=opt)
                        item_id = ritem.id
                    else:
                        ritem = ServiceRegisterItem.objects.filter(id=item_id)
                        ritem.update(**item)
                        fitem = ritem.first()
                        commodity_id = fitem.serviceitem_id if fitem and fitem.serviceitem_id else 0
                        saved_items.append(fitem)
                        # 非标准应该只有一个opt
                        # sku标准化兼容为了不报错
                        itemkey = ServiceRegisterItemKey.objects.filter(serviceregisteritem=fitem).first()
                        auditattroptions = AuditAttrOptions.objects.filter(serviceregisteritem=fitem, is_delete=False).first()
                        if auditattroptions:
                            auditattroptions.name = name
                            auditattroptions.save()
                        elif itemkey and itemkey.serviceregisterattroption.name != name:
                            auditattroptions, _ = AuditAttrOptions.objects.get_or_create(
                                name=name,
                                serviceregisteritem=fitem,
                                is_delete=False)

                    # 重置类目信息
                    CommodityCategoryRelation.objects.filter(commodity_register_id=item_id).delete()
                    CommodityCategoryPropertyRelation.objects.filter(commodity_register_id=item_id).delete()

                    if commodity_category_id:
                        CommodityCategoryRelation.objects.create(commodity_register_id=item_id,
                                                                 commodity_id=commodity_id,
                                                                 category_id=commodity_category_id)
                    if category_roperty:
                        CommodityCategoryPropertyRelation.objects.bulk_create([CommodityCategoryPropertyRelation(
                            commodity_register_id=item_id, property_name=property_name,
                            commodity_id=commodity_id,
                            property_type=property_type) for
                            property_type, property_name in
                            category_roperty.items() if property_name])

            # 保留提交过来的数据，未提交的以软删算
            ServiceRegisterItem.objects.filter(service_register=register) \
                .exclude(id__in=[x.id for x in saved_items]) \
                .update(is_delete=True)
            ServiceRegisterItem.objects.filter(id__in=[x.id for x in saved_items]).update(is_delete=False)
    video_url = data['video_url'] if data.get('video_url') else ''
    video_pic = data['video_pic'] if data.get('video_pic') else ''
    if video_url != '' or video_pic != '':
        if video_url != '':
            video_url = ServiceRegisterVideo.cleaned_video_url(video_url)
        if ServiceRegisterVideo.objects.filter(serviceregister_id=register.id).exists():
            video = ServiceRegisterVideo.objects.get(serviceregister_id=register.id)
            if video_url != video.get_url() or video_pic != video.video_pic:
                if video_url != video.get_url():
                    if video_url == '':
                        video.video_url = video_url
                        video.video_pic = video_pic
                        video.persistent_status = VIDEO_CODE_STATUS.NOSTART
                        video.water_url = ''
                        video.persistentId = ''
                        video.save()
                    else:
                        video.video_url = video_url
                        video.video_pic = video_pic
                        video.persistent_status = VIDEO_CODE_STATUS.NOSTART
                        video.water_url = ''
                        video.persistentId = ''
                        video.save()
                        set_water_mark_to_video_service.delay(video.id)
                else:
                    video.video_pic = video_pic
                    video.save()
        else:
            video = ServiceRegisterVideo()
            video.serviceregister_id = register.id
            video.video_url = video_url
            video.video_pic = video_pic
            video.save()
            set_water_mark_to_video_service.delay(video.id)
    else:
        if ServiceRegisterVideo.objects.filter(serviceregister_id=register.id).exists():
            ServiceRegisterVideo.objects.get(serviceregister_id=register.id).delete()

    if data.get('is_draft'):
        return None

    review_type = SERVICE_REVIEW_TYPE.ORDINARY
    if data['is_specialreview']:
        review_type = SERVICE_REVIEW_TYPE.SPECIAL
    return add_reviewrecord(register, applier.id, review_type=review_type, explanation=explanation)

@bind_context('doctor/service/skus', login_required=True)
def doctor_skus(ctx, doctor_id=None, service_id=None):
    """
        获取医生可售卖的sku
    """
    if doctor_id:
        doctor = Doctor.objects.get(pk=doctor_id)
    else:
        doctor = get_doctor_from_context(ctx)
    if not doctor:
        return gen(CODES.DOCTOR_NOT_FOUND)
    sku_ids = doctor.get_can_sell_sku_ids(doctor_id=doctor.id, service_id=service_id)
    return {
        'skus': skus_for_coupon(sku_ids),
    }


@bind_context('doctor/service/all', login_required=True)
def doctor_all_services(ctx, is_store_classification=None, page=None, search=None):
    """
        获取医生 所有 可售美购
    """
    doctor = get_doctor_from_context(ctx)
    if not doctor:
        return gen(CODES.DOCTOR_NOT_FOUND)
    merchant = doctor.merchant
    if is_store_classification:
        filter_fields = {'merchant_id': merchant.id}
        if search:
            try:
                filter_fields['id'] = int(search)
            except:
                filter_fields['name__contains'] = search

        services = Service.objects.filter(**filter_fields).order_by('-id')
        total = services.count()
        services = services[(int(page) - 1)*10:int(page)*10].values('id', 'name', 'is_online')
        return {
                'services': {'services': list(services), 'total': total},
            }
    services = Service.objects.filter(merchant_id=merchant.id, is_online=True).order_by('-id').values('id', 'name')
    return {
        'services': list(services),
    }


@bind_context('doctor/service/is_online', login_required=True)
def judge_is_onlie(ctx, service_ids=[]):
    """
        判断美购是否是该医生的 且 是否在线
        返回合法美购
    """
    doctor = get_doctor_from_context(ctx)
    if not doctor:
        return gen(CODES.DOCTOR_NOT_FOUND)
    online_services = Service.objects.filter(doctor_id=doctor.id, id__in=service_ids, is_online=True).values('id',
                                                                                                             'name')
    return {
        'online_services': list(online_services),
    }

@bind_context('doctor/merchant_service/is_online', login_required=True)
def merchant_service_is_onlie(ctx, service_ids=[]):
    """
        判断美购是否是该医生所属机构的 且 是否在线
        返回合法美购
    """
    doctor = get_doctor_from_context(ctx)
    if not doctor:
        return gen(CODES.DOCTOR_NOT_FOUND)
    merchant = doctor.merchant
    online_services = Service.objects.filter(merchant_id=merchant.id, id__in=service_ids, is_online=True).values('id',
                                                                                                             'name')
    return {
        'online_services': list(online_services),
    }


@bind_context('doctor/service/can_use')
def doctor_service_can_use(ctx):
    """
    获取医生 可管理的所有可售美购
    如果是机构管理者，则为该机构下所有受该机构管理的医生的上线美购
    如果是普通医生，则为该医生的所有上线美购
    :param ctx:
    :return:
    """
    doctor = get_doctor_from_context(ctx)
    doctors = []
    doctors.append(doctor)
    if doctor.doctor_type == DOCTOR_TYPE.OFFICER:
        for item in Doctor.objects.filter(hospital=doctor.hospital, allow_hospital_agent=True):
            doctors.append(item)
    services = Service.objects.filter(doctor__in=doctors, is_online=True).order_by('-id').values('id', 'name')
    return {
        'services': list(services),
    }


@bind_context('doctor/get_merchant/service')
def doctor_merchant_service(ctx):
    """
    获取商家可管理的美购列表
    :param ctx:
    :return:
    """
    doctor = get_doctor_from_context(ctx)
    doctors = doctor.get_merchant_doctors()
    doctor_ids = [item['doctor_id'] for item in doctors]
    services = Service.objects.filter(doctor_id__in=doctor_ids)
    return [{
                'id': item.id,
                'name': item.name
            }
            for item in services]


@bind_context('doctor/service/info')
def doctor_service_info(ctx, service_id):
    """
    根据美购id获取美购信息
    :param service_id:
    :return:
    """
    service = Service.objects.get(id=service_id)
    return {
        'service_name': service.name,
        'is_online': service.is_online,
        'doctor_name': service.doctor.name if service.doctor else ''
    }


@bind_context('doctor/service_list/info')
def doctor_service_info(ctx, service_ids):
    """
    根据美购id list获取美购信息
    :param service_ids: list
    :return: list
    """
    services = Service.objects.filter(id__in=service_ids)
    service_info_list = []
    service_info_map = {}
    for service in services:
        service_info_map[service.id] = service
    for service_id in service_ids:
        service_info = service_info_map.get(service_id)
        if service_info:
            service_info_list.append({
                'id': service_id,
                'service_name': service_info.name,
                'doctor_name': service_info.doctor.name if service_info.doctor else '',
            })
    return service_info_list


@bind_context('doctor/service/delete/list')
def service_delete_list(ctx, doctor_id, count=10, start_num=0,
                        start_time=None, end_time=None, service_register_id=None, service_id=None):
    """
        获取医生美购
        is_online: True or False
    """
    if not doctor_id:
        return gen(CODES.DOCTOR_NOT_FOUND)
    result = {
        'services': [],
        'total_count': 0,  # 总数
    }
    if isinstance(doctor_id, list):
        servicesregisters = ServiceRegister.objects.filter(doctor_id__in=doctor_id)
    else:
        servicesregisters = ServiceRegister.objects.filter(doctor_id=doctor_id)
    servicesregisters = servicesregisters.filter(service__is_delete=True)
    if start_time:
        servicesregisters = servicesregisters.filter(service__delete_time__gte=start_time)
    if end_time:
        servicesregisters = servicesregisters.filter(service__delete_time__lte=end_time)
    if service_register_id:
        servicesregisters = servicesregisters.filter(id=service_register_id)
    if service_id:
        servicesregisters = servicesregisters.filter(service_id=service_id)

    result['total_count'] = servicesregisters.count()
    result['services'] = [{
        "service_register_id": item.id,
        "service_id": item.service.id,
        "name": item.name,
        "short_description": item.short_description,
        "is_special": item.is_specialreview,
        "service_type": item.service_type,
        "doctor_name": item.doctor.name,
        "delete_time": item.service.delete_time.strftime('%Y-%m-%d %H:%M:%S'),
        'upgrade': item.upgrade
         } for item in (servicesregisters[start_num:start_num + count])]

    return result


@bind_context('doctor/service/delete')
def delete_service(ctx, service_register_id, is_delete):
    """
    删除美购
    :param ctx:
    :param service_register_id:
    :param is_delete:
    :return:
    """
    service_register = ServiceRegister.objects.get(id=service_register_id)
    if is_delete:
        if service_register.service.is_online:
           return {
               "message": u"该美购未下线，不能删除！",
               "code": 0
           }
        service_register.service.is_delete = True
        service_register.service.delete_time = datetime.now()
        service_register.service.save()
        return {
            "message": u"删除成功！",
            "code": 1
        }
    else:
        if service_register.service.is_online:
            return {
                "message": u"该美购未下线，不能做删除回复操作！",
                "code": 0
            }
        service_register.service.is_delete=False
        service_register.service.save()
        return {
            "message": u"恢复成功！",
            "code": 1
        }


@bind_context('doctor/cpc_doctor/can_use')
def doctor_can_use(ctx):
    """
    获取医生 可管理的所有医生
    如果是机构管理者，则为该机构下所有受该机构管理的医生的上线美购
    如果是普通医生，则为该医生
    :para, ctx:
    :return:
    """
    doctor = get_doctor_from_context(ctx)
    doctors = []
    doctors.append(doctor)
    if doctor.doctor_type == DOCTOR_TYPE.OFFICER:
        for item in Doctor.objects.filter(hospital=doctor.hospital, allow_hospital_agent=True):
            doctors.append(item)

    doctor_ids = []
    for doctor in doctors:
        doctor_ids.append(doctor.id)
    doctors = Doctor.objects.filter(id__in=doctor_ids, is_online=True).order_by('-id').values('id', 'name')
    return {
        'doctors': list(doctors),
    }

@bind_context('doctor/doctor_list/info')
def doctor_list_info(ctx, doctor_ids):
    """
    根据医生id list获取医生信息
    :return: list
    """
    doctors = Doctor.objects.filter(id__in=doctor_ids)
    doctor_info_list = []
    doctor_info_map = {}
    for doctor in doctors:
        doctor_info_map[doctor.id] = doctor
    for doctor_id in doctor_ids:
        doctor_info = doctor_info_map.get(doctor_id)
        if doctor_info:
            doctor_info_list.append({
                'id': doctor_id,
                'doctor_name': doctor_info.name,
            })
    return doctor_info_list


@bind_context('doctor/cpc/info')
def doctor_info(ctx, doctor_id):
    """
    根据医生id获取医生信息
    :param doctor_id:
    :return:
    """
    doctor = Doctor.objects.get(id=doctor_id)
    return {
        'is_online': doctor.is_online,
        'doctor_name': doctor.name,
    }


@bind('doctor/commodity/category/property')
def standard_category_info(id):
    """
    获取类目属性信息
    """

    category = CommodityCategory.objects.filter(id=id).first()
    res = {}
    if category.property_info:
        res = json.loads(category.property_info)
        #补充计量选项  默认为空
        res[str(CommodityCategoryProperty.MEASURE)] = []
    return res


@bind('doctor/commodity/categorys')
def standard_category_info():
    """
    获取类目属性信息
    """

    categorys = CommodityCategory.objects.all()

    # 一级类目
    level_1 = [{"id": item.id, "name": item.name} for item in categorys if item.father_id == 0]

    #类目关系
    commodity_relation_dict = defaultdict(list)
    for item in categorys:
        if not item.father_id == 0:
            commodity_relation_dict[item.father_id].append({
                'id': item.id,
                'name': item.name,
                "child": []
            })

    #组装类目
    res = []
    for one_level_1_data in level_1:
        #组装一级类目
        one_level_1_id = one_level_1_data["id"]
        level_2 = commodity_relation_dict.get(one_level_1_id, [])

        #组装二级类目
        for one_level_2_data in level_2:
            one_level_2_id = one_level_2_data["id"]
            level_3 = commodity_relation_dict.get(one_level_2_id, [])
            one_level_2_data["child"] = level_3

        one_level_1_data["child"] = level_2
        res.append(one_level_1_data)

    return res

@bind_context('doctor/services/query', login_required=True)
def doctor_all_services(ctx, filters={}):
    """
        获取美购信息
    """
    doctor = get_doctor_from_context(ctx)
    if not doctor:
        return gen(CODES.DOCTOR_NOT_FOUND)
    if doctor.merchant and MasterMerchant.objects.filter(
            mastermerchant_id=doctor.merchant.id, is_operetor_related=True).exists():
        doctors = get_doctors(doctor_id=doctor.id, only_doctor_id=False)
    else:
        doctors = get_doctors(doctor.id)
    doctor_ids = [d.get('doctor_id') for d in doctors]
    filters['doctor_id__in'] = doctor_ids
    services = Service.objects.filter(**filters).order_by('-id')
    services_tags = ServiceTag.objects.filter(service_id__in=[item.id for item in services])
    services_tag_dict = defaultdict(list)
    for item in services_tags:
        services_tag_dict[item.service_id].append(item.tag_id)

    res = {}
    for item in services:
        res[str(item.id)] = {
            "id": item.id,
            "name": item.name,
            "image_url": item.image_header,
            "tag_ids": services_tag_dict.get(item.id, [])
        }

    return res


@bind_context('doctor/service_items/query', login_required=True)
def doctor_service_items(ctx, filters={}):
    """
        获取美购信息
    """
    from api.manager.service_info_manager import get_sku_id_to_sku_name_info

    doctor = get_doctor_from_context(ctx)
    if not doctor:
        return gen(CODES.DOCTOR_NOT_FOUND)

    if filters.get("name") and not filters.get("id"):
        name = filters.pop("name")
        attr_options = AttrOptions.objects.filter(
            is_online=True,
            name__contains=name
        ).values("id")
        option_ids = [ao["id"] for ao in attr_options]
        serviceitem_ids = list(ServiceItemKey.objects.filter(
            serviceattroption_id__in=option_ids
        ).values_list("serviceitem_id", flat=True))
        filters['id__in'] = serviceitem_ids

    services_items = ServiceItem.objects.filter(**filters).order_by('-id')
    all_service_item_id=[item.id for item in services_items]
    service_item_id_to_sku_name_info=get_sku_id_to_sku_name_info(all_service_item_id,is_toc=False)

    # sku_names = ServiceItem.get_items_name([item.id for item in services_items])
    sku_names = {item.id: item.items_name for item in services_items}

    services_items_price = ServiceItemPrice.objects.filter(service_item_id__in=[item.id for item in services_items],
                                                           is_enable=True, selling_rule=None).all()

    services_items_price_dict = {item.service_item_id: item for item in services_items_price}
    service_items = {}
    for item in services_items:
        services_item_price = services_items_price_dict.get(item.id)
        service_items[str(item.id)] = {
            "id": item.id,
            "name": service_item_id_to_sku_name_info.get(str(item.id),{}).get("name",""),
            "service_id": item.service_id,
            "gengmei_price": services_item_price.gengmei_price if services_item_price else 0,
            "pre_payment_price": services_item_price.pre_payment_price if services_item_price else 0,
        }

    return service_items


@bind_context('doctor/city/info', login_required=True)
def city_info(ctx, city_id):

    city_obj = City.objects.filter(id=city_id).first()
    return {
        "id": city_obj.id,
        "name": city_obj.name,
        "province_id": city_obj.province_id,
        "province_name": city_obj.province.name,
        "region_id": city_obj.province.region.id,
        "region_name": city_obj.province.region.name,
    } if city_obj else {}


@bind_context('doctor/service/register/detail', login_required=True)
def register_service_detail(ctx, register_id):
    """
    获取注册美购详细信息
    :param ctx:
    :param register_id:
    :return:
    """
    try:
        register = ServiceRegister.objects.get(id=register_id)
    except ServiceRegister.DoesNotExist:
        return gen(CODES.NO_SERVICE_REGISTER)
    project_type = []
    if register.upgrade:
        tag_ids = list(ServiceRegisterTag.objects.filter(serviceregister_id=register_id).values_list('tag_id', flat=True))
        tag_info = list(Tag.objects.filter(id__in=tag_ids).values("id", "name"))
        project_type.extend(tag_info)
    else:
        project_type.append({
            'id':register.project_type.id,
            'name':register.project_type.name
        })

    def get_old_items(register):
        items = []
        all_item_obj_list = register.items.filter(is_delete=False)
        for item in all_item_obj_list:
            opt = ServiceRegisterItemKey.objects.filter(serviceregisteritem=item, serviceregisterattroption__is_online=True).first()

            items.append({
                'name':opt.serviceregisterattroption.name if getattr(opt, "serviceregisterattroption") else '',
                'id': item.id,
                'sort': item.sort,
                'original_price': item.original_price,
                'gengmei_price': item.gengmei_price,
                'is_online': item.is_online,
                'sku_description': item.sku_description,
                'discount': item.discount,
                'now_pre_payment': item.pre_payment_price_int,
                'serviceitem_id': item.serviceitem.id if item.serviceitem else None,
                'pre_payment_price': item.pre_payment_price_int
            })
        return items

    def get_items(register):
        items = []
        all_item_obj_list = register.items.filter(is_delete=False)
        for item in all_item_obj_list:
            items.append({
                'id': item.id,
                'sort': item.sort,
                'original_price': item.original_price,
                'gengmei_price': item.gengmei_price,
                'is_online': item.is_online,
                'sku_description': item.sku_description,
                'discount': item.discount,
                'image_header': item.image_header,
                'property_id': item.property_id,
                'now_pre_payment': item.pre_payment_price_int,
                'serviceitem_id': item.serviceitem.id if item.serviceitem else None,
                'pre_payment_price': item.pre_payment_price_int
            })
        return items

    try:
        service_review_record_obj = register.servicereviewrecord_set.order_by('-id').first()
        reason = service_review_record_obj.reason or ''
        explanation = service_review_record_obj.explanation or ''
    except:
        # 美购老数据可能没有 record
        reason = ''
        explanation = ''

    invoker = create_default_invoker(debug=settings.DEBUG)
    service_tags_info = invoker['pims/catalog/servicesregister/move_check'](registers=[register_id]).unwrap()
    hasvideo = ServiceRegisterVideo.objects.filter(serviceregister_id=register.id).exists()
    if hasvideo:
        video_info = ServiceRegisterVideo.objects.get(serviceregister_id=register.id).get_video_info()
    result = {
        'name': register.name,
        'project_type': project_type,
        'service_id': register.service.id if register.service else None,
        'id': register_id,
        'upgrade': register.upgrade,
        'short_description': register.short_description,
        'doctor_id': register.doctor_id,
        'doctor_name': register.doctor.name,
        'start_time': get_timestamp_epoch(register.start_time),
        'end_time': get_timestamp_epoch(register.end_time),
        'photo_details': register.photo_details,
        'reject_reason': reason,
        'review_status': register.review_status,
        'supplement_images': register.get_supplement_images(),
        'video_token': get_video_upload_token(),
        'video_pic': video_info['video_pic'] if hasvideo else '',
        'video_url': video_info['video_url'] if hasvideo else '',
        'turn_down_reason': reason,
        'image_header': register.image_header,
        'service_type': register.service_type,
        'is_specialreview': register.is_specialreview,
        'is_move': service_tags_info['result'].get(str(register.id), False),
        'reservation': register.reservation,
        'have_extra_pay': register.have_extra_pay,
        'extra_pay_info': register.extra_pay_info,
        'is_draft': register.is_draft,
        'explanation': explanation,
        'recommend_services': register.get_recommend_services(),
        'items': get_items(register) if register.upgrade else [],
        'old_items': get_old_items(register) if not register.upgrade else []
    }
    return result