- StandardCost/ActualCost 增加 research_flag(int,idx)/project_type(varchar30,idx) project_type: platform_dev平台研发/client_delivery客户交付/internal内部管理 - 生产库两表 ALTER 完成, 存量 29+134 行默认 internal(保守防误归研发) - API: create/update 支持写入维度, 未传默认 client_delivery(录入默认), research_flag 未显式传入按 project_type 联动(platform_dev=1); create/update/delete 绑定 entity_id(token优先, 防跨账套) - API: standard/actual 列表支持 project_type/research_flag 过滤 - 前端 CostDashboard: 表单加归集类型下拉(默认客户交付+研发提示), 列表加归集类型列(标签), 工具栏按归集类型过滤 - tests: test_cost.py +6 用例(默认值/联动/过滤/更新) - scripts: verify_cost_research_dimension_e2e.py 生产E2E(标记+清理+回查)
86 lines
5.2 KiB
Python
86 lines
5.2 KiB
Python
"""成本分析模型 — 管理会计OS
|
||
标准成本卡片、实际成本归集、作业成本法(ABC)
|
||
"""
|
||
from sqlalchemy import Column, Integer, String, Float, DateTime, Text, ForeignKey, JSON, func
|
||
from app.database import Base
|
||
|
||
|
||
RESEARCH_PROJECT_TYPES = ("platform_dev", "client_delivery", "internal")
|
||
|
||
|
||
class StandardCost(Base):
|
||
"""标准成本卡片 — 每项产品或服务的标准成本构成"""
|
||
__tablename__ = "standard_costs"
|
||
|
||
id = Column(Integer, primary_key=True, index=True)
|
||
entity_id = Column(Integer, default=1, comment="企业ID (P2多租户隔离 2026-08-23)")
|
||
research_flag = Column(Integer, default=0, index=True, comment="是否研发投入 0/1(研发费用加计扣除归集 2026-09-05)")
|
||
project_type = Column(String(30), default="internal", index=True, comment="归集类型: platform_dev平台研发/client_delivery客户交付/internal内部管理(默认internal保守防误归研发)")
|
||
product_code = Column(String(50), nullable=False, comment="产品/服务编码")
|
||
product_name = Column(String(200), nullable=False, comment="产品/服务名称")
|
||
cost_type = Column(String(20), nullable=False, comment="成本类型: material/labor/overhead")
|
||
item_name = Column(String(200), nullable=False, comment="成本项目名称")
|
||
standard_quantity = Column(Float, nullable=False, comment="标准用量")
|
||
unit = Column(String(20), nullable=True, comment="单位")
|
||
standard_price = Column(Float, nullable=False, comment="标准单价")
|
||
standard_cost = Column(Float, nullable=False, comment="标准成本 = 用量×单价")
|
||
version = Column(String(20), default="v1.0", comment="版本号")
|
||
status = Column(String(20), default="active", comment="active/archived")
|
||
remark = Column(Text, nullable=True)
|
||
created_at = Column(DateTime, server_default=func.now())
|
||
updated_at = Column(DateTime, server_default=func.now(), onupdate=func.now())
|
||
|
||
|
||
class ActualCost(Base):
|
||
"""实际成本归集 — 从ERP/手工录入的实际成本"""
|
||
__tablename__ = "actual_costs"
|
||
|
||
id = Column(Integer, primary_key=True, index=True)
|
||
entity_id = Column(Integer, default=1, comment="企业ID (P2多租户隔离 2026-08-23)")
|
||
research_flag = Column(Integer, default=0, index=True, comment="是否研发投入 0/1(研发费用加计扣除归集 2026-09-05)")
|
||
project_type = Column(String(30), default="internal", index=True, comment="归集类型: platform_dev平台研发/client_delivery客户交付/internal内部管理(默认internal保守防误归研发)")
|
||
period = Column(String(20), nullable=False, comment="期间 2026-05")
|
||
product_code = Column(String(50), nullable=False, comment="产品/服务编码")
|
||
product_name = Column(String(200), nullable=False, comment="产品/服务名称")
|
||
cost_type = Column(String(20), nullable=False, comment="成本类型: material/labor/overhead")
|
||
item_name = Column(String(200), nullable=False, comment="成本项目名称")
|
||
actual_quantity = Column(Float, nullable=False, comment="实际用量")
|
||
actual_price = Column(Float, nullable=False, comment="实际单价")
|
||
actual_cost = Column(Float, nullable=False, comment="实际成本 = 用量×单价")
|
||
source = Column(String(50), default="manual", comment="数据来源: erp/manual")
|
||
created_at = Column(DateTime, server_default=func.now())
|
||
|
||
|
||
class AbcActivity(Base):
|
||
"""ABC作业中心定义"""
|
||
__tablename__ = "abc_activities"
|
||
|
||
id = Column(Integer, primary_key=True, index=True)
|
||
entity_id = Column(Integer, default=1, comment="企业ID (P2多租户隔离 2026-08-23)")
|
||
activity_code = Column(String(50), unique=True, nullable=False, comment="作业编码")
|
||
activity_name = Column(String(200), nullable=False, comment="作业名称")
|
||
activity_desc = Column(Text, nullable=True, comment="作业描述")
|
||
cost_driver = Column(String(100), nullable=False, comment="成本动因")
|
||
driver_unit = Column(String(50), nullable=True, comment="动因单位")
|
||
total_cost = Column(Float, default=0, comment="作业总成本")
|
||
driver_volume = Column(Float, default=0, comment="动因总量")
|
||
driver_rate = Column(Float, default=0, comment="动因分配率 = 总成本/动因总量")
|
||
status = Column(String(20), default="active", comment="active/inactive")
|
||
created_at = Column(DateTime, server_default=func.now())
|
||
updated_at = Column(DateTime, server_default=func.now(), onupdate=func.now())
|
||
|
||
|
||
class AbcAllocation(Base):
|
||
"""ABC成本分配记录 — 按动因分配到产品"""
|
||
__tablename__ = "abc_allocations"
|
||
|
||
id = Column(Integer, primary_key=True, index=True)
|
||
entity_id = Column(Integer, default=1, comment="企业ID (P2多租户隔离 2026-08-23)")
|
||
period = Column(String(20), nullable=False, comment="期间 2026-05")
|
||
activity_id = Column(Integer, ForeignKey("abc_activities.id"), nullable=False)
|
||
product_code = Column(String(50), nullable=False, comment="产品/服务编码")
|
||
product_name = Column(String(200), nullable=False, comment="产品/服务名称")
|
||
driver_consumed = Column(Float, nullable=False, comment="消耗的动因量")
|
||
allocated_cost = Column(Float, nullable=False, comment="分配的成本")
|
||
created_at = Column(DateTime, server_default=func.now())
|