Files
shanxia2.0/backend/app/crud/crm/invoice_info.py
T
zlwuandCursor bf73b6b2d8 feat(crm): 联系人、产品、报价与合同域接入数据权限过滤
补全 PR3 Phase 2.4–2.7,列表 apply_data_scope、详情/CUD assert_row_in_data_scope,合同/报价主表支持 owner_user_id。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-28 21:00:12 +08:00

254 lines
7.1 KiB
Python

"""CRM 客户开票信息 CRUD"""
from __future__ import annotations
from datetime import datetime
from typing import Any, Dict, List, Optional
from sqlalchemy.orm import Session
from app.core.utils import generate_uuid
from app.crud.crm.data_scope_helpers import (
ensure_crm_customer_linked_row_in_scope,
ensure_crm_owner_row_in_scope,
)
from app.models.crm_models import CrmInvoiceInfo
_FMT = "%Y-%m-%d %H:%M:%S"
def _row_to_dict(row: CrmInvoiceInfo) -> Dict[str, Any]:
return {
"id": row.id,
"customerId": row.customer_id or "",
"companyName": row.company_name or "",
"taxNo": row.tax_no or "",
"companyAddress": row.company_address or "",
"legalRepresentative": row.legal_representative or "",
"agent": row.agent or "",
"phoneFax": row.phone_fax or "",
"bankName": row.bank_name or "",
"bankAccount": row.bank_account or "",
"isDefault": row.is_default or "0",
"orderNum": row.order_num if row.order_num is not None else 0,
"remark": row.remark or "",
"createBy": row.create_by or "",
"createTime": row.create_time.strftime(_FMT) if row.create_time else "",
"updateBy": row.update_by or "",
"updateTime": row.update_time.strftime(_FMT) if row.update_time else "",
}
def list_invoice_info_by_customer(
db: Session,
tenant_no: str,
customer_id: str,
*,
user_info=None,
) -> List[Dict[str, Any]]:
if user_info:
from app.crud.crm.customer import get_customer
customer = get_customer(db, customer_id)
if not customer or customer.tenant_no != tenant_no:
raise ValueError("客户不存在")
ensure_crm_owner_row_in_scope(
db, customer, user_info, tenant_no, message="无权访问该客户"
)
rows = (
db.query(CrmInvoiceInfo)
.filter(
CrmInvoiceInfo.tenant_no == tenant_no,
CrmInvoiceInfo.customer_id == customer_id,
CrmInvoiceInfo.del_flag == 0,
)
.order_by(CrmInvoiceInfo.is_default.desc(), CrmInvoiceInfo.create_time.desc())
.all()
)
return [_row_to_dict(r) for r in rows]
def get_invoice_info(db: Session, invoice_id: str) -> Optional[CrmInvoiceInfo]:
return (
db.query(CrmInvoiceInfo)
.filter(
CrmInvoiceInfo.id == invoice_id,
CrmInvoiceInfo.del_flag == 0,
)
.first()
)
def _clear_default_for_customer(
db: Session,
tenant_no: str,
customer_id: str,
exclude_id: str = None,
) -> None:
q = db.query(CrmInvoiceInfo).filter(
CrmInvoiceInfo.tenant_no == tenant_no,
CrmInvoiceInfo.customer_id == customer_id,
CrmInvoiceInfo.del_flag == 0,
CrmInvoiceInfo.is_default == "1",
)
if exclude_id:
q = q.filter(CrmInvoiceInfo.id != exclude_id)
q.update({"is_default": "0"})
def create_invoice_info(
db: Session,
*,
tenant_no: str,
user_id: str = None,
dept_id: str = "",
user_info=None,
**kwargs,
) -> CrmInvoiceInfo:
customer_id = kwargs.get("customer_id")
if not customer_id:
raise ValueError("缺少客户ID")
if user_info:
from app.crud.crm.customer import get_customer
customer = get_customer(db, customer_id)
if not customer or customer.tenant_no != tenant_no:
raise ValueError("客户不存在")
ensure_crm_owner_row_in_scope(
db, customer, user_info, tenant_no, message="无权访问该客户"
)
company_name = (kwargs.get("company_name") or "").strip()
if not company_name:
raise ValueError("单位名称不能为空")
is_default = kwargs.get("is_default") or "0"
if is_default == "1":
_clear_default_for_customer(db, tenant_no, customer_id)
obj = CrmInvoiceInfo(
id=generate_uuid(),
customer_id=customer_id,
company_name=company_name,
tax_no=kwargs.get("tax_no") or "",
company_address=kwargs.get("company_address") or "",
legal_representative=kwargs.get("legal_representative") or "",
agent=kwargs.get("agent") or "",
phone_fax=kwargs.get("phone_fax") or "",
bank_name=kwargs.get("bank_name") or "",
bank_account=kwargs.get("bank_account") or "",
is_default=is_default,
tenant_no=tenant_no,
order_num=kwargs.get("order_num"),
remark=kwargs.get("remark"),
create_by=user_id,
create_dept_id=dept_id,
del_flag=0,
)
db.add(obj)
db.commit()
db.refresh(obj)
return obj
def update_invoice_info(
db: Session,
invoice_id: str,
*,
tenant_no: str = None,
user_id: str = None,
user_info=None,
**kwargs,
) -> CrmInvoiceInfo:
obj = get_invoice_info(db, invoice_id)
if not obj:
raise ValueError("开票信息不存在")
if tenant_no and obj.tenant_no != tenant_no:
raise ValueError("开票信息不存在")
ensure_crm_customer_linked_row_in_scope(
db, obj, user_info, obj.tenant_no, message="无权访问该开票信息"
)
_updatable = (
"company_name",
"tax_no",
"company_address",
"legal_representative",
"agent",
"phone_fax",
"bank_name",
"bank_account",
"is_default",
"order_num",
"remark",
)
for field in _updatable:
if field in kwargs and kwargs[field] is not None:
setattr(obj, field, kwargs[field])
if kwargs.get("is_default") == "1":
_clear_default_for_customer(
db,
obj.tenant_no,
obj.customer_id,
exclude_id=invoice_id,
)
obj.is_default = "1"
obj.update_by = user_id
obj.update_time = datetime.now()
db.commit()
db.refresh(obj)
return obj
def set_default_invoice_info(
db: Session,
invoice_id: str,
customer_id: str,
*,
tenant_no: str,
user_id: str = None,
user_info=None,
) -> CrmInvoiceInfo:
obj = get_invoice_info(db, invoice_id)
if not obj or obj.tenant_no != tenant_no:
raise ValueError("开票信息不存在")
if obj.customer_id != customer_id:
raise ValueError("开票信息与客户不匹配")
ensure_crm_customer_linked_row_in_scope(
db, obj, user_info, tenant_no, message="无权访问该开票信息"
)
_clear_default_for_customer(db, tenant_no, customer_id, exclude_id=invoice_id)
obj.is_default = "1"
obj.update_by = user_id
obj.update_time = datetime.now()
db.commit()
db.refresh(obj)
return obj
def soft_delete_invoice_info(
db: Session,
invoice_id: str,
user_id: str = None,
*,
tenant_no: str = None,
user_info=None,
) -> bool:
obj = get_invoice_info(db, invoice_id)
if not obj:
raise ValueError("开票信息不存在")
if tenant_no and obj.tenant_no != tenant_no:
raise ValueError("开票信息不存在")
ensure_crm_customer_linked_row_in_scope(
db, obj, user_info, obj.tenant_no, message="无权访问该开票信息"
)
obj.del_flag = 1
obj.update_by = user_id
obj.update_time = datetime.now()
db.commit()
return True