feat: 初步统计能管相关数据产量和成本

This commit is contained in:
caoqianming 2023-07-17 15:33:35 +08:00
parent 3fbe3e7d0e
commit f8bc2294f0
11 changed files with 309 additions and 58 deletions

View File

@ -40,5 +40,8 @@ class EnStatFilter(filters.FilterSet):
"sflog": ["exact"],
"day_s": ["exact"],
"month_s": ["exact"],
"year_s": ["exact"]
"year_s": ["exact"],
"year": ["exact"],
"month": ['exact'],
"hour": ['exact']
}

View File

@ -0,0 +1,18 @@
# Generated by Django 3.2.12 on 2023-07-17 02:05
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('enm', '0007_mpointstat_mgroup'),
]
operations = [
migrations.AddField(
model_name='mpoint',
name='is_all',
field=models.BooleanField(default=False, verbose_name='是否记录是整个工段'),
),
]

View File

@ -0,0 +1,43 @@
# Generated by Django 3.2.12 on 2023-07-17 06:03
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('enm', '0008_mpoint_is_all'),
]
operations = [
migrations.AddField(
model_name='enstat',
name='day',
field=models.PositiveSmallIntegerField(blank=True, null=True, verbose_name=''),
),
migrations.AddField(
model_name='enstat',
name='hour',
field=models.PositiveSmallIntegerField(blank=True, null=True, verbose_name='小时'),
),
migrations.AddField(
model_name='enstat',
name='imaterial_data',
field=models.JSONField(blank=True, default=list, verbose_name='成本物料数据'),
),
migrations.AddField(
model_name='enstat',
name='month',
field=models.PositiveSmallIntegerField(blank=True, null=True, verbose_name=''),
),
migrations.AddField(
model_name='enstat',
name='other_cost_data',
field=models.JSONField(blank=True, default=list, verbose_name='其他成本数据'),
),
migrations.AddField(
model_name='enstat',
name='year',
field=models.PositiveSmallIntegerField(blank=True, null=True, verbose_name=''),
),
]

View File

@ -0,0 +1,23 @@
# Generated by Django 3.2.12 on 2023-07-17 07:32
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('enm', '0009_auto_20230717_1403'),
]
operations = [
migrations.AlterField(
model_name='enstat',
name='type',
field=models.CharField(default='hour', help_text='year_s/month_s/day_s/sflog/hour_s', max_length=50, verbose_name='统计维度'),
),
migrations.AlterField(
model_name='mpointstat',
name='type',
field=models.CharField(default='hour', help_text='year/month/day/year_s/month_s/day_s/sflog/hour_s/hour', max_length=50, verbose_name='统计维度'),
),
]

View File

@ -17,6 +17,7 @@ class Mpoint(CommonBModel):
mgroup = models.ForeignKey('mtm.mgroup', verbose_name='所在集合', on_delete=models.SET_NULL, null=True, blank=True)
mgroups_allocate = models.JSONField('各工段分配', default=list, blank=True, help_text='[{"mgroup":"x", "ratio": 1}]')
is_auto = models.BooleanField('是否自动采集', default=True)
is_all = models.BooleanField('是否记录是整个工段', default=False)
class MpLog(BaseModel):
@ -32,7 +33,7 @@ class MpLog(BaseModel):
class MpointStat(CommonADModel):
"""测点统计表
"""
type = models.CharField('统计维度', max_length=50, default='hour', help_text='year/month/day/year_s/month_s/day_s/sflog/hour')
type = models.CharField('统计维度', max_length=50, default='hour', help_text='year/month/day/year_s/month_s/day_s/sflog/hour_s/hour')
year = models.PositiveSmallIntegerField('', null=True, blank=True)
month = models.PositiveSmallIntegerField('', null=True, blank=True)
day = models.PositiveSmallIntegerField('', null=True, blank=True)
@ -52,14 +53,20 @@ class EnStat(BaseModel):
"""
能源数据统计表
"""
type = models.CharField('统计维度', max_length=50, default='hour', help_text='year_s/month_s/day_s/sflog/hour')
type = models.CharField('统计维度', max_length=50, default='hour', help_text='year_s/month_s/day_s/sflog/hour_s')
sflog = models.ForeignKey(SfLog, verbose_name='关联值班记录', on_delete=models.CASCADE, null=True, blank=True)
mgroup = models.ForeignKey(Mgroup, verbose_name='关联工段', on_delete=models.CASCADE)
year = models.PositiveSmallIntegerField('', null=True, blank=True)
month = models.PositiveSmallIntegerField('', null=True, blank=True)
day = models.PositiveSmallIntegerField('', null=True, blank=True)
hour = models.PositiveSmallIntegerField('小时', null=True, blank=True)
year_s = models.PositiveSmallIntegerField('班年', null=True, blank=True)
month_s = models.PositiveSmallIntegerField('班月', null=True, blank=True)
day_s = models.PositiveSmallIntegerField('班日', null=True, blank=True)
total_production = models.FloatField('总产量', null=True, blank=True, help_text='t')
elec_consume = models.FloatField('总电耗', null=True, blank=True, help_text='kw·h')
imaterial_data = models.JSONField('成本物料数据', default=list, blank=True)
other_cost_data = models.JSONField('其他成本数据', default=list, blank=True)
production_cost_unit = models.FloatField('单位产品成本', null=True, blank=True, help_text='y/t')
elec_consume_unit = models.FloatField('单位产品分布电耗', null=True, blank=True, help_text='kw·h/t')
celec_consume_unit = models.FloatField('单位产品综合电耗', null=True, blank=True, help_text='kw·h/t')

View File

@ -13,7 +13,9 @@ from dateutil import tz
from django.conf import settings
from django.utils.timezone import localtime
from apps.wpm.services import make_sflogs
from apps.mtm.models import Mgroup
from apps.mtm.models import Mgroup, Material
from apps.fim.services import get_cost_unit, get_price_unit
from apps.fim.models import Fee
def get_current_and_previous_time():
now = datetime.datetime.now()
@ -97,44 +99,29 @@ def cal_mpointstat_hour(mpointId: str, year: int, month: int, day: int, hour: in
sflog = SfLog.objects.filter(start_time__lte=dt, end_time__gt=dt, mgroup=mgroup).first()
end_time_local = localtime(sflog.end_time)
year_s, month_s, day_s = end_time_local.year, end_time_local.month, end_time_local.day
ms.year_s = year_s
ms.month_s = month_s
ms.day_s = day_s
ms.save()
mgroup = sflog.mgroup
params_hour_s = {'type': 'hour_s', 'mpoint': mpoint, 'sflog': sflog, 'mgroup': mgroup, 'year': year, 'month': month, 'day': day, 'year_s': year_s, 'month_s': month_s, 'day_s': day_s, 'hour': hour}
ms_hour_s, _ = MpointStat.objects.get_or_create(**params_hour_s, defaults=params_hour_s)
ms_hour_s.val = ms.val*ratio
ms_hour_s.save()
# 开始往上计算
sum_dict_sflog_s = MpointStat.objects.filter(type='hour', mpoint=mpoint, year_s=year_s, month_s=month_s, day_s=day_s).aggregate(sum=Sum('val'))
params_sflog_s = {'type':'sflog', 'mpoint': mpoint, 'year_s': year_s, 'month_s': month_s, 'day_s': day_s, 'mgroup': mgroup}
sum_dict_sflog_s = MpointStat.objects.filter(type='hour_s', mpoint=mpoint, year_s=year_s, month_s=month_s, day_s=day_s).aggregate(sum=Sum('val'))
params_sflog_s = {'type':'sflog', 'mpoint': mpoint, 'sflog': sflog, 'year_s': year_s, 'month_s': month_s, 'day_s': day_s, 'mgroup': mgroup}
ms_sflog_s, _ = MpointStat.objects.get_or_create(**params_sflog_s, defaults=params_sflog_s)
ms_sflog_s.val = sum_dict_sflog_s['sum']*ratio
ms_sflog_s.val = sum_dict_sflog_s['sum']
ms_sflog_s.save()
sum_dict_day_s = MpointStat.objects.filter(type='sflog', mpoint=mpoint, year_s=year_s, month_s=month_s, day_s=day_s, mgroup=mgroup).aggregate(sum=Sum('val'))
params_day_s = {'type':'day_s', 'mpoint': mpoint, 'year_s': year_s, 'month_s': month_s, 'day_s': day_s, 'mgroup': mgroup}
ms_day_s, _ = MpointStat.objects.get_or_create(**params_day_s, defaults=params_day_s)
ms_day_s.val = sum_dict_day_s['sum']
ms_day_s.save()
cal_mpointstat_manual(mpoint.id, mgroup.id, year_s, month_s, day_s)
compute_enstat('hour_s', sflog.id, mgroup.id, year, month, day, hour, year_s, month_s, day_s)
sum_dict_month_s = MpointStat.objects.filter(type='day_s', mpoint=mpoint, year_s=year_s, month_s=month_s, mgroup=mgroup).aggregate(sum=Sum('val'))
params_month_s = {'type':'month_s', 'mpoint': mpoint, 'year_s': year_s, 'month_s': month_s, 'mgroup': mgroup}
ms_month_s, _ = MpointStat.objects.get_or_create(**params_month_s, defaults=params_month_s)
ms_month_s.val = sum_dict_month_s['sum']
ms_month_s.save()
sum_dict_year_s = MpointStat.objects.filter(type='month_s', mpoint=mpoint, year_s=year_s, mgroup=mgroup).aggregate(sum=Sum('val'))
params_year_s = {'type':'year_s', 'mpoint': mpoint, 'year_s': year_s, 'mgroup': mgroup}
ms_year_s, _ = MpointStat.objects.get_or_create(**params_year_s, defaults=params_year_s)
ms_year_s.val = sum_dict_year_s['sum']
ms_year_s.save()
# compute_enstat.delay(mpoint.id, year_s, month_s, day_s, hour)
@shared_task(base=CustomTask)
def cal_mpointstats(is_now=1):
"""
计算所有测点的统计值默认当前小时
计算所有自动采集测点的统计值默认当前小时
"""
now, pre = get_current_and_previous_time()
if is_now:
@ -145,42 +132,112 @@ def cal_mpointstats(is_now=1):
cal_mpointstat_hour.delay(mpoint.id, pre.year, pre.month, pre.day, pre.hour)
@shared_task(base=CustomTask)
def cal_mpointstat_manual(mpointId: str, mgroupId: str, year_s: int, month_s: int, day_s: int):
"""
手动录入的测点数据进行往上统计一级一级往上
"""
mpoint = Mpoint.objects.get(id=mpointId)
mgroup = Mgroup.objects.get(id=mgroupId)
if mpoint.material:
sum_dict_day_s = MpointStat.objects.filter(type='sflog', mpoint=mpoint, year_s=year_s, month_s=month_s, day_s=day_s, mgroup=mgroup).aggregate(sum=Sum('val'))
params_day_s = {'type':'day_s', 'mpoint': mpoint, 'year_s': year_s, 'month_s': month_s, 'day_s': day_s, 'mgroup': mgroup}
ms_day_s, _ = MpointStat.objects.get_or_create(**params_day_s, defaults=params_day_s)
ms_day_s.val = sum_dict_day_s['sum']
ms_day_s.save()
sum_dict_day_s = MpointStat.objects.filter(type='sflog', mpoint=mpoint, year_s=year_s, month_s=month_s, day_s=day_s, mgroup=mgroup).aggregate(sum=Sum('val'))
params_day_s = {'type':'day_s', 'mpoint': mpoint, 'year_s': year_s, 'month_s': month_s, 'day_s': day_s, 'mgroup': mgroup}
ms_day_s, _ = MpointStat.objects.get_or_create(**params_day_s, defaults=params_day_s)
ms_day_s.val = sum_dict_day_s['sum']
ms_day_s.save()
sum_dict_month_s = MpointStat.objects.filter(type='day_s', mpoint=mpoint, year_s=year_s, month_s=month_s, mgroup=mgroup).aggregate(sum=Sum('val'))
params_month_s = {'type':'month_s', 'mpoint': mpoint, 'year_s': year_s, 'month_s': month_s, 'mgroup': mgroup}
ms_month_s, _ = MpointStat.objects.get_or_create(**params_month_s, defaults=params_month_s)
ms_month_s.val = sum_dict_month_s['sum']
ms_month_s.save()
sum_dict_month_s = MpointStat.objects.filter(type='day_s', mpoint=mpoint, year_s=year_s, month_s=month_s, mgroup=mgroup).aggregate(sum=Sum('val'))
params_month_s = {'type':'month_s', 'mpoint': mpoint, 'year_s': year_s, 'month_s': month_s, 'mgroup': mgroup}
ms_month_s, _ = MpointStat.objects.get_or_create(**params_month_s, defaults=params_month_s)
ms_month_s.val = sum_dict_month_s['sum']
ms_month_s.save()
sum_dict_year_s = MpointStat.objects.filter(type='month_s', mpoint=mpoint, year_s=year_s, mgroup=mgroup).aggregate(sum=Sum('val'))
params_year_s = {'type':'year_s', 'mpoint': mpoint, 'year_s': year_s, 'mgroup': mgroup}
ms_year_s, _ = MpointStat.objects.get_or_create(**params_year_s, defaults=params_year_s)
ms_year_s.val = sum_dict_year_s['sum']
ms_year_s.save()
sum_dict_year_s = MpointStat.objects.filter(type='month_s', mpoint=mpoint, year_s=year_s, mgroup=mgroup).aggregate(sum=Sum('val'))
params_year_s = {'type':'year_s', 'mpoint': mpoint, 'year_s': year_s, 'mgroup': mgroup}
ms_year_s, _ = MpointStat.objects.get_or_create(**params_year_s, defaults=params_year_s)
ms_year_s.val = sum_dict_year_s['sum']
ms_year_s.save()
def compute_enstat(mpointId: str, year_s, month_s, day_s, sflogId, hour):
def compute_enstat(type, sflogId, mgroupId, year, month, day, hour, year_s, month_s, day_s):
"""
计算能源数据统计
"""
mpoint = Mpoint.objects.get(id=mpointId)
mgroup = mpoint.mgroup
mgroup = Mgroup.objects.get(id=mgroupId)
sflog = SfLog.objects.get(id=sflogId)
if mpoint.material.code == 'elec':
MpointStat.objects.filter(type="hour", mpoint__material__code='elec', mpoint__mgroup=mgroup, year_s=year_s, month_s=month_s, day_s=day_s, hour=hour).aggregate(sum=Sum('val'))
# hour
enm_hour, _ = EnStat.objects.get_or_create(type='hour', )
elif mpoint.material == mgroup.product:
pass
if type == 'hour_s':
enstat, _ = EnStat.objects.get_or_create(type="hour_s", mgroup=mgroup, year=year, month=month, day=day, hour=hour,
defaults={'type': 'hour_s', 'mgroup': mgroup, 'year_s': year_s, 'month_s': month_s, 'day_s': day_s,
'year': year, 'month': month, 'day': day, 'hour': hour,
'total_production': 0, 'elec_consume': 0})
elif type == 'sflog':
enstat, _ = EnStat.objects.get_or_create(type="sflog", sflog=sflog,
defaults={'type': 'sflog', 'sflog': sflog, 'mgroup': mgroup, 'year_s': year_s, 'month_s': month_s, 'day_s': day_s, 'total_production': 0, 'elec_consume': 0})
elif type == 'day_s':
enstat, _ = EnStat.objects.get_or_create(type="day_s", mgroup=mgroup, year_s=year_s, month_s=month_s, day_s=day_s,
defaults={'type': 'day_s', 'mgroup': mgroup, 'year_s': year_s, 'month_s': month_s, 'day_s': day_s, 'total_production': 0, 'elec_consume': 0})
elif type == 'month_s':
enstat, _ = EnStat.objects.get_or_create(type="month_s", mgroup=mgroup, year_s=year_s, month_s=month_s,
defaults={'type': 'month_s', 'mgroup': mgroup, 'year_s': year_s, 'month_s': month_s, 'total_production': 0, 'elec_consume': 0})
elif type == 'year_s':
enstat, _ = EnStat.objects.get_or_create(type="year_s", mgroup=mgroup, year_s=year_s, month_s=month_s,
defaults={'type': 'year_s', 'mgroup': mgroup, 'year_s': year_s, 'total_production': 0, 'elec_consume': 0})
# 物料统计
input_materials = mgroup.input_materials
if mgroup.product:
input_materials.insert(0, mgroup.product.id)
cost_unit_total = 0
imaterial_data = []
for mid in input_materials:
material = Material.objects.get(id=mid)
if type == 'hour_s':
mps = MpointStat.objects.filter(type='hour_s', mgroup=mgroup, year_s=year_s, month_s=month_s, day_s=day_s, hour=hour, mpoint__material=material)
elif type == 'sflog':
mps = MpointStat.objects.filter(type='sflog', sflog=sflog, mpoint__material=material)
elif type == 'day_s':
mps = MpointStat.objects.filter(type='day_s', mgroup=mgroup, year_s=year_s, month_s=month_s, day_s=day_s, mpoint__material=material)
elif type == 'month_s':
mps = MpointStat.objects.filter(type='month_s', mgroup=mgroup, year_s=year_s, month_s=month_s, mpoint__material=material)
elif type == 'year_s':
mps = MpointStat.objects.filter(type='year_s', mgroup=mgroup, year_s=year_s, mpoint__material=material)
if mps.filter(mpoint__is_all=True).exists():
mps = mps.filter(mpoint__is_all=True)
amount_consume = mps.aggregate(sum=Sum('val'))['sum']
if amount_consume is None:
amount_consume = 0
if mid == mgroup.product.id:
enstat.total_production = amount_consume
enstat.save()
else:
price_unit = get_price_unit(material, year_s, month_s)
cost = amount_consume * price_unit
try:
cost_unit = cost/ enstat.total_production
except:
cost_unit = 0
cost_unit_total = cost_unit_total + cost_unit
if material.code == 'elec':
enstat.elec_consume = amount_consume
enstat.save()
imaterial_data.append({'material': mid, 'material_name': material.name, 'material_type': material.type, 'price_unit': price_unit, 'cost': cost, 'cost_unit': cost_unit})
enstat.imaterial_data = imaterial_data
enstat.save()
other_cost_data = []
for fee in Fee.objects.order_by('sort'):
item = {'element': fee.element, 'cate': fee.cate, 'name': fee.name, 'id': fee.id}
item['cost_unit'] = get_cost_unit(mgroup, fee, year_s, month_s)
cost_unit_total = cost_unit_total + item['cost_unit']
other_cost_data.append(item)
enstat.other_cost_data = other_cost_data
enstat.production_cost_unit = cost_unit_total
enstat.save()
if type == 'hour_s':
compute_enstat('sflog', sflogId, mgroupId, year, month, day, hour, year_s, month_s, day_s)
elif type == 'sflog':
compute_enstat('day_s', sflogId, mgroupId, year, month, day, hour, year_s, month_s, day_s)
elif type == 'day_s':
compute_enstat('month_s', sflogId, mgroupId, year, month, day, hour, year_s, month_s, day_s)
elif type == 'month_s':
compute_enstat('year_s', sflogId, mgroupId, year, month, day, hour, year_s, month_s, day_s)

View File

@ -0,0 +1,18 @@
# Generated by Django 3.2.12 on 2023-07-17 02:05
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('fim', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='fee',
name='sort',
field=models.PositiveSmallIntegerField(default=1, verbose_name='排序'),
),
]

View File

@ -9,6 +9,7 @@ class Fee(BaseModel):
name = models.CharField('名称', max_length=20)
cate = models.CharField('父名称', max_length=20)
element = models.CharField('要素', max_length=20, help_text='直接材料/直接人工/制造费用')
sort = models.PositiveSmallIntegerField('排序', default=1)
class FeeSet(CommonADModel):

View File

@ -2,6 +2,9 @@ from rest_framework import serializers
from apps.utils.serializers import CustomModelSerializer
from apps.utils.constants import EXCLUDE_FIELDS
from apps.fim.models import PriceSet, FeeSet, Fee
from apps.mtm.models import Mgroup
from apps.wpm.models import SfLog
from rest_framework.exceptions import ParseError
class FeeSerializer(CustomModelSerializer):
class Meta:
@ -24,3 +27,23 @@ class PriceSetSerializer(CustomModelSerializer):
model = PriceSet
fields = '__all__'
read_only_fields = EXCLUDE_FIELDS
class CostStatSerializer(serializers.Serializer):
type = serializers.CharField(label="统计维度", help_text="sflog/day_s/month_s/year_s")
mgroup = serializers.PrimaryKeyRelatedField(label='工段ID', required=False, queryset=Mgroup.objects.all())
sflog = serializers.PrimaryKeyRelatedField(label='值班记录ID', required=False, queryset=SfLog.objects.all())
year_s = serializers.IntegerField(label="", required=False)
month_s = serializers.IntegerField(label="", required=False)
day_s = serializers.IntegerField(label="", required=False)
def validate(self, attrs):
if type == 'sflog' and 'sflog' not in attrs:
raise ParseError('未提供值班记录')
elif type in ['year_s', 'month_s', 'day_s'] and 'mgroup' not in attrs:
raise ParseError('未提供工段ID')
elif type not in attrs:
raise ParseError('缺少年月日')
return super().validate(attrs)

48
apps/fim/services.py Normal file
View File

@ -0,0 +1,48 @@
from apps.fim.models import FeeSet, Fee, PriceSet
from apps.mtm.models import Mgroup, Material
import datetime
def get_cost_unit(mgroup: Mgroup, fee: Fee, year: int = 0, month: int = 0):
"""
获取某工段某费用的月成本, 默认本月
"""
now = datetime.datetime.now()
if year and month:
params = {'mgroup': mgroup, 'fee': fee, 'year': year, 'month': month}
else:
params = {'mgroup': mgroup, 'fee': fee, 'year': now.year, 'month': now.month}
qs = FeeSet.objects.filter(**params)
if qs.exists():
feeset = qs.first()
return feeset.cost_unit
else:
feeset_last = FeeSet.objects.filter(mgroup=mgroup, fee=fee).order_by('year', 'month').last()
if feeset_last:
params.update({'cost_unit': feeset_last.cost_unit})
else:
params.update({'cost_unit': 0})
feeset = FeeSet.objects.create(**params)
return feeset.cost_unit
def get_price_unit(material: Material, year: int = 0, month: int = 0):
"""
获取某物料的月成本, 默认本月
"""
now = datetime.datetime.now()
if year and month:
params = {'material': material, 'year': year, 'month': month}
else:
params = {'material': material, 'year': now.year, 'month': now.month}
qs = PriceSet.objects.filter(**params)
if qs.exists():
ps = qs.first()
return ps.price_unit
else:
ps_last = PriceSet.objects.filter(material=material).order_by('year', 'month').last()
if ps_last:
params.update({'price_unit': ps_last.price_unit})
else:
params.update({'price_unit': 0})
ps = PriceSet.objects.create(**params)
return ps.price_unit

View File

@ -2,6 +2,16 @@ from apps.fim.models import PriceSet, FeeSet, Fee
from apps.utils.viewsets import CustomModelViewSet, CustomGenericViewSet
from rest_framework.mixins import ListModelMixin, UpdateModelMixin
from apps.fim.serializers import (PriceSetSerializer, FeeSetSerializer, FeeSerializer)
from rest_framework.views import APIView
from rest_framework.response import Response
from drf_yasg.utils import swagger_auto_schema
from apps.fim.serializers import CostStatSerializer
from apps.mtm.models import Material
import datetime
from django.utils.timezone import localtime
from apps.enm.models import EnStat, MpointStat
from django.db.models import Sum
from apps.fim.services import get_price_unit, get_cost_unit
# Create your views here.
class FeeViewSet(ListModelMixin, CustomGenericViewSet):