#coding=utf-8

from rest_framework import serializers

from apps import base
from apps.account.models import User
from apps.base import Formater
from apps.exceptions import CustomError
from apps.foundation.models import BizLog
from apps.purchase.models import GodownEntryDetail
from apps.serializer_errors import dump_serializer_errors
from apps.warehouse.biz import BizWarehouse
from models import Material, Consumable, Deliver, DeliverDetail, DeliverReturn, DeliverReturnDetail
from libs.booleancharfield import BooleanCharField, CountShowCharField, AmountShowCharField, PriceShowCharField
from apps.warehouse.models import Inventory, InventoryDetail, WarehouseStock
from apps import base
from apps.goods.models import GoodsGodownEntryDetail
from apps.purchase.models import GodownEntryDetail
from apps.product.models import ProductBase


class MaterialSerializer(serializers.ModelSerializer):
    name = serializers.CharField(source='product_base.name', read_only=True)
    model = serializers.CharField(source='product_base.model', read_only=True)
    option_type = serializers.CharField(source='product_base.option_type.id', read_only=True)
    option_type_text = serializers.CharField(source='product_base.option_type.name', read_only=True)
    unit = serializers.CharField(source='product_base.unit', read_only=True)
    standard = serializers.CharField(source='product_base.standard', read_only=True)
    warehouse_place = serializers.CharField(source='product_base.warehouse_place', read_only=True)
    purchase_suggest_text = serializers.CharField(source='get_purchase_suggest_display', read_only=True)
    stock_upper_limit = CountShowCharField()
    stock_lower_limit = CountShowCharField()
    enabled_text = BooleanCharField(source='product_base.enabled', read_only=True)
    enabled = serializers.BooleanField(source='product_base.enabled', read_only=True)
    notes = serializers.CharField(source='product_base.notes', read_only=True)

    class Meta:
        model = Material
        fields = '__all__'

    @staticmethod
    def factory(user, data, id=None):
        if id:
            instance = Material.getById(id)
        else:
            instance = None
        serializer = MaterialSerializer(instance, data=data)
        serializer.user = user
        return serializer

    def create(self, validated_data):
        product = Material.objects.create(**validated_data)
        BizLog.objects.addnew(
            self.user,
            BizLog.INSERT,
            u"添加原料[%s]，id=%d" % (product.product_base.name, product.id),
            validated_data
        )
        return product

    def update(self, instance, validated_data):
        instance = super(MaterialSerializer, self).update(instance, validated_data)
        BizLog.objects.addnew(
            self.user,
            BizLog.UPDATE,
            u"修改原料[%s]，id=%d" % (instance.product_base.name, instance.id),
            validated_data
        )
        return instance

    def validSave(self):
        if self.is_valid():
            return self.save()
        else:
            raise CustomError(dump_serializer_errors(self))


    def validate(self, data):
        if 'stock_upper_limit' in data:
            data['stock_upper_limit'] = Formater.formatCount(data['stock_upper_limit'])
        if 'stock_lower_limit' in data:
            data['stock_lower_limit'] = Formater.formatCount(data['stock_lower_limit'])
        return data


class ConsumableSerializer(serializers.ModelSerializer):
    name = serializers.CharField(source='product_base.name', read_only=True)
    model = serializers.CharField(source='product_base.model', read_only=True)
    option_type = serializers.CharField(source='product_base.option_type.id', read_only=True)
    option_type_text = serializers.CharField(source='product_base.option_type.name', read_only=True)
    unit = serializers.CharField(source='product_base.unit', read_only=True)
    standard = serializers.CharField(source='product_base.standard', read_only=True)
    warehouse_place = serializers.CharField(source='product_base.warehouse_place', read_only=True)
    purchase_suggest_text = serializers.CharField(source='get_purchase_suggest_display', read_only=True)
    stock_upper_limit = CountShowCharField()
    stock_lower_limit = CountShowCharField()
    enabled_text = BooleanCharField(source='product_base.enabled', read_only=True)
    enabled = serializers.BooleanField(source='product_base.enabled', read_only=True)
    notes = serializers.CharField(source='product_base.notes', read_only=True)
    class Meta:
        model = Consumable
        fields = '__all__'

    @staticmethod
    def factory(user, data, id=None):
        if id:
            instance = Consumable.getById(id)
        else:
            instance = None
        serializer = ConsumableSerializer(instance, data=data)
        serializer.user = user
        return serializer

    def create(self, validated_data):
        product = Consumable.objects.create(**validated_data)
        BizLog.objects.addnew(
            self.user,
            BizLog.INSERT,
            u"添加耗材[%s]，id=%d" % (product.product_base.name, product.id),
            validated_data
        )
        return product

    def update(self, instance, validated_data):
        instance = super(ConsumableSerializer, self).update(instance, validated_data)
        BizLog.objects.addnew(
            self.user,
            BizLog.UPDATE,
            u"修改耗材[%s]，id=%d" % (instance.product_base.name, instance.id),
            validated_data
        )
        return instance

    def validSave(self):
        if self.is_valid():
            return self.save()
        else:
            raise CustomError(dump_serializer_errors(self))

    def validate(self, data):
        if 'stock_upper_limit' in data:
            data['stock_upper_limit'] = Formater.formatCount(data['stock_upper_limit'])
        if 'stock_lower_limit' in data:
            data['stock_lower_limit'] = Formater.formatCount(data['stock_lower_limit'])
        return data


class DeliverSerializer(serializers.ModelSerializer):
    status = serializers.CharField(read_only=True)
    product_type_text = serializers.CharField(source='get_product_type_display', read_only=True)
    status_text = serializers.CharField(source='get_status_display', read_only=True)
    create_user_text = serializers.CharField(source='create_user.name', read_only=True)
    create_time = serializers.DateTimeField(format=base.DATETIME_FORMAT, read_only=True)
    check_user_text = serializers.CharField(source='check_user.name', read_only=True)
    check_time = serializers.DateTimeField(format=base.DATETIME_FORMAT, read_only=True)
    receiver_text = serializers.CharField(source='receiver.name', read_only=True)
    receiver_department_text = serializers.CharField(source='receiver_department.name', read_only=True)
    goods_text = serializers.CharField(source='goods.product_base.name', read_only=True)
    warehouse_text = serializers.CharField(source='warehouse.name', read_only=True)
    total_count = CountShowCharField(read_only=True)
    total_cost = AmountShowCharField(read_only=True)

    class Meta:
        model = Deliver
        fields = '__all__'

    @staticmethod
    def factory(user, data, id=None):
        if id:
            instance = Deliver.getById(id)
        else:
            instance = None
        serializer =DeliverSerializer(instance, data=data)
        serializer.user = user
        return serializer

    def create(self, validated_data):
        validated_data['create_user'] = self.user
        validated_data['department'] = self.user.department
        deliver = Deliver.objects.create(**validated_data)
        BizLog.objects.addnew(
            self.user,
            BizLog.INSERT,
            u"添加原料/耗材出库单[%s]，id=%d" % (deliver.no, deliver.id),
            validated_data
        )
        return deliver

    def update(self, instance, validated_data):
        instance = super(DeliverSerializer, self).update(instance, validated_data)
        BizLog.objects.addnew(
            self.user,
            BizLog.UPDATE,
            u"修改原料/耗材出库单[%s]，id=%d" % (instance.no, instance.id),
            validated_data
        )
        return instance

    def validate(self, data):
        data['receiver_department'] = data['receiver'].department
        return data

    def validSave(self):
        if self.is_valid():
            return self.save()
        else:
            raise CustomError(dump_serializer_errors(self))

class DeliverDetailSerializer(serializers.ModelSerializer):
    name = serializers.CharField(source='product_base.name', read_only=True)
    model = serializers.CharField(source='product_base.model', read_only=True)
    unit_text = serializers.CharField(source='product_base.unit', read_only=True)
    no = serializers.SerializerMethodField()
    count = CountShowCharField()
    warehouse_stock_count = CountShowCharField(source='warehouse_stock.count', read_only=True)
    total_cost = AmountShowCharField()

    class Meta:
        model = DeliverDetail
        fields = '__all__'

    @staticmethod
    def factory(user, data):
        serializer = DeliverDetailSerializer(None, data=data)
        serializer.user = user
        return serializer

    def get_no(self, obj):
        instance = GodownEntryDetail.objects.filter(stock_record=obj.warehouse_stockrecord).first()
        if instance:
            no = instance.main.no
        else:
            no = InventoryDetail.objects.filter(warehouse_stock_record=obj.warehouse_stockrecord).first().main.no
        return no

    def create(self, validated_data):
        instance = DeliverDetail.objects.create(**validated_data)

        BizLog.objects.addnew(
            self.user,
            BizLog.INSERT,
            u"添加原料/耗材出库明细[%s]，id=%d" % (instance.product_base.name, instance.id),
            validated_data
        )
        return instance

    def validSave(self):
        if self.is_valid():
            return self.save()
        else:
            raise CustomError(dump_serializer_errors(self))

    def validate(self, data):
        data['count'] = Formater.formatCount(data['count'])
        data['total_cost'] = Formater.formatAmount(data['total_cost'])
        warehouse_stock = WarehouseStock.getByWarehouseAndProduct(data['main'].warehouse, data['product_base'])
        data['warehouse_stock'] = warehouse_stock
        return data


class InventorySerializer(serializers.ModelSerializer):
    create_time = serializers.DateTimeField(format=base.DATETIME_FORMAT, read_only=True)
    check_time = serializers.DateTimeField(format=base.DATETIME_FORMAT, read_only=True)
    check_status_text = serializers.CharField(source='get_check_status_display', read_only=True)
    check_user_text = serializers.CharField(source='check_user.name', read_only=True)
    create_user_text = serializers.CharField(source='create_user.name', read_only=True)
    type_text = serializers.CharField(source='get_type_display', read_only=True)
    warehouse_text = serializers.CharField(source='warehouse.name', read_only=True)
    total_count = CountShowCharField(read_only=True)
    total_amount = AmountShowCharField(read_only=True)


    class Meta:
        model = Inventory
        fields = '__all__'

    @staticmethod
    def factory(user, data, id=None):
        if id:
            instance = Inventory.getById(id)
        else:
            instance = None
        serializer = InventorySerializer(instance, data=data)
        serializer.user = user
        return serializer

    def create(self, validated_data):
        validated_data['create_user'] = self.user
        validated_data['department'] = self.user.department
        order = Inventory.objects.create(**validated_data)
        BizLog.objects.addnew(
            self.user,
            BizLog.INSERT,
            u"添加盘存单[%s]，id=%d" % (order.no, order.id),
            validated_data
        )
        return order

    def update(self, instance, validated_data):
        instance = super(InventorySerializer, self).update(instance, validated_data)
        BizLog.objects.addnew(
            self.user,
            BizLog.UPDATE,
            u"修改盘存单[%s]，id=%d" % (instance.no, instance.id),
            validated_data
        )
        return instance

    def validSave(self):
        if self.is_valid():
            return self.save()
        else:
            raise CustomError(dump_serializer_errors(self))


class InventoryDetailSerializer(serializers.ModelSerializer):
    name = serializers.CharField(source='product.name', read_only=True)
    model = serializers.CharField(source='product.model', read_only=True)
    warehouse_text = serializers.CharField(source='main.warehouse.name', read_only=True)
    entry_no = serializers.SerializerMethodField()
    count = CountShowCharField()
    price = PriceShowCharField()
    amount = AmountShowCharField(read_only=True)

    class Meta:
        model = InventoryDetail
        fields = '__all__'


    def get_entry_no(self, obj):
        if obj.product.type == ProductBase.GOODS:
            g_row = GoodsGodownEntryDetail.objects.filter(stock_record_id=obj.loss_stock_record_id).first()
        else:
            g_row = GodownEntryDetail.objects.filter(stock_record_id=obj.loss_stock_record_id).first()

        if not g_row:
            g_row = InventoryDetail.objects.filter(warehouse_stock_record_id=obj.loss_stock_record_id).first()
        return g_row and g_row.main.no or ''

    @staticmethod
    def factory(user, data):
        instances = None
        serializer = InventoryDetailSerializer(instances, data=data)
        serializer.user = user
        return serializer

    def create(self, validated_data):
        order = InventoryDetail.objects.create(**validated_data)
        BizLog.objects.addnew(
            self.user,
            BizLog.INSERT,
            u"添加盘存明细[%s]，id=%d" % (order.main.no, order.id),
            validated_data
        )
        return order

    def validSave(self):
        if self.is_valid():
            return self.save()
        else:
            raise CustomError(dump_serializer_errors(self))

    def validate(self, data):
        data['price'] = Formater.formatPrice(data['price'])
        data['count'] = Formater.formatCount(data['count'])
        data['amount'] = data['price'] * data['count']

        warehouse_stock = WarehouseStock.getByWarehouseAndProduct(data['main'].warehouse, data['product'])
        data['warehouse_stock'] = warehouse_stock
        return data

    def update(self, instance, validated_data):
        instance = super(InventoryDetailSerializer, self).update(instance, validated_data)
        BizLog.objects.addnew(
            self.user,
            BizLog.INSERT,
            u"修改盘存明细[%s]，id=%d" % (instance.main.no, instance.id),
            validated_data
        )
        return instance


class DeliverReturnViewSerializer(serializers.ModelSerializer):
    create_user_text = serializers.CharField(source='create_user.name', read_only=True)
    create_time = serializers.DateTimeField(format=base.DATETIME_FORMAT, read_only=True)
    receiver_text = serializers.CharField(source='receiver.name', read_only=True)
    warehouse_text = serializers.CharField(source='warehouse.name', read_only=True)
    total_count = CountShowCharField(read_only=True)
    total_cost = AmountShowCharField(read_only=True)
    return_count = CountShowCharField(read_only=True)
    return_cost = AmountShowCharField(read_only=True)

    class Meta:
        model = Deliver
        fields = '__all__'


class DeliverReturnSerializer(serializers.ModelSerializer):
    create_time = serializers.DateTimeField(format=base.DATETIME_FORMAT, read_only=True)
    class Meta:
        model = DeliverReturn
        fields = '__all__'

    @staticmethod
    def factory(user, data):
        serializer = DeliverReturnSerializer(data=data)
        serializer.user = user
        return serializer

    def create(self, validated_data):
        validated_data['create_user'] = self.user
        validated_data['department'] = self.user.department
        deliver_return = DeliverReturn.objects.create(**validated_data)
        BizLog.objects.addnew(
            self.user,
            BizLog.INSERT,
            u"添加原料/耗材退料单[%s]，id=%d" % (deliver_return.no, deliver_return.id),
            validated_data
        )
        return deliver_return


    def validSave(self):
        if self.is_valid():
            return self.save()
        else:
            raise CustomError(dump_serializer_errors(self))


class DeliverReturnDetailSerializer(serializers.ModelSerializer):

    class Meta:
        model = DeliverReturnDetail
        fields = '__all__'

    @staticmethod
    def factory(user, data):
        serializer = DeliverReturnDetailSerializer(data=data)
        serializer.user = user
        return serializer

    def create(self, validated_data):
        deliver_return_detail = DeliverReturnDetail.objects.create(**validated_data)
        BizLog.objects.addnew(
            self.user,
            BizLog.INSERT,
            u"添加原料/耗材退料明细[%s]，id=%d" % (deliver_return_detail.main.no, deliver_return_detail.id),
            validated_data
        )
        return deliver_return_detail


    def validSave(self):
        if self.is_valid():
            return self.save()
        else:
            raise CustomError(dump_serializer_errors(self))

    def validate(self, data):
        data['return_count'] = Formater.formatCount(data['return_count'])
        warehouse_stock = WarehouseStock.getByWarehouseAndProduct(data['deliver_detail'].main.warehouse, data['product_base'])
        data['warehouse_stock'] = warehouse_stock
        data['warehouse_record'] = BizWarehouse.deliveredBack(data['deliver_detail'].warehouse_record, data['return_count'])
        data['return_cost'] = data['warehouse_record'].amount
        return data