chore: [workflow] 提交工作区代码
This commit is contained in:
1 parent
2ff588a65d
commit
01f3d7aaf7
131 files changed
+24306
-1320
No files matched your search
+312
-35
@@ -115,6 +115,7 @@ _CONTENT_POSTGRES_WORKFLOW_IDS = frozenset(
|
||||
{
|
||||
"content.notes_master.daily",
|
||||
"content.metrics.daily",
|
||||
"content.metrics.self_operated.daily",
|
||||
"content.metrics.backfill",
|
||||
"content.marketing_report.daily",
|
||||
"content.creator_report.monthly",
|
||||
@@ -167,7 +168,8 @@ _MODULES = (
|
||||
|
||||
_WORKFLOW_NAMES = {
|
||||
"content.notes_master.daily": "笔记清单与合作同步",
|
||||
"content.metrics.daily": "内容指标日报采集",
|
||||
"content.metrics.daily": "合作达人内容指标日报采集",
|
||||
"content.metrics.self_operated.daily": "自营内容指标日报采集",
|
||||
"content.marketing_report.daily": "营销日报生成与发送",
|
||||
"content.relogin.weekly": "内容平台登录态刷新",
|
||||
"content.creator_report.monthly": "达人月报生成",
|
||||
@@ -193,6 +195,14 @@ _WORKFLOW_NAMES = {
|
||||
"shop.metrics.weekly": "店铺经营指标周采集",
|
||||
"shop.competitor.weekly": "竞店指标周采集",
|
||||
"shop.jd_self_operated.daily": "京东自营业绩日采集",
|
||||
"shop.jd_customer_service.daily": "京东客服消息采集",
|
||||
"shop.jd_negative_reviews.daily": "京东差评采集",
|
||||
"shop.dy_negative_reviews.daily": "抖音差评采集",
|
||||
"shop.jd_after_sales_issues.daily": "京东品退问题采集",
|
||||
"shop.douyin_customer_service.daily": "抖音客服消息采集",
|
||||
"shop.tmall_customer_service.daily": "天猫客服消息采集",
|
||||
"shop.tmall_negative_reviews.daily": "天猫差评采集",
|
||||
"shop.douyin_after_sales_quality.daily": "抖音品退采集",
|
||||
"shop.douyin_price_appeal": "抖音待改价申诉",
|
||||
"shop.jd_self_operated.history": "京东自营业绩单日回采",
|
||||
"supply.purchase_confirmation.daily": "采购确认日处理",
|
||||
@@ -201,6 +211,69 @@ _WORKFLOW_NAMES = {
|
||||
"supply.purchase_order_update": "采购单更新",
|
||||
}
|
||||
|
||||
JD_CUSTOMER_SERVICE_WORKFLOW_ID = "shop.jd_customer_service.daily"
|
||||
JD_NEGATIVE_REVIEWS_WORKFLOW_ID = "shop.jd_negative_reviews.daily"
|
||||
JD_AFTER_SALES_ISSUES_WORKFLOW_ID = "shop.jd_after_sales_issues.daily"
|
||||
DOUYIN_CUSTOMER_SERVICE_WORKFLOW_ID = "shop.douyin_customer_service.daily"
|
||||
TMALL_CUSTOMER_SERVICE_WORKFLOW_ID = "shop.tmall_customer_service.daily"
|
||||
TMALL_NEGATIVE_REVIEWS_WORKFLOW_ID = "shop.tmall_negative_reviews.daily"
|
||||
DOUYIN_NEGATIVE_REVIEWS_WORKFLOW_ID = "shop.dy_negative_reviews.daily"
|
||||
DOUYIN_AFTER_SALES_QUALITY_WORKFLOW_ID = "shop.douyin_after_sales_quality.daily"
|
||||
JD_DATE_RANGE_WORKFLOW_IDS = frozenset(
|
||||
{
|
||||
JD_CUSTOMER_SERVICE_WORKFLOW_ID,
|
||||
JD_NEGATIVE_REVIEWS_WORKFLOW_ID,
|
||||
JD_AFTER_SALES_ISSUES_WORKFLOW_ID,
|
||||
}
|
||||
)
|
||||
# 支持控制台自定义开始/结束日期的工作流;京东系在此之上额外提供店铺选择。
|
||||
DATE_RANGE_WORKFLOW_IDS = JD_DATE_RANGE_WORKFLOW_IDS | {
|
||||
DOUYIN_CUSTOMER_SERVICE_WORKFLOW_ID,
|
||||
TMALL_CUSTOMER_SERVICE_WORKFLOW_ID,
|
||||
TMALL_NEGATIVE_REVIEWS_WORKFLOW_ID,
|
||||
DOUYIN_NEGATIVE_REVIEWS_WORKFLOW_ID,
|
||||
DOUYIN_AFTER_SALES_QUALITY_WORKFLOW_ID,
|
||||
}
|
||||
JD_CUSTOMER_SERVICE_STORE_OPTIONS = (
|
||||
{
|
||||
"value": "flagship",
|
||||
"label": "光影行星旗舰店",
|
||||
"account_id": "jd-shop",
|
||||
},
|
||||
{
|
||||
"value": "self-operated",
|
||||
"label": "京东自营店(光影自营研发)",
|
||||
"account_id": "jd-self-operated",
|
||||
},
|
||||
)
|
||||
JD_CUSTOMER_SERVICE_STORE_VALUES = frozenset(
|
||||
item["value"] for item in JD_CUSTOMER_SERVICE_STORE_OPTIONS
|
||||
)
|
||||
JD_AFTER_SALES_STORE_OPTIONS = (
|
||||
{
|
||||
"value": "flagship",
|
||||
"label": "光影行星旗舰店(研发账号)",
|
||||
"account_id": "jd-shop",
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
def _jd_store_options(workflow_id: str) -> tuple[dict[str, str], ...]:
|
||||
if workflow_id == JD_AFTER_SALES_ISSUES_WORKFLOW_ID:
|
||||
return JD_AFTER_SALES_STORE_OPTIONS
|
||||
return JD_CUSTOMER_SERVICE_STORE_OPTIONS
|
||||
|
||||
|
||||
def _tmall_customer_service_date_range_constraints(
|
||||
today: date,
|
||||
) -> dict[str, str]:
|
||||
month_index = today.year * 12 + today.month - 1 - 3
|
||||
year, zero_based_month = divmod(month_index, 12)
|
||||
month = zero_based_month + 1
|
||||
oldest_day = min(today.day, calendar.monthrange(year, month)[1])
|
||||
oldest = date(year, month, oldest_day)
|
||||
return {"min": oldest.isoformat(), "max": today.isoformat()}
|
||||
|
||||
_SECRET_VALUE = re.compile(
|
||||
r"(?i)([\"']?(?:api[_-]?key|access[_-]?token|token|password|secret)"
|
||||
r"[\"']?\s*[=:]\s*)"
|
||||
@@ -250,6 +323,8 @@ class RunLauncher(Protocol):
|
||||
tmall_topic_keyword: str | None = None,
|
||||
force_refresh: bool = False,
|
||||
tmall_baibu_import_mode: str | None = None,
|
||||
jd_customer_service_store: str | None = None,
|
||||
business_date_end: date | None = None,
|
||||
) -> dict[str, object]: ...
|
||||
|
||||
def active(self) -> tuple[dict[str, object], ...]: ...
|
||||
@@ -318,6 +393,7 @@ class _ActiveConsoleRun:
|
||||
operation_id: str
|
||||
workflow_id: str
|
||||
business_date: str
|
||||
business_date_end: str | None
|
||||
mode: str
|
||||
shadow: bool
|
||||
started_at: str
|
||||
@@ -375,6 +451,8 @@ class SubprocessConsoleRunLauncher:
|
||||
"status": "completed",
|
||||
"exit_code": exit_code,
|
||||
}
|
||||
if active.business_date_end is not None:
|
||||
result["business_date_end"] = active.business_date_end
|
||||
self._remember_finished_locked(result)
|
||||
return result
|
||||
|
||||
@@ -399,6 +477,7 @@ class SubprocessConsoleRunLauncher:
|
||||
"started_at": item.started_at,
|
||||
"status": "running",
|
||||
}
|
||||
| ({"business_date_end": item.business_date_end} if item.business_date_end else {})
|
||||
for item in self._runs.values()
|
||||
)
|
||||
|
||||
@@ -413,6 +492,8 @@ class SubprocessConsoleRunLauncher:
|
||||
tmall_topic_keyword: str | None = None,
|
||||
force_refresh: bool = False,
|
||||
tmall_baibu_import_mode: str | None = None,
|
||||
jd_customer_service_store: str | None = None,
|
||||
business_date_end: date | None = None,
|
||||
) -> dict[str, object]:
|
||||
with self._lock:
|
||||
self._reap_locked()
|
||||
@@ -423,19 +504,52 @@ class SubprocessConsoleRunLauncher:
|
||||
|
||||
operation_id = f"op-{uuid.uuid4().hex[:16]}"
|
||||
started_at = datetime.now(timezone.utc).isoformat(timespec="microseconds")
|
||||
known_run_ids = self._journal_run_ids(workflow_id, business_date)
|
||||
range_end = business_date_end or business_date
|
||||
if range_end < business_date:
|
||||
raise ConsoleRequestError("结束日期不能早于开始日期")
|
||||
known_run_ids = self._journal_run_ids_range(
|
||||
workflow_id, business_date, range_end
|
||||
)
|
||||
self.log_root.mkdir(parents=True, exist_ok=True)
|
||||
log_path = self.log_root / f"{workflow_id}-{operation_id}.log"
|
||||
stream = log_path.open("a", encoding="utf-8", newline="\n")
|
||||
argv = [
|
||||
str(self.python_executable),
|
||||
"-m",
|
||||
"gyxx_flow",
|
||||
"run",
|
||||
workflow_id,
|
||||
"--date",
|
||||
business_date.isoformat(),
|
||||
]
|
||||
if range_end != business_date and workflow_id in {
|
||||
DOUYIN_NEGATIVE_REVIEWS_WORKFLOW_ID,
|
||||
TMALL_CUSTOMER_SERVICE_WORKFLOW_ID,
|
||||
TMALL_NEGATIVE_REVIEWS_WORKFLOW_ID,
|
||||
}:
|
||||
# 这些后台都支持按日期区间直接查询,无需逐日启动。
|
||||
argv = [
|
||||
str(self.python_executable),
|
||||
"-m",
|
||||
"gyxx_flow",
|
||||
"run",
|
||||
workflow_id,
|
||||
"--date",
|
||||
business_date.isoformat(),
|
||||
]
|
||||
elif range_end != business_date:
|
||||
argv = [
|
||||
str(self.python_executable),
|
||||
"-m",
|
||||
"gyxx_flow",
|
||||
"backfill",
|
||||
workflow_id,
|
||||
"--from",
|
||||
business_date.isoformat(),
|
||||
"--to",
|
||||
range_end.isoformat(),
|
||||
]
|
||||
else:
|
||||
argv = [
|
||||
str(self.python_executable),
|
||||
"-m",
|
||||
"gyxx_flow",
|
||||
"run",
|
||||
workflow_id,
|
||||
"--date",
|
||||
business_date.isoformat(),
|
||||
]
|
||||
if execute:
|
||||
argv.append("--execute")
|
||||
if shadow:
|
||||
@@ -455,10 +569,34 @@ class SubprocessConsoleRunLauncher:
|
||||
},
|
||||
workflow_id=workflow_id,
|
||||
)
|
||||
if (
|
||||
workflow_id == DOUYIN_NEGATIVE_REVIEWS_WORKFLOW_ID
|
||||
and range_end != business_date
|
||||
):
|
||||
environment["GYXX_NEG_REVIEW_FROM"] = business_date.isoformat()
|
||||
environment["GYXX_NEG_REVIEW_TO"] = range_end.isoformat()
|
||||
if workflow_id == TMALL_CUSTOMER_SERVICE_WORKFLOW_ID:
|
||||
environment["GYXX_TMALL_CUSTOMER_SERVICE_START_DATE"] = (
|
||||
business_date.isoformat()
|
||||
)
|
||||
environment["GYXX_TMALL_CUSTOMER_SERVICE_END_DATE"] = (
|
||||
range_end.isoformat()
|
||||
)
|
||||
if workflow_id == TMALL_NEGATIVE_REVIEWS_WORKFLOW_ID:
|
||||
environment["GYXX_TMALL_NEGATIVE_REVIEWS_START_DATE"] = (
|
||||
business_date.isoformat()
|
||||
)
|
||||
environment["GYXX_TMALL_NEGATIVE_REVIEWS_END_DATE"] = (
|
||||
range_end.isoformat()
|
||||
)
|
||||
if video_upload_store is not None:
|
||||
environment["GYXX_VIDEO_UPLOAD_STORE"] = video_upload_store
|
||||
if tmall_topic_keyword is not None:
|
||||
environment["GYXX_TMALL_TOPIC_KEYWORD"] = tmall_topic_keyword
|
||||
if jd_customer_service_store is not None:
|
||||
environment["GYXX_JD_CUSTOMER_SERVICE_STORE"] = (
|
||||
jd_customer_service_store
|
||||
)
|
||||
if force_refresh:
|
||||
environment["GYXX_FORCE_REFRESH"] = "true"
|
||||
else:
|
||||
@@ -496,6 +634,9 @@ class SubprocessConsoleRunLauncher:
|
||||
operation_id=operation_id,
|
||||
workflow_id=workflow_id,
|
||||
business_date=business_date.isoformat(),
|
||||
business_date_end=(
|
||||
range_end.isoformat() if range_end != business_date else None
|
||||
),
|
||||
mode="execute" if execute else "dry_run",
|
||||
shadow=shadow,
|
||||
started_at=started_at,
|
||||
@@ -515,6 +656,8 @@ class SubprocessConsoleRunLauncher:
|
||||
"started_at": started_at,
|
||||
"status": "accepted",
|
||||
}
|
||||
if active.business_date_end is not None:
|
||||
result["business_date_end"] = active.business_date_end
|
||||
if video_upload_store is not None:
|
||||
result["store"] = video_upload_store
|
||||
if tmall_topic_keyword is not None:
|
||||
@@ -523,6 +666,8 @@ class SubprocessConsoleRunLauncher:
|
||||
result["force_refresh"] = True
|
||||
if tmall_baibu_import_mode is not None:
|
||||
result["tmall_baibu_import_mode"] = tmall_baibu_import_mode
|
||||
if jd_customer_service_store is not None:
|
||||
result["store"] = jd_customer_service_store
|
||||
return result
|
||||
|
||||
def cancel(
|
||||
@@ -572,6 +717,8 @@ class SubprocessConsoleRunLauncher:
|
||||
"already_cancelled": False,
|
||||
"journal_status": journal_status,
|
||||
}
|
||||
if active.business_date_end is not None:
|
||||
result["business_date_end"] = active.business_date_end
|
||||
if run_id is not None:
|
||||
result["run_id"] = run_id
|
||||
self._write_cancellation_record(result)
|
||||
@@ -616,6 +763,8 @@ class SubprocessConsoleRunLauncher:
|
||||
"log_path": log_path.relative_to(self.settings.data_root).as_posix(),
|
||||
"known_run_ids": sorted(active.known_run_ids),
|
||||
}
|
||||
if active.business_date_end is not None:
|
||||
payload["business_date_end"] = active.business_date_end
|
||||
try:
|
||||
atomic_write_json(self._active_path(active.operation_id), payload)
|
||||
except OSError:
|
||||
@@ -645,6 +794,7 @@ class SubprocessConsoleRunLauncher:
|
||||
operation_id = payload["operation_id"]
|
||||
workflow_id = payload["workflow_id"]
|
||||
business_date = payload["business_date"]
|
||||
business_date_end = payload.get("business_date_end")
|
||||
mode = payload["mode"]
|
||||
shadow = payload["shadow"]
|
||||
started_at = payload["started_at"]
|
||||
@@ -663,6 +813,10 @@ class SubprocessConsoleRunLauncher:
|
||||
parsed_date = date.fromisoformat(business_date)
|
||||
if parsed_date.isoformat() != business_date:
|
||||
return None
|
||||
if business_date_end is not None:
|
||||
parsed_end = date.fromisoformat(business_date_end)
|
||||
if parsed_end.isoformat() != business_date_end or parsed_end < parsed_date:
|
||||
return None
|
||||
if mode not in {"execute", "dry_run"} or not isinstance(shadow, bool):
|
||||
return None
|
||||
if not isinstance(started_at, str):
|
||||
@@ -695,6 +849,7 @@ class SubprocessConsoleRunLauncher:
|
||||
operation_id=operation_id,
|
||||
workflow_id=workflow_id,
|
||||
business_date=business_date,
|
||||
business_date_end=business_date_end,
|
||||
mode=mode,
|
||||
shadow=shadow,
|
||||
started_at=started_at,
|
||||
@@ -734,6 +889,19 @@ class SubprocessConsoleRunLauncher:
|
||||
root = self._journal_run_root(workflow_id, business_date.isoformat())
|
||||
return frozenset(path.parent.name for path in root.glob("*/run.json"))
|
||||
|
||||
def _journal_run_ids_range(
|
||||
self,
|
||||
workflow_id: str,
|
||||
start_date: date,
|
||||
end_date: date,
|
||||
) -> frozenset[str]:
|
||||
run_ids: set[str] = set()
|
||||
current = start_date
|
||||
while current <= end_date:
|
||||
run_ids.update(self._journal_run_ids(workflow_id, current))
|
||||
current += timedelta(days=1)
|
||||
return frozenset(run_ids)
|
||||
|
||||
def _locked_run_id(self, active: _ActiveConsoleRun) -> str | None:
|
||||
lock_root = self.settings.data_root / "state" / "locks"
|
||||
for path in lock_root.glob("*.lock"):
|
||||
@@ -762,24 +930,29 @@ class SubprocessConsoleRunLauncher:
|
||||
return None
|
||||
|
||||
def _candidate_journals(self, active: _ActiveConsoleRun) -> list[Path]:
|
||||
root = self._journal_run_root(active.workflow_id, active.business_date)
|
||||
candidates: list[Path] = []
|
||||
for path in root.glob("*/run.json"):
|
||||
if path.parent.name in active.known_run_ids:
|
||||
continue
|
||||
try:
|
||||
payload = json.loads(path.read_text(encoding="utf-8"))
|
||||
except (OSError, UnicodeError, json.JSONDecodeError):
|
||||
continue
|
||||
if not isinstance(payload, dict):
|
||||
continue
|
||||
if (
|
||||
payload.get("workflow_id") == active.workflow_id
|
||||
and payload.get("business_date") == active.business_date
|
||||
and payload.get("shadow") is active.shadow
|
||||
and payload.get("status") == "running"
|
||||
):
|
||||
candidates.append(path)
|
||||
start_date = date.fromisoformat(active.business_date)
|
||||
end_date = date.fromisoformat(active.business_date_end or active.business_date)
|
||||
current = start_date
|
||||
while current <= end_date:
|
||||
root = self._journal_run_root(active.workflow_id, current.isoformat())
|
||||
for path in root.glob("*/run.json"):
|
||||
if path.parent.name in active.known_run_ids:
|
||||
continue
|
||||
try:
|
||||
payload = json.loads(path.read_text(encoding="utf-8"))
|
||||
except (OSError, UnicodeError, json.JSONDecodeError):
|
||||
continue
|
||||
if not isinstance(payload, dict):
|
||||
continue
|
||||
if (
|
||||
payload.get("workflow_id") == active.workflow_id
|
||||
and payload.get("business_date") == current.isoformat()
|
||||
and payload.get("shadow") is active.shadow
|
||||
and payload.get("status") == "running"
|
||||
):
|
||||
candidates.append(path)
|
||||
current += timedelta(days=1)
|
||||
return candidates
|
||||
|
||||
def _finalize_cancelled_journal(
|
||||
@@ -790,13 +963,19 @@ class SubprocessConsoleRunLauncher:
|
||||
) -> tuple[str, str | None]:
|
||||
path: Path | None = None
|
||||
if run_id is not None:
|
||||
candidate = (
|
||||
self._journal_run_root(active.workflow_id, active.business_date)
|
||||
/ run_id
|
||||
/ "run.json"
|
||||
)
|
||||
if candidate.exists():
|
||||
path = candidate
|
||||
start_date = date.fromisoformat(active.business_date)
|
||||
end_date = date.fromisoformat(active.business_date_end or active.business_date)
|
||||
current = start_date
|
||||
while current <= end_date:
|
||||
candidate = (
|
||||
self._journal_run_root(active.workflow_id, current.isoformat())
|
||||
/ run_id
|
||||
/ "run.json"
|
||||
)
|
||||
if candidate.exists():
|
||||
path = candidate
|
||||
break
|
||||
current += timedelta(days=1)
|
||||
if path is None:
|
||||
candidates = self._candidate_journals(active)
|
||||
if len(candidates) == 1:
|
||||
@@ -1389,6 +1568,36 @@ class WorkflowConsoleService:
|
||||
if entry.workflow_id == "product.sales_sheet.daily"
|
||||
else "date"
|
||||
),
|
||||
"date_range_mode": (
|
||||
"date_range"
|
||||
if entry.workflow_id in DATE_RANGE_WORKFLOW_IDS
|
||||
else "single"
|
||||
),
|
||||
**(
|
||||
{
|
||||
"date_range_constraints": (
|
||||
_tmall_customer_service_date_range_constraints(
|
||||
now.date()
|
||||
)
|
||||
),
|
||||
"date_range_hint": (
|
||||
"仅支持最近三个月;系统按每次最多 31 天拆分查询,"
|
||||
"聊天记录可能延迟一天。"
|
||||
),
|
||||
}
|
||||
if entry.workflow_id == TMALL_CUSTOMER_SERVICE_WORKFLOW_ID
|
||||
else {}
|
||||
),
|
||||
**(
|
||||
{
|
||||
"date_range_hint": (
|
||||
"请指定评价时间范围;页面不选时间会查询所有日期,"
|
||||
"工作流会固定选择负面评价后再搜索。"
|
||||
)
|
||||
}
|
||||
if entry.workflow_id == TMALL_NEGATIVE_REVIEWS_WORKFLOW_ID
|
||||
else {}
|
||||
),
|
||||
"registered": entry.workflow_id in registered_ids,
|
||||
"note": entry.note,
|
||||
"source_task_name": entry.source_task_name,
|
||||
@@ -1405,6 +1614,23 @@ class WorkflowConsoleService:
|
||||
if entry.topic_config is not None
|
||||
else {}
|
||||
),
|
||||
**(
|
||||
{
|
||||
"store_config": {
|
||||
"label": "京东店铺/账号",
|
||||
"hint": (
|
||||
"选择账号对应的店铺;支持直接提交自定义日期范围,"
|
||||
"相同店铺、业务日和数据身份重复执行会幂等更新。"
|
||||
),
|
||||
"options": [
|
||||
dict(item)
|
||||
for item in _jd_store_options(entry.workflow_id)
|
||||
],
|
||||
}
|
||||
}
|
||||
if entry.workflow_id in JD_DATE_RANGE_WORKFLOW_IDS
|
||||
else {}
|
||||
),
|
||||
"schedule": _schedule_payload(schedule),
|
||||
"next_run_at": _next_run_at(schedule, now),
|
||||
"last_run": _run_payload(
|
||||
@@ -1959,6 +2185,10 @@ class WorkflowConsoleService:
|
||||
if workflow_id == "product.video_upload":
|
||||
allowed.add("store")
|
||||
allowed.add("tmall_topic_keyword")
|
||||
if workflow_id in JD_DATE_RANGE_WORKFLOW_IDS:
|
||||
allowed.add("store")
|
||||
if workflow_id in DATE_RANGE_WORKFLOW_IDS:
|
||||
allowed.add("business_date_end")
|
||||
if workflow_id == TMALL_BAIBU_WORKFLOW_ID:
|
||||
allowed.add("tmall_baibu_import_mode")
|
||||
unknown = set(payload) - allowed
|
||||
@@ -1971,6 +2201,35 @@ class WorkflowConsoleService:
|
||||
raise ConsoleRequestError("业务日期必须使用 YYYY-MM-DD 格式") from exc
|
||||
if business_date.isoformat() != raw_date:
|
||||
raise ConsoleRequestError("业务日期必须使用 YYYY-MM-DD 格式")
|
||||
business_date_end: date | None = None
|
||||
if workflow_id in DATE_RANGE_WORKFLOW_IDS:
|
||||
raw_end = payload.get("business_date_end", raw_date)
|
||||
try:
|
||||
business_date_end = date.fromisoformat(raw_end)
|
||||
except (TypeError, ValueError) as exc:
|
||||
raise ConsoleRequestError("结束日期必须使用 YYYY-MM-DD 格式") from exc
|
||||
if business_date_end.isoformat() != raw_end:
|
||||
raise ConsoleRequestError("结束日期必须使用 YYYY-MM-DD 格式")
|
||||
if business_date_end < business_date:
|
||||
raise ConsoleRequestError("结束日期不能早于开始日期")
|
||||
if workflow_id == TMALL_CUSTOMER_SERVICE_WORKFLOW_ID:
|
||||
constraints = _tmall_customer_service_date_range_constraints(
|
||||
datetime.now(ZoneInfo("Asia/Shanghai")).date()
|
||||
)
|
||||
oldest = date.fromisoformat(constraints["min"])
|
||||
latest = date.fromisoformat(constraints["max"])
|
||||
if business_date < oldest:
|
||||
raise ConsoleRequestError(
|
||||
f"天猫客服最早仅支持 {oldest.isoformat()} 起的数据"
|
||||
)
|
||||
if business_date_end > latest:
|
||||
raise ConsoleRequestError(
|
||||
f"天猫客服结束日期不能晚于 {latest.isoformat()}"
|
||||
)
|
||||
if workflow_id == TMALL_NEGATIVE_REVIEWS_WORKFLOW_ID:
|
||||
latest = datetime.now(ZoneInfo("Asia/Shanghai")).date()
|
||||
if business_date_end is not None and business_date_end > latest:
|
||||
raise ConsoleRequestError("天猫差评结束日期不能晚于今天")
|
||||
execute = payload.get("execute", False)
|
||||
shadow = payload.get("shadow", False)
|
||||
if not isinstance(execute, bool) or not isinstance(shadow, bool):
|
||||
@@ -1984,6 +2243,7 @@ class WorkflowConsoleService:
|
||||
raise ConsoleRequestError("正式执行前必须确认外部影响")
|
||||
video_upload_store: str | None = None
|
||||
tmall_topic_keyword: str | None = None
|
||||
jd_customer_service_store: str | None = None
|
||||
if workflow_id == "product.video_upload":
|
||||
raw_store = payload.get("store", "flagship")
|
||||
if raw_store not in {"flagship", "luggage"}:
|
||||
@@ -1993,6 +2253,19 @@ class WorkflowConsoleService:
|
||||
payload.get("tmall_topic_keyword"),
|
||||
entry,
|
||||
)
|
||||
if workflow_id in JD_DATE_RANGE_WORKFLOW_IDS:
|
||||
raw_store = payload.get("store", "flagship")
|
||||
allowed_store_values = {
|
||||
item["value"] for item in _jd_store_options(workflow_id)
|
||||
}
|
||||
if raw_store not in allowed_store_values:
|
||||
message = (
|
||||
"京东品退店铺参数无效"
|
||||
if workflow_id == JD_AFTER_SALES_ISSUES_WORKFLOW_ID
|
||||
else "京东客服店铺参数无效"
|
||||
)
|
||||
raise ConsoleRequestError(message)
|
||||
jd_customer_service_store = str(raw_store)
|
||||
tmall_baibu_import_mode: str | None = None
|
||||
if workflow_id == TMALL_BAIBU_WORKFLOW_ID:
|
||||
raw_import_mode = payload.get(
|
||||
@@ -2030,6 +2303,10 @@ class WorkflowConsoleService:
|
||||
}
|
||||
if tmall_baibu_import_mode is not None:
|
||||
launch_kwargs["tmall_baibu_import_mode"] = tmall_baibu_import_mode
|
||||
if jd_customer_service_store is not None:
|
||||
launch_kwargs["jd_customer_service_store"] = jd_customer_service_store
|
||||
if business_date_end is not None and business_date_end != business_date:
|
||||
launch_kwargs["business_date_end"] = business_date_end
|
||||
return self.launcher.launch(
|
||||
workflow_id,
|
||||
business_date,
|
||||
|
||||
Reference in new issue
Block a user