销售记录接口

This commit is contained in:
caoqianming 2021-12-06 10:00:04 +08:00
parent 58d1ccc9bf
commit c2b38f3f1e
13 changed files with 273 additions and 29 deletions

View File

@ -1,9 +1,17 @@
from django_filters import rest_framework as filters
from apps.mtm.models import Material
from .models import MaterialBatch
from .models import IProduct, MaterialBatch
class MbFilterSet(filters.FilterSet):
material = filters.ModelMultipleChoiceFilter(field_name="material", queryset=Material.objects.all())
class Meta:
model = MaterialBatch
fields = ['material', 'warehouse']
class IProductFilterSet(filters.FilterSet):
order = filters.NumberFilter(field_name="wproduct__subproduction_plan__production_plan__order")
class Meta:
model = IProduct
fields = ['material', 'warehouse', 'batch', 'order']

View File

@ -0,0 +1,18 @@
# Generated by Django 3.2.9 on 2021-12-06 01:58
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inm', '0019_auto_20211201_1011'),
]
operations = [
migrations.AddField(
model_name='iproduct',
name='is_saled',
field=models.BooleanField(default=False, verbose_name='是否售出'),
),
]

View File

@ -102,5 +102,6 @@ class IProduct(BaseModel):
warehouse = models.ForeignKey(WareHouse, on_delete=models.CASCADE, verbose_name='所在仓库')
batch = models.CharField('所属批次号', max_length=100, default='')
wproduct = models.ForeignKey('wpm.wproduct', on_delete=models.CASCADE, verbose_name='关联的动态产品', db_constraint=False, null=True, blank=True)
is_saled = models.BooleanField('是否售出', default=False)

View File

@ -2,6 +2,7 @@ from rest_framework import serializers
from apps.inm.models import FIFO, FIFOItem, FIFOItemProduct, IProduct, MaterialBatch, WareHouse,Inventory
from apps.qm.models import TestRecord, TestRecordItem
from apps.sam.serializers import OrderSimpleSerializer
from apps.system.serializers import UserSimpleSerializer
from apps.mtm.serializers import MaterialSimpleSerializer
@ -40,10 +41,18 @@ class MaterialBatchSerializer(serializers. ModelSerializer):
class IProductListSerializer(serializers.ModelSerializer):
material_= MaterialSimpleSerializer(source='material', read_only=True)
warehouse_ = WareHouseSimpleSerializer(source='warehouse', read_only=True)
order_ = serializers.SerializerMethodField()
class Meta:
model = IProduct
fields = '__all__'
def get_order_(self, obj):
if obj.wproduct:
order = obj.wproduct.subproduction_plan.production_plan.order
if order:
return OrderSimpleSerializer(instance=order).data
return None
class FIFOListSerializer(serializers.ModelSerializer):
auditor_ = UserSimpleSerializer(source='auditor', read_only=True)

View File

@ -3,7 +3,7 @@ from rest_framework import serializers
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 MbFilterSet
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, InmTestRecordCreateSerializer, MaterialBatchQuerySerializer, MaterialBatchSerializer, WareHouseSerializer, WareHouseCreateUpdateSerializer,InventorySerializer
@ -167,9 +167,9 @@ class IProductViewSet(ListModelMixin, GenericViewSet):
半成品库存表
"""
perms_map = {'*': '*'}
queryset = IProduct.objects.select_related('material', 'warehouse').all()
queryset = IProduct.objects.select_related('material', 'warehouse', 'wproduct__subproduction_plan__production_plan__order').filter(is_saled=False)
serializer_class = IProductListSerializer
filterset_fields = ['material', 'warehouse', 'batch']
filterset_class = IProductFilterSet
search_fields = []
ordering_fields = ['create_time']
ordering = ['-create_time']

View File

@ -0,0 +1,28 @@
# Generated by Django 3.2.9 on 2021-12-03 07:01
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('sam', '0004_order_planed_count'),
]
operations = [
migrations.AddField(
model_name='order',
name='delivered_count',
field=models.PositiveIntegerField(default=0, verbose_name='交货数量'),
),
migrations.AlterField(
model_name='order',
name='count',
field=models.PositiveIntegerField(default=0, verbose_name='所需数量'),
),
migrations.AlterField(
model_name='order',
name='planed_count',
field=models.PositiveIntegerField(default=0, verbose_name='已排数量'),
),
]

View File

@ -0,0 +1,65 @@
# Generated by Django 3.2.9 on 2021-12-06 01:58
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('inm', '0020_iproduct_is_saled'),
('mtm', '0041_alter_material_type'),
('sam', '0005_auto_20211203_1501'),
]
operations = [
migrations.AlterField(
model_name='order',
name='delivered_count',
field=models.PositiveIntegerField(default=0, verbose_name='已交货数量'),
),
migrations.AlterField(
model_name='order',
name='number',
field=models.CharField(max_length=100, unique=True, verbose_name='订单编号'),
),
migrations.CreateModel(
name='Sale',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')),
('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')),
('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')),
('count', models.PositiveIntegerField(default=0, verbose_name='交货数量')),
('is_audited', models.BooleanField(default=False, verbose_name='是否审核')),
('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='sale_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
('customer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='sam.customer', verbose_name='客户')),
('order', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='sam.order', verbose_name='关联订单')),
('product', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mtm.material', verbose_name='所需产品')),
('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='sale_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')),
],
options={
'abstract': False,
},
),
migrations.CreateModel(
name='SaleProduct',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')),
('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')),
('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')),
('number', models.CharField(max_length=50, unique=True, verbose_name='物品编号')),
('is_mtested', models.BooleanField(default=False, verbose_name='是否军检')),
('is_mtestok', models.BooleanField(default=True, verbose_name='是否军检合格')),
('iproduct', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='sale_iproduct', to='inm.iproduct', verbose_name='关联库存产品')),
('sale', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='sam.sale', verbose_name='关联销售记录')),
],
options={
'unique_together': {('sale', 'iproduct')},
},
),
]

View File

@ -1,4 +1,4 @@
from apps.system.models import CommonAModel
from apps.system.models import CommonADModel, CommonAModel
from django.db import models
from django.contrib.auth.models import AbstractUser
from django.db.models.base import Model
@ -58,12 +58,13 @@ class Order(CommonAModel):
"""
订单信息
"""
number = models.CharField('订单编号', max_length=100)
number = models.CharField('订单编号', max_length=100, unique=True)
customer = models.ForeignKey(Customer, verbose_name='客户', on_delete=models.CASCADE)
contract = models.ForeignKey(Contract, verbose_name='所属合同', null=True, blank=True, on_delete=models.SET_NULL)
product = models.ForeignKey(Material, verbose_name='所需产品', on_delete=models.CASCADE)
count = models.IntegerField('所需数量', default=0)
planed_count = models.IntegerField('已排数量', default=0)
count = models.PositiveIntegerField('所需数量', default=0)
planed_count = models.PositiveIntegerField('已排数量', default=0)
delivered_count = models.PositiveIntegerField('已交货数量', default=0)
delivery_date = models.DateField('交货日期')
class Meta:
verbose_name = '订单信息'
@ -71,3 +72,33 @@ class Order(CommonAModel):
def __str__(self):
return self.name
class Sale(CommonADModel):
"""
销售记录
"""
customer = models.ForeignKey(Customer, verbose_name='客户', on_delete=models.CASCADE)
order = models.ForeignKey(Order, verbose_name='关联订单', on_delete=models.CASCADE, null=True, blank=True)
product = models.ForeignKey(Material, verbose_name='所需产品', on_delete=models.CASCADE)
count = models.PositiveIntegerField('交货数量', default=0)
is_audited = models.BooleanField('是否审核', default=False)
class SaleProduct(BaseModel):
"""
具体产品
"""
sale = models.ForeignKey(Sale, verbose_name='关联销售记录', on_delete=models.CASCADE)
number = models.CharField('物品编号', unique=True, max_length=50)
iproduct = models.ForeignKey('inm.iproduct', verbose_name='关联库存产品', on_delete=models.CASCADE, related_name='sale_iproduct')
is_mtested = models.BooleanField('是否军检', default=False)
is_mtestok = models.BooleanField('是否军检合格', default=True)
class Meta:
unique_together = (
('sale','iproduct'), # 联合唯一
)

View File

@ -1,6 +1,8 @@
from rest_framework import serializers
from .models import Contract, Customer, Order
from apps.inm.models import IProduct
from .models import Contract, Customer, Order, Sale, SaleProduct
from apps.mtm.serializers import MaterialSimpleSerializer
@ -54,3 +56,38 @@ class OrderSimpleSerializer(serializers.ModelSerializer):
class Meta:
model = Order
fields = '__all__'
class SaleCreateSerializer(serializers.ModelSerializer):
iproducts = serializers.PrimaryKeyRelatedField(queryset=IProduct.objects.all(), many=True)
class Meta:
model = Sale
fields = ['customer', 'order', 'product', 'iproducts']
def validate(self, attrs):
order = attrs.get('order', None)
if order:
if order.customer:
attrs['customer'] = order.customer
attrs['product'] = order.product
return super().validate(attrs)
def create(self, validated_data):
iproducts = validated_data.pop('iproducts')
sale = Sale.objects.create(**validated_data)
i_l = []
for i in iproducts:
i_d ={}
i_d['sale'] = sale
i_d['number'] = i.number
i_d['iproduct'] = i
i_l.append(SaleProduct(**i_d))
SaleProduct.objects.bulk_create(i_l)
return sale
class SaleListSerializer(serializers.ModelSerializer):
customer_ = CustomerSimpleSerializer(source='customer', read_only=True)
order_ = OrderSimpleSerializer(source='order', read_only=True)
product_ = MaterialSimpleSerializer(source='product', read_only=True)
class Meta:
model = Sale
fields = '__all__'

View File

@ -1,6 +1,6 @@
from django.db.models import base
from rest_framework import urlpatterns
from apps.sam.views import CustomerViewSet,ContractViewSet,OrderViewSet
from apps.sam.views import CustomerViewSet,ContractViewSet,OrderViewSet, SaleViewSet
from django.urls import path, include
from rest_framework.routers import DefaultRouter
@ -8,6 +8,7 @@ router = DefaultRouter()
router.register('customer', CustomerViewSet, basename='customer')
router.register('contract', ContractViewSet, basename='contract')
router.register('order', OrderViewSet, basename='order')
router.register('sale', SaleViewSet, basename='sale')
urlpatterns = [
path('', include(router.urls)),

View File

@ -1,6 +1,7 @@
from apps.sam.serializers import ContractCreateUpdateSerializer, ContractSerializer, CustomerCreateUpdateSerializer, CustomerSerializer, OrderCreateUpdateSerializer, OrderSerializer
from apps.sam.models import Contract, Customer, Order
from rest_framework.viewsets import ModelViewSet
from rest_framework.mixins import CreateModelMixin, ListModelMixin, RetrieveModelMixin
from apps.sam.serializers import ContractCreateUpdateSerializer, ContractSerializer, CustomerCreateUpdateSerializer, CustomerSerializer, OrderCreateUpdateSerializer, OrderSerializer, SaleCreateSerializer, SaleListSerializer
from apps.sam.models import Contract, Customer, Order, Sale
from rest_framework.viewsets import GenericViewSet, ModelViewSet
from apps.system.mixins import CreateUpdateCustomMixin
from django.shortcuts import render
from rest_framework.decorators import action
@ -57,7 +58,7 @@ class OrderViewSet(CreateUpdateCustomMixin, ModelViewSet):
def get_serializer_class(self):
if self.action in ['create', 'update']:
return OrderCreateUpdateSerializer
return OrderSerializer
return super().get_serializer_class()
@action(methods=['get'], detail=False, perms_map={'get':'*'})
def toplan(self, request, pk=None):
@ -68,3 +69,23 @@ class OrderViewSet(CreateUpdateCustomMixin, ModelViewSet):
return self.get_paginated_response(serializer.data)
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)
class SaleViewSet(CreateUpdateCustomMixin, ListModelMixin, RetrieveModelMixin, CreateModelMixin, GenericViewSet):
"""
销售记录
"""
perms_map = {'*': '*'}
queryset = Sale.objects.select_related('customer', 'order', 'product').all()
serializer_class = SaleListSerializer
search_fields = ['customer__name', 'order__number']
filterset_fields = ['product', 'order', 'customer']
ordering_fields = ['create_time']
ordering = ['-create_time']
def get_serializer_class(self):
if self.action == 'create':
return SaleCreateSerializer
elif self.action == 'retrieve':
return SaleListSerializer
return super().get_serializer_class()

View File

@ -0,0 +1,23 @@
# Generated by Django 3.2.9 on 2021-12-03 07:01
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('wf', '0016_auto_20211024_2349'),
]
operations = [
migrations.AlterField(
model_name='customfield',
name='field_type',
field=models.CharField(choices=[('string', '字符串'), ('int', '整型'), ('float', '浮点'), ('boolean', '布尔'), ('date', '日期'), ('datetime', '日期时间'), ('radio', '单选'), ('checkbox', '多选'), ('select', '单选下拉'), ('selects', '多选下拉'), ('textarea', '文本域'), ('selectuser', '单选用户'), ('selectusers', '多选用户'), ('file', '附件'), ('draw', '绘图')], help_text='5.字符串10.整形15.浮点型20.布尔25.日期30.日期时间35.单选框40.多选框45.下拉列表50.多选下拉列表55.文本域60.用户名, 70.多选的用户名, 80.附件(只保存路径,多个使用逗号隔开)', max_length=50, verbose_name='类型'),
),
migrations.AlterField(
model_name='ticket',
name='ticket_data',
field=models.JSONField(default=dict, help_text='工单自定义字段内容', verbose_name='工单数据'),
),
]

View File

@ -152,7 +152,8 @@ class CustomField(CommonAModel):
('textarea', '文本域'),
('selectuser', '单选用户'),
('selectusers', '多选用户'),
('file', '附件')
('file', '附件'),
('draw', '绘图')
)
workflow = models.ForeignKey(Workflow, on_delete=models.CASCADE, verbose_name='所属工作流')
field_type = models.CharField('类型', max_length=50, choices=field_type_choices, help_text='5.字符串10.整形15.浮点型20.布尔25.日期30.日期时间35.单选框40.多选框45.下拉列表50.多选下拉列表55.文本域60.用户名, 70.多选的用户名, 80.附件(只保存路径,多个使用逗号隔开)')
@ -201,7 +202,7 @@ class Ticket(CommonBModel):
state = models.ForeignKey(State, on_delete=models.CASCADE, verbose_name='当前状态', related_name='ticket_state')
parent = models.ForeignKey('self', null=True, blank=True, on_delete=models.CASCADE, verbose_name='父工单')
parent_state = models.ForeignKey(State, null=True, blank=True, on_delete=models.CASCADE, verbose_name='父工单状态', related_name='ticket_parent_state')
ticket_data = models.JSONField('工单数据', default=dict, help_text='工单所有字段内容')
ticket_data = models.JSONField('工单数据', default=dict, help_text='工单自定义字段内容')
in_add_node = models.BooleanField('加签状态中', default=False, help_text='是否处于加签状态下')
add_node_man = models.ForeignKey(User, verbose_name='加签人', on_delete=models.SET_NULL, null=True, blank=True, help_text='加签操作的人,工单当前处理人处理完成后会回到该处理人,当处于加签状态下才有效')
@ -211,16 +212,17 @@ class Ticket(CommonBModel):
multi_all_person = models.JSONField('全部处理的结果', default=dict, blank=True, help_text='需要当前状态处理人全部处理时实际的处理结果json格式')
class TicketData():
"""
工单数据,自定义字段值
"""
form_field = models.ForeignKey(CustomField, verbose_name='关联字段', on_delete=models.SET_NULL, db_constraint=False, null=True, blank=True)
field_name = models.CharField('字段名', max_length=50)
field_key = models.CharField('字段标识', max_length=50)
field_type = models.CharField('字段类型', choices=CustomField.field_type_choices, max_length=50)
field_value = models.JSONField('录入值', default=dict, blank=True)
sort = models.IntegerField('排序号', default=1)
# class TicketCustomField(BaseModel):
# """
# 工单数据,自定义字段值
# """
# ticket = models.ForeignKey(Ticket, verbose_name='关联工单', on_delete=models.CASCADE)
# form_field = models.ForeignKey(CustomField, verbose_name='关联字段', on_delete=models.SET_NULL, db_constraint=False, null=True, blank=True)
# field_name = models.CharField('字段名', max_length=50)
# field_key = models.CharField('字段标识', max_length=50)
# field_type = models.CharField('字段类型', choices=CustomField.field_type_choices, max_length=50)
# field_value = models.JSONField('录入值', default=dict, blank=True)
# sort = models.IntegerField('排序号', default=1)
class TicketFlow(BaseModel):
"""