|
|
@@ -12,13 +12,19 @@ from sqlalchemy.orm import Session
|
|
|
from app.core.utils import generate_uuid, parse_datetime
|
|
|
from app.crud.collection_protocol import urls_to_attachment_list
|
|
|
from app.models.models import (
|
|
|
+ BizCellSampleType,
|
|
|
BizCollectionProtocol,
|
|
|
BizPresignOrder,
|
|
|
BizPresignOrderSampleType,
|
|
|
BizPresignTransfer,
|
|
|
BizProtocolPartyCustomer,
|
|
|
+ SysUser,
|
|
|
+)
|
|
|
+from app.services.protocol_transfer_status import (
|
|
|
+ can_confirm_receipt,
|
|
|
+ can_submit_receipt,
|
|
|
+ can_withdraw_receipt,
|
|
|
)
|
|
|
-from app.services.protocol_transfer_status import can_confirm_receipt, can_submit_receipt
|
|
|
|
|
|
|
|
|
def _now() -> datetime:
|
|
|
@@ -31,6 +37,17 @@ def _dec(v: Any) -> Optional[Decimal]:
|
|
|
return Decimal(str(v))
|
|
|
|
|
|
|
|
|
+def _user_nick_name_map(db: Session, user_ids: List[str]) -> Dict[str, str]:
|
|
|
+ ids = [str(x).strip() for x in user_ids if str(x or "").strip()]
|
|
|
+ if not ids:
|
|
|
+ return {}
|
|
|
+ rows = db.query(SysUser.id, SysUser.nick_name, SysUser.user_no).filter(SysUser.id.in_(ids)).all()
|
|
|
+ out: Dict[str, str] = {}
|
|
|
+ for u in rows:
|
|
|
+ out[str(u.id)] = (u.nick_name or u.user_no or "").strip()
|
|
|
+ return out
|
|
|
+
|
|
|
+
|
|
|
def assert_presign_convertible(*, order_status: Optional[str]) -> None:
|
|
|
st = (order_status or "").strip() or "draft"
|
|
|
if st == "converted":
|
|
|
@@ -39,6 +56,24 @@ def assert_presign_convertible(*, order_status: Optional[str]) -> None:
|
|
|
raise ValueError("已作废的预签约订单不能转正式")
|
|
|
|
|
|
|
|
|
+def resolve_convert_staff_fields(
|
|
|
+ *,
|
|
|
+ collector_user_id: Optional[str],
|
|
|
+ sales_user_id: Optional[str],
|
|
|
+ region_manager_user_id: Optional[str],
|
|
|
+ fallback_user_id: Optional[str] = None,
|
|
|
+) -> Dict[str, Optional[str]]:
|
|
|
+ """转正式人员映射:采集专员→采集专员+市场专员;采集经理→地区经理。"""
|
|
|
+ _ = sales_user_id # 正式单市场专员以采集专员为准,不再沿用预签市场专员
|
|
|
+ collector = (collector_user_id or "").strip() or (fallback_user_id or "").strip() or None
|
|
|
+ region_mgr = (region_manager_user_id or "").strip() or None
|
|
|
+ return {
|
|
|
+ "collector_user_id": collector,
|
|
|
+ "sales_user_id": collector,
|
|
|
+ "region_manager_user_id": region_mgr,
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
def _get_order_or_raise(
|
|
|
db: Session, *, order_id: str, tenant_no: str
|
|
|
) -> BizPresignOrder:
|
|
|
@@ -117,6 +152,27 @@ def confirmed_deposit_amount(
|
|
|
return total
|
|
|
|
|
|
|
|
|
+def _sample_type_names(
|
|
|
+ db: Session, *, presign_order_id: str, tenant_no: str
|
|
|
+) -> str:
|
|
|
+ ids = list_sample_type_ids(
|
|
|
+ db, presign_order_id=presign_order_id, tenant_no=tenant_no
|
|
|
+ )
|
|
|
+ if not ids:
|
|
|
+ return ""
|
|
|
+ rows = (
|
|
|
+ db.query(BizCellSampleType.id, BizCellSampleType.type_name)
|
|
|
+ .filter(
|
|
|
+ BizCellSampleType.id.in_(ids),
|
|
|
+ BizCellSampleType.del_flag == 0,
|
|
|
+ )
|
|
|
+ .all()
|
|
|
+ )
|
|
|
+ name_map = {str(r.id): (r.type_name or "").strip() for r in rows}
|
|
|
+ names = [name_map.get(i, "") for i in ids if name_map.get(i)]
|
|
|
+ return "、".join(names)
|
|
|
+
|
|
|
+
|
|
|
def list_sample_type_ids(
|
|
|
db: Session, *, presign_order_id: str, tenant_no: str
|
|
|
) -> List[str]:
|
|
|
@@ -218,6 +274,7 @@ def order_to_dict(
|
|
|
else "",
|
|
|
"payMode": o.pay_mode or "",
|
|
|
"contractAmount": float(o.contract_amount) if o.contract_amount is not None else None,
|
|
|
+ "collectorUserId": o.collector_user_id or "",
|
|
|
"salesUserId": o.sales_user_id or "",
|
|
|
"regionManagerUserId": o.region_manager_user_id or "",
|
|
|
"orderStatus": o.order_status or "",
|
|
|
@@ -227,6 +284,17 @@ def order_to_dict(
|
|
|
"createTime": o.create_time.strftime("%Y-%m-%d %H:%M:%S") if o.create_time else "",
|
|
|
"updateTime": o.update_time.strftime("%Y-%m-%d %H:%M:%S") if o.update_time else "",
|
|
|
}
|
|
|
+ name_map = _user_nick_name_map(
|
|
|
+ db,
|
|
|
+ [
|
|
|
+ data["collectorUserId"],
|
|
|
+ data["salesUserId"],
|
|
|
+ data["regionManagerUserId"],
|
|
|
+ ],
|
|
|
+ )
|
|
|
+ data["collectorUserName"] = name_map.get(data["collectorUserId"], "")
|
|
|
+ data["salesUserName"] = name_map.get(data["salesUserId"], "")
|
|
|
+ data["regionManagerUserName"] = name_map.get(data["regionManagerUserId"], "")
|
|
|
if with_children:
|
|
|
data["sampleTypeIds"] = list_sample_type_ids(
|
|
|
db, presign_order_id=o.id, tenant_no=tenant_no
|
|
|
@@ -339,6 +407,11 @@ def create_presign_order(
|
|
|
sample_collect_time=sct,
|
|
|
pay_mode=pay_mode,
|
|
|
contract_amount=_dec(fields.get("contract_amount", fields.get("contractAmount"))),
|
|
|
+ collector_user_id=(
|
|
|
+ fields.get("collector_user_id") or fields.get("collectorUserId") or ""
|
|
|
+ ).strip()
|
|
|
+ or user_id
|
|
|
+ or None,
|
|
|
sales_user_id=(fields.get("sales_user_id") or fields.get("salesUserId") or "").strip()
|
|
|
or None,
|
|
|
region_manager_user_id=(
|
|
|
@@ -411,6 +484,8 @@ def update_presign_order(
|
|
|
"hospitalId": "hospital_id",
|
|
|
"pay_mode": "pay_mode",
|
|
|
"payMode": "pay_mode",
|
|
|
+ "collector_user_id": "collector_user_id",
|
|
|
+ "collectorUserId": "collector_user_id",
|
|
|
"sales_user_id": "sales_user_id",
|
|
|
"salesUserId": "sales_user_id",
|
|
|
"region_manager_user_id": "region_manager_user_id",
|
|
|
@@ -430,6 +505,7 @@ def update_presign_order(
|
|
|
"region_id",
|
|
|
"hospital_id",
|
|
|
"pay_mode",
|
|
|
+ "collector_user_id",
|
|
|
"sales_user_id",
|
|
|
"region_manager_user_id",
|
|
|
"order_status",
|
|
|
@@ -540,7 +616,7 @@ def update_transfer_draft(
|
|
|
) -> BizPresignTransfer:
|
|
|
t = _get_transfer_or_raise(db, transfer_id=transfer_id, tenant_no=tenant_no)
|
|
|
if t.pay_status != "dfj":
|
|
|
- raise ValueError("仅待缴费状态可编辑意向金转账笔")
|
|
|
+ raise ValueError("仅已缴费状态可编辑意向金转账笔")
|
|
|
if "transfer_amount" in fields or "transferAmount" in fields:
|
|
|
t.transfer_amount = _dec(
|
|
|
fields.get("transfer_amount", fields.get("transferAmount"))
|
|
|
@@ -579,7 +655,7 @@ def submit_receipt_finance(
|
|
|
) -> BizPresignTransfer:
|
|
|
t = _get_transfer_or_raise(db, transfer_id=transfer_id, tenant_no=tenant_no)
|
|
|
if not can_submit_receipt(t.pay_status):
|
|
|
- raise ValueError("仅待缴费状态可提交财务确认")
|
|
|
+ raise ValueError("仅已缴费状态可提交财务确认")
|
|
|
if not (t.transfer_type or "").strip():
|
|
|
raise ValueError("请选择转账方式")
|
|
|
if t.transfer_amount is None or Decimal(str(t.transfer_amount)) <= 0:
|
|
|
@@ -593,6 +669,22 @@ def submit_receipt_finance(
|
|
|
return t
|
|
|
|
|
|
|
|
|
+def withdraw_receipt(
|
|
|
+ db: Session, *, transfer_id: str, tenant_no: str, user_id: Optional[str]
|
|
|
+) -> BizPresignTransfer:
|
|
|
+ t = _get_transfer_or_raise(db, transfer_id=transfer_id, tenant_no=tenant_no)
|
|
|
+ if not can_withdraw_receipt(t.pay_status):
|
|
|
+ raise ValueError("仅缴费确认中可撤回")
|
|
|
+ t.pay_status = "dfj"
|
|
|
+ # 故意不改 finance_remark / finance_confirm_attachments
|
|
|
+ t.update_by = user_id
|
|
|
+ t.update_time = _now()
|
|
|
+ db.add(t)
|
|
|
+ db.commit()
|
|
|
+ db.refresh(t)
|
|
|
+ return t
|
|
|
+
|
|
|
+
|
|
|
def confirm_receipt(
|
|
|
db: Session,
|
|
|
*,
|
|
|
@@ -690,6 +782,42 @@ def list_presign_transfers_for_finance(
|
|
|
item["motherName"] = (order.mother_name if order else "") or ""
|
|
|
item["sampleCode"] = ""
|
|
|
item["presignOrderId"] = order.id if order else ""
|
|
|
+ item["orderDate"] = (order.order_date if order else "") or ""
|
|
|
+ item["expectedDeliveryDate"] = (
|
|
|
+ (order.expected_delivery_date if order else "") or ""
|
|
|
+ )
|
|
|
+ item["contractAmount"] = (
|
|
|
+ float(order.contract_amount)
|
|
|
+ if order and order.contract_amount is not None
|
|
|
+ else None
|
|
|
+ )
|
|
|
+ item["contractPayMode"] = (order.pay_mode if order else "") or ""
|
|
|
+ item["orderStatus"] = (order.order_status if order else "") or ""
|
|
|
+ item["orderRemark"] = (order.remark if order else "") or ""
|
|
|
+ name_map = _user_nick_name_map(
|
|
|
+ db,
|
|
|
+ [
|
|
|
+ (order.collector_user_id if order else "") or "",
|
|
|
+ (order.sales_user_id if order else "") or "",
|
|
|
+ (order.region_manager_user_id if order else "") or "",
|
|
|
+ ],
|
|
|
+ )
|
|
|
+ item["collectorUserName"] = name_map.get(
|
|
|
+ (order.collector_user_id if order else "") or "", ""
|
|
|
+ )
|
|
|
+ item["salesUserName"] = name_map.get(
|
|
|
+ (order.sales_user_id if order else "") or "", ""
|
|
|
+ )
|
|
|
+ item["regionManagerUserName"] = name_map.get(
|
|
|
+ (order.region_manager_user_id if order else "") or "", ""
|
|
|
+ )
|
|
|
+ item["sampleTypeNames"] = (
|
|
|
+ _sample_type_names(
|
|
|
+ db, presign_order_id=order.id, tenant_no=tenant_no
|
|
|
+ )
|
|
|
+ if order
|
|
|
+ else ""
|
|
|
+ )
|
|
|
out.append(item)
|
|
|
return out, int(total)
|
|
|
|
|
|
@@ -701,19 +829,26 @@ def convert_to_protocol(
|
|
|
tenant_no: str,
|
|
|
user_id: Optional[str],
|
|
|
) -> Dict[str, Any]:
|
|
|
- """转正式协议:创建协议主单 + 当事人/采集信息 + 样本类型行;不写入样本缴费金额。"""
|
|
|
+ """转正式协议:创建协议主单 + 当事人/采集信息 + 样本类型行;意向金仅关联预签订单 ID,不拷贝。"""
|
|
|
from app.crud import collection_protocol as cp_svc
|
|
|
|
|
|
order = _get_order_or_raise(db, order_id=order_id, tenant_no=tenant_no)
|
|
|
assert_presign_convertible(order_status=order.order_status)
|
|
|
|
|
|
+ staff = resolve_convert_staff_fields(
|
|
|
+ collector_user_id=order.collector_user_id,
|
|
|
+ sales_user_id=order.sales_user_id,
|
|
|
+ region_manager_user_id=order.region_manager_user_id,
|
|
|
+ fallback_user_id=user_id,
|
|
|
+ )
|
|
|
+
|
|
|
type_ids = list_sample_type_ids(db, presign_order_id=order.id, tenant_no=tenant_no)
|
|
|
protocol = cp_svc.create_collection_protocol(
|
|
|
db,
|
|
|
protocol_no=order.protocol_no or "",
|
|
|
protocol_status="dsx",
|
|
|
register_date=order.order_date,
|
|
|
- collector_user_id=user_id,
|
|
|
+ collector_user_id=staff["collector_user_id"],
|
|
|
source_presign_order_id=order.id,
|
|
|
payment_model_version=2,
|
|
|
protocol_total_amount=None,
|
|
|
@@ -731,7 +866,8 @@ def convert_to_protocol(
|
|
|
collection_fields: Dict[str, Any] = {
|
|
|
"region_id": order.region_id,
|
|
|
"hospital_id": order.hospital_id,
|
|
|
- "sales_user_id": order.sales_user_id,
|
|
|
+ "sales_user_id": staff["sales_user_id"],
|
|
|
+ "region_manager_user_id": staff["region_manager_user_id"],
|
|
|
"sample_collect_time": order.sample_collect_time,
|
|
|
}
|
|
|
cp_svc.upsert_collection_info(
|