修feat: 渠道库存同步支持字段任意排序并增加字段异常告警

- 按字段名校验并写入渠道库存,取消字段顺序校验及表头重建
- 严格校验必填字段名称、类型和数字格式,失败时不修改表头或记录
- 字段校验失败时发送飞书群通知
- 添加字段校验与通知流程测试
- 忽略 Python 字节码、__pycache__ 和 .DS_Store
This commit is contained in:
2026-07-22 14:28:23 +08:00
parent 58b38adc6f
commit e234bfbe7a
7 changed files with 189 additions and 76 deletions
+25 -2
View File
@@ -7,7 +7,7 @@ from typing import Any
from inventory_analytics.logging_utils import log_event as emit_log_event
from .feishu import FeishuApiError, FeishuClient
from .feishu import FeishuApiError, FeishuClient, FeishuFieldValidationError
from .postgres import query_postgres
from .settings import AppConfig
from .specs import BRAND_SYNC_TARGETS, FIELD_SPECS, PRIMARY_FIELD_NAME, PRIMARY_FIELD_SOURCE, BrandSyncTarget, FieldSpec
@@ -15,6 +15,8 @@ from .specs import BRAND_SYNC_TARGETS, FIELD_SPECS, PRIMARY_FIELD_NAME, PRIMARY_
logger = logging.getLogger("inventory_sync.service")
CHANNEL_INVENTORY_SCHEMA_ALERT_CHAT_ID = "oc_8a4b6891bade81d116914aa55054a49d"
LOG_FIELD_LABELS = {
"advanced_permission_enabled": "高级权限已开启",
"brand_name": "品牌",
@@ -159,7 +161,28 @@ def sync_brand_target(
source_rows = postgres_rows or []
target_rows, shop_names = pivot_shop_stock_rows(source_rows)
field_specs = build_channel_inventory_field_specs(shop_names)
available_fields = client.ensure_target_fields(access_token, app_token, table_id, field_specs)
try:
available_fields = client.ensure_target_fields(access_token, app_token, table_id, field_specs)
except FeishuFieldValidationError as exc:
notification = (
"【渠道库存同步未执行】\n"
f"品牌:{target.brand_name}\n"
f"数据表:{target.table_name}\n"
"原因:飞书表头字段校验失败。本次不会删除或重建字段,也不会删除或写入记录。\n"
f"详情:{exc}"
)
try:
client.send_text_message(access_token, CHANNEL_INVENTORY_SCHEMA_ALERT_CHAT_ID, notification)
except Exception as notification_exc: # noqa: BLE001
log_event(
logging.ERROR,
"渠道库存字段校验失败通知发送失败",
stage="schema_validation",
brand_name=target.brand_name,
table_name=target.table_name,
error=str(notification_exc),
)
raise
existing_records = client.list_records(access_token, app_token, table_id)
existing_record_ids = [record.get("record_id") for record in existing_records if record.get("record_id")]
log_event(