forked from erp-dev/erp
feat: printing module
This commit is contained in:
@@ -1,6 +1,171 @@
|
||||
from django.db import models
|
||||
from django.conf import settings
|
||||
from flower.common import ModelBase
|
||||
from basic_info import models as basic_models
|
||||
from stateflow import models as stateflow_models
|
||||
|
||||
|
||||
class PlateOrder(ModelBase):
|
||||
"""开版管理订单"""
|
||||
|
||||
# 自动编号相关
|
||||
design_code = models.CharField(max_length=50, blank=True, null=True, verbose_name='设计编号')
|
||||
|
||||
# 版相关信息
|
||||
plate_type = models.CharField(max_length=20, blank=True, null=True, verbose_name='起版情况') # 首版/复版等
|
||||
plate_date = models.DateTimeField(null=True, blank=True, verbose_name='下版时间')
|
||||
plate_method = models.CharField(max_length=50, blank=True, null=True, verbose_name='开版方式')
|
||||
plate_image = models.FileField(upload_to='plate_images/', null=True, blank=True, verbose_name='开版图')
|
||||
plate_notes = models.TextField(blank=True, null=True, verbose_name='打版注意事项')
|
||||
reprint_reason = models.TextField(blank=True, null=True, verbose_name='复版原因')
|
||||
|
||||
# 状态和进程
|
||||
# development_status = models.CharField(max_length=20, blank=True, null=True, verbose_name='开发进程') # 未打印/待画图等
|
||||
urgency_level = models.CharField(max_length=20, default='正常', verbose_name='紧急程度') # 正常/加急
|
||||
|
||||
# 人员关联
|
||||
salesperson = models.ForeignKey(
|
||||
basic_models.Employee,
|
||||
on_delete=models.PROTECT,
|
||||
null=True,
|
||||
blank=True,
|
||||
related_name='plate_orders_as_salesperson',
|
||||
verbose_name='销售员'
|
||||
)
|
||||
merchandiser = models.ForeignKey(
|
||||
basic_models.Employee,
|
||||
on_delete=models.PROTECT,
|
||||
null=True,
|
||||
blank=True,
|
||||
related_name='plate_orders_as_merchandiser',
|
||||
verbose_name='跟单员'
|
||||
)
|
||||
|
||||
# 客户和地址信息
|
||||
customer = models.ForeignKey(
|
||||
basic_models.Customer,
|
||||
on_delete=models.PROTECT,
|
||||
related_name='plate_orders',
|
||||
verbose_name='客户'
|
||||
)
|
||||
area = models.CharField(max_length=255, blank=True, null=True, verbose_name='区域')
|
||||
default_address = models.CharField(max_length=500, blank=True, null=True, verbose_name='默认地址')
|
||||
|
||||
# 质量评级
|
||||
is_mark_frame = models.BooleanField(default=False, verbose_name='是否套唛架')
|
||||
drawing_rating = models.CharField(max_length=20, blank=True, null=True, verbose_name='画图评级')
|
||||
color_matching_rating = models.CharField(max_length=20, blank=True, null=True, verbose_name='调色评级')
|
||||
sample_rating = models.CharField(max_length=20, blank=True, null=True, verbose_name='套样评级')
|
||||
difficulty_rating = models.CharField(max_length=20, blank=True, null=True, verbose_name='难度评级')
|
||||
|
||||
# 时间相关
|
||||
required_completion_date = models.DateField(null=True, blank=True, verbose_name='要求完成时间')
|
||||
completion_date = models.DateTimeField(null=True, blank=True, verbose_name='完成时间')
|
||||
|
||||
# 产品信息
|
||||
fabric = models.CharField(max_length=100, blank=True, null=True, verbose_name='布料')
|
||||
width = models.CharField(max_length=50, blank=True, null=True, verbose_name='幅宽')
|
||||
style_name = models.CharField(max_length=100, blank=True, null=True, verbose_name='款号名称')
|
||||
|
||||
# 生产方式
|
||||
production_method = models.CharField(max_length=50, blank=True, null=True, verbose_name='做货方式')
|
||||
|
||||
# 样品相关
|
||||
sample_meter = models.CharField(max_length=100, blank=True, null=True, verbose_name='米样')
|
||||
required_sample_meters = models.DecimalField(
|
||||
max_digits=10,
|
||||
decimal_places=2,
|
||||
null=True,
|
||||
blank=True,
|
||||
verbose_name='客户要求米样米数'
|
||||
)
|
||||
|
||||
# 审批和订单状态
|
||||
approval_result = models.CharField(max_length=50, blank=True, null=True, verbose_name='审批结果')
|
||||
is_ordered = models.BooleanField(default=False, verbose_name='是否已下单')
|
||||
is_invalid = models.BooleanField(default=False, verbose_name='是否作废')
|
||||
customer_feedback = models.TextField(blank=True, null=True, verbose_name='客户修改意见')
|
||||
|
||||
# 流程管理
|
||||
business_object = models.OneToOneField(
|
||||
stateflow_models.BusinessObject,
|
||||
on_delete=models.SET_NULL,
|
||||
null=True,
|
||||
blank=True,
|
||||
related_name='plate_order',
|
||||
verbose_name='流程实例',
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
return self.human_id or f'PlateOrder-{self.id}'
|
||||
|
||||
class Meta:
|
||||
verbose_name = '开版订单'
|
||||
verbose_name_plural = '开版订单'
|
||||
ordering = ['-created_at']
|
||||
permissions = [
|
||||
('can_invalidate_plateorder', '可以作废开版订单'),
|
||||
('can_activate_plateorder', '可以恢复开版订单'),
|
||||
]
|
||||
|
||||
@property
|
||||
def status(self) -> str:
|
||||
"""返回当前状态名称"""
|
||||
if not self.business_object:
|
||||
return '未开始'
|
||||
|
||||
current_state = self.business_object.get_current_state()
|
||||
|
||||
# current_state 为 None 有两种情况:未开始或已完成
|
||||
if current_state is None:
|
||||
# 检查是否有完成记录来区分
|
||||
has_completed_records = self.business_object.state_logs.filter(is_cancelled=False).exists()
|
||||
if has_completed_records:
|
||||
return '已完成'
|
||||
else:
|
||||
return '未开始'
|
||||
|
||||
return current_state.name
|
||||
|
||||
@property
|
||||
def status_id(self):
|
||||
"""返回当前状态ID"""
|
||||
if not self.business_object:
|
||||
return None
|
||||
current_state = self.business_object.get_current_state()
|
||||
return current_state.id if current_state else None
|
||||
|
||||
@property
|
||||
def is_completed(self) -> bool:
|
||||
"""判断是否完成"""
|
||||
if not self.business_object:
|
||||
return False
|
||||
|
||||
# 检查流程是否完成
|
||||
from stateflow.services import get_overall_status
|
||||
return get_overall_status(self.business_object) == 'completed'
|
||||
|
||||
@property
|
||||
def has_started(self) -> bool:
|
||||
"""判断是否已开始"""
|
||||
if not self.business_object:
|
||||
return False
|
||||
|
||||
# 检查是否有状态流转记录
|
||||
from stateflow.models import StateFlowRecord
|
||||
has_records = StateFlowRecord.objects.filter(
|
||||
business_object=self.business_object
|
||||
).exists()
|
||||
|
||||
return has_records
|
||||
|
||||
@property
|
||||
def progress_percentage(self) -> float:
|
||||
"""计算进度百分比"""
|
||||
if not self.business_object:
|
||||
return 0.0
|
||||
|
||||
return self.business_object.get_progress_percentage()
|
||||
|
||||
|
||||
class PrintingOrder(ModelBase):
|
||||
@@ -28,6 +193,14 @@ class PrintingOrder(ModelBase):
|
||||
rolling_warn = models.TextField(blank=True, null=True, verbose_name='滚筒注意事项')
|
||||
production_warn = models.TextField(blank=True, null=True, verbose_name='生产注意事项')
|
||||
is_invalid = models.BooleanField(default=False, verbose_name='是否作废')
|
||||
process = models.ForeignKey(
|
||||
stateflow_models.Process,
|
||||
on_delete=models.PROTECT,
|
||||
null=True,
|
||||
blank=True,
|
||||
related_name='printing_orders',
|
||||
verbose_name='印染流程',
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
return self.human_id
|
||||
@@ -42,8 +215,24 @@ class PrintingOrder(ModelBase):
|
||||
|
||||
@property
|
||||
def human_id(self) -> str:
|
||||
if self.id is None or self.created_at is None:
|
||||
return ""
|
||||
return f"{self.created_at.year}{self.created_at.month:02d}{self.created_at.day:02d}{self.id:06d}"
|
||||
|
||||
def can_change_process(self) -> bool:
|
||||
"""检查是否可以修改流程(所有job都未开始)"""
|
||||
return not any(job.has_started for job in self.printing_jobs.all())
|
||||
|
||||
@property
|
||||
def progress(self) -> int:
|
||||
"""计算订单完成进度百分比(已完成的任务数 / 总任务数)"""
|
||||
jobs = self.printing_jobs.all()
|
||||
if not jobs.exists():
|
||||
return 0
|
||||
|
||||
completed_count = sum(1 for job in jobs if job.is_completed)
|
||||
return int((completed_count / jobs.count()) * 100)
|
||||
|
||||
|
||||
class PrintingJob(ModelBase):
|
||||
"""PrintingJob model representing a printing job associated with an order."""
|
||||
@@ -61,13 +250,81 @@ class PrintingJob(ModelBase):
|
||||
)
|
||||
quantity = models.PositiveIntegerField(verbose_name='数量')
|
||||
unit = models.CharField(max_length=50, verbose_name='单位')
|
||||
size = models.CharField(max_length=100, verbose_name='一段尺寸')
|
||||
pieces = models.PositiveIntegerField(verbose_name='件数')
|
||||
description = models.TextField(blank=True, verbose_name='备注')
|
||||
size = models.CharField(max_length=100, null=True, blank=True, verbose_name='一段尺寸')
|
||||
pieces = models.PositiveIntegerField(null=True, blank=True, verbose_name='件数')
|
||||
description = models.TextField(blank=True, null=True, verbose_name='备注')
|
||||
business_object = models.OneToOneField(
|
||||
stateflow_models.BusinessObject,
|
||||
on_delete=models.SET_NULL,
|
||||
null=True,
|
||||
blank=True,
|
||||
related_name='printing_job',
|
||||
verbose_name='流程实例',
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
return self.printing_order.human_id
|
||||
|
||||
@property
|
||||
def status(self) -> str:
|
||||
"""返回当前状态名称"""
|
||||
if not self.business_object:
|
||||
return '未开始'
|
||||
|
||||
current_state = self.business_object.get_current_state()
|
||||
|
||||
# current_state 为 None 有两种情况:未开始或已完成
|
||||
if current_state is None:
|
||||
# 检查是否有完成记录来区分
|
||||
has_completed_records = self.business_object.state_logs.filter(is_cancelled=False).exists()
|
||||
if has_completed_records:
|
||||
return '已完成'
|
||||
else:
|
||||
return '未开始'
|
||||
|
||||
return current_state.name
|
||||
|
||||
@property
|
||||
def status_id(self):
|
||||
"""返回当前状态ID"""
|
||||
if not self.business_object:
|
||||
return None
|
||||
current_state = self.business_object.get_current_state()
|
||||
return current_state.id if current_state else None
|
||||
|
||||
@property
|
||||
def is_completed(self) -> bool:
|
||||
"""判断是否完成(所有流程节点都已完成)"""
|
||||
if not self.business_object or not self.printing_order.process:
|
||||
return False
|
||||
|
||||
# 获取流程的所有节点
|
||||
process_nodes = self.printing_order.process.process_nodes.all()
|
||||
total_nodes = process_nodes.count()
|
||||
|
||||
if total_nodes == 0:
|
||||
return False
|
||||
|
||||
# 检查已完成的节点数
|
||||
completed_count = self.business_object.state_logs.filter(is_cancelled=False).count()
|
||||
|
||||
# 所有节点都完成了才算完成
|
||||
return completed_count >= total_nodes
|
||||
|
||||
@property
|
||||
def has_started(self) -> bool:
|
||||
"""判断是否已开始(有BusinessObject且有状态记录,或不在初始状态)"""
|
||||
if not self.business_object:
|
||||
return False
|
||||
|
||||
# 检查是否有状态流转记录
|
||||
from stateflow.models import StateFlowRecord
|
||||
has_records = StateFlowRecord.objects.filter(
|
||||
business_object=self.business_object
|
||||
).exists()
|
||||
|
||||
return has_records
|
||||
|
||||
class Meta:
|
||||
verbose_name = '印染款式明细'
|
||||
verbose_name_plural = '印染款式明细'
|
||||
|
||||
Reference in New Issue
Block a user