diff --git a/apps/ofm/migrations/0005_alter_vehicleuse_end_km.py b/apps/ofm/migrations/0005_alter_vehicleuse_end_km.py new file mode 100644 index 00000000..9761d933 --- /dev/null +++ b/apps/ofm/migrations/0005_alter_vehicleuse_end_km.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.12 on 2026-01-04 06:15 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ofm', '0004_auto_20251218_1636'), + ] + + operations = [ + migrations.AlterField( + model_name='vehicleuse', + name='end_km', + field=models.PositiveIntegerField(default=0, verbose_name='归还公里数'), + ), + ] diff --git a/apps/ofm/models.py b/apps/ofm/models.py index 808dce92..a0f4d743 100644 --- a/apps/ofm/models.py +++ b/apps/ofm/models.py @@ -60,7 +60,7 @@ class VehicleUse(CommonBDModel): via = models.CharField('途经地点', null=True, blank=True, max_length=100) destination = models.CharField('到达地点', null=True, blank=True, max_length=100) start_km = models.PositiveIntegerField('出发公里数', null=True, blank=True) - end_km = models.PositiveIntegerField('归还公里数') + end_km = models.PositiveIntegerField('归还公里数', default=0) actual_km = models.PositiveIntegerField('实际行驶公里数', editable=False) is_city = models.BooleanField('是否市内用车', default=True) reason = models.CharField('用车事由', max_length=100) diff --git a/apps/pum/migrations/0010_quotationapply.py b/apps/pum/migrations/0010_quotationapply.py new file mode 100644 index 00000000..18e0a83b --- /dev/null +++ b/apps/pum/migrations/0010_quotationapply.py @@ -0,0 +1,44 @@ +# Generated by Django 3.2.12 on 2025-12-26 07:29 + +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), + ('wf', '0006_auto_20251215_1645'), + ('pum', '0009_supplieraudit'), + ] + + operations = [ + migrations.CreateModel( + name='QuotationApply', + fields=[ + ('id', models.CharField(editable=False, help_text='主键ID', max_length=20, 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='删除标记')), + ('customer_name', models.CharField(max_length=50, verbose_name='客户名称')), + ('product_name', models.CharField(max_length=50, verbose_name='产品名称')), + ('contact_person', models.CharField(max_length=50, verbose_name='联系人')), + ('contact_phone', models.CharField(blank=True, max_length=20, null=True, verbose_name='联系电话')), + ('receive_address', models.CharField(blank=True, max_length=100, null=True, verbose_name='收件地址')), + ('product_spec_quantity', models.TextField(blank=True, null=True, verbose_name='产品规格/数量')), + ('quotation_basis', models.TextField(blank=True, null=True, verbose_name='报价依据')), + ('suggested_price_calc', models.TextField(blank=True, null=True, verbose_name='建议价格及计算方式')), + ('quotation_range', models.CharField(blank=True, max_length=100, null=True, verbose_name='报价区间')), + ('quoter', models.CharField(blank=True, max_length=50, null=True, verbose_name='报价人')), + ('apply_date', models.DateField(auto_now_add=True, verbose_name='申请日期')), + ('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='quotationapply_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')), + ('ticket', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='quo_ticket', to='wf.ticket', verbose_name='关联工单')), + ('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='quotationapply_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')), + ], + options={ + 'abstract': False, + }, + ), + ] diff --git a/apps/pum/models.py b/apps/pum/models.py index 1515a4a1..d13754e1 100644 --- a/apps/pum/models.py +++ b/apps/pum/models.py @@ -107,3 +107,22 @@ class PuPlanItem(CommonBDModel): null=True, blank=True, related_name='item_puplan') pu_order = models.ForeignKey(PuOrder, verbose_name='关联采购订单', on_delete=models.SET_NULL, null=True, blank=True, related_name='puplan_item_puorder') + + +class QuotationApply(CommonADModel): + """ + TN:报价申请表 + """ + customer_name = models.CharField(max_length=50,verbose_name="客户名称") + product_name = models.CharField(max_length=50,verbose_name="产品名称") + contact_person = models.CharField(max_length=50,verbose_name="联系人") + contact_phone = models.CharField(max_length=20,verbose_name="联系电话", null=True, blank=True) + receive_address = models.CharField(max_length=100,verbose_name="收件地址", null=True, blank=True) + product_spec_quantity = models.TextField(verbose_name="产品规格/数量", null=True, blank=True) + quotation_basis = models.TextField(verbose_name="报价依据", null=True, blank=True) + suggested_price_calc = models.TextField(verbose_name="建议价格及计算方式", null=True, blank=True) + quotation_range = models.CharField(max_length=100,verbose_name="报价区间", null=True, blank=True) + quoter = models.CharField(max_length=50,verbose_name="报价人", null=True, blank=True) + apply_date = models.DateField(verbose_name="申请日期",auto_now_add=True) + ticket = models.OneToOneField('wf.ticket', verbose_name='关联工单', + on_delete=models.CASCADE, related_name='quo_ticket', null=True, blank=True) \ No newline at end of file diff --git a/apps/pum/serializers.py b/apps/pum/serializers.py index 675c9b7b..23b5cda5 100644 --- a/apps/pum/serializers.py +++ b/apps/pum/serializers.py @@ -3,7 +3,7 @@ from apps.utils.serializers import CustomModelSerializer from apps.utils.constants import EXCLUDE_FIELDS_DEPT, EXCLUDE_FIELDS_BASE, EXCLUDE_FIELDS from rest_framework.exceptions import ValidationError, ParseError -from apps.pum.models import Supplier, PuPlan, PuPlanItem, PuOrder, PuOrderItem, SupplierAudit +from apps.pum.models import Supplier, PuPlan, PuPlanItem, PuOrder, PuOrderItem, SupplierAudit, QuotationApply from apps.mtm.serializers import MaterialSerializer, MaterialSimpleSerializer from django.db import transaction from .services import PumService @@ -157,4 +157,11 @@ class SupplierAuditSerializer(CustomModelSerializer): name = validated_data["name"] if Supplier.objects.filter(name=name).exists(): raise ParseError('供应商名称已存在') - return super().create(validated_data) \ No newline at end of file + return super().create(validated_data) + +class QuotationApplySerializer(CustomModelSerializer): + ticket_ = TicketSimpleSerializer(source='ticket', read_only=True) + class Meta: + model = QuotationApply + fields = "__all__" + read_only_fields = EXCLUDE_FIELDS \ No newline at end of file diff --git a/apps/pum/urls.py b/apps/pum/urls.py index 5032da70..cb316589 100644 --- a/apps/pum/urls.py +++ b/apps/pum/urls.py @@ -1,6 +1,7 @@ from django.urls import path, include from rest_framework.routers import DefaultRouter -from apps.pum.views import (SupplierViewSet, PuPlanViewSet, PuPlanItemViewSet, PuOrderViewSet, PuOrderItemViewSet, SupplierAuditViewSet) +from apps.pum.views import (SupplierViewSet, PuPlanViewSet, PuPlanItemViewSet, PuOrderViewSet, PuOrderItemViewSet, SupplierAuditViewSet, QuotationApplyViewSet) +# from apps.pum.views import SupplierViewSet, PuPlanViewSet, PuPlanItemViewSet, PuOrderViewSet, PuOrderItemViewSet API_BASE_URL = 'api/pum/' HTML_BASE_URL = 'dhtml/pum/' @@ -12,6 +13,7 @@ router.register('pu_plan', PuPlanViewSet, basename='pu_plan') router.register('pu_planitem', PuPlanItemViewSet, basename='pu_planitem') router.register('pu_order', PuOrderViewSet, basename='pu_order') router.register('pu_orderitem', PuOrderItemViewSet, basename='pu_orderitem') +router.register('quotation', QuotationApplyViewSet, basename='quotation') urlpatterns = [ path(API_BASE_URL, include(router.urls)), ] \ No newline at end of file diff --git a/apps/pum/views.py b/apps/pum/views.py index 37793033..9899b8b7 100644 --- a/apps/pum/views.py +++ b/apps/pum/views.py @@ -1,7 +1,7 @@ from django.shortcuts import render -from apps.pum.models import Supplier, PuPlan, PuPlanItem, PuOrder, PuOrderItem, SupplierAudit +from apps.pum.models import Supplier, PuPlan, PuPlanItem, PuOrder, PuOrderItem, SupplierAudit, QuotationApply from apps.utils.viewsets import CustomGenericViewSet, CustomModelViewSet, EuModelViewSet -from apps.pum.serializers import (SupplierSerializer, PuPlanSerializer, PuPlanItemSerializer, +from apps.pum.serializers import (SupplierSerializer, PuPlanSerializer, PuPlanItemSerializer, QuotationApplySerializer, PuOrderSerializer, PuOrderItemSerializer, AddSerializer, SupplierAuditSerializer) from rest_framework.exceptions import ParseError, PermissionDenied from rest_framework.decorators import action @@ -210,3 +210,16 @@ class PuOrderItemViewSet(CustomModelViewSet): item.pu_order = puorder item.save() return Response() + +class QuotationApplyViewSet(TicketMixin, CustomModelViewSet): + """ + list: 报价申请 + + 报价申请 + """ + queryset = QuotationApply.objects.all() + serializer_class = QuotationApplySerializer + filterset_fields = ['product_name', 'customer_name','apply_date', 'quoter'] + search_fields = ['product_name', 'customer_name','contact_person'] + ordering = ['create_time'] + workflow_key = "wf_quotation" \ No newline at end of file