Jelajahi Sumber

perf(birthday): 缓存工作台数据并校准赠礼统计

- 按门店和日期缓存生日工作台汇总,Redis 异常时回退实时计算
- 修改生日后清理缓存,并明确年度赠礼记录的创建更新职责
- 将待领取赠礼归入待处理统计并保留已领取口径
- API: 工作台汇总增加最多 4 小时缓存,赠礼统计调整待领取分类
- Database: 无结构或数据变更
- Breaking Changes: 无
shizhongqi 1 bulan lalu
induk
melakukan
2ff71103b0
1 mengubah file dengan 82 tambahan dan 20 penghapusan
  1. 82 20
      biz-hd/birthday/classes/BirthdayGiftClass.php

+ 82 - 20
biz-hd/birthday/classes/BirthdayGiftClass.php

@@ -32,6 +32,7 @@ class BirthdayGiftClass extends BaseClass
     const STATUS_COLLECTED = 4;      // 4已领取
     const STATUS_EXPIRED = 5;        // 5超时放弃
     const EXPIRE_SECONDS = 86400;    // 通知后24小时内回复有效
+    const WORKBENCH_SUMMARY_CACHE_TTL = 14400;
 
     public static function getStatusMap()
     {
@@ -51,7 +52,7 @@ class BirthdayGiftClass extends BaseClass
     public static function getLevelBenefitMap($mainId, $shopId)
     {
         $shop = ShopClass::getById($shopId, true);
-        $memberLevelSet = $shop->memberLevelSet ?? 0;
+        $memberLevelSet = $shop->memberLevelSet ?? 0; //会员等级 0未设置 1设置了
         if ($memberLevelSet == 1) {
             $list = MemberLevelClass::getAllByCondition(['shopId' => $shopId], 'level ASC', '*', null);
         } else {
@@ -64,6 +65,7 @@ class BirthdayGiftClass extends BaseClass
                 }
             }
         }
+
         $map = [];
         if (!empty($list)) {
             foreach ($list as $row) {
@@ -89,35 +91,43 @@ class BirthdayGiftClass extends BaseClass
 
     public static function hasBirthdayBenefit($custom, $levelMap)
     {
-        $member = intval($custom->member ?? $custom['member'] ?? 0);
+        $member = intval($custom->member ?? 0);
         return $member > 0 && !empty(self::getGiftNameForMember($member, $levelMap));
     }
 
     /**
-     * 当年用于比对的公历月日
+     * 获取生日公历月日数组 [月, 日]
      */
     public static function getBirthdayMonthDay($custom)
     {
-        $birthdayTime = intval($custom->birthdayTime ?? $custom['birthdayTime'] ?? 0);
+        $birthdayTime = intval($custom->birthdayTime ?? 0);
         if ($birthdayTime <= 0) {
             return null;
         }
-        $lunar = intval($custom->lunar ?? $custom['lunar'] ?? 0);
-        $birthday = $custom->birthday ?? $custom['birthday'] ?? '';
+        $lunar = $custom->lunar;
+        $birthday = $custom->birthday;
         if ($lunar == 1 && !empty($birthday) && $birthday != '0000-00-00 00:00:00') {
             $ts = strtotime($birthday);
             if ($ts > 0) {
                 return [intval(date('n', $ts)), intval(date('j', $ts))];
             }
         }
-        $m = intval($custom->birthdayMonth ?? $custom['birthdayMonth'] ?? 0);
-        $d = intval($custom->birthdayDate ?? $custom['birthdayDate'] ?? 0);
+        $m = intval($custom->birthdayMonth);
+        $d = intval($custom->birthdayDate);
         if ($m > 0 && $d > 0) {
             return [$m, $d];
         }
         return null;
     }
 
+    /**
+     * 转换农历生日为公历月日
+     * @param int $lunar 是否农历 1是 0否
+     * @param int $birthdayMonth 农历月
+     * @param int $birthdayDate 农历日
+     * @param int $year 年份
+     * @return array [公历月, 公历日]
+     */
     public static function convertBirthdayMonthDay($lunar, $birthdayMonth, $birthdayDate, $year = null)
     {
         $birthdayMonth = intval($birthdayMonth);
@@ -258,10 +268,24 @@ class BirthdayGiftClass extends BaseClass
      */
     public static function getWorkbenchSummary($shopId, $mainId)
     {
-        list($customs,) = self::getEligibleCustoms($shopId, $mainId);
+        $cacheKey = self::getWorkbenchSummaryCacheKey($shopId, $mainId);
+        try {
+            $cached = Yii::$app->redis->get($cacheKey);
+            if ($cached !== false && $cached !== null) {
+                $data = json_decode($cached, true);
+                if (is_array($data)) {
+                    return $data;
+                }
+            }
+        } catch (\Throwable $throwable) {
+            Yii::warning('读取生日工作台缓存失败:' . $throwable->getMessage(), __METHOD__);
+        }
+
         $today = 0;
         $tomorrow = 0;
         $week = 0;
+
+        list($customs,) = self::getEligibleCustoms($shopId, $mainId);
         foreach ($customs as $custom) {
             if (self::getBirthdayMonthDay($custom) === null) {
                 continue;
@@ -276,11 +300,40 @@ class BirthdayGiftClass extends BaseClass
                 $week++;
             }
         }
-        return [
+        $data = [
             'today' => $today,
             'tomorrow' => $tomorrow,
             'week' => $week,
         ];
+
+        try {
+            Yii::$app->redis->executeCommand('SETEX', [
+                $cacheKey,
+                self::WORKBENCH_SUMMARY_CACHE_TTL,
+                json_encode($data),
+            ]);
+        } catch (\Throwable $throwable) {
+            Yii::warning('写入生日工作台缓存失败:' . $throwable->getMessage(), __METHOD__);
+        }
+
+        return $data;
+    }
+
+    private static function getWorkbenchSummaryCacheKey($shopId, $mainId)
+    {
+        return 'hd:birthdayGift:workbenchSummary:'
+            . intval($mainId) . ':' . intval($shopId) . ':' . date('Ymd');
+    }
+
+    private static function clearWorkbenchSummaryCache($shopId, $mainId)
+    {
+        try {
+            Yii::$app->redis->executeCommand('DEL', [
+                self::getWorkbenchSummaryCacheKey($shopId, $mainId),
+            ]);
+        } catch (\Throwable $throwable) {
+            Yii::warning('清理生日工作台缓存失败:' . $throwable->getMessage(), __METHOD__);
+        }
     }
 
     public static function generateClaimToken()
@@ -298,7 +351,15 @@ class BirthdayGiftClass extends BaseClass
         ], true);
     }
 
-    public static function getOrCreateYearRecord($shop, $custom, $levelMap)
+    /**
+     * 创建或更新客户今年生日记录(按“门店 + 客户 + 自然年”唯一:一年一条活动记录)
+     * @param $shop
+     * @param $custom
+     * @param $levelMap
+     * @return mixed
+     * @throws IntegrityException
+     */
+    public static function createOrUpdateYearRecord($shop, $custom, $levelMap)
     {
         $year = intval(date('Y'));
         $shopId = intval($shop->id);
@@ -308,7 +369,6 @@ class BirthdayGiftClass extends BaseClass
         $member = intval($custom->member);
         $giftName = self::getGiftNameForMember($member, $levelMap);
         $hd = HdClass::getByCondition(['customId' => $customId, 'shopId' => $shopId], true);
-        $hdId = $hd->id ?? 0;
         $birthdayTime = intval($custom->birthdayTime);
         $status = $birthdayTime > 0 ? self::STATUS_PENDING_NOTIFY : self::STATUS_NO_BIRTHDAY;
         list($birthdayMonth, $birthdayDate) = self::convertBirthdayMonthDay(
@@ -321,7 +381,7 @@ class BirthdayGiftClass extends BaseClass
             'mainId' => $mainId,
             'shopId' => $shopId,
             'customId' => $customId,
-            'hdId' => $hdId,
+            'hdId' => $hd->id ?? 0,
             'userId' => intval($custom->userId),
             'year' => $year,
             'member' => $member,
@@ -369,8 +429,9 @@ class BirthdayGiftClass extends BaseClass
         try {
             $custom = CustomClass::modifyBirthday($customId, $shop->id, $params);
             $levelMap = self::getLevelBenefitMap($shop->mainId, $shop->id);
-            $gift = self::getOrCreateYearRecord($shop, $custom, $levelMap);
+            $gift = self::createOrUpdateYearRecord($shop, $custom, $levelMap);
             $transaction->commit();
+            self::clearWorkbenchSummaryCache($shop->id, $shop->mainId);
             return $gift;
         } catch (\Exception $exception) {
             $transaction->rollBack();
@@ -387,7 +448,7 @@ class BirthdayGiftClass extends BaseClass
     public static function ensureYearRecords($shop)
     {
         $shopId = intval($shop->id);
-        $year = intval(date('Y'));
+        $year = intval(date('Y')); //今年
         list($customs, $levelMap) = self::getEligibleCustoms($shopId, $shop->mainId);
         if (empty($customs)) {
             return true;
@@ -402,12 +463,13 @@ class BirthdayGiftClass extends BaseClass
                 }
             }
         }
+        // 遍历所有符合条件的客户,如果客户已存在当年记录,则跳过,否则创建当年生日记录
         foreach ($customs as $custom) {
             $customId = intval($custom->id);
             if (isset($existingIds[$customId])) {
                 continue;
             }
-            self::getOrCreateYearRecord($shop, $custom, $levelMap);
+            self::createOrUpdateYearRecord($shop, $custom, $levelMap);
             $existingIds[$customId] = 1;
         }
         return true;
@@ -596,9 +658,9 @@ class BirthdayGiftClass extends BaseClass
                     $name = '未配置礼品';
                 }
                 $st = intval($gift->status);
-                if ($st == self::STATUS_PENDING_NOTIFY) {
+                if (in_array($st, [self::STATUS_PENDING_NOTIFY, self::STATUS_PENDING_CLAIM])) {
                     $pending[$name] = ($pending[$name] ?? 0) + 1;
-                } elseif (in_array($st, [self::STATUS_PENDING_CLAIM, self::STATUS_PICKING_UP, self::STATUS_COLLECTED])) {
+                } elseif (in_array($st, [self::STATUS_PICKING_UP, self::STATUS_COLLECTED])) {
                     $collected[$name] = ($collected[$name] ?? 0) + 1;
                 }
             }
@@ -733,7 +795,7 @@ class BirthdayGiftClass extends BaseClass
             if (!self::matchesBirthdayOffset($custom, 1)) {
                 continue;
             }
-            $gift = self::getOrCreateYearRecord($shop, $custom, $levelMap);
+            $gift = self::createOrUpdateYearRecord($shop, $custom, $levelMap);
             if (intval($gift->status) != self::STATUS_PENDING_NOTIFY) {
                 continue;
             }
@@ -823,7 +885,7 @@ class BirthdayGiftClass extends BaseClass
                 'status' => self::STATUS_PENDING_CLAIM,
                 'notifyTime' => $now,
                 'expireTime' => $expire,
-                'smsSent' => 1,
+                'smsSent' => 1, // 更新为接收方已经收到短信
                 'orderSn' => $orderSn,
             ], [
                 'id' => intval($giftId),