# coding=utf-8

from django.db import models
from django.db.models import Sum
from django.utils import timezone
from django.conf import settings
from apps.account.models import User, Department
from apps.exceptions import CustomError
from apps.goods.models import Goods
from apps.product.models import ProductBase
from apps.warehouse.models import Warehouse, WarehouseStock, WarehouseRecord, WarehouseStockRecord


class Material(models.Model):
    NONE = 0
    LOWER = 1
    UPPER = 2
    SUGGEST_CHOICES = (
        (NONE, u'不开启'),
        (LOWER, u'按库存下限预警'),
        (UPPER, u'按库存上限预警'),
    )
    product_base = models.ForeignKey(ProductBase, verbose_name=u"产品", on_delete=models.PROTECT, blank=True)
    htc_identification = models.CharField(max_length=100, verbose_name=u"产品标识", null=True, blank=True)
    stock_upper_limit = models.BigIntegerField(verbose_name=u"库存上限", null=True, blank=True)
    stock_lower_limit = models.BigIntegerField(verbose_name=u"库存下限", null=True, blank=True)
    purchase_suggest = models.PositiveSmallIntegerField(choices=SUGGEST_CHOICES, verbose_name=u"库存预警", default=NONE)

    class Meta:
        db_table = "material"
        verbose_name = u"原料产品管理"
        ordering = ('-id',)
        default_permissions = ()
        permissions = (
            ("view_material", u"浏览"),
            ("add_material", u"添加"),
            ("delete_material", u"删除"),
            ("export_material", u"导出"),
            ("import_material", u"导入"),
            ("view_material_cost", u"查看成本"),
        )

    @staticmethod
    def getById(id):
        instance = Material.objects.filter(pk=id).first()
        if not instance:
            raise CustomError(u'未找到相应的原料')
        return instance

    @staticmethod
    def getPurchaseSuggest():
        purchasesuggest = {
            u'不开启' : 0,
            u'按库存下限预警': 1,
            u'按库存上限预警': 2
        }
        return purchasesuggest

    @staticmethod
    def getPurchaseSuggestValue(value):
        purchasesuggest = Material.getPurchaseSuggest()
        try:
            purchase_suggest = purchasesuggest[value]
        except:
            raise CustomError(u'库存预警填写不正确')
        return purchase_suggest


class Consumable(models.Model):
    product_base = models.ForeignKey(ProductBase, verbose_name=u"产品", on_delete=models.PROTECT, blank=True)
    stock_upper_limit = models.BigIntegerField(verbose_name=u"库存上限", null=True, blank=True)
    stock_lower_limit = models.BigIntegerField(verbose_name=u"库存下限", null=True, blank=True)
    purchase_suggest = models.PositiveSmallIntegerField(choices=Material.SUGGEST_CHOICES, verbose_name=u"库存预警", default=Material.NONE)

    class Meta:
        db_table = "consumable"
        verbose_name = u"耗材产品管理"
        ordering = ('-id',)
        default_permissions = ()
        permissions = (
            ("view_consumable", u"浏览"),
            ("add_consumable", u"添加"),
            ("delete_consumable", u"删除"),
            ("export_consumable", u"导出"),
            ("import_consumable", u"导入"),
            ("view_consumable_cost", u"查看成本"),
        )

    @staticmethod
    def getById(id):
        instance = Consumable.objects.filter(pk=id).first()
        if not instance:
            raise CustomError(u'未找到相应的耗材')
        return instance


class Deliver(models.Model):
    MATERIAL = 0
    CONSUMABLE = 1
    PRODUCT_CHOICES = (
        (MATERIAL, u'原料'),
        (CONSUMABLE, u'耗材'),
    )
    PREFIX_CHOICES = (
        (MATERIAL, 'CM'),
        (CONSUMABLE, 'CC')
    )
    no = models.CharField(max_length=20, verbose_name=u"出库单号", editable=False)
    product_type = models.PositiveSmallIntegerField(choices=PRODUCT_CHOICES, verbose_name=u"产品类型")

    create_time = models.DateTimeField(verbose_name=u"创建时间", default=timezone.now)
    create_user = models.ForeignKey(User, verbose_name=u"创建人", related_name='deliver_ref_create_user', on_delete=models.PROTECT, blank=True, editable=False)
    department = models.ForeignKey(Department, verbose_name=u"创建部门", related_name='deliver_ref_department', on_delete=models.PROTECT, blank=True, editable=False)

    receiver = models.ForeignKey(User, verbose_name=u"领用人", related_name='deliver_ref_receiver',on_delete=models.PROTECT)
    receiver_department = models.ForeignKey(Department, verbose_name=u"领用车间", related_name='deliver_ref_receiver_department',
                                            on_delete=models.PROTECT, blank=True, editable=False)

    status = models.PositiveSmallIntegerField(choices=settings.CHECK_STATUS_CHOICES, verbose_name=u"审核状态", default=settings.DEFAULT)
    check_user = models.ForeignKey(User, related_name='deliver_ref_check_user', verbose_name=u"审核人", on_delete=models.PROTECT, blank=True, null=True)
    check_time = models.DateTimeField(verbose_name=u"审核时间", blank=True, null=True)

    warehouse = models.ForeignKey(Warehouse, verbose_name=u'仓别', on_delete=models.PROTECT)
    notes = models.CharField(max_length=200, verbose_name=u"备注", blank=True, null=True)
    goods = models.ForeignKey(Goods, verbose_name=u'成品', on_delete=models.PROTECT, blank=True, null=True)

    total_count = models.BigIntegerField(verbose_name=u'合计数量', default=0)
    total_cost = models.BigIntegerField(verbose_name=u'合计成本', default=0)
    return_count = models.BigIntegerField(verbose_name=u"合计退料数量", default=0)
    return_cost = models.BigIntegerField(verbose_name=u"合计退料成本", default=0)


    class Meta:
        db_table = "deliver"
        verbose_name = u"出库管理"
        ordering = ('-id',)
        index_together = (
            'create_time', 'check_time', 'status'
        )
        unique_together = (
            'no',
        )
        default_permissions = ()
        permissions = (
            ("view_material_deliver", u"浏览"),
            ("add_material_deliver", u"添加"),
            ("check_material_deliver", u"审核"),
            ("delete_material_deliver", u"删除"),
            ("export_material_deliver", u"导出"),
            ("print_material_deliver", u"打印"),
        )

    def getPermission(self, action):
            permissions = Deliver.getPermissionMap()
            return permissions[self.product_type][action]

    @staticmethod
    def getById(id):
        instances = Deliver.objects.filter(id=id).first()
        if not instances:
            raise CustomError(u'未找到相应的出库单')
        return instances

    @staticmethod
    def getPermissionByType(type, action):
        permissions = Deliver.getPermissionMap()
        type = Deliver.getValidType(type)
        return permissions[type][action]

    @staticmethod
    def getPermissionMap():
        permissions = {
            Deliver.MATERIAL: {'view': 'material.view_material_deliver',
                                   'add': 'material.add_material_deliver',
                                   'check': 'material.check_material_deliver',
                                   'delete': 'material.delete_material_deliver',
                                   'export': 'material.export_material_deliver',
                                   'import': 'material.import_material_deliver',
                                   'print': 'material.print_material_deliver'
                                   },

            Deliver.CONSUMABLE: {'view': 'material.view_consumable_deliver',
                                     'add': 'material.add_consumable_deliver',
                                     'check': 'material.check_consumable_deliver',
                                     'delete': 'material.delete_consumable_deliver',
                                     'export': 'material.export_consumable_deliver',
                                     'import': 'material.import_consumable_deliver',
                                     'print': 'material.print_consumable_deliver'
                                     },
        }
        return permissions
    
    @staticmethod
    def getValidType(type):
        try:
            type = int(type)
        except:
            raise CustomError(u'错误的出库类型')

        types = (r[0] for r in Deliver.PRODUCT_CHOICES)
        if type not in types:
            raise CustomError(u'无效的出库类型')
        return type

    def save(self, *args, **kwargs):
        if self.no == None or self.no == '':
            now = timezone.now()
            rows = Deliver.objects.filter(create_time__gte=now.strftime('%Y-%m-%d')).order_by('-no')
            count = rows.count()
            prefix = self.PREFIX_CHOICES[self.product_type][1]
            if count == 0:
                self.no = '%s%s%03d' % (prefix, now.strftime('%Y%m%d'), count + 1)
            else:
                self.no = rows[0].no[:2] + str(int(rows[0].no[2:]) + 1)
        super(Deliver, self).save(*args, **kwargs)

    def update_total(self):
        total_count = 0
        total_cost = 0
        sum_row = DeliverDetail.objects.filter(main=self).aggregate(total_count=Sum('count'), total_cost=Sum('total_cost'))
        if sum_row:
            total_count = sum_row['total_count'] or 0
            total_cost = sum_row['total_cost'] or 0
        self.total_count = total_count
        self.total_cost = total_cost
        self.save()

    def update_return(self):
        return_count = 0
        return_cost = 0
        sum_row = DeliverDetail.objects.filter(main=self).aggregate(return_count=Sum('return_count'),
                                                                    return_cost=Sum('return_cost'))
        if sum_row:
            return_count = sum_row['return_count'] or 0
            return_cost = sum_row['return_cost'] or 0
        self.return_count = return_count
        self.return_cost = return_cost
        self.save()
        

        
class DeliverDetail(models.Model):
    main = models.ForeignKey(Deliver, verbose_name=u'出库单', on_delete=models.PROTECT, related_name='deliver_details')
    product_base = models.ForeignKey(ProductBase, verbose_name=u'产品', on_delete=models.PROTECT)
    count = models.BigIntegerField(verbose_name=u'数量', default=0)
    warehouse_stock = models.ForeignKey(WarehouseStock, verbose_name=u'仓别库存', on_delete=models.PROTECT, editable=False)
    warehouse_record = models.ForeignKey(WarehouseRecord, verbose_name=u'库存记录', on_delete=models.PROTECT, null=True,blank=True, related_name='deliver_detail_ref_warehouse_record')
    warehouse_stockrecord = models.ForeignKey(WarehouseStockRecord, verbose_name=u'入库库存记录', on_delete=models.PROTECT, null=True,blank=True, related_name='deliver_detail_ref_warehouse_stock_record')

    total_cost = models.BigIntegerField(verbose_name=u'成本合计', default=0)
    return_count = models.BigIntegerField(verbose_name=u'退料数量',default=0)
    return_cost = models.BigIntegerField(verbose_name=u'退料成本合计', default=0)
    notes = models.CharField(max_length=200, verbose_name=u"备注", blank=True, null=True)
    
    class Meta:
        db_table = "deliver_detail"
        verbose_name = u"出库管理"
        ordering = ('-id',)
        default_permissions = ()
        permissions = (
            ("view_consumable_deliver", u"浏览"),
            ("add_consumable_deliver", u"添加"),
            ("check_consumable_deliver", u"审核"),
            ("delete_consumable_deliver", u"删除"),
            ("export_consumable_deliver", u"导出"),
            ("print_consumable_deliver", u"打印"),
        )

    def updateReturn(self):
        return_count = 0
        return_cost = 0
        sum_row = DeliverReturnDetail.objects.filter(deliver_detail=self).aggregate(return_count=Sum('return_count'),
                                                                                    return_cost=Sum('return_cost'))
        if sum_row:
            return_count = sum_row['return_count'] or 0
            return_cost = sum_row['return_cost'] or 0
        self.return_count = return_count
        self.return_cost = return_cost
        self.save()

class DeliverReturn(models.Model):
    PREFIX_CHOICES = (
        (Deliver.MATERIAL, 'TM'),
        (Deliver.CONSUMABLE, 'TC')
    )
    no = models.CharField(max_length=20, verbose_name=u"退料单号", editable=False)
    product_type = models.PositiveSmallIntegerField(choices=Deliver.PRODUCT_CHOICES, verbose_name=u"产品类型")
    reason = models.CharField(max_length=500, verbose_name=u"原因", editable=False)
    create_time = models.DateTimeField(verbose_name=u"创建时间", default=timezone.now)
    create_user = models.ForeignKey(User, verbose_name=u"创建人", on_delete=models.PROTECT, blank=True, editable=False)
    department = models.ForeignKey(Department, verbose_name=u"创建部门", on_delete=models.PROTECT, blank=True, editable=False)
    return_count = models.BigIntegerField(verbose_name=u'退料合计数量', default=0)
    return_cost = models.BigIntegerField(verbose_name=u'退料合计成本', default=0)

    class Meta:
        db_table = "deliver_return"
        verbose_name = u"退料管理"
        ordering = ('-id',)
        index_together = (
            'create_time',
        )
        unique_together = (
            'no',
        )
        default_permissions = ()
        permissions = (
            ("view_material_deliver_return", u"浏览"),
            ("add_material_deliver_return", u"添加"),
            ("print_material_deliver_return", u"打印"),
        )

    @staticmethod
    def getByIds(ids):
        return DeliverReturn.objects.filter(id__in=ids)

    def getPermission(self, action):
        permissions = DeliverReturn.getPermissionMap()
        return permissions[self.product_type][action]

    @staticmethod
    def getById(id):
        instances = DeliverReturn.objects.filter(id=id).first()
        if not instances:
            raise CustomError(u'未找到相应的退料单')
        return instances

    @staticmethod
    def getPermissionByType(type, action):
        permissions = DeliverReturn.getPermissionMap()
        type = DeliverReturn.getValidType(type)
        return permissions[type][action]

    @staticmethod
    def getPermissionMap():
        permissions = {
            Deliver.MATERIAL: {'view': 'material.view_material_deliver_return',
                               'add': 'material.add_material_deliver_return',
                               'print': 'material.print_material_deliver_return'
                               },

            Deliver.CONSUMABLE: {'view': 'material.view_consumable_deliver_return',
                                 'add': 'material.add_consumable_deliver_return',
                                 'print': 'material.print_consumable_deliver_return'
                                 },
        }
        return permissions

    @staticmethod
    def getValidType(type):
        try:
            type = int(type)
        except:
            raise CustomError(u'错误的退料类型')

        types = (r[0] for r in Deliver.PRODUCT_CHOICES)
        if type not in types:
            raise CustomError(u'无效的退料类型')
        return type

    def save(self, *args, **kwargs):
        if self.no == None or self.no == '':
            now = timezone.now()
            rows = DeliverReturn.objects.filter(create_time__gte=now.strftime('%Y-%m-%d')).order_by('-no')
            count = rows.count()
            prefix = self.PREFIX_CHOICES[self.product_type][1]
            if count == 0:
                self.no = '%s%s%03d' % (prefix, now.strftime('%Y%m%d'), count + 1)
            else:
                self.no = rows[0].no[:2] + str(int(rows[0].no[2:]) + 1)
        super(DeliverReturn, self).save(*args, **kwargs)

    def update_total(self):
        return_count = 0
        return_cost = 0
        sum_row = DeliverReturnDetail.objects.filter(main=self).aggregate(return_count=Sum('return_count'),
                                                                          return_cost=Sum('return_cost'))
        if sum_row:
            return_count = sum_row['return_count'] or 0
            return_cost = sum_row['return_cost'] or 0
        self.return_count = return_count
        self.return_cost = return_cost
        self.save()


class DeliverReturnDetail(models.Model):
    main = models.ForeignKey(DeliverReturn, verbose_name=u'退料单', on_delete=models.PROTECT, related_name='deliver_return_details')
    deliver_detail = models.ForeignKey(DeliverDetail, verbose_name=u'出库明细', on_delete=models.PROTECT)
    product_base = models.ForeignKey(ProductBase, verbose_name=u'产品', on_delete=models.PROTECT)
    return_count = models.BigIntegerField(verbose_name=u'退料数量', default=0)
    return_cost = models.BigIntegerField(verbose_name=u'退料成本合计', default=0)
    warehouse_stock = models.ForeignKey(WarehouseStock, verbose_name=u'仓别库存', on_delete=models.PROTECT, editable=False)
    warehouse_record = models.ForeignKey(WarehouseRecord, verbose_name=u'库存记录', on_delete=models.PROTECT, null=True,
                                         blank=True, related_name='deliver_return_detail_ref_warehouse_record')
    notes = models.CharField(max_length=200, verbose_name=u"备注", blank=True, null=True)

    class Meta:
        db_table = "deliver_detail_return"
        verbose_name = u"退料管理"
        ordering = ('-id',)
        default_permissions = ()
        permissions = (# 退料管理明细
            ("view_consumable_deliver_return", u"浏览"),
            ("add_consumable_deliver_return", u"添加"),
            ("print_consumable_deliver_return", u"打印"),
        )