后端设计治理:批次 0-4 全部完成(安全/部署/一致性/结构/架构)

按 ROADMAP §3.1 治理批次推进的后端设计审查整改:

- 批次 0(安全):/api/status/{task_id} 补 JWT 鉴权与任务归属校验;
  pythonocc_available 真实探测;bcrypt 超 72 字节显式拒绝;
  SECRET_KEY/RUSTFS_* 惰性校验,代码侧弱默认移除
- 批次 1(部署正确性):主处理链路改走 RustFS(分派入参 stp_file_id 化,
  worker 按 object_key 下载);AUTO_MIGRATE 开关 + 迁移目录 alembic/→migrations/
  修复包遮蔽(自动迁移此前从未真正生效);OCC 镜像改 conda 原生执行 +
  基础镜像 tag 锁定;compose 关键项改 ${VAR:?} 强制显式配置
- 批次 2(任务一致性):删除 Redis 进程内存回退,PG 为任务状态单一事实源;
  批量元数据入库(processing_tasks.batch_id,迁移 a3f8c2d91e47);
  型腔失败任务标 failed 不再静默 completed;事务边界收口
  (数据本体写 flush-only、失败先回滚再置 failed、进度更新保留即时 commit)
- 批次 3(API 与代码结构):592 行 advanced_router 拆为 design/cost/machining/
  export 四子路由,请求体全量 Pydantic 化;ROUTE_MODULES + route_registry
  (/api/health 呈现 degraded,DEBUG fail fast);纯计算端点统一 to_thread;
  StorageIntegrationService 按职责三拆;MAX_FILE_SIZE 接线生效、
  celery 复用 Settings.redis_url;管理员重置密码改 JSON body(端到端断裂修复);
  openapi.json 重导出(76 paths)+ 前端 gen:api
- 批次 4(架构演进):共享 ORM 按模块拆分(shared/models/base.py + identity.py、
  moldinsight/models/、inventory/models/,删除三条无使用方的跨模块
  relationship,跨模块桥接收敛为裸 FK 硬规则,无兼容 facade);
  OCC executor 重建补 cancel_futures=True(消除旧队列被慢恢复线程
  并行消化的数据竞争);OCC 吞吐方案设计先行
  (docs/topics/performance/OCC_THROUGHPUT.md);顺手清偿 D15
  (vite.config.ts 未用参数致 npm run build 失败)

测试基线:125 passed, 2 skipped(pytest + sqlite+aiosqlite;归属边界、
路由契约、配置治理、鉴权回归等随批新增)
文档同步:STATUS / TECH_DEBT / ROADMAP / ARCHITECTURE / API_CONTRACT /
OPERATIONS / AGENTS

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
2026-09-17 16:15:49 +08:00
parent 4537faf2c4
commit 0e6b3b1811
82 changed files with 6513 additions and 3709 deletions
+2 -1
View File
@@ -17,7 +17,8 @@ from datetime import datetime
from shared.database.database import get_db_session
from shared.services.auth_service import get_current_active_user, get_current_admin_user
from shared.models.database import User, Customer
from shared.models.identity import User
from inventory.models import Customer
from ..schemas import CustomerCreate, CustomerResponse
router = APIRouter(prefix="/customers", tags=["客户管理"])
+2 -4
View File
@@ -15,10 +15,8 @@ from sqlalchemy import select, func
from shared.database.database import get_db_session
from shared.services.auth_service import get_current_active_user
from shared.models.database import (
User, Product, Supplier, Customer, Warehouse,
Inventory, PurchaseOrder, SalesOrder
)
from shared.models.identity import User
from inventory.models import Product, Supplier, Customer, Warehouse, Inventory, PurchaseOrder, SalesOrder
router = APIRouter(prefix="/dashboard", tags=["仪表盘"])
+1 -1
View File
@@ -8,7 +8,7 @@ from typing import Optional, List
from shared.database.database import get_db_session
from shared.services.auth_service import get_current_active_user
from shared.models.database import User
from shared.models.identity import User
from ..schemas import (
ReceiptCreate,
PaymentCreate,
+1 -1
View File
@@ -9,7 +9,7 @@ from typing import Optional
from shared.database.database import get_db_session
from shared.services.auth_service import get_current_active_user
from shared.models.database import User
from shared.models.identity import User
from ..schemas import InventoryResponse, InventoryCreate, InventoryUpdate, PaginatedResponse
from ..services.inventory_service import inventory_service
+2 -1
View File
@@ -15,7 +15,8 @@ from typing import Optional, List
from shared.database.database import get_db_session
from shared.services.auth_service import get_current_active_user
from shared.models.database import User, Product, MaterialPriceHistory, MaterialSupplier, Supplier
from shared.models.identity import User
from inventory.models import Product, MaterialPriceHistory, MaterialSupplier, Supplier
from ..schemas import (
MaterialPriceHistoryCreate,
MaterialPriceHistoryResponse,
+3 -1
View File
@@ -18,7 +18,9 @@ from pathlib import Path
from shared.database.database import get_db_session
from shared.services.auth_service import get_current_active_user, get_current_admin_user
from shared.models.database import User, Product, ProductMaterial, STPFile, ProcessingTask
from shared.models.identity import User
from moldinsight.models import STPFile, ProcessingTask
from inventory.models import Product, ProductMaterial
from ..schemas import (
ProductCreate,
ProductResponse,
+1 -1
View File
@@ -8,7 +8,7 @@ from sqlalchemy.ext.asyncio import AsyncSession
from shared.database.database import get_db_session
from shared.services.auth_service import get_current_active_user
from shared.models.database import User
from shared.models.identity import User
from ..schemas import (
PurchaseDemandCalculateRequest,
PurchaseDemandResponse,
+1 -1
View File
@@ -9,7 +9,7 @@ from typing import Optional
from shared.database.database import get_db_session
from shared.services.auth_service import get_current_active_user
from shared.models.database import User
from shared.models.identity import User
from ..schemas import (
PurchaseOrderCreate,
PurchaseOrderResponse,
+1 -1
View File
@@ -9,7 +9,7 @@ from typing import Optional
from shared.database.database import get_db_session
from shared.services.auth_service import get_current_active_user
from shared.models.database import User
from shared.models.identity import User
from ..schemas import (
SalesOrderCreate,
SalesOrderResponse,
+1 -1
View File
@@ -9,7 +9,7 @@ from typing import Optional
from shared.database.database import get_db_session
from shared.services.auth_service import get_current_active_user
from shared.models.database import User
from shared.models.identity import User
from ..schemas import StockMovementCreate, StockMovementResponse, PaginatedResponse
from ..services.stock_movement_service import stock_movement_service
+2 -1
View File
@@ -17,7 +17,8 @@ from datetime import datetime
from shared.database.database import get_db_session
from shared.services.auth_service import get_current_active_user, get_current_admin_user
from shared.models.database import User, Supplier
from shared.models.identity import User
from inventory.models import Supplier
from ..schemas import SupplierCreate, SupplierResponse
router = APIRouter(prefix="/suppliers", tags=["供应商管理"])
+2 -1
View File
@@ -15,7 +15,8 @@ from datetime import datetime
from shared.database.database import get_db_session
from shared.services.auth_service import get_current_active_user
from shared.models.database import User, Warehouse
from shared.models.identity import User
from inventory.models import Warehouse
from ..schemas import WarehouseCreate, WarehouseResponse
router = APIRouter(prefix="/warehouses", tags=["仓库管理"])
+46
View File
@@ -0,0 +1,46 @@
"""inventory 域模型出口(目录 / 仓储 / 交易 / 财务四个域文件)。
全量模型注册点见 shared/models/base.py 模块 docstring;
业务代码按需 `from inventory.models import Product, ...`。
"""
from inventory.models.catalog import (
Product,
ProductMaterial,
MaterialPriceHistory,
MaterialSupplier,
Supplier,
Customer,
)
from inventory.models.warehouse import (
Warehouse,
Inventory,
StockMovement,
)
from inventory.models.trading import (
PurchaseOrder,
PurchaseOrderItem,
SalesOrder,
SalesOrderItem,
)
from inventory.models.finance import (
FinanceTransaction,
FinanceAllocation,
)
__all__ = [
"Product",
"ProductMaterial",
"MaterialPriceHistory",
"MaterialSupplier",
"Supplier",
"Customer",
"Warehouse",
"Inventory",
"StockMovement",
"PurchaseOrder",
"PurchaseOrderItem",
"SalesOrder",
"SalesOrderItem",
"FinanceTransaction",
"FinanceAllocation",
]
+166
View File
@@ -0,0 +1,166 @@
"""inventory 目录域模型:成品/物料/BOM/价格/供应商/客户。
从旧 shared/models/database.py 拆出(D3,2026-09-17)。
跨模块桥接只保留裸 FK(base.py 约定):operator 类字段 user_id -> users.id 不建 relationship。
"""
from sqlalchemy import Column, Integer, String, Text, DateTime, Boolean, Numeric, ForeignKey, UniqueConstraint
from sqlalchemy.sql import func
from sqlalchemy.orm import relationship
from shared.models.base import Base
class Product(Base):
"""产品表"""
__tablename__ = "products"
id = Column(Integer, primary_key=True, index=True)
sku = Column(String(50), unique=True, index=True, nullable=False)
name = Column(String(200), nullable=False)
description = Column(Text, nullable=True)
category = Column(String(100), nullable=True)
unit = Column(String(20), default="件")
item_type = Column(String(20), default="finished", index=True)
cost_price = Column(Numeric(12, 2), default=0)
sale_price = Column(Numeric(12, 2), default=0)
min_stock = Column(Integer, default=0)
max_stock = Column(Integer, default=1000)
is_active = Column(Boolean, default=True)
created_at = Column(DateTime, default=func.now())
updated_at = Column(DateTime, default=func.now(), onupdate=func.now())
inventory = relationship("Inventory", back_populates="product", uselist=False)
stock_movements = relationship("StockMovement", back_populates="product")
bom_materials = relationship(
"ProductMaterial",
foreign_keys="ProductMaterial.finished_product_id",
back_populates="finished_product",
cascade="all, delete-orphan"
)
used_in_products = relationship(
"ProductMaterial",
foreign_keys="ProductMaterial.material_product_id",
back_populates="material_product"
)
def __repr__(self):
return f"<Product(id={self.id}, sku='{self.sku}', name='{self.name}')>"
class ProductMaterial(Base):
__tablename__ = "product_materials"
__table_args__ = (
UniqueConstraint("finished_product_id", "material_product_id", name="uq_product_material_unique"),
)
id = Column(Integer, primary_key=True, index=True)
finished_product_id = Column(Integer, ForeignKey("products.id"), nullable=False, index=True)
material_product_id = Column(Integer, ForeignKey("products.id"), nullable=False, index=True)
quantity = Column(Numeric(12, 4), nullable=False)
loss_rate = Column(Numeric(5, 4), default=0)
created_at = Column(DateTime, default=func.now())
updated_at = Column(DateTime, default=func.now(), onupdate=func.now())
finished_product = relationship(
"Product",
foreign_keys=[finished_product_id],
back_populates="bom_materials"
)
material_product = relationship(
"Product",
foreign_keys=[material_product_id],
back_populates="used_in_products"
)
def __repr__(self):
return f"<ProductMaterial(finished_product_id={self.finished_product_id}, material_product_id={self.material_product_id})>"
class MaterialPriceHistory(Base):
"""物料价格历史表"""
__tablename__ = "material_price_history"
id = Column(Integer, primary_key=True, index=True)
product_id = Column(Integer, ForeignKey("products.id"), nullable=False, index=True)
price = Column(Numeric(12, 2), nullable=False)
effective_date = Column(DateTime, default=func.now(), index=True)
supplier_id = Column(Integer, ForeignKey("suppliers.id"), nullable=True, index=True)
remark = Column(Text, nullable=True)
created_at = Column(DateTime, default=func.now())
product = relationship("Product", backref="price_history")
supplier = relationship("Supplier", backref="price_history")
def __repr__(self):
return f"<MaterialPriceHistory(product_id={self.product_id}, price={self.price}, date={self.effective_date})>"
class MaterialSupplier(Base):
"""物料供应商关联表"""
__tablename__ = "material_suppliers"
id = Column(Integer, primary_key=True, index=True)
product_id = Column(Integer, ForeignKey("products.id"), nullable=False, index=True)
supplier_id = Column(Integer, ForeignKey("suppliers.id"), nullable=False, index=True)
is_primary = Column(Boolean, default=False)
contact_person = Column(String(100), nullable=True)
contact_phone = Column(String(50), nullable=True)
lead_time = Column(Integer, nullable=True) # 交货周期(天)
min_order_quantity = Column(Integer, nullable=True)
created_at = Column(DateTime, default=func.now())
updated_at = Column(DateTime, default=func.now(), onupdate=func.now())
product = relationship("Product", backref="suppliers")
supplier = relationship("Supplier", backref="materials")
def __repr__(self):
return f"<MaterialSupplier(product_id={self.product_id}, supplier_id={self.supplier_id}, primary={self.is_primary})>"
class Supplier(Base):
"""供应商表"""
__tablename__ = "suppliers"
id = Column(Integer, primary_key=True, index=True)
code = Column(String(50), unique=True, index=True)
name = Column(String(200), nullable=False)
contact_person = Column(String(100), nullable=True)
phone = Column(String(50), nullable=True)
email = Column(String(100), nullable=True)
address = Column(Text, nullable=True)
bank_name = Column(String(100), nullable=True)
bank_account = Column(String(50), nullable=True)
tax_number = Column(String(50), nullable=True)
is_active = Column(Boolean, default=True)
created_at = Column(DateTime, default=func.now())
updated_at = Column(DateTime, default=func.now(), onupdate=func.now())
purchase_orders = relationship("PurchaseOrder", back_populates="supplier")
def __repr__(self):
return f"<Supplier(id={self.id}, name='{self.name}')>"
class Customer(Base):
"""客户表"""
__tablename__ = "customers"
id = Column(Integer, primary_key=True, index=True)
code = Column(String(50), unique=True, index=True)
name = Column(String(200), nullable=False)
contact_person = Column(String(100), nullable=True)
phone = Column(String(50), nullable=True)
email = Column(String(100), nullable=True)
address = Column(Text, nullable=True)
bank_name = Column(String(100), nullable=True)
bank_account = Column(String(50), nullable=True)
tax_number = Column(String(50), nullable=True)
credit_limit = Column(Numeric(12, 2), default=0)
is_active = Column(Boolean, default=True)
created_at = Column(DateTime, default=func.now())
updated_at = Column(DateTime, default=func.now(), onupdate=func.now())
sales_orders = relationship("SalesOrder", back_populates="customer")
def __repr__(self):
return f"<Customer(id={self.id}, name='{self.name}')>"
+45
View File
@@ -0,0 +1,45 @@
"""inventory 财务域模型:收付款交易与订单分摊。"""
from sqlalchemy import Column, Integer, String, Text, DateTime, Numeric, ForeignKey
from sqlalchemy.sql import func
from sqlalchemy.orm import relationship
from shared.models.base import Base
class FinanceTransaction(Base):
__tablename__ = "finance_transactions"
id = Column(Integer, primary_key=True, index=True)
txn_no = Column(String(50), unique=True, index=True, nullable=False)
txn_type = Column(String(20), nullable=False, index=True)
partner_type = Column(String(20), nullable=False, index=True)
partner_id = Column(Integer, nullable=False, index=True)
amount = Column(Numeric(12, 2), nullable=False)
txn_date = Column(DateTime, default=func.now(), index=True)
method = Column(String(30), default="bank")
account_name = Column(String(100), nullable=True)
status = Column(String(20), default="confirmed", index=True)
remark = Column(Text, nullable=True)
operator_id = Column(Integer, ForeignKey("users.id"), nullable=True)
created_at = Column(DateTime, default=func.now(), index=True)
allocations = relationship("FinanceAllocation", back_populates="transaction", cascade="all, delete-orphan")
def __repr__(self):
return f"<FinanceTransaction(txn_no='{self.txn_no}', txn_type='{self.txn_type}', amount={self.amount})>"
class FinanceAllocation(Base):
__tablename__ = "finance_allocations"
id = Column(Integer, primary_key=True, index=True)
transaction_id = Column(Integer, ForeignKey("finance_transactions.id"), nullable=False, index=True)
order_type = Column(String(20), nullable=False, index=True)
order_id = Column(Integer, nullable=False, index=True)
allocated_amount = Column(Numeric(12, 2), nullable=False)
created_at = Column(DateTime, default=func.now(), index=True)
transaction = relationship("FinanceTransaction", back_populates="allocations")
def __repr__(self):
return f"<FinanceAllocation(transaction_id={self.transaction_id}, order_type='{self.order_type}', amount={self.allocated_amount})>"
+108
View File
@@ -0,0 +1,108 @@
"""inventory 交易域模型:采购订单/销售订单及明细。"""
from sqlalchemy import Column, Integer, String, Text, DateTime, Date, Numeric, ForeignKey, CheckConstraint
from sqlalchemy.sql import func
from sqlalchemy.orm import relationship
from shared.models.base import Base
class PurchaseOrder(Base):
"""采购订单表"""
__tablename__ = "purchase_orders"
id = Column(Integer, primary_key=True, index=True)
order_no = Column(String(50), unique=True, index=True, nullable=False)
supplier_id = Column(Integer, ForeignKey("suppliers.id"), nullable=False, index=True)
order_date = Column(DateTime, default=func.now())
expected_date = Column(Date, nullable=True)
status = Column(String(20), default="draft")
total_amount = Column(Numeric(12, 2), default=0)
paid_amount = Column(Numeric(12, 2), default=0)
remark = Column(Text, nullable=True)
operator_id = Column(Integer, ForeignKey("users.id"), nullable=True)
created_at = Column(DateTime, default=func.now())
updated_at = Column(DateTime, default=func.now(), onupdate=func.now())
# 状态变更时间
received_date = Column(DateTime, nullable=True) # 已收货时间
paid_date = Column(DateTime, nullable=True) # 已付款时间
supplier = relationship("Supplier", back_populates="purchase_orders")
items = relationship("PurchaseOrderItem", back_populates="order", cascade="all, delete-orphan")
def __repr__(self):
return f"<PurchaseOrder(order_no='{self.order_no}', status='{self.status}')>"
class PurchaseOrderItem(Base):
"""采购订单明细表"""
__tablename__ = "purchase_order_items"
__table_args__ = (
CheckConstraint("quantity > 0 AND received_quantity >= 0 AND received_quantity <= quantity", name="ck_purchase_order_items_qty"),
)
id = Column(Integer, primary_key=True, index=True)
order_id = Column(Integer, ForeignKey("purchase_orders.id"), nullable=False)
product_id = Column(Integer, ForeignKey("products.id"), nullable=False)
quantity = Column(Integer, nullable=False)
received_quantity = Column(Integer, default=0)
unit_price = Column(Numeric(12, 2), nullable=False)
amount = Column(Numeric(12, 2), nullable=False)
remark = Column(Text, nullable=True)
order = relationship("PurchaseOrder", back_populates="items")
def __repr__(self):
return f"<PurchaseOrderItem(order_id={self.order_id}, product_id={self.product_id})>"
class SalesOrder(Base):
"""销售订单表"""
__tablename__ = "sales_orders"
id = Column(Integer, primary_key=True, index=True)
order_no = Column(String(50), unique=True, index=True, nullable=False)
customer_id = Column(Integer, ForeignKey("customers.id"), nullable=False, index=True)
order_date = Column(DateTime, default=func.now())
delivery_date = Column(Date, nullable=True)
manufacturing_date = Column(DateTime, nullable=True)
actual_delivery_date = Column(DateTime, nullable=True)
actual_payment_date = Column(DateTime, nullable=True)
status = Column(String(20), default="draft")
production_status = Column(String(20), default="not_started", index=True)
production_no = Column(String(50), nullable=True, index=True)
planned_material_cost = Column(Numeric(12, 2), default=0)
actual_material_cost = Column(Numeric(12, 2), default=0)
total_amount = Column(Numeric(12, 2), default=0)
received_amount = Column(Numeric(12, 2), default=0)
remark = Column(Text, nullable=True)
operator_id = Column(Integer, ForeignKey("users.id"), nullable=True)
created_at = Column(DateTime, default=func.now())
updated_at = Column(DateTime, default=func.now(), onupdate=func.now())
customer = relationship("Customer", back_populates="sales_orders")
items = relationship("SalesOrderItem", back_populates="order", cascade="all, delete-orphan")
def __repr__(self):
return f"<SalesOrder(order_no='{self.order_no}', status='{self.status}')>"
class SalesOrderItem(Base):
"""销售订单明细表"""
__tablename__ = "sales_order_items"
__table_args__ = (
CheckConstraint("quantity > 0 AND delivered_quantity >= 0 AND delivered_quantity <= quantity", name="ck_sales_order_items_qty"),
)
id = Column(Integer, primary_key=True, index=True)
order_id = Column(Integer, ForeignKey("sales_orders.id"), nullable=False)
product_id = Column(Integer, ForeignKey("products.id"), nullable=False)
quantity = Column(Integer, nullable=False)
delivered_quantity = Column(Integer, default=0)
unit_price = Column(Numeric(12, 2), nullable=False)
amount = Column(Numeric(12, 2), nullable=False)
remark = Column(Text, nullable=True)
order = relationship("SalesOrder", back_populates="items")
def __repr__(self):
return f"<SalesOrderItem(order_id={self.order_id}, product_id={self.product_id})>"
+80
View File
@@ -0,0 +1,80 @@
"""inventory 仓储域模型:仓库/库存/库存流水。"""
from sqlalchemy import Column, Integer, String, Text, DateTime, Boolean, Numeric, ForeignKey, UniqueConstraint, CheckConstraint
from sqlalchemy.sql import func
from sqlalchemy.orm import relationship
from shared.models.base import Base
class Warehouse(Base):
"""仓库表"""
__tablename__ = "warehouses"
id = Column(Integer, primary_key=True, index=True)
code = Column(String(50), unique=True, index=True)
name = Column(String(200), nullable=False)
address = Column(Text, nullable=True)
manager = Column(String(100), nullable=True)
phone = Column(String(50), nullable=True)
is_active = Column(Boolean, default=True)
is_default = Column(Boolean, default=False)
created_at = Column(DateTime, default=func.now())
inventories = relationship("Inventory", back_populates="warehouse")
def __repr__(self):
return f"<Warehouse(id={self.id}, name='{self.name}')>"
class Inventory(Base):
"""库存表"""
__tablename__ = "inventory"
__table_args__ = (
UniqueConstraint("product_id", "warehouse_id", name="uq_inventory_product_warehouse"),
CheckConstraint("quantity >= 0 AND locked_quantity >= 0 AND locked_quantity <= quantity", name="ck_inventory_qty_nonnegative"),
)
id = Column(Integer, primary_key=True, index=True)
product_id = Column(Integer, ForeignKey("products.id"), nullable=False, index=True)
warehouse_id = Column(Integer, ForeignKey("warehouses.id"), nullable=False, index=True)
quantity = Column(Numeric(12, 4), default=0)
locked_quantity = Column(Numeric(12, 4), default=0)
batch_number = Column(String(50), nullable=True)
location = Column(String(100), nullable=True)
updated_at = Column(DateTime, default=func.now(), onupdate=func.now())
product = relationship("Product", back_populates="inventory")
warehouse = relationship("Warehouse", back_populates="inventories")
def __repr__(self):
return f"<Inventory(product_id={self.product_id}, quantity={self.quantity})>"
@property
def available_quantity(self):
return self.quantity - self.locked_quantity
class StockMovement(Base):
"""库存变动记录表"""
__tablename__ = "stock_movements"
id = Column(Integer, primary_key=True, index=True)
product_id = Column(Integer, ForeignKey("products.id"), nullable=False, index=True)
warehouse_id = Column(Integer, ForeignKey("warehouses.id"), nullable=False)
movement_type = Column(String(20), nullable=False)
quantity = Column(Numeric(12, 4), nullable=False)
before_quantity = Column(Numeric(12, 4), default=0)
after_quantity = Column(Numeric(12, 4), default=0)
reference_type = Column(String(50), nullable=True)
reference_id = Column(Integer, nullable=True)
reference_no = Column(String(50), nullable=True)
unit_price = Column(Numeric(12, 2), nullable=True)
total_amount = Column(Numeric(12, 2), nullable=True)
remark = Column(Text, nullable=True)
operator_id = Column(Integer, ForeignKey("users.id"), nullable=True)
created_at = Column(DateTime, default=func.now(), index=True)
product = relationship("Product", back_populates="stock_movements")
def __repr__(self):
return f"<StockMovement(id={self.id}, type='{self.movement_type}', qty={self.quantity})>"
+2 -12
View File
@@ -11,18 +11,8 @@ from typing import Optional, List, Dict, Tuple
from datetime import datetime
from decimal import Decimal
from shared.models.database import (
User,
Customer,
Supplier,
Product,
SalesOrder,
SalesOrderItem,
PurchaseOrder,
PurchaseOrderItem,
FinanceTransaction,
FinanceAllocation,
)
from shared.models.identity import User
from inventory.models import Customer, Supplier, Product, SalesOrder, SalesOrderItem, PurchaseOrder, PurchaseOrderItem, FinanceTransaction, FinanceAllocation
from ..schemas import (
ReceiptCreate,
PaymentCreate,
+2 -1
View File
@@ -10,7 +10,8 @@ from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, func
from sqlalchemy.exc import IntegrityError
from shared.models.database import User, Product, Warehouse, Inventory
from shared.models.identity import User
from inventory.models import Product, Warehouse, Inventory
from ..schemas import InventoryResponse, InventoryCreate, InventoryUpdate, PaginatedResponse
@@ -10,18 +10,8 @@ from fastapi import HTTPException
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, func
from shared.models.database import (
User,
Product,
ProductMaterial,
SalesOrder,
SalesOrderItem,
Inventory,
MaterialSupplier,
Supplier,
PurchaseOrder,
PurchaseOrderItem,
)
from shared.models.identity import User
from inventory.models import Product, ProductMaterial, SalesOrder, SalesOrderItem, Inventory, MaterialSupplier, Supplier, PurchaseOrder, PurchaseOrderItem
from ..utils import generate_order_no
from ..schemas.purchase_demand_schemas import (
PurchaseDemandItemResponse,
@@ -10,16 +10,8 @@ from fastapi import HTTPException
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, func, update
from shared.models.database import (
User,
Supplier,
Product,
Warehouse,
Inventory,
StockMovement,
PurchaseOrder,
PurchaseOrderItem,
)
from shared.models.identity import User
from inventory.models import Supplier, Product, Warehouse, Inventory, StockMovement, PurchaseOrder, PurchaseOrderItem
from ..schemas import (
PurchaseOrderCreate,
PurchaseOrderResponse,
+2 -11
View File
@@ -12,17 +12,8 @@ from fastapi import HTTPException
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, func, delete, update
from shared.models.database import (
User,
Customer,
Product,
ProductMaterial,
Warehouse,
Inventory,
StockMovement,
SalesOrder,
SalesOrderItem,
)
from shared.models.identity import User
from inventory.models import Customer, Product, ProductMaterial, Warehouse, Inventory, StockMovement, SalesOrder, SalesOrderItem
from ..schemas import (
SalesOrderCreate,
SalesOrderResponse,
@@ -9,7 +9,8 @@ from fastapi import HTTPException
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, update, func
from shared.models.database import User, Product, Warehouse, Inventory, StockMovement
from shared.models.identity import User
from inventory.models import Product, Warehouse, Inventory, StockMovement
from ..schemas import StockMovementCreate, StockMovementResponse, PaginatedResponse
from ..utils import generate_order_no