1
0
forked from erp-dev/erp
Files
erpnew/printing/admin.py

414 lines
15 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from django.contrib import admin
from django.contrib.admin import action
from django.forms import BaseInlineFormSet
from django.utils.html import format_html
from . import models
@admin.register(models.PlateOrder)
class PlateOrderAdmin(admin.ModelAdmin):
list_display = (
'id',
'design_code_display',
'customer_name',
'style_name',
'plate_type',
'development_status_display',
'urgency_display',
'progress_display',
'salesperson_name',
'required_completion_date',
'created_at',
)
list_filter = (
'urgency_level',
'plate_type',
'is_ordered',
'is_mark_frame',
'created_at',
'required_completion_date',
)
search_fields = (
'design_code',
'style_name',
'customer__name',
'salesperson__name',
'merchandiser__name',
'designer__name',
)
readonly_fields = ('progress_display', 'status_display')
actions = ['advance_to_next_state_action', 'step_back_one_state_action', 'reset_progress_action']
autocomplete_fields = ['customer', 'salesperson', 'merchandiser', 'designer']
fieldsets = [
('基本信息', {
'fields': ['design_code', 'plate_type', 'plate_date', 'urgency_level']
}),
('客户信息', {
'fields': ['customer', 'area', 'default_address', 'salesperson', 'merchandiser', 'designer']
}),
('产品信息', {
'fields': ['style_name', 'fabric', 'fabric_source', 'width', 'production_method']
}),
('开版信息', {
'fields': [
'plate_method', 'plate_image', 'plate_notes', 'reprint_reason',
'is_mark_frame', 'sample_meter', 'required_sample_meters'
]
}),
('质量评级', {
'fields': [
'drawing_rating', 'color_matching_rating',
'sample_rating', 'difficulty_rating'
]
}),
('时间管理', {
'fields': ['required_completion_date', 'completion_date']
}),
('审批与反馈', {
'fields': [
'approval_result', 'customer_feedback',
'is_ordered'
]
}),
('流程管理', {
'fields': ['business_object', 'status_display', 'progress_display'],
'classes': ['collapse']
}),
]
@admin.display(description='设计编号')
def design_code_display(self, obj):
return obj.design_code or (str(obj.id) if obj.id else '-')
@admin.display(description='客户')
def customer_name(self, obj):
return obj.customer.name if obj.customer else '-'
@admin.display(description='销售员')
def salesperson_name(self, obj):
return obj.salesperson.name if obj.salesperson else '-'
@admin.display(description='开发进程')
def development_status_display(self, obj):
return obj.status
@admin.display(description='紧急程度')
def urgency_display(self, obj):
if obj.urgency_level == '加急':
return format_html(
'<span style="color: red; font-weight: bold;">⚠️ 加急</span>'
)
return obj.urgency_level
@admin.display(description='进度')
def progress_display(self, obj):
return obj.progress_percentage
@admin.display(description='当前状态')
def status_display(self, obj):
return obj.status
@action(description='推进到下一个状态')
def advance_to_next_state_action(self, request, queryset):
from stateflow import services
success_count = 0
messages = []
for obj in queryset:
if not obj.business_object:
messages.append(f"{obj.id}: 没有关联的流程实例,无法推进")
continue
success, message, state_log = services.advance_to_next_state(obj.business_object, request.user)
if success:
success_count += 1
messages.append(f"{obj.id}: {message}")
self.message_user(request, f'成功推进 {success_count}/{queryset.count()} 个开版订单。详情: {"; ".join(messages[:5])}')
@action(description='回退一步')
def step_back_one_state_action(self, request, queryset):
from stateflow import services
success_count = 0
messages = []
for obj in queryset:
if not obj.business_object:
messages.append(f"{obj.id}: 没有关联的流程实例,无法回退")
continue
success, message = services.step_back_one_state(obj.business_object, request.user)
if success:
success_count += 1
messages.append(f"{obj.id}: {message}")
self.message_user(request, f'成功回退 {success_count}/{queryset.count()} 个开版订单。详情: {"; ".join(messages[:5])}')
@action(description='重置进度')
def reset_progress_action(self, request, queryset):
from stateflow import services
reset_count = 0
for obj in queryset:
if not obj.business_object:
continue
services.reset_business_object_progress(obj.business_object)
reset_count += 1
self.message_user(request, f'已重置 {reset_count} 个开版订单的进度。')
class PrintingJobInlineFormSet(BaseInlineFormSet):
"""自定义 formset 处理 PrintingJob 的创建"""
def save_new(self, form, commit=True):
"""保存新的 PrintingJob暂时不创建 BusinessObject等 order 保存完成后再创建)"""
obj = super().save_new(form, commit=commit)
return obj
class PrintingJobInline(admin.StackedInline):
model = models.PrintingJob
formset = PrintingJobInlineFormSet
extra = 1
@admin.register(models.PrintingOrder)
class PrintingOrderAdmin(admin.ModelAdmin):
list_display = (
'oid',
'customer_name',
'progress_percent',
'created_at',
'outgoing_date',
)
inlines = [PrintingJobInline]
def save_formset(self, request, form, formset, change):
"""保存 formset 后,为新创建的 PrintingJob 创建 BusinessObject"""
# 先调用默认的保存
formset.save()
# 此时 PrintingOrder 已经保存完成(包括 process 字段)
# 为所有新创建且没有 business_object 的 job 创建 BusinessObject
if isinstance(formset.model, type) and issubclass(formset.model, models.PrintingJob):
order = form.instance
for job in order.printing_jobs.all():
if not job.business_object and order.process:
from stateflow.models import BusinessObject
business_object = BusinessObject.objects.create(
name=f"PrintingJob-{job.id}",
process=order.process,
description=f"印染任务 {job.id} 的流程实例",
)
job.business_object = business_object
job.save(update_fields=['business_object'])
def save_model(self, request, obj, form, change):
"""保存 PrintingOrder 时使用 service 层"""
from api_v1.views.printing.services import PrintingOrderService
if not change: # 新创建
# 使用 service 创建(会自动设置默认 process
data = {
'customer': obj.customer,
'fabric': obj.fabric,
'width': obj.width,
'is_urgent': obj.is_urgent,
'area': obj.area,
'address': obj.address,
'fabric_source': obj.fabric_source,
'is_fabric_received': obj.is_fabric_received,
'craft': obj.craft,
'description': obj.description,
'outgoing_date': obj.outgoing_date,
'curve': obj.curve,
'new_curve': obj.new_curve,
'position': obj.position,
'printing_warn': obj.printing_warn,
'rolling_warn': obj.rolling_warn,
'production_warn': obj.production_warn,
'is_invalid': obj.is_invalid,
'process': obj.process,
}
created_obj = PrintingOrderService.create_printing_order(data, request.user)
# 将创建的对象的所有字段复制到当前对象
for field in created_obj._meta.fields:
setattr(obj, field.name, getattr(created_obj, field.name))
else: # 更新
# 使用 service 更新
data = {
'customer': obj.customer,
'fabric': obj.fabric,
'width': obj.width,
'is_urgent': obj.is_urgent,
'area': obj.area,
'address': obj.address,
'fabric_source': obj.fabric_source,
'is_fabric_received': obj.is_fabric_received,
'craft': obj.craft,
'description': obj.description,
'outgoing_date': obj.outgoing_date,
'curve': obj.curve,
'new_curve': obj.new_curve,
'position': obj.position,
'printing_warn': obj.printing_warn,
'rolling_warn': obj.rolling_warn,
'production_warn': obj.production_warn,
'is_invalid': obj.is_invalid,
'process': obj.process,
}
success, message, updated_obj = PrintingOrderService.update_printing_order(
obj, data, request.user
)
if not success:
from django.core.exceptions import ValidationError
raise ValidationError(message)
@admin.display(description='客户名称')
def customer_name(self, obj: models.PrintingOrder):
return obj.customer.name
@admin.display(description='订单编号(虚拟)')
def oid(self, obj: models.PrintingOrder):
return obj.human_id
@admin.display(description='进度')
def progress_percent(self, obj: models.PrintingOrder):
return f"{obj.progress}%"
@admin.register(models.PrintingJob)
class PrintingJobAdmin(admin.ModelAdmin):
list_display = (
'id',
'printing_order',
'customer_name',
'product',
'quantity',
'unit',
'size',
'pieces',
'business_object',
'current_progress',
'execution_status',
'created_at',
)
search_fields = ('printing_order__human_id', 'product__name')
list_filter = ('created_at', 'printing_order__customer__name')
actions = ['advance_to_next_state_action', 'step_back_one_state_action', 'reset_progress_action']
def save_model(self, request, obj, form, change):
"""保存 PrintingJob 时使用 service 层"""
from api_v1.views.printing.services import PrintingJobService
if not change: # 新创建
# 使用 service 创建(这样会自动创建 BusinessObject
data = {
'printing_order': obj.printing_order,
'product': obj.product,
'quantity': obj.quantity,
'unit': obj.unit,
'size': obj.size,
'pieces': obj.pieces,
'description': obj.description,
}
created_obj = PrintingJobService.create_printing_job(data, request.user)
# 将创建的对象的 ID 赋值给当前对象(这样 admin 可以正确跳转)
obj.pk = created_obj.pk
obj.id = created_obj.id
else: # 更新
# 使用 service 更新
data = {
'printing_order': obj.printing_order,
'product': obj.product,
'quantity': obj.quantity,
'unit': obj.unit,
'size': obj.size,
'pieces': obj.pieces,
'description': obj.description,
}
success, message, updated_obj = PrintingJobService.update_printing_job(
obj, data, request.user
)
if not success:
from django.core.exceptions import ValidationError
raise ValidationError(message)
@admin.display(description='客户名称')
def customer_name(self, obj: models.PrintingJob):
return obj.printing_order.customer.name
@admin.display(description='当前进度')
def current_progress(self, obj: models.PrintingJob):
"""显示该 job 自己的进度(已完成节点数 / 总节点数)"""
if not obj.business_object or not obj.printing_order.process:
return "0%"
total_nodes = obj.business_object.process.process_nodes.count()
if total_nodes == 0:
return "0%"
completed_nodes = obj.business_object.state_logs.filter(is_cancelled=False).count()
progress = int((completed_nodes / total_nodes) * 100)
return f"{progress}%"
@admin.display(description='执行状态')
def execution_status(self, obj: models.PrintingJob):
return obj.status
@action(description='前进到下一个状态')
def advance_to_next_state_action(self, request, queryset):
from stateflow import services
success_count = 0
messages = []
for obj in queryset:
# 检查是否有 business_object
if not obj.business_object:
messages.append(f"PrintingJob #{obj.id}: 没有关联的业务对象,无法推进")
continue
success, message, state_log = services.advance_to_next_state(obj.business_object, request.user)
if success:
success_count += 1
messages.append(f"PrintingJob #{obj.id}: {message}")
self.message_user(request, f'成功推进 {success_count}/{queryset.count()} 个印染任务。详情: {"; ".join(messages[:5])}')
@action(description='回退一步')
def step_back_one_state_action(self, request, queryset):
from stateflow import services
success_count = 0
messages = []
for obj in queryset:
# 检查是否有 business_object
if not obj.business_object:
messages.append(f"PrintingJob #{obj.id}: 没有关联的业务对象,无法回退")
continue
success, message = services.step_back_one_state(obj.business_object, request.user)
if success:
success_count += 1
messages.append(f"PrintingJob #{obj.id}: {message}")
self.message_user(request, f'成功回退 {success_count}/{queryset.count()} 个印染任务。详情: {"; ".join(messages[:5])}')
@action(description='重置进度')
def reset_progress_action(self, request, queryset):
from stateflow import services
reset_count = 0
for obj in queryset:
# 检查是否有 business_object
if not obj.business_object:
continue
services.reset_business_object_progress(obj.business_object)
reset_count += 1
self.message_user(request, f'已重置 {reset_count} 个印染任务的进度。')