diff --git a/shierfeng-fastapi-backend/module_business/entity/do/master_do.py b/shierfeng-fastapi-backend/module_business/entity/do/master_do.py index 26fcfdc..ac6a350 100644 --- a/shierfeng-fastapi-backend/module_business/entity/do/master_do.py +++ b/shierfeng-fastapi-backend/module_business/entity/do/master_do.py @@ -30,10 +30,10 @@ class BizStrain(Base): strain_code = Column(String(64), nullable=False, unique=True, comment='菌种编码') strain_name = Column(String(100), nullable=False, comment='菌种名称') status = Column(CHAR(1), nullable=False, server_default='0', comment='状态(0正常 1停用)') - create_by = Column(String(64), nullable=True, server_default="''", comment='创建者') - create_time = Column(DateTime, nullable=True, default=datetime.now(), comment='创建时间') - update_by = Column(String(64), nullable=True, server_default="''", comment='更新者') - update_time = Column(DateTime, nullable=True, default=datetime.now(), comment='更新时间') + create_by = Column(String(64), nullable=True, server_default='', comment='创建者') + create_time = Column(DateTime, nullable=True, default=datetime.now, comment='创建时间') + update_by = Column(String(64), nullable=True, server_default='', comment='更新者') + update_time = Column(DateTime, nullable=True, default=datetime.now, comment='更新时间') remark = Column( String(500), nullable=True, @@ -56,10 +56,10 @@ class BizWarehouse(Base): warehouse_name = Column(String(100), nullable=False, comment='仓库名称') address = Column(String(500), nullable=True, comment='仓库地址') status = Column(CHAR(1), nullable=False, server_default='0', comment='状态(0正常 1停用)') - create_by = Column(String(64), nullable=True, server_default="''", comment='创建者') - create_time = Column(DateTime, nullable=True, default=datetime.now(), comment='创建时间') - update_by = Column(String(64), nullable=True, server_default="''", comment='更新者') - update_time = Column(DateTime, nullable=True, default=datetime.now(), comment='更新时间') + create_by = Column(String(64), nullable=True, server_default='', comment='创建者') + create_time = Column(DateTime, nullable=True, default=datetime.now, comment='创建时间') + update_by = Column(String(64), nullable=True, server_default='', comment='更新者') + update_time = Column(DateTime, nullable=True, default=datetime.now, comment='更新时间') remark = Column( String(500), nullable=True, @@ -81,10 +81,10 @@ class BizCustomer(Base): customer_code = Column(String(64), nullable=False, unique=True, comment='客户编码') customer_name = Column(String(100), nullable=False, comment='客户名称') status = Column(CHAR(1), nullable=False, server_default='0', comment='状态(0正常 1停用)') - create_by = Column(String(64), nullable=True, server_default="''", comment='创建者') - create_time = Column(DateTime, nullable=True, default=datetime.now(), comment='创建时间') - update_by = Column(String(64), nullable=True, server_default="''", comment='更新者') - update_time = Column(DateTime, nullable=True, default=datetime.now(), comment='更新时间') + create_by = Column(String(64), nullable=True, server_default='', comment='创建者') + create_time = Column(DateTime, nullable=True, default=datetime.now, comment='创建时间') + update_by = Column(String(64), nullable=True, server_default='', comment='更新者') + update_time = Column(DateTime, nullable=True, default=datetime.now, comment='更新时间') remark = Column( String(500), nullable=True, @@ -114,10 +114,10 @@ class BizCustomerSite(Base): site_name = Column(String(100), nullable=False, comment='现场名称') address = Column(String(500), nullable=True, comment='现场地址') status = Column(CHAR(1), nullable=False, server_default='0', comment='状态(0正常 1停用)') - create_by = Column(String(64), nullable=True, server_default="''", comment='创建者') - create_time = Column(DateTime, nullable=True, default=datetime.now(), comment='创建时间') - update_by = Column(String(64), nullable=True, server_default="''", comment='更新者') - update_time = Column(DateTime, nullable=True, default=datetime.now(), comment='更新时间') + create_by = Column(String(64), nullable=True, server_default='', comment='创建者') + create_time = Column(DateTime, nullable=True, default=datetime.now, comment='创建时间') + update_by = Column(String(64), nullable=True, server_default='', comment='更新者') + update_time = Column(DateTime, nullable=True, default=datetime.now, comment='更新时间') remark = Column( String(500), nullable=True, @@ -146,10 +146,10 @@ class BizProductionLine(Base): line_code = Column(String(64), nullable=False, comment='产线编码') line_name = Column(String(100), nullable=False, comment='产线名称') status = Column(CHAR(1), nullable=False, server_default='0', comment='状态(0正常 1停用)') - create_by = Column(String(64), nullable=True, server_default="''", comment='创建者') - create_time = Column(DateTime, nullable=True, default=datetime.now(), comment='创建时间') - update_by = Column(String(64), nullable=True, server_default="''", comment='更新者') - update_time = Column(DateTime, nullable=True, default=datetime.now(), comment='更新时间') + create_by = Column(String(64), nullable=True, server_default='', comment='创建者') + create_time = Column(DateTime, nullable=True, default=datetime.now, comment='创建时间') + update_by = Column(String(64), nullable=True, server_default='', comment='更新者') + update_time = Column(DateTime, nullable=True, default=datetime.now, comment='更新时间') remark = Column( String(500), nullable=True, @@ -173,10 +173,10 @@ class BizPallet(Base): qr_token = Column(String(128), nullable=False, unique=True, comment='二维码固定标识') capacity_packages = Column(Integer, nullable=False, comment='容量包数') asset_status = Column(CHAR(1), nullable=False, server_default='0', comment='资产状态(0正常 1停用)') - create_by = Column(String(64), nullable=True, server_default="''", comment='创建者') - create_time = Column(DateTime, nullable=True, default=datetime.now(), comment='创建时间') - update_by = Column(String(64), nullable=True, server_default="''", comment='更新者') - update_time = Column(DateTime, nullable=True, default=datetime.now(), comment='更新时间') + create_by = Column(String(64), nullable=True, server_default='', comment='创建者') + create_time = Column(DateTime, nullable=True, default=datetime.now, comment='创建时间') + update_by = Column(String(64), nullable=True, server_default='', comment='更新者') + update_time = Column(DateTime, nullable=True, default=datetime.now, comment='更新时间') remark = Column( String(500), nullable=True, @@ -205,8 +205,8 @@ class BizUserWarehouse(Base): nullable=False, comment='仓库ID', ) - create_by = Column(String(64), nullable=True, server_default="''", comment='创建者') - create_time = Column(DateTime, nullable=True, default=datetime.now(), comment='创建时间') + create_by = Column(String(64), nullable=True, server_default='', comment='创建者') + create_time = Column(DateTime, nullable=True, default=datetime.now, comment='创建时间') class BizUserSite(Base): @@ -229,5 +229,5 @@ class BizUserSite(Base): nullable=False, comment='现场ID', ) - create_by = Column(String(64), nullable=True, server_default="''", comment='创建者') - create_time = Column(DateTime, nullable=True, default=datetime.now(), comment='创建时间') + create_by = Column(String(64), nullable=True, server_default='', comment='创建者') + create_time = Column(DateTime, nullable=True, default=datetime.now, comment='创建时间') diff --git a/shierfeng-fastapi-backend/module_business/entity/do/operation_do.py b/shierfeng-fastapi-backend/module_business/entity/do/operation_do.py index af3edac..d57d426 100644 --- a/shierfeng-fastapi-backend/module_business/entity/do/operation_do.py +++ b/shierfeng-fastapi-backend/module_business/entity/do/operation_do.py @@ -29,10 +29,10 @@ class BizInboundOrder(Base): confirm_request_hash = Column(String(64), nullable=True, comment='确认请求摘要') confirmed_by = Column(BigInteger, ForeignKey('sys_user.user_id'), nullable=True, comment='确认人ID') confirmed_at = Column(DateTime, nullable=True, comment='确认时间') - create_by = Column(String(64), nullable=True, server_default="''", comment='创建者') - create_time = Column(DateTime, nullable=True, default=datetime.now(), comment='创建时间') - update_by = Column(String(64), nullable=True, server_default="''", comment='更新者') - update_time = Column(DateTime, nullable=True, default=datetime.now(), comment='更新时间') + create_by = Column(String(64), nullable=True, server_default='', comment='创建者') + create_time = Column(DateTime, nullable=True, default=datetime.now, comment='创建时间') + update_by = Column(String(64), nullable=True, server_default='', comment='更新者') + update_time = Column(DateTime, nullable=True, default=datetime.now, comment='更新时间') remark = Column( String(500), nullable=True, @@ -64,8 +64,8 @@ class BizInboundItem(Base): comment='入库单ID', ) pallet_id = Column(BigInteger, ForeignKey('biz_pallet.pallet_id'), nullable=False, comment='托盘ID') - create_by = Column(String(64), nullable=True, server_default="''", comment='创建者') - create_time = Column(DateTime, nullable=True, default=datetime.now(), comment='创建时间') + create_by = Column(String(64), nullable=True, server_default='', comment='创建者') + create_time = Column(DateTime, nullable=True, default=datetime.now, comment='创建时间') class BizFillingRecord(Base): @@ -103,10 +103,10 @@ class BizFillingRecord(Base): request_hash = Column(String(64), nullable=False, comment='请求摘要') operator_id = Column(BigInteger, ForeignKey('sys_user.user_id'), nullable=False, comment='操作人ID') operated_at = Column(DateTime, nullable=False, comment='操作时间') - create_by = Column(String(64), nullable=True, server_default="''", comment='创建者') - create_time = Column(DateTime, nullable=True, default=datetime.now(), comment='创建时间') - update_by = Column(String(64), nullable=True, server_default="''", comment='更新者') - update_time = Column(DateTime, nullable=True, default=datetime.now(), comment='更新时间') + create_by = Column(String(64), nullable=True, server_default='', comment='创建者') + create_time = Column(DateTime, nullable=True, default=datetime.now, comment='创建时间') + update_by = Column(String(64), nullable=True, server_default='', comment='更新者') + update_time = Column(DateTime, nullable=True, default=datetime.now, comment='更新时间') remark = Column( String(500), nullable=True, @@ -143,10 +143,10 @@ class BizShipmentOrder(Base): confirm_request_hash = Column(String(64), nullable=True, comment='确认请求摘要') confirmed_by = Column(BigInteger, ForeignKey('sys_user.user_id'), nullable=True, comment='确认人ID') confirmed_at = Column(DateTime, nullable=True, comment='确认时间') - create_by = Column(String(64), nullable=True, server_default="''", comment='创建者') - create_time = Column(DateTime, nullable=True, default=datetime.now(), comment='创建时间') - update_by = Column(String(64), nullable=True, server_default="''", comment='更新者') - update_time = Column(DateTime, nullable=True, default=datetime.now(), comment='更新时间') + create_by = Column(String(64), nullable=True, server_default='', comment='创建者') + create_time = Column(DateTime, nullable=True, default=datetime.now, comment='创建时间') + update_by = Column(String(64), nullable=True, server_default='', comment='更新者') + update_time = Column(DateTime, nullable=True, default=datetime.now, comment='更新时间') remark = Column( String(500), nullable=True, @@ -189,8 +189,8 @@ class BizShipmentItem(Base): comment='确认时活动装填记录ID', ) package_qty = Column(Integer, nullable=True, comment='确认时包数快照') - create_by = Column(String(64), nullable=True, server_default="''", comment='创建者') - create_time = Column(DateTime, nullable=True, default=datetime.now(), comment='创建时间') + create_by = Column(String(64), nullable=True, server_default='', comment='创建者') + create_time = Column(DateTime, nullable=True, default=datetime.now, comment='创建时间') class BizUsageRecord(Base): @@ -257,10 +257,10 @@ class BizReturnOrder(Base): requested_at = Column(DateTime, nullable=False, comment='申请时间') confirmed_by = Column(BigInteger, ForeignKey('sys_user.user_id'), nullable=True, comment='确认人ID') confirmed_at = Column(DateTime, nullable=True, comment='确认时间') - create_by = Column(String(64), nullable=True, server_default="''", comment='创建者') - create_time = Column(DateTime, nullable=True, default=datetime.now(), comment='创建时间') - update_by = Column(String(64), nullable=True, server_default="''", comment='更新者') - update_time = Column(DateTime, nullable=True, default=datetime.now(), comment='更新时间') + create_by = Column(String(64), nullable=True, server_default='', comment='创建者') + create_time = Column(DateTime, nullable=True, default=datetime.now, comment='创建时间') + update_by = Column(String(64), nullable=True, server_default='', comment='更新者') + update_time = Column(DateTime, nullable=True, default=datetime.now, comment='更新时间') remark = Column( String(500), nullable=True, @@ -303,8 +303,8 @@ class BizReturnItem(Base): comment='申请时活动装填记录快照', ) remaining_packages_snapshot = Column(Integer, nullable=False, comment='申请时剩余包数快照') - create_by = Column(String(64), nullable=True, server_default="''", comment='创建者') - create_time = Column(DateTime, nullable=True, default=datetime.now(), comment='创建时间') + create_by = Column(String(64), nullable=True, server_default='', comment='创建者') + create_time = Column(DateTime, nullable=True, default=datetime.now, comment='创建时间') class BizPalletInventory(Base): @@ -367,7 +367,7 @@ class BizPalletInventory(Base): comment='最后事件ID', ) version = Column(Integer, nullable=False, server_default='0', comment='并发版本号') - updated_at = Column(DateTime, nullable=False, default=datetime.now(), comment='更新时间') + updated_at = Column(DateTime, nullable=False, default=datetime.now, comment='更新时间') class BizPalletEvent(Base): diff --git a/shierfeng-fastapi-backend/tests/module_business/test_model_contract.py b/shierfeng-fastapi-backend/tests/module_business/test_model_contract.py index 0e45488..08e420d 100644 --- a/shierfeng-fastapi-backend/tests/module_business/test_model_contract.py +++ b/shierfeng-fastapi-backend/tests/module_business/test_model_contract.py @@ -1,6 +1,8 @@ import unittest from sqlalchemy import CHAR, BigInteger, CheckConstraint, DateTime, Integer, String, Table, UniqueConstraint +from sqlalchemy.dialects import mysql, postgresql +from sqlalchemy.schema import CreateColumn from config.database import Base from module_business.entity.do import master_do, operation_do @@ -694,6 +696,63 @@ EXPECTED_NULLABILITY = { }, } +EXPECTED_CALLABLE_DATETIME_DEFAULTS = { + ('biz_strain', 'create_time'), + ('biz_strain', 'update_time'), + ('biz_warehouse', 'create_time'), + ('biz_warehouse', 'update_time'), + ('biz_customer', 'create_time'), + ('biz_customer', 'update_time'), + ('biz_customer_site', 'create_time'), + ('biz_customer_site', 'update_time'), + ('biz_production_line', 'create_time'), + ('biz_production_line', 'update_time'), + ('biz_pallet', 'create_time'), + ('biz_pallet', 'update_time'), + ('biz_user_warehouse', 'create_time'), + ('biz_user_site', 'create_time'), + ('biz_inbound_order', 'create_time'), + ('biz_inbound_order', 'update_time'), + ('biz_inbound_item', 'create_time'), + ('biz_filling_record', 'create_time'), + ('biz_filling_record', 'update_time'), + ('biz_shipment_order', 'create_time'), + ('biz_shipment_order', 'update_time'), + ('biz_shipment_item', 'create_time'), + ('biz_return_order', 'create_time'), + ('biz_return_order', 'update_time'), + ('biz_return_item', 'create_time'), + ('biz_pallet_inventory', 'updated_at'), +} + +EXPECTED_EMPTY_AUDIT_SERVER_DEFAULTS = { + ('biz_strain', 'create_by'), + ('biz_strain', 'update_by'), + ('biz_warehouse', 'create_by'), + ('biz_warehouse', 'update_by'), + ('biz_customer', 'create_by'), + ('biz_customer', 'update_by'), + ('biz_customer_site', 'create_by'), + ('biz_customer_site', 'update_by'), + ('biz_production_line', 'create_by'), + ('biz_production_line', 'update_by'), + ('biz_pallet', 'create_by'), + ('biz_pallet', 'update_by'), + ('biz_user_warehouse', 'create_by'), + ('biz_user_site', 'create_by'), + ('biz_inbound_order', 'create_by'), + ('biz_inbound_order', 'update_by'), + ('biz_inbound_item', 'create_by'), + ('biz_filling_record', 'create_by'), + ('biz_filling_record', 'update_by'), + ('biz_shipment_order', 'create_by'), + ('biz_shipment_order', 'update_by'), + ('biz_shipment_item', 'create_by'), + ('biz_return_order', 'create_by'), + ('biz_return_order', 'update_by'), + ('biz_return_item', 'create_by'), +} + EXPECTED_PRIMARY_KEYS = { 'biz_strain': ('strain_id',), 'biz_warehouse': ('warehouse_id',), @@ -930,6 +989,53 @@ class BusinessModelContractTest(unittest.TestCase): with self.subTest(table_name=table_name, column_name=column_name): self.assertIs(expected_nullable, table.c[column_name].nullable) + def test_datetime_python_defaults_are_callable(self) -> None: + business_tables = [table for table in Base.metadata.tables.values() if table.name.startswith('biz_')] + actual_defaults = { + (table.name, column.name) + for table in business_tables + for column in table.columns + if type(column.type) is DateTime and column.default is not None + } + self.assertEqual(EXPECTED_CALLABLE_DATETIME_DEFAULTS, actual_defaults) + + violations = [] + for table_name, column_name in sorted(EXPECTED_CALLABLE_DATETIME_DEFAULTS): + column_default = Base.metadata.tables[table_name].c[column_name].default + if column_default is None or not column_default.is_callable or column_default.is_scalar: + violations.append( + ( + table_name, + column_name, + None if column_default is None else column_default.is_callable, + None if column_default is None else column_default.is_scalar, + ) + ) + self.assertEqual([], violations) + + def test_audit_user_server_defaults_compile_to_empty_strings(self) -> None: + business_tables = [table for table in Base.metadata.tables.values() if table.name.startswith('biz_')] + actual_audit_columns = { + (table.name, column.name) + for table in business_tables + for column in table.columns + if column.name in {'create_by', 'update_by'} + } + self.assertEqual(EXPECTED_EMPTY_AUDIT_SERVER_DEFAULTS, actual_audit_columns) + + violations = [] + dialects = {'mysql': mysql.dialect(), 'postgresql': postgresql.dialect()} + for table_name, column_name in sorted(EXPECTED_EMPTY_AUDIT_SERVER_DEFAULTS): + column = Base.metadata.tables[table_name].c[column_name] + for dialect_name, dialect in dialects.items(): + compiled_column = str(CreateColumn(column).compile(dialect=dialect)) + _, separator, compiled_default = compiled_column.partition(' DEFAULT ') + if separator: + compiled_default = compiled_default.split(' COMMENT ', maxsplit=1)[0].strip() + if compiled_default != "''": + violations.append((dialect_name, table_name, column_name, compiled_default)) + self.assertEqual([], violations) + def test_primary_keys_and_foreign_keys_match_contract(self) -> None: for table_name, expected_primary_key in EXPECTED_PRIMARY_KEYS.items(): table = Base.metadata.tables[table_name]