from BaseModels.api.base_api_views import *
from .user_api_serializars import *
from ...api_permissions import Auth_API_perms
from datetime import datetime
from rest_framework.decorators import action
from django.db.models import Sum, FloatField, F, Value as V, Q, Count
from django.db.models.functions import Concat
import json
from BaseModels.mailSender import techSendMail
from operator import itemgetter
from rest_framework import status
from CompaniesApp.models import Company, DeliveryData
from BaseModels.api.api_inter import check_and_get_specific_output_format
from django.contrib.contenttypes.models import ContentType
from ..permissions.personal_api_permissions import Personal_API_perms

from B2BApp.funcs import pay_terms_for_report_list


def get_kwargs_by_get_query_params(request):
    kwargs = {}
    stat_kwargs = {}

    if not request.user.has_perm('AuthApp.UI_managers_all_stat'):
        kwargs.update({'id': request.user.id})

    if not request.query_params:
        return kwargs, stat_kwargs
    else:

        try:

            params = request.query_params

            for param_key, param_val in params.items():

                if 'for_managers_stat_DT_from' == param_key:
                    # param_key = 'orders_for_manager__delivery_DT__gte'
                    param_key = 'delivery_DT__gte'
                    kwargs.update({
                        param_key: datetime.strptime(param_val, '%Y-%m-%d %H:%M')
                    })
                elif 'for_managers_stat_DT_to' == param_key:
                    # param_key = 'orders_for_manager__delivery_DT__lte'
                    param_key = 'delivery_DT__lte'
                    kwargs.update({
                        param_key: datetime.strptime(param_val, '%Y-%m-%d %H:%M')
                    })

                elif '_D_from' in param_key:
                    param_key = param_key.replace('_from', '__gte')
                    kwargs.update({
                        param_key: datetime.strptime(param_val, '%Y-%m-%d')
                    })
                elif '_D_to' in param_key:
                    param_key = param_key.replace('_to', '__lte')
                    kwargs.update({
                        param_key: datetime.strptime(param_val, '%Y-%m-%d')
                    })

                elif param_key == 'regions':
                    param_val = json.loads(param_val)
                    kwargs.update({
                        'company__region__in'.format(param_key): param_val
                    })


                elif 'rel_products_in_order_for_product__order__delivery_DT_from' in param_key:

                    # param_key = 'orders_for_manager__delivery_DT__gte'
                    param_key = 'delivery_DT__gte'

                    kwargs.update({

                        param_key: datetime.strptime(param_val, '%Y-%m-%d %H:%M')

                    })

                elif 'rel_products_in_order_for_product__order__delivery_DT_to' in param_key:

                    param_key = 'orders_for_manager__delivery_DT__lte'
                    # param_key = 'delivery_DT__lte'

                    kwargs.update({

                        param_key: datetime.strptime(param_val, '%Y-%m-%d %H:%M')

                    })

                # only_stat_kwargs
                elif '_from' in param_key:
                    param_key = param_key.replace('_from', '__gte')
                    stat_kwargs.update({
                        param_key: param_val
                    })
                elif '_to' in param_key:
                    param_key = param_key.replace('_to', '__lte')
                    stat_kwargs.update({
                        param_key: param_val
                    })
                # ---------------------

                elif param_key in ('pay_terms', 'status'):
                    param_val = json.loads(param_val)
                    kwargs.update({
                        '{0}__in'.format(param_key): param_val
                    })

                elif param_key in ['manager_obj', '']:
                    kwargs.update({
                        '{0}__id'.format(param_key): param_val
                    })

                elif param_key in ['series_name']:
                    param_val = json.loads(param_val)
                    kwargs.update({
                        # 'orders_for_manager__rel_products_in_order_for_order__product__product_series__id__in': param_val
                        'rel_products_in_order_for_order__product__product_series__id__in': param_val
                    })

                elif param_key in ['brand_name']:
                    param_val = json.loads(param_val)
                    kwargs.update({
                        # 'orders_for_manager__rel_products_in_order_for_order__product__brand__id__in': param_val
                        'rel_products_in_order_for_order__product__brand__id__in': param_val
                    })
                elif param_key == 'enable':
                    param_val = json.loads(param_val)
                    kwargs.update({
                        # 'orders_for_manager__rel_products_in_order_for_order__product__enable': param_val
                        'rel_products_in_order_for_order__product__enable': param_val
                    })

        except Exception as e:
            msg = 'Ошибка разбора параметров фильтра<br>{0}({1})<br>{2}'.format(
                str(e),
                str(e.args),
                str(request.query_params)
            )
            print(msg)
            title = 'ОШИБКА tE AuthApp get_kwargs_by_get_query_params'
            techSendMail(msg, title)

    return kwargs, stat_kwargs


def get_sales_for_managers_by_goods(user, objs, ord_kwargs, receipts_kwargs, stat_kwargs=None):
    objs_ids = objs.values_list('id', flat=True)
    objs_ids = list(objs_ids)

    from B2BApp.models import ProductInReceipt, ProductInOrder
    from django.db.models import Sum, FloatField, F

    prod_in_orders = ProductInOrder.objects.filter(
        order__status_shipment='shipped',
        order__defective_goods=False,
        order__manager_obj__id__in=objs_ids,
        **ord_kwargs
        # ).exclude(
        #     order__pay_terms='no_pay'
    )

    allow_values_in_orders = [
        'id', 'sales_count',
        # 'paid_sum',
        'order__manager_obj__id'
    ]

    allow_values_in_receipts = [
        'id', 'receipts_count',
        'receipt__company__manager_obj__id'
    ]

    if user.has_perm('B2BApp.UI_show_summ_for_sales'):
        allow_values_in_orders.append('sales_sum')
        allow_values_in_receipts.append('receipts_sum')

    prod_in_orders = prod_in_orders.annotate(
        sales_count=F('count'),
        sales_sum=F('product_sum_byn'),
        # paid_sum=F('order__paid_sum_byn')
    ).values(
        *allow_values_in_orders
    ).order_by('order__manager_obj__id')

    prod_in_orders = list(prod_in_orders)

    prod_in_receipts = ProductInReceipt.objects.filter(
        receipt__receipt_type='return',
        receipt__company__manager_obj__id__in=objs_ids,
        **receipts_kwargs
    )

    prod_in_receipts = prod_in_receipts.annotate(
        receipts_count=Sum('count',
                           output_field=FloatField()),
        receipts_sum=Sum('product_sum_byn'),
    ).values(
        *allow_values_in_receipts
    ).order_by('receipt__company__manager_obj__id')

    prod_in_receipts = list(prod_in_receipts)

    objs = list(objs)
    objs.sort(key=itemgetter('full_name'), reverse=False)

    objs_i = 0
    while objs_i < len(objs):
        obj = objs[objs_i]
        obj['sales_count'] = 0
        obj['sales_sum'] = 0
        # obj['paid_sum'] = 0
        i = 0
        while i < len(prod_in_orders):
            if obj['id'] == prod_in_orders[i]['order__manager_obj__id']:
                obj['sales_count'] += prod_in_orders[i]['sales_count']
                if 'sales_sum' in prod_in_orders[i]:
                    obj['sales_sum'] += prod_in_orders[i]['sales_sum']
                # obj['paid_sum'] += prod_in_orders[i]['paid_sum']
                del prod_in_orders[i]
                # break
            else:
                i += 1

        i = 0
        while i < len(prod_in_receipts):
            if obj['id'] == prod_in_receipts[i]['receipt__company__manager_obj__id']:
                obj['sales_count'] -= prod_in_receipts[i]['receipts_count']
                if 'receipts_sum' in prod_in_receipts[i]:
                    obj['sales_sum'] -= prod_in_receipts[i]['receipts_sum']

                del prod_in_receipts[i]
                # break
            else:
                i += 1

        if stat_kwargs:
            if stat_kwargs and 'sales_count__gte' in stat_kwargs and stat_kwargs['sales_count__gte'] and objs[objs_i][
                'sales_count'] < float(stat_kwargs['sales_count__gte']):
                del objs[objs_i]
            elif stat_kwargs and 'sales_count__lte' in stat_kwargs and stat_kwargs['sales_count__lte'] and objs[objs_i][
                'sales_count'] > float(stat_kwargs['sales_count__lte']):
                del objs[objs_i]
            elif stat_kwargs and 'sales_sum__gte' in stat_kwargs and stat_kwargs['sales_sum__gte'] and objs[objs_i][
                'sales_sum'] < float(stat_kwargs['sales_sum__gte']):
                del objs[objs_i]
            elif stat_kwargs and 'sales_sum__lte' in stat_kwargs and stat_kwargs['sales_sum__lte'] and objs[objs_i][
                'sales_sum'] > float(stat_kwargs['sales_sum__lte']):
                del objs[objs_i]

            else:
                objs[objs_i]['sales_count'] = round(objs[objs_i]['sales_count'], 2)
                objs[objs_i]['sales_sum'] = round(objs[objs_i]['sales_sum'], 2)

                objs_i += 1
        else:
            objs_i += 1

    return objs


def get_sales_for_managers_by_orders(objs, ord_kwargs, receipts_kwargs, pay_kwargs, stat_kwargs=None):
    from datetime import date, timedelta
    from collections import OrderedDict

    chart_data_Dict = {}

    try:

        from_date = None
        to_date = None

        objs_ids = objs.values_list('id', flat=True)
        objs_ids = list(objs_ids)

        from B2BApp.models import Order, ReceiptDocument, Pay
        orders = Order.objects.filter(
            status_shipment='shipped',
            defective_goods=False,
            manager_obj__id__in=objs_ids,
            **ord_kwargs
        )

        if orders:
            from_date = orders.order_by('delivery_DT')[0].delivery_DT.date()
            to_date = orders.order_by('-delivery_DT')[0].delivery_DT.date()

        orders = orders.annotate(
            sales_count=Sum('rel_products_in_order_for_order__count',
                            output_field=FloatField()),
            sales_sum=F('order_sum_byn'),
            paid_sum=F('paid_sum_byn')
        ).values(
            'id', 'sales_count', 'sales_sum', 'delivery_DT',
            'paid_sum', 'pay_type',
            'manager_obj__id', 'company__name'
        ).order_by('manager_obj__id')

        orders = list(orders)

        receipts = ReceiptDocument.objects.filter(
            receipt_type='return',
            manager_obj__id__in=objs_ids,
            **receipts_kwargs
        )

        if receipts:
            from_date_tmp = receipts.order_by('receipt_D')[0].receipt_D
            if not from_date or from_date_tmp < from_date:
                from_date = from_date_tmp
            to_date_tmp = receipts.order_by('-receipt_D')[0].receipt_D
            if not to_date or to_date_tmp > to_date:
                to_date = to_date_tmp

        receipts = receipts.annotate(
            receipts_count=Sum('rel_products_in_receipt_for_receipt__count',
                               output_field=FloatField()),
            receipts_sum=Sum('rel_products_in_receipt_for_receipt__product_sum_byn'),
        ).values(
            'id', 'receipts_count', 'receipts_sum', 'manager_obj__id', 'pay_type', 'receipt_D'  # , 'company__name'
        ).order_by('manager_obj__id')

        receipts = list(receipts)

        pays = Pay.objects.filter(
            manager__id__in=objs_ids,
            **pay_kwargs
        )

        if pays:
            from_date_tmp = pays.order_by('oper_D')[0].oper_D
            if not from_date or from_date_tmp < from_date:
                from_date = from_date_tmp
            to_date_tmp = pays.order_by('-oper_D')[0].oper_D
            if not to_date or to_date_tmp > to_date:
                to_date = to_date_tmp

        pay_objs = pays.values(
            'id', 'oper_D', 'sum_pay_byn', 'manager__id',
            'shipment_doc__id', 'shipment_doc__rel_orders_for_documents',
            'shipment_doc__rel_orders_for_documents__manager_obj__id',
            'company__id', 'bank_doc_D'
        ).order_by('oper_D', 'company__name')
        # ).order_by('company__manager_obj__id', 'oper_D')

        pays = list(pay_objs)

        # from CompaniesApp.models import Document
        # its = Pay.objects.filter(documents__id=30069)

        objs = list(objs)
        objs.sort(key=itemgetter('full_name'), reverse=False)

        if from_date:
            from_DT = from_date
        else:
            from_DT = date(year=2000, month=1, day=1)

        if to_date:
            to_DT = to_date + timedelta(days=1)
        else:
            to_DT = datetime.now().date() + timedelta(days=1)

        chart_data_Dict = OrderedDict({
            str(from_DT + timedelta(n)): {
                'sales_count': 0,
                'sales_sum': 0,
                'paid_sum': 0,
                'paid_cash': 0,
                'paid_invoice': 0
            } for n in range(int((to_DT - from_DT).days) + 1)
        })

        total_pays_cash = 0
        total_pays_invoice = 0

        objs_i = 0
        while objs_i < len(objs):
            obj = objs[objs_i]
            # if obj['id'] == 31:
            #     print('!')

            orders_items = []
            receipts_items = []
            pays_items = []
            obj['sales_count'] = 0
            obj['sales_sum'] = 0
            obj['paid_sum'] = 0
            obj['paid_cash'] = 0
            i = 0
            while i < len(orders):
                if obj['id'] == orders[i]['manager_obj__id']:
                    if orders[i]['sales_count']:
                        obj['sales_count'] += orders[i]['sales_count']
                    if orders[i]['sales_sum']:
                        obj['sales_sum'] += orders[i]['sales_sum']
                        chart_data_Dict[str(orders[i]['delivery_DT'].date())]['sales_sum'] += round(
                            orders[i]['sales_sum'], 2)
                    if orders[i]['pay_type'] == 'cash' and orders[i]['paid_sum']:
                        obj['paid_cash'] += orders[i]['paid_sum']
                        chart_data_Dict[str(orders[i]['delivery_DT'].date())]['paid_cash'] += round(
                            orders[i]['paid_sum'], 2)
                        chart_data_Dict[str(orders[i]['delivery_DT'].date())]['paid_sum'] += round(
                            orders[i]['paid_sum'], 2)

                    orders_items.append(orders[i])

                    del orders[i]

                    # break
                else:
                    i += 1

            i = 0
            while i < len(receipts):
                if obj['id'] == receipts[i]['manager_obj__id']:
                    if receipts[i]['receipts_count']:
                        obj['sales_count'] -= receipts[i]['receipts_count']
                    if receipts[i]['receipts_sum']:
                        obj['sales_sum'] -= receipts[i]['receipts_sum']
                        chart_data_Dict[str(receipts[i]['receipt_D'])]['sales_sum'] -= round(
                            receipts[i]['receipts_sum'], 2)
                    receipts_items.append(receipts[i])

                    if receipts[i]['pay_type'] == 'cash':
                        if receipts[i]['receipts_sum']:
                            obj['paid_cash'] -= receipts[i]['receipts_sum']
                            chart_data_Dict[str(receipts[i]['receipt_D'])]['paid_cash'] -= round(
                                receipts[i]['receipts_sum'], 2)

                            chart_data_Dict[str(receipts[i]['receipt_D'])]['paid_sum'] -= round(
                                receipts[i]['receipts_sum'], 2)

                    del receipts[i]

                    # break
                else:
                    i += 1

            i = 0
            obj['paid_invoice'] = 0
            while i < len(pays):

                if obj['id'] == pays[i]['manager__id'] and pays[i]['sum_pay_byn']:

                    # if pays[i]['id'] == 2879:
                    #     print('!')

                    obj['paid_invoice'] += pays[i]['sum_pay_byn']
                    pays_items.append(pays[i])

                    chart_data_Dict[str(pays[i]['oper_D'])]['paid_invoice'] += round(pays[i]['sum_pay_byn'], 2)
                    chart_data_Dict[str(pays[i]['oper_D'])]['paid_sum'] += round(pays[i]['sum_pay_byn'], 2)

                    del pays[i]
                # elif obj['id'] == pays[i]['shipment_doc__rel_orders_for_documents__manager_obj__id']:
                #     obj['paid_sum'] += pays[i]['sum_pay_byn']
                #     pays_items.append(pays[i])
                #     del pays[i]
                # break
                else:
                    i += 1

            if stat_kwargs:
                if stat_kwargs and 'sales_count__gte' in stat_kwargs and stat_kwargs['sales_count__gte'] and \
                        objs[objs_i][
                            'sales_count'] < float(stat_kwargs['sales_count__gte']):
                    del objs[objs_i]
                elif stat_kwargs and 'sales_count__lte' in stat_kwargs and stat_kwargs['sales_count__lte'] and \
                        objs[objs_i][
                            'sales_count'] > float(stat_kwargs['sales_count__lte']):
                    del objs[objs_i]
                elif stat_kwargs and 'sales_sum__gte' in stat_kwargs and stat_kwargs['sales_sum__gte'] and objs[objs_i][
                    'sales_sum'] < float(stat_kwargs['sales_sum__gte']):
                    del objs[objs_i]
                elif stat_kwargs and 'sales_sum__lte' in stat_kwargs and stat_kwargs['sales_sum__lte'] and objs[objs_i][
                    'sales_sum'] > float(stat_kwargs['sales_sum__lte']):
                    del objs[objs_i]

                else:
                    objs[objs_i]['sales_count'] = round(objs[objs_i]['sales_count'], 2)
                    objs[objs_i]['sales_sum'] = round(objs[objs_i]['sales_sum'], 2)

                    objs_i += 1
            else:
                objs_i += 1

            obj['paid_sum'] = obj['paid_cash'] + obj['paid_invoice']

            # obj['sales_count'] = round(obj['sales_count'], 2)
            # obj['sales_sum'] = round(obj['sales_sum'], 2)
            obj['paid_sum'] = round(obj['paid_sum'], 2)

            total_pays_cash += obj['paid_cash']
            total_pays_invoice += obj['paid_invoice']

            # print('{0}. ord_count={1}, recepts_count={2}'.format(obj['full_name'], len(orders_items), len(receipts_items)))

    except Exception as e:
        msg = 'Ошибка сбора статистики<br>{0}({1})'.format(
            str(e),
            str(e.args),
        )
        print(msg)
        title = 'ОШИБКА tE AuthApp get_sales_for_managers_by_orders'
        techSendMail(msg, title)

    return objs, chart_data_Dict


class v1_Personal_ViewSet(APIViewSet_ModelClass):
    queryset = User.objects.filter().order_by('last_name', 'first_name')
    serializer_class = Personal_list_Serializer
    permission_classes = (Personal_API_perms,)

    def get_serializer_class(self):

        try:
            if self.action == 'list':
                return Personal_list_Serializer
            if self.action == 'add_communication_item':
                from GeneralApp.api.v1.communications.communications_api_serializers import \
                    Communications_create_Serializer
                return Communications_create_Serializer
            if self.action == 'retrieve':
                return Personal_list_Serializer
            if self.action == 'change_mailing_status':
                return Personal_change_mailing_status_Serializer

        except (KeyError, AttributeError):
            pass

        return super(v1_Personal_ViewSet, self).get_serializer_class()

    def get_queryset(self, *args, **kwargs):

        user = self.request.user
        if not user or user.is_anonymous or not user.is_active:
            return []

        persons = super(v1_Personal_ViewSet, self).get_queryset()
        persons = persons.exclude(is_superuser=True)

        if user.has_perm('AuthApp.UI_company_staff_modify_any') or user.has_perm(
                'AuthApp.UI_company_staff_retrieve_any_no_staff'):
            return persons.filter(user_profile__enable=True)
        elif user.has_perm('AuthApp.UI_company_staff_modify_if_manager'):
            persons = persons.filter(
                # user_profile__company_obj__manager_obj=user,
                user_profile__enable=True
            )
            return persons
        elif user.has_perm('AuthApp.UI_company_staff_modify_if_staff_company'):
            persons = persons.filter(
                user_profile__company_obj=user.user_profile.company_obj,
                user_profile__enable=True
            )
            return persons

        return []

    @action(methods=['GET'], detail=False)
    def possible_departaments_list(self, request, *args, **kwargs):

        data_list = UserProfile.objects.exclude(
            departament=None
        ).exclude(
            company_position=''
        ).values_list('departament', flat=True).order_by('departament').distinct()
        return Response(data_list)

    @action(methods=['PATCH'], detail=True)
    def change_mailing_status(self, request, *args, **kwargs):
        from MailingApp.models import Mailing

        obj = self.get_object()

        data = request.data

        res = obj.user_profile.change_mailing_status(data['mailing_ID'], data['mailing_status'])

        return Response(res)

    @action(methods=['GET'], detail=True)
    def possible_mailings(self, request, *args, **kwargs):
        from MailingApp.models import Mailing

        person = self.get_object()

        if not person or not person.user_profile or not person.user_profile.company_obj or \
                not person.user_profile.company_obj.manager_obj:
            raise serializers.ValidationError(
                u'user is not connected w company'
            )

        manager_of_person = person.user_profile.company_obj.manager_obj

        if manager_of_person != request.user:
            from AuthApp.funcs import get_subordinate_staff
            subordinate_users_for_cur_user = get_subordinate_staff(request.user)
            if not manager_of_person in subordinate_users_for_cur_user:
                raise serializers.ValidationError(
                    u'нет прав для доступа к управлению рассылкой'
                )

        mailings = request.user.user_profile.get_allow_mailings(for_user=person)
        if mailings:
            mailings = list(
                mailings.values('id', 'name', 'enable', 'pass_weekends', 'last_send_DT', 'next_send_DT', 'creator__id',
                                'creator_name'))

        connected_mailings_ids = person.user_profile.connected_mailings.all().values_list('id', flat=True)

        for mailing in mailings:
            if mailing['id'] in connected_mailings_ids:
                mailing['connected'] = True
            else:
                mailing['connected'] = False

            if mailing['next_send_DT']:
                mailing['next_send_DT'] = str(mailing['next_send_DT'])
            if mailing['last_send_DT']:
                mailing['last_send_DT'] = str(mailing['last_send_DT'])

        return Response(mailings)

    @action(methods=['GET'], detail=False)
    def possible_company_positions_list(self, request, *args, **kwargs):

        data_list = UserProfile.objects.exclude(
            company_position=None
        ).exclude(
            company_position=''
        ).values_list('company_position', flat=True).order_by('company_position').distinct()
        return Response(data_list)

    @action(methods=['GET'], detail=True)
    def get_connected_mailings(self, request, *args, **kwargs):

        obj = self.get_object()
        data_list = obj.user_profile.get_connected_mailings().values('id', 'name', 'enable')
        return Response(data_list)

    @action(methods=['POST'], detail=True)
    def add_communication_item(self, request, *args, **kwargs):

        data = request.data
        if not 'connection_name' in data or not 'connection_value' in data:
            raise serializers.ValidationError(
                u'Ошибка, недостаточно данных'
            )

        obj = self.get_object()

        from GeneralApp.views import create_communication_item

        ct = ContentType.objects.get_for_model(obj.user_profile)
        res = create_communication_item(ct, obj.user_profile.id, data)
        if 'error' in res:
            raise serializers.ValidationError(res['error'])

        serializer = Personal_list_Serializer(obj)

        return Response(serializer.data)

    def list(self, request, *args, **kwargs):

        filter_kwargs, stat_kwargs = get_kwargs_by_get_query_params(request)

        res = check_and_get_specific_output_format(self, data=None, filename='personal_list.xlsx')
        if res:
            return res

        return super(v1_Personal_ViewSet, self).list(request, *args, **kwargs)

    @action(methods=['GET'], detail=True)
    def list_by_company_id(self, request, *args, **kwargs):
        if not kwargs or not 'pk' in kwargs:
            raise serializers.ValidationError(
                u'Ошибка, не указан id компании'
            )

        try:
            company = Company.objects.get(id=kwargs['pk'])
        except Company.DoesNotExist:
            raise serializers.ValidationError(
                u'Ошибка, неверный id компании'
            )

        personal_objs = self.get_queryset().filter(user_profile__company_obj=company)
        serializer = Personal_list_Serializer(personal_objs, many=True)

        res = check_and_get_specific_output_format(self, serializer.data, '{0}_personal.xlsx'.format(str(company.name)))
        if res:
            return res

        data = serializer.data

        return Response(data)

    @action(methods=['GET'], detail=True)
    def list_by_office_id(self, request, *args, **kwargs):
        if not kwargs or not 'pk' in kwargs:
            raise serializers.ValidationError(
                u'Ошибка, не указан id подразделения'
            )

        try:
            office = DeliveryData.objects.get(id=kwargs['pk'])
        except DeliveryData.DoesNotExist:
            raise serializers.ValidationError(
                u'Ошибка, неверный id компании'
            )

        personal_objs = self.queryset.filter(user_profile__office=office)
        serializer = Personal_list_Serializer(personal_objs, many=True)

        res = check_and_get_specific_output_format(self, data=serializer.data,
                                                   filename='{0}_personal.xlsx'.format(str(office.name)))
        if res:
            return res

        return Response(serializer.data)

    def partial_update(self, request, *args, **kwargs):
        user = self.get_object()

        data = request.data

        if 'id' in data and not data['id']:
            return Response({'error': 'Изменение невозможно. Нет идентификатора пользователя'},
                            status=status.HTTP_400_BAD_REQUEST)

        if 'email' in data and not data['email']:
            return Response({'error': 'Изменение невозможно. Нет email идентификатора пользователя'},
                            status=status.HTTP_400_BAD_REQUEST)

        users = User.objects.filter(
            id=user.id
        )

        if not users:
            return Response({'error': 'Изменение невозможно. Пользователь не найден'},
                            status=status.HTTP_400_BAD_REQUEST)

        company = None
        profile_data = None
        if 'user_profile' in data:
            profile_data = data['user_profile']
            if 'company_obj' in profile_data and profile_data['company_obj']:
                try:
                    company = Company.objects.get(id=profile_data['company_obj'])
                    profile_data['company_obj'] = company

                except Company.DoesNotExist:
                    return Response({'error': u'Компания не существует'},
                                    status=status.HTTP_400_BAD_REQUEST)

            office = None
            if 'office' in profile_data and profile_data['office']:
                try:
                    office = DeliveryData.objects.get(id=profile_data['office'])
                    profile_data['office'] = office
                except Company.DoesNotExist:
                    return Response({'error': u'Подразделение не существует'},
                                    status=status.HTTP_400_BAD_REQUEST)

            if 'id' in profile_data:
                del profile_data['id']
            if 'office__name' in profile_data:
                del profile_data['office__name']

        user_data = data

        if profile_data:
            del user_data['user_profile']
        if 'id' in user_data:
            del user_data['id']
        if 'full_name' in user_data:
            del user_data['full_name']
        if 'email' in user_data:
            user_data['username'] = user_data['email']

        if users.count() > 1:
            return Response({'error': u'Ошибка, найдено более одного пользователя, соответствующего id'},
                            status=status.HTTP_400_BAD_REQUEST)

        users.update(**user_data)
        user = users.first()

        if profile_data:
            UserProfile.objects.filter(user=user).update(**profile_data)

            if 'mailing_sets' in profile_data:
                if not company and user.user_profile:
                    company = user.user_profile.company_obj
                if company:
                    company.update_mailing_on()

        serializer = Personal_list_Serializer(user)
        data = serializer.data

        # data.update(get_editable_fields_list_Dict(request.user, self.action, serializer.Meta.fields))

        return Response(data)

    def create(self, request, *args, **kwargs):

        data = request.data

        serializer = self.get_serializer_class()(data=data)
        if not serializer.is_valid():
            raise serializers.ValidationError(serializer.errors)

        errors_Dict = {}

        if not 'email' in data or not data['email']:
            errors_Dict.update({'email': 'обязательное поле'})
            # return Response(
            #     {
            #         'errors': {
            #             'Создание невозможно. Не не введен email'
            #         }
            #     },
            #     status=status.HTTP_400_BAD_REQUEST
            # )
        else:

            try:
                user = User.objects.get(
                    email=data['email']
                )

                errors_Dict.update({'email': 'Создание невозможно. Пользователь с указанным email уже существует'})

                # return Response({'error': u'Создание невозможно. Пользователь с указанным email уже существует'},
                #                 status=status.HTTP_400_BAD_REQUEST)

            except User.DoesNotExist:
                pass

        company = None
        office = None
        if 'office' in data['user_profile'] and data['user_profile']['office']:
            try:
                office = DeliveryData.objects.get(id=data['user_profile']['office'])
                data['user_profile']['office'] = office
                company = office.company
            except Company.DoesNotExist:
                return Response({'error': u'Подразделение не существует'},
                                status=status.HTTP_400_BAD_REQUEST)

        if not company and ('company_obj' in data['user_profile'] and data['user_profile']['company_obj']):
            try:
                company = Company.objects.get(id=data['user_profile']['company_obj'])
                data['user_profile']['company_obj'] = company
            except Company.DoesNotExist:
                return Response({'error': u'Компания не существует'},
                                status=status.HTTP_400_BAD_REQUEST)

        if 'creator' in data['user_profile'] and data['user_profile']['creator']:
            try:
                creator = User.objects.get(id=data['user_profile']['creator'])
                data['user_profile']['creator'] = company
            except Company.DoesNotExist:
                pass
                # return Response({'error': u'Пользователь не существует'},
                #                 status=status.HTTP_400_BAD_REQUEST)

        if errors_Dict:
            raise serializers.ValidationError(errors_Dict)
            # return Response({
            #     'errors': errors_Dict
            # })

        from ....views import create_personal_user
        res = create_personal_user(data, request.user)
        if 'error' in res:
            raise serializers.ValidationError(res['error'])
            # return Response({'error': res['error']},
            #                 status=status.HTTP_400_BAD_REQUEST)

        serializer = Personal_list_Serializer(res['user'])
        data = serializer.data

        # data.update(get_editable_fields_list_Dict(request.user, self.action, serializer.Meta.fields))

        return Response(data)


class v1_Managers_ViewSet(APIViewSet_ModelClass):
    queryset = User.objects.filter(is_staff=True).order_by('last_name', 'first_name')
    serializer_class = User_list_Serializer
    permission_classes = (Auth_API_perms,)

    def get_serializer_class(self):

        try:
            if self.action == 'list':
                return User_list_Serializer
            if self.action == 'retrieve':
                return User_list_Serializer

        except (KeyError, AttributeError):
            pass

        return super(v1_Managers_ViewSet, self).get_serializer_class()

    def get_queryset(self, *args, **kwargs):

        user = self.request.user
        if user.has_perm('AuthApp.UI_managers_all_stat'):
            managers = User.objects.filter(
                is_staff=True,
            )
        else:
            managers = User.objects.filter(
                id=user.id,
                is_staff=True,
            )

        managers = managers.order_by('-is_active', 'last_name', 'first_name')

        # if self.action in ('stat_list', ):
        #
        #     filter_kwargs, stat_kwargs = get_kwargs_by_get_query_params(self.request)
        #     if kwargs:
        #         filter_kwargs.update(kwargs)
        #
        #     managers = managers.filter(
        #
        #         orders_for_manager__status_shipment='shipped',
        #         orders_for_manager__defective_goods=False,
        #         **filter_kwargs
        #     ).annotate(
        #         # sales_count=Sum('orders_for_manager__rel_products_in_order_for_order__count',
        #         #                 output_field=FloatField()),
        #         # sales_sum=Sum('orders_for_manager__rel_products_in_order_for_order__product_sum_byn',
        #         #               output_field=FloatField()),
        #         # paid_sum=Sum('orders_for_manager__paid_sum_byn',
        #         #               output_field=FloatField()),
        #         full_name=Concat(F('last_name'), V(' '), F('first_name'))
        #     ).filter(
        #         **stat_kwargs
        #     ).order_by(
        #         'full_name'
        #     ).distinct()
        #     # return managers
        #
        #
        # if self.action in ('get_sales_stat_by_productid', ):
        #
        #     filter_kwargs, stat_kwargs = get_kwargs_by_get_query_params(self.request)
        #     if kwargs:
        #         filter_kwargs.update(kwargs)
        #
        #     managers = managers.filter(
        #         is_staff=True,
        #         orders_for_manager__status_shipment='shipped',
        #         orders_for_manager__defective_goods=False,
        #         **filter_kwargs
        #     ).annotate(
        #         # sales_count=Sum('orders_for_manager__rel_products_in_order_for_order__count',
        #         #                 output_field=FloatField()),
        #         # sales_sum=Sum('orders_for_manager__rel_products_in_order_for_order__product_sum_byn',
        #         #               output_field=FloatField()),
        #         # paid_sum=Sum('orders_for_manager__paid_sum_byn',
        #         #               output_field=FloatField()),
        #         full_name=Concat(F('last_name'), V(' '), F('first_name'))
        #     ).filter(
        #         **stat_kwargs
        #     ).order_by(
        #         'full_name'
        #     ).distinct()
        # return managers
        # else:
        #     if self.request.user:
        #         user = self.request.user
        #         if user.active and not self.request.user.is_anonymus:
        #             managers = User.objects.filter(id=user.id)
        #             return managers

        # return super(v1_Managers_ViewSet, self).get_queryset()
        return managers

    def list(self, request, *args, **kwargs):
        res = check_and_get_specific_output_format(self, data=None, filename='managers_list.xlsx')
        if res:
            return res

        res = super(v1_Managers_ViewSet, self).list(request, *args, **kwargs)
        return res

    @action(methods=['GET'], detail=False)
    def get_all_staff(self, request, *args, **kwargs):

        from ....funcs import get_all_staff
        objs = get_all_staff()
        serializer = self.get_serializer_class()(objs, many=True)
        return Response(serializer.data)

    @action(methods=['GET'], detail=False)
    def get_sales_managers_only(self, request, *args, **kwargs):

        from ....funcs import get_sales_managers
        objs = get_sales_managers()
        serializer = self.get_serializer_class()(objs, many=True)
        return Response(serializer.data)

    @action(methods=['GET'], detail=False)
    def get_sales_department_staff(self, request, *args, **kwargs):

        from ....funcs import get_sales_department_staff
        objs = get_sales_department_staff()
        serializer = self.get_serializer_class()(objs, many=True)
        return Response(serializer.data)

    @action(methods=['GET'], detail=False)
    def get_sales_department_staff(self, request, *args, **kwargs):

        from ....funcs import get_sales_department_staff
        objs = get_sales_department_staff()
        serializer = self.get_serializer_class()(objs, many=True)
        return Response(serializer.data)

    @action(methods=['GET'], detail=False)
    def get_subordinate_staff(self, request, *args, **kwargs):
        objs = None

        if request.user.is_superuser:
            objs = self.get_queryset()
        else:
            from ....funcs import get_subordinate_staff
            objs = get_subordinate_staff(request.user, include_cur_user=True)

        if not objs:
            objs = self.get_queryset().filter(id=request.user.id)

        serializer = self.get_serializer_class()(objs, many=True)
        return Response(serializer.data)

    @action(methods=['GET'], detail=False)
    def stat_list(self, request, *args, **kwargs):

        filter_kwargs, stat_kwargs = get_kwargs_by_get_query_params(request)

        period_from = None
        period_to = None
        region_ids = None
        if 'delivery_DT__gte' in filter_kwargs:
            period_from = filter_kwargs['delivery_DT__gte']
        if 'delivery_DT__lte' in filter_kwargs:
            period_to = filter_kwargs['delivery_DT__lte']
        if 'company__region__in' in filter_kwargs:
            region_ids = filter_kwargs['company__region__in']

        from ....stat_funcs import managers_sales_by_period_n_regions
        managers, chart_Data = managers_sales_by_period_n_regions(
            period_from=period_from, period_to=period_to,
            region_ids=region_ids
        )

        if request.query_params and 'chart' in request.query_params and request.query_params[
            'chart'] == 'line':
            return Response(chart_Data)
        else:
            return Response(managers)

        res = check_and_get_specific_output_format(self, data=managers, filename='managers_stat.xlsx')
        if res:
            return res

        return Response(managers)

    @action(methods=['GET'], detail=True)
    def get_sales_stat_by_productid(self, request, *args, **kwargs):
        from django.db.models import Sum, FloatField, F, Value as V

        filter_kwargs, stat_kwargs = get_kwargs_by_get_query_params(request)

        ords_kwargs = {}

        ords_kwargs.update({
            'enable': True,
            'status_shipment': 'shipped',
            'defective_goods': False,
            'rel_products_in_order_for_order__product__id': kwargs['pk']
        })

        rec_kwargs = {
            'receipt_type': 'return',
            'enable': True,
        }

        for key, val in filter_kwargs.items():
            if 'delivery_DT__gte' in key:
                ords_kwargs.update({'delivery_DT__gte': val})
                rec_kwargs.update({'receipt_D__gte': val})

            elif 'delivery_DT__lte' in key:
                ords_kwargs.update({'delivery_DT__lte': val})
                rec_kwargs.update({'receipt_D__lte': val})
            elif 'company__region__in' in key:
                ords_kwargs.update({key: val})
                rec_kwargs.update({'company__region__in': val})
            else:
                ords_kwargs.update({key: val})

        if kwargs and 'pk' in kwargs:
            rec_kwargs.update({
                'rel_products_in_receipt_for_receipt__product__id': kwargs['pk']
            })

        # print(str(ords_kwargs))
        from B2BApp.models import Order, ReceiptDocument
        ords_ids = Order.objects.filter(
            **ords_kwargs
        ).exclude(
            pay_terms='no_pay'
        ).values_list('id', flat=True)

        receipts_ids = ReceiptDocument.objects.filter(
            **rec_kwargs
        ).values_list('id', flat=True)

        managers = self.get_queryset().annotate(
            full_name=Concat(F('last_name'), V(' '), F('first_name'))
            # ).filter(
            #     **stat_kwargs
        ).order_by(
            'full_name'
        ).distinct(
        ).values(
            'id', 'full_name',
        )

        ord_managers = managers.filter(orders_for_manager__in=ords_ids)

        recipt_managers = managers.filter(receipts_for_manager__in=receipts_ids)

        managers = ord_managers.union(recipt_managers)

        receipt_kwargs = {
            'enable': True,
        }
        ord_kwargs = {
            'order__enable': True,
            'order__pay_terms__in': pay_terms_for_report_list,
        }
        for key, val in filter_kwargs.items():
            if 'delivery_DT__gte' in key:
                ord_kwargs.update({'order__delivery_DT__gte': val})
                receipt_kwargs.update({'receipt__receipt_D__gte': val})

            elif 'delivery_DT__lte' in key:
                ord_kwargs.update({'order__delivery_DT__lte': val})
                receipt_kwargs.update({'receipt__receipt_D__lte': val})

            elif 'company__region__in' in key:
                ord_kwargs.update({'order__company__region__in': val})
                receipt_kwargs.update({'receipt__company__region__in': val})

        ord_kwargs.update({
            'product__id': kwargs['pk'],
        })

        receipt_kwargs.update({
            'product__id': kwargs['pk'],
            # 'receipt__receipt_type': 'return'
        })

        if managers:
            managers = get_sales_for_managers_by_goods(request.user, managers, ord_kwargs, receipt_kwargs)

        filename = 'managers_sales_by_product_{0}.xlsx'.format(str(kwargs['pk']))
        res = check_and_get_specific_output_format(self, data=managers, filename=filename)
        if res:
            return res

        return Response(managers)
