Przeglądaj źródła

支持短信回复领取

shizhongqi 2 miesięcy temu
rodzic
commit
aeaa5658a0

+ 2 - 0
app-hd/controllers/BirthdayGiftController.php

@@ -57,4 +57,6 @@ class BirthdayGiftController extends BaseController
         BirthdayGiftClass::manualPrint($this->shopId, $id);
         util::complete('打印指令已发送');
     }
+
+
 }

+ 10 - 0
app-mall/controllers/BirthdayGiftController.php

@@ -28,6 +28,16 @@ class BirthdayGiftController extends BaseController
         if (empty($post)) {
             $post = Yii::$app->request->get();
         }
+        if (BirthdayGiftClass::isSmsClaimPush($post)) {
+            Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
+            try {
+                BirthdayGiftClass::claimBySmsPush($post);
+                return ['clcode' => '000000'];
+            } catch (\Throwable $e) {
+                Yii::error('birthday gift sms claim failed: ' . $e->getMessage() . ' params=' . json_encode($post, JSON_UNESCAPED_UNICODE), __METHOD__);
+                return ['clcode' => '111111'];
+            }
+        }
         $token = trim($post['token'] ?? '');
         $account = intval($post['account'] ?? 0);
         $pickupTime = trim($post['pickupTime'] ?? '');

+ 156 - 21
biz-hd/birthday/classes/BirthdayGiftClass.php

@@ -506,14 +506,6 @@ class BirthdayGiftClass extends BaseClass
         return $shopName == '首店' ? $sjName : trim($sjName . ' ' . $shopName);
     }
 
-    public static function buildShortLink($shopId, $token)
-    {
-        $page = 'pages/home/recent'; // TODO 测试用
-        //$page = 'pages/member/birthdayGift?account=' . $shopId . '&token=' . urlencode($token); // 正式 TODO
-        $ret = \bizMall\wx\classes\WxMiniClass::getShortLink($page);
-        return $ret['link'] ?? '';
-    }
-
     public static function scheduleExpireDelay($giftId, $expireAt)
     {
         $giftId = intval($giftId);
@@ -567,16 +559,10 @@ class BirthdayGiftClass extends BaseClass
         }
         $shopName = self::getShopDisplayName($shop);
         $giftDesc = $gift->giftName ?: '生日礼品';
-        $shortLink = $gift->shortLink;
-        if (empty($shortLink)) {
-            $shortLink = self::buildShortLink($shop->id, $gift->claimToken);
-            Yii::info("短链地址:" . $shortLink);
-            $gift->shortLink = $shortLink;
-        }
-        $msg = "{$shopName}:亲爱的会员,明天是您生日,这边有份生日福利礼包{$giftDesc},请24小时内点击下方链接领取{$shortLink}。祝您生活愉快!天天开心!";
-        $re = sms::freeSend($mobile, $msg, ['name' => '253云通讯']);
-        if ($re == false) {
-            return [$re, '短信余额不足'];
+        $msg = "{$shopName}:亲爱的会员您好,明天就是您生日啦!为您准备了专属生日礼品:{$giftDesc}。请您回复领取时间,如(5月20日10点),24小时内回复有效。不领取请忽略短信,祝您生活愉快!";
+        $re = sms::freeSend($mobile, $msg, ['name' => '厦门中花汇信息'], $gift->id);
+        if (!$re) {
+            return [false, '短信发送失败'];
         }
         return [$re, ''];
     }
@@ -657,17 +643,166 @@ class BirthdayGiftClass extends BaseClass
         ];
     }
 
-    public static function claimByToken($shopId, $token, $pickupTime)
+    public static function isSmsClaimPush($params)
     {
-        if (empty($pickupTime)) {
-            util::fail('请选择领取时间');
+        return is_array($params) && !empty($params['mobile']) && array_key_exists('msg', $params);
+    }
+
+    public static function claimBySmsPush($params)
+    {
+        $mobile = preg_replace('/\D/', '', trim($params['mobile'] ?? ''));
+        $content = self::normalizeSmsReply($params['msg'] ?? '');
+        if (empty($mobile) || empty($content)) {
+            util::fail('参数错误');
+        }
+        if (self::isGiveUpReply($content)) {
+            Yii::info('birthday gift sms claim ignored give up reply: mobile=' . $mobile . ' content=' . $content, __METHOD__);
+            return true;
+        }
+        $extend = trim($params['extend'] ?? '');
+        $gift = self::findGiftBySmsReply($mobile, $extend);
+        $pickupTime = self::parsePickupTime($content, $params['moTime'] ?? '');
+        return self::claimGift($gift, $pickupTime, false, true);
+    }
+
+    public static function normalizeSmsReply($content)
+    {
+        $content = trim((string)$content);
+        if ($content !== '' && strpos($content, '%') !== false) {
+            $content = urldecode($content);
+        }
+        return trim($content);
+    }
+
+    public static function isGiveUpReply($content)
+    {
+        return preg_match('/不领|不要|不用|放弃|取消|算了/u', $content) === 1;
+    }
+
+    public static function findGiftBySmsReply($mobile, $extend = '')
+    {
+        $gift = null;
+        $giftId = intval($extend);
+        if ($giftId > 0) {
+            $gift = self::getById($giftId, true);
+            if (!empty($gift)) {
+                $custom = CustomClass::getById($gift->customId, true);
+                $customMobile = preg_replace('/\D/', '', trim($custom->mobile ?? ''));
+                if ($customMobile != $mobile) {
+                    util::fail('手机号与领取记录不匹配');
+                }
+                return $gift;
+            }
+        }
+
+        $customs = CustomClass::getAllByCondition([
+            'mobile' => $mobile,
+            'delStatus' => 0,
+        ], null, 'id', null, false);
+        $customIds = [];
+        foreach ($customs as $custom) {
+            $customIds[] = intval($custom['id'] ?? 0);
+        }
+        $customIds = array_filter($customIds);
+        if (empty($customIds)) {
+            util::fail('未找到会员信息');
+        }
+        $gifts = self::getAllByCondition([
+            'customId' => ['in', $customIds],
+            'status' => self::STATUS_PENDING_CLAIM,
+            'smsSent' => 1,
+            'expireTime>=' => date('Y-m-d H:i:s'),
+        ], 'notifyTime DESC,id DESC', '*', null, true);
+        if (empty($gifts)) {
+            util::fail('未找到可领取的生日礼品');
+        }
+        return $gifts[0];
+    }
+
+    public static function parsePickupTime($content, $moTime = '')
+    {
+        $baseTime = self::parseMoTime($moTime);
+        $date = null;
+        $hour = null;
+        $minute = 0;
+        $period = '';
+        $text = preg_replace('/\s+/u', '', $content);
+
+        if (preg_match('/(\d{1,2})月(\d{1,2})(?:日|号)?.*?(上午|中午|下午|晚上|傍晚)?(\d{1,2})(?:[::点时](\d{1,2})?分?)?/u', $text, $match)) {
+            $year = intval(date('Y', $baseTime));
+            $month = intval($match[1]);
+            $day = intval($match[2]);
+            if (!checkdate($month, $day, $year)) {
+                return '';
+            }
+            $date = sprintf('%04d-%02d-%02d', $year, $month, $day);
+            $period = $match[3] ?? '';
+            $hour = intval($match[4]);
+            $minute = intval($match[5] ?? 0);
+        } elseif (preg_match('/(\d{1,2})[-\/.](\d{1,2}).*?(上午|中午|下午|晚上|傍晚)?(\d{1,2})(?:[::点时](\d{1,2})?分?)?/u', $text, $match)) {
+            $year = intval(date('Y', $baseTime));
+            $month = intval($match[1]);
+            $day = intval($match[2]);
+            if (!checkdate($month, $day, $year)) {
+                return '';
+            }
+            $date = sprintf('%04d-%02d-%02d', $year, $month, $day);
+            $period = $match[3] ?? '';
+            $hour = intval($match[4]);
+            $minute = intval($match[5] ?? 0);
+        } elseif (preg_match('/(今天|明天|后天).*?(上午|中午|下午|晚上|傍晚)?(\d{1,2})(?:[::点时](\d{1,2})?分?)?/u', $text, $match)) {
+            $offsetMap = ['今天' => 0, '明天' => 1, '后天' => 2];
+            $date = date('Y-m-d', strtotime('+' . $offsetMap[$match[1]] . ' days', $baseTime));
+            $period = $match[2] ?? '';
+            $hour = intval($match[3]);
+            $minute = intval($match[4] ?? 0);
+        }
+
+        if ($date === null || $hour === null || $hour > 23 || $minute > 59) {
+            return '';
+        }
+        if (in_array($period, ['下午', '晚上', '傍晚']) && $hour < 12) {
+            $hour += 12;
+        } elseif ($period == '中午' && $hour < 11) {
+            $hour += 12;
+        }
+        return $date . sprintf(' %02d:%02d:00', $hour, $minute);
+    }
+
+    public static function parseMoTime($moTime)
+    {
+        $moTime = trim((string)$moTime);
+        if (preg_match('/^\d{10}$/', $moTime)) {
+            $date = \DateTime::createFromFormat('ymdHi', $moTime);
+            if ($date !== false) {
+                return $date->getTimestamp();
+            }
         }
+        return time();
+    }
+
+    public static function claimByToken($shopId, $token, $pickupTime)
+    {
         $gift = self::getByCondition(['shopId' => $shopId, 'claimToken' => $token], true);
         if (empty($gift)) {
             util::fail('链接无效');
         }
+        return self::claimGift($gift, $pickupTime, true, false);
+    }
+
+    public static function claimGift($gift, $pickupTime, $requirePickupTime = true, $idempotent = false)
+    {
+        if (empty($gift)) {
+            util::fail('记录不存在');
+        }
+        if ($requirePickupTime && empty($pickupTime)) {
+            util::fail('请选择领取时间');
+        }
         $status = intval($gift->status);
         if ($status == self::STATUS_COLLECTED) {
+            if ($idempotent) {
+                return $gift;
+            }
             util::fail('已领取,请勿重复操作');
         }
         if ($status == self::STATUS_EXPIRED) {

+ 5 - 1
common/components/ChuanglanSmsApi.php

@@ -53,8 +53,9 @@ class ChuanglanSmsApi {
 	 *
 	 * @param string $msg 			短信内容
 	 * @param string $params 	最多不能超过1000个参数组
+	 * @param string $extend 	上行回复匹配用扩展码
 	 */
-	public function sendVariableSMS( $msg, $params) {
+	public function sendVariableSMS( $msg, $params, $extend = '') {
 		
 		//创蓝接口参数
 		$postArr = array (
@@ -64,6 +65,9 @@ class ChuanglanSmsApi {
 			'params' => $params,
 			'report' => 'true'
         	);
+		if ($extend !== '') {
+			$postArr['extend'] = (string)$extend;
+		}
 
 		$result = $this->curlPost( self::API_VARIABLE_URL, $postArr);
 		return $result;

+ 5 - 2
common/components/sms.php

@@ -53,7 +53,7 @@ class sms
     }
 
     //自由发短,无ip和数量限制 ssh 2019.12.24
-    public static function freeSend($params, $msg, $merchant = null)
+    public static function freeSend($params, $msg, $merchant = null, $extend = '')
     {
         $ptStyle = dict::getDict('ptStyle', 'hd');
         if (isset(Yii::$app->params['ptStyle'])) {
@@ -64,16 +64,19 @@ class sms
         $sign = isset($merchant) == true ? "【{$merchant['name']}】" : "【{$name}】";
         $msg = $sign . $msg;
         $sms = new ChuanglanSmsApi();
-        $result = $sms->sendVariableSMS($msg, $params);
+        $result = $sms->sendVariableSMS($msg, $params, $extend);
         if (!is_null(json_decode($result))) {
             $output = json_decode($result, true);
             if (isset($output['code']) && $output['code'] == '0') {
                 Yii::info("短信发送成功,参数:{$params} 返回:" . $result);
+                return true;
             } else {
                 Yii::info("短信发送失败,参数:{$params} 返回:" . $result);
+                return false;
             }
         } else {
             Yii::info("短信发送失败,参数:{$params} 返回:" . $result);
+            return false;
         }
     }