from django.shortcuts import render
from rest_framework import serializers
from rest_framework import exceptions
from rest_framework.exceptions import APIException
from rest_framework.mixins import DestroyModelMixin, ListModelMixin, RetrieveModelMixin
from rest_framework.viewsets import GenericViewSet, ModelViewSet
from apps.inm.filters import IProductFilterSet, MbFilterSet

from apps.inm.models import FIFO, FIFOItem, IProduct, MaterialBatch, WareHouse,Inventory
from apps.inm.serializers import FIFOItemSerializer, FIFOInPurSerializer, FIFOListSerializer, IProductListSerializer, IProductMtestSerializer, InmTestRecordCreateSerializer, MaterialBatchQuerySerializer, MaterialBatchSerializer, WareHouseSerializer, WareHouseCreateUpdateSerializer,InventorySerializer
from apps.inm.signals import update_inm
from apps.mtm.models import Material
from apps.qm.models import TestRecordItem
from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin
from rest_framework.decorators import action
from rest_framework.response import Response
from django.db import transaction

# Create your views here.
class WarehouseViewSet(CreateUpdateModelAMixin, ModelViewSet):
    """
    仓库-增删改查
    """
    perms_map = {'*': '*'}
    queryset = WareHouse.objects.select_related('create_by').all()
    serializer_class = WareHouseSerializer
    search_fields = ['name', 'number', 'place']
    filterset_fields = []
    ordering_fields = ['create_time']
    ordering = ['-create_time']

    def  get_serializer_class(self):
        if self.action in ['create', 'update']:
            return WareHouseCreateUpdateSerializer
        return WareHouseSerializer

class InventoryViewSet(ListModelMixin, GenericViewSet):
    """
    仓库物料表
    """
    perms_map = {'*': '*'}
    queryset = Inventory.objects.select_related('material', 'warehouse').all()
    serializer_class = InventorySerializer
    filterset_fields = ['material', 'warehouse']
    search_fields = []
    ordering_fields = ['create_time']
    ordering = ['-create_time']

class MaterialBatchViewSet(ListModelMixin, GenericViewSet):
    perms_map = {'*': '*'}
    queryset = MaterialBatch.objects.select_related('material', 'warehouse').all()
    serializer_class = MaterialBatchSerializer
    # filterset_fields = ['material', 'warehouse']
    filterset_class = MbFilterSet
    search_fields = []
    ordering_fields = ['create_time']
    ordering = ['-create_time']

    @action(methods=['post'], detail=False, perms_map={'post':'*'}, serializer_class=MaterialBatchQuerySerializer)
    def query(self, request, pk=None):
        """
        复杂查询
        """
        data = request.data
        serializer = MaterialBatchQuerySerializer(data=data)
        serializer.is_valid(raise_exception=True)
        queryset = self.queryset.filter(warehouse__id=data['warehouse'], material__id__in=data['materials'])
        return Response(MaterialBatchSerializer(instance=queryset, many=True).data)

class FIFOItemViewSet(ListModelMixin, DestroyModelMixin, GenericViewSet):
    """
    出入库记录详情表
    """
    perms_map = {'*': '*'}
    queryset = FIFOItem.objects.select_related('material', 'fifo').all()
    serializer_class = FIFOItemSerializer
    filterset_fields = ['material', 'fifo']
    search_fields = []
    ordering_fields = ['create_time']
    ordering = ['-create_time']

    def perform_destroy(self, instance):
        if instance.fifo.is_audited:
            raise APIException('该出入库记录已通过审核, 无法删除')
        return super().perform_destroy(instance)

    @action(methods=['post'], detail=False, perms_map={'post':'*'}, serializer_class=InmTestRecordCreateSerializer)
    def test(self, request, pk=None):
        """
        检测
        """
        serializer = InmTestRecordCreateSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        vdata = serializer.validated_data
        record_data = vdata.pop('record_data')
        if 'is_testok' not in vdata:
            raise APIException('未填写检测结论')
        with transaction.atomic():
            obj = serializer.save(create_by = self.request.user)
            tris = []
            for m in record_data: # 保存记录详情
                form_field = m['form_field']
                m['field_name'] = form_field.field_name
                m['field_key'] = form_field.field_key
                m['field_type'] = form_field.field_type
                m['field_value'] = m['field_value']
                m['sort'] = form_field.sort
                m['need_judge'] = form_field.need_judge
                m['is_testok'] = m['is_testok'] if 'is_testok' in m else True
                m['test_record'] = obj
                tris.append(TestRecordItem(**m))
            TestRecordItem.objects.bulk_create(tris)

            # 如果检测合格
            if obj.fifo_item:
                obj.fifo_item.is_testok = True if obj.is_testok else False
                obj.fifo_item.is_tested = True
                obj.fifo_item.save()
        return Response()

class FIFOViewSet(ListModelMixin, GenericViewSet):
    """
    出入库记录
    """
    perms_map = {'*': '*'}
    queryset = FIFO.objects.select_related('auditor', 'create_by')
    serializer_class = FIFOListSerializer
    filterset_fields = '__all__'
    ordering_fields = '__all__'
    search_fields = []
    ordering = ['-pk']

    def get_serializer_class(self):
        if self.action == 'list':
            return FIFOListSerializer
        return super().get_serializer_class()

    @action(methods=['post'], detail=False, perms_map={'post':'*'}, serializer_class=FIFOInPurSerializer)
    def in_pur(self, request, pk=None):
        """
        采购入库
        """
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        serializer.save(create_by=request.user)
        return Response()

    @action(methods=['post'], detail=True, perms_map={'post':'*'}, serializer_class=serializers.Serializer)
    def audit(self, request, pk=None):
        """
        审核通过
        """
        obj = self.get_object()
        # for i in FIFOItem.objects.filter(fifo=obj):
        #     if not i.is_testok:
        #         raise APIException('未检验通过, 不可审核')
        if obj.is_audited:
            raise APIException('该入库记录已审核通过')
        with transaction.atomic():
            obj.is_audited = True
            obj.auditor = request.user
            obj.save()
            update_inm(obj) # 更新库存
        return Response()
    

class IProductViewSet(ListModelMixin, GenericViewSet):
    """
    半成品库存表
    """
    perms_map = {'*': '*'}
    queryset = IProduct.objects.select_related('material', 'warehouse', 'wproduct__subproduction_plan__production_plan__order').filter(is_saled=False)
    serializer_class = IProductListSerializer
    filterset_class = IProductFilterSet
    search_fields = []
    ordering_fields = ['create_time']
    ordering = ['-create_time']

    @action(methods=['post'], detail=True, perms_map={'post':'*'}, serializer_class=IProductMtestSerializer)
    def mtest(self, request, pk=None):
        """
        军检
        """
        obj = self.get_object()
        if obj.is_mtested:
            raise exceptions.APIException('已进行军检')
        if obj.wproduct:
            if obj.wproduct.material.type != Material.MA_TYPE_GOOD:
                raise exceptions.APIException('军检必须是成品')
        obj.remark_mtest = request.data.get('remark_mtest', None)
        obj.is_mtested = True
        obj.is_mtestok = request.data.get('is_mtestok')
        obj.save()
        return Response()