后端: - 客户模块 CRUD+搜索 (api/services/repositories 分层) - 合同模块: FG单号规则/意向单转正式单/订单创建自动快照客户信息 - 优化下料: FFD首递减装箱算法(利用率统计/余料/未排入清单) 前端 (Vue3+TS+Element Plus): - 7页面: 登录/工作台/订单中心/合同/客户/样板库/优化下料 - 自研二维窗型画布渲染器: 解析drawing_data渲染玻璃区域/外框/ 扇开向标记/尺寸标注, 支持缩放平移复位 - 样板库与订单联动(用此样板下单自动带图纸) - axios统一envelope拦截/登录守卫/付费墙提示 工程: - SPA history 回退路由, 构建产物挂载后端 - 全接口回归 6/6 通过
45 lines
1.7 KiB
Python
45 lines
1.7 KiB
Python
"""合同业务逻辑层:意向单→正式单流转。"""
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from huamenchuang.models.contract import Contract
|
|
from huamenchuang.models.user import User
|
|
from huamenchuang.repositories.contract_repo import ContractRepository
|
|
|
|
|
|
class ContractService:
|
|
def __init__(self, db: AsyncSession) -> None:
|
|
self.repo = ContractRepository(db)
|
|
|
|
async def create(self, user: User, data: dict) -> Contract:
|
|
contract = await self.repo.create(Contract(
|
|
company_id=user.company_id,
|
|
user_id=user.id,
|
|
contract_no=await self.repo.next_contract_no(user.company_id),
|
|
**data,
|
|
))
|
|
return contract
|
|
|
|
async def update(self, user: User, contract_id: int, data: dict) -> Contract:
|
|
contract = await self.repo.get(contract_id, user.company_id)
|
|
if contract is None:
|
|
raise KeyError("合同不存在")
|
|
for k, v in data.items():
|
|
setattr(contract, k, v)
|
|
return contract
|
|
|
|
async def convert_to_formal(self, user: User, contract_id: int) -> Contract:
|
|
"""意向单转正式单(对齐目标站 convert-contract 语义)。"""
|
|
contract = await self.repo.get(contract_id, user.company_id)
|
|
if contract is None:
|
|
raise KeyError("合同不存在")
|
|
if contract.status != 0:
|
|
raise ValueError("仅意向单可转正式单")
|
|
contract.status = 1
|
|
return contract
|
|
|
|
async def delete(self, user: User, contract_id: int) -> None:
|
|
contract = await self.repo.get(contract_id, user.company_id)
|
|
if contract is None:
|
|
raise KeyError("合同不存在")
|
|
await self.repo.delete(contract)
|