- data/orders/dao.py (530 lines): OrdersDAO class
* CRUD: create / get / get_by_external_id / find_by_phone / list / count / stats_by_status / update / delete
* 事务: transaction() 上下文 + 嵌套深度计数(外层事务中内层不重复 commit)
* 加密透明化: API 入口 Order dataclass 走明文 PII,DAO 内部 to_db_row/from_db_row 转换
* 状态机守护: transition_status() 单事务内 UPDATE orders + INSERT order_status_history
+ 时间戳联动 (paid_at/started_at/delivered_at/completed_at COALESCE 保留首次值)
* 幂等 upsert_by_external_id: 4 种 action 与 data/channel_sync/dao_extension 对齐
* 防御: update() 显式拒绝 status 字段; _row_factory_ctx() 不污染外部 row_factory
* 异常: OrderNotFound(LookupError) / DuplicateOrder(ValueError)
- data/orders/tests/test_dao.py (51 cases): 加密透明化、状态机合法/非法路径、
事务回滚、upsert 4 种 action、状态历史时间线、row_factory 隔离、删除 cascade、
与 dao_extension 的契约对齐
- data/orders/__init__.py: 导出 OrdersDAO / UpsertResult / StatusChange /
OrderNotFound / DuplicateOrder
- 验证: data/orders/tests/ 163/163, data/ 386/386, ruff 0 warning, py_compile clean
107 lines
2.1 KiB
Python
107 lines
2.1 KiB
Python
"""订单数据模块 (T4.1 + T4.2)
|
||
|
||
提供:
|
||
- SQLite schema(AES-256 加密字段 + 6 态状态机 + 审计表)
|
||
- Fernet 加密/解密/索引哈希派生
|
||
- 6 态订单状态机
|
||
- ``Order`` dataclass + 加密/脱敏序列化
|
||
- ``OrdersDAO`` 完整 CRUD + 事务 + 状态机守护(**T4.2**)
|
||
|
||
下游使用
|
||
--------
|
||
|
||
```python
|
||
import os
|
||
os.environ["GAOKAO_ORDERS_FERNET_KEY"] = "your-secret-here"
|
||
|
||
from data.orders import (
|
||
# schema
|
||
apply_schema,
|
||
# crypto
|
||
encrypt, decrypt, hash_for_index,
|
||
# state machine
|
||
assert_valid_transition, OrderStatus,
|
||
# models
|
||
Order, generate_order_id,
|
||
# DAO (T4.2)
|
||
OrdersDAO, UpsertResult, StatusChange,
|
||
OrderNotFound, DuplicateOrder,
|
||
)
|
||
```
|
||
"""
|
||
|
||
from .crypto import (
|
||
ENV_KEY_NAME,
|
||
EncryptionError,
|
||
MissingEncryptionKey,
|
||
constant_time_equals,
|
||
decrypt,
|
||
derive_key,
|
||
encrypt,
|
||
get_fernet,
|
||
hash_for_index,
|
||
)
|
||
from .dao import (
|
||
DuplicateOrder,
|
||
OrderNotFound,
|
||
OrdersDAO,
|
||
StatusChange,
|
||
UpsertResult,
|
||
)
|
||
from .models import (
|
||
DecryptPolicy,
|
||
Order,
|
||
generate_order_id,
|
||
utc_now_iso,
|
||
)
|
||
from .schema import SCHEMA_SQL, apply_schema, get_schema_version
|
||
from .state_machine import (
|
||
ALLOWED_TRANSITIONS,
|
||
InvalidStateTransition,
|
||
OrderStatus,
|
||
TERMINAL_STATUSES,
|
||
assert_valid_transition,
|
||
is_known_status,
|
||
is_terminal,
|
||
is_valid_transition,
|
||
next_states,
|
||
)
|
||
|
||
__all__ = [
|
||
# schema
|
||
"SCHEMA_SQL",
|
||
"apply_schema",
|
||
"get_schema_version",
|
||
# crypto
|
||
"ENV_KEY_NAME",
|
||
"EncryptionError",
|
||
"MissingEncryptionKey",
|
||
"constant_time_equals",
|
||
"decrypt",
|
||
"derive_key",
|
||
"encrypt",
|
||
"get_fernet",
|
||
"hash_for_index",
|
||
# state machine
|
||
"ALLOWED_TRANSITIONS",
|
||
"InvalidStateTransition",
|
||
"OrderStatus",
|
||
"TERMINAL_STATUSES",
|
||
"assert_valid_transition",
|
||
"is_known_status",
|
||
"is_terminal",
|
||
"is_valid_transition",
|
||
"next_states",
|
||
# models
|
||
"DecryptPolicy",
|
||
"Order",
|
||
"generate_order_id",
|
||
"utc_now_iso",
|
||
# DAO
|
||
"DuplicateOrder",
|
||
"OrderNotFound",
|
||
"OrdersDAO",
|
||
"StatusChange",
|
||
"UpsertResult",
|
||
]
|