1
0
forked from erp-dev/erp

feat: retry haobuye sync order

This commit is contained in:
2026-04-07 16:56:46 +08:00
parent ebd687ccdd
commit 76ea445880
15 changed files with 1098 additions and 118 deletions

View File

@@ -16,6 +16,7 @@ from shipment.models import (
ExternalFinishedProduct,
SalesItem,
SalesItemChangeRecord,
SalesItemRebuildRecord,
Shipment,
ShipmentDelivery,
ShipmentDeliveryStatus,
@@ -50,6 +51,25 @@ def ensure_sales_item_can_be_soft_deleted(sales_item: SalesItem) -> None:
raise ValueError("已关联出货单的销售品不允许删除")
def _get_printing_job_for_sales_item(*, printing_job_id: int, merchant):
from printing.models import PrintingJob
try:
return PrintingJob.objects.select_related("printing_order").get(
id=printing_job_id,
merchant=merchant,
)
except PrintingJob.DoesNotExist:
raise ValueError(f"生产任务 {printing_job_id} 不存在或不属于当前商户")
def _normalize_sales_item_quantity(quantity: str | Decimal) -> Decimal:
try:
return Decimal(str(quantity))
except (InvalidOperation, ValueError, TypeError) as e:
raise ValueError(f"数量 {quantity} 格式无效: {e}")
def _resolve_delivery_shipments(
*,
shipment_ids: list[int],
@@ -302,6 +322,64 @@ def delete_sales_item(
return sales_item
@transaction.atomic
def rebuild_sales_item(
sales_item: SalesItem,
*,
new_printing_job_id: int,
operator,
quantity: str | Decimal | None = None,
) -> SalesItem:
"""
软删除旧销售品,并基于新 printing_job 重建一个新销售品。
"""
ensure_sales_item_can_be_soft_deleted(sales_item)
merchant = sales_item.merchant
printing_job = _get_printing_job_for_sales_item(
printing_job_id=new_printing_job_id,
merchant=merchant,
)
new_quantity = (
_normalize_sales_item_quantity(quantity)
if quantity is not None
else sales_item.quantity
)
deleted_sales_item = delete_sales_item(sales_item, deleted_by=operator)
customer_id = sales_item.customer_id
if customer_id is None and printing_job.printing_order and printing_job.printing_order.customer:
customer_id = printing_job.printing_order.customer_id
new_sales_item = SalesItem.objects.create(
shipment=None,
merchant=merchant,
name=sales_item.name,
quantity=new_quantity,
unit=sales_item.unit,
created_by=sales_item.created_by,
printing_job_id=printing_job.id,
customer_id=customer_id,
remark=sales_item.remark,
position=sales_item.position,
)
SalesItemRebuildRecord.objects.create(
old_sales_item=deleted_sales_item,
new_sales_item=new_sales_item,
operator=operator,
rebuilt_at=timezone.now(),
old_printing_job_id=deleted_sales_item.printing_job_id,
new_printing_job_id=printing_job.id,
old_quantity=deleted_sales_item.quantity,
new_quantity=new_sales_item.quantity,
)
return new_sales_item
@transaction.atomic
def create_shipment_delivery(
*,
@@ -841,6 +919,7 @@ def create_sales_item(
customer_id: int | None = None,
remark: str = "",
position: str = "",
merge_remark: dict | None = None,
) -> SalesItem:
"""
手动创建销售品
@@ -861,8 +940,6 @@ def create_sales_item(
Raises:
ValueError: 如果生产任务不存在或不属于当前商户
"""
from printing.models import PrintingJob
# 获取当前用户的商户
emp = getattr(created_by, "employee", None)
merchant = getattr(emp, "merchant", None) if emp else None
@@ -870,19 +947,13 @@ def create_sales_item(
raise ValueError("用户未关联商户,无法创建销售品")
# 验证生产任务存在且属于当前商户
try:
printing_job = PrintingJob.objects.select_related("printing_order").get(
id=printing_job_id,
merchant=merchant,
)
except PrintingJob.DoesNotExist:
raise ValueError(f"生产任务 {printing_job_id} 不存在或不属于当前商户")
printing_job = _get_printing_job_for_sales_item(
printing_job_id=printing_job_id,
merchant=merchant,
)
# 转换数量为Decimal
try:
quantity_decimal = Decimal(str(quantity))
except (InvalidOperation, ValueError, TypeError) as e:
raise ValueError(f"数量 {quantity} 格式无效: {e}")
quantity_decimal = _normalize_sales_item_quantity(quantity)
# 如果未提供客户ID尝试从主订单获取
if (
@@ -904,6 +975,35 @@ def create_sales_item(
customer_id=customer_id,
remark=remark,
position=position,
merge_remark=merge_remark,
)
return sales_item
def get_merge_remark_jobs_by_main_job(
printing_job_id: int,
merchant,
) -> list[list[int]]:
"""
查找指定 printing_job_id 作为 main_job 的所有销售品,返回每条记录的 jobs 列表。
同一个 printing_job_id 可能出现在多条销售品的 main_job 中,
因此返回值是一个二维列表,每个元素对应一条匹配记录的 jobs。
Args:
printing_job_id: 要查询的生产任务ID
merchant: 当前商户
Returns:
匹配记录的 jobs 列表集合,无匹配时返回空列表。
示例: [[9777, 9776], [9777, 9780]]
"""
merge_remarks = list(
get_active_sales_items_queryset()
.filter(merchant=merchant, merge_remark__main_job=printing_job_id)
.values_list("merge_remark", flat=True)
)
if not merge_remarks:
return []
return [mr.get("jobs", []) for mr in merge_remarks if mr]