# -*- coding: utf-8 -*- """会员ETL任务""" import json from .base_task import BaseTask from loaders.dimensions.member import MemberLoader from models.parsers import TypeParser class MembersTask(BaseTask): """会员ETL任务""" def get_task_code(self) -> str: return "MEMBERS" def execute(self) -> dict: """执行会员ETL""" self.logger.info(f"开始执行 {self.get_task_code()} 任务") params = { "storeId": self.config.get("app.store_id"), } try: records, pages_meta = self.api.get_paginated( endpoint="/MemberProfile/GetTenantMemberList", params=params, page_size=self.config.get("api.page_size", 200), data_path=("data",) ) parsed_records = [] for rec in records: parsed = self._parse_member(rec) if parsed: parsed_records.append(parsed) loader = MemberLoader(self.db) store_id = self.config.get("app.store_id") inserted, updated, skipped = loader.upsert_members(parsed_records, store_id) self.db.commit() counts = { "fetched": len(records), "inserted": inserted, "updated": updated, "skipped": skipped, "errors": 0 } self.logger.info(f"{self.get_task_code()} 完成: {counts}") return self._build_result("SUCCESS", counts) except Exception as e: self.db.rollback() self.logger.error(f"{self.get_task_code()} 失败", exc_info=True) raise def _parse_member(self, raw: dict) -> dict: """解析会员记录""" try: return { "store_id": self.config.get("app.store_id"), "member_id": TypeParser.parse_int(raw.get("memberId")), "member_name": raw.get("memberName"), "phone": raw.get("phone"), "balance": TypeParser.parse_decimal(raw.get("balance")), "status": raw.get("status"), "register_time": TypeParser.parse_timestamp(raw.get("registerTime"), self.tz), "raw_data": json.dumps(raw, ensure_ascii=False) } except Exception as e: self.logger.warning(f"解析会员记录失败: {e}, 原始数据: {raw}") return None