|
|
@@ -0,0 +1,712 @@
|
|
|
+<?php
|
|
|
+
|
|
|
+namespace bizHd\birthday\classes;
|
|
|
+
|
|
|
+use biz\sj\classes\SjClass;
|
|
|
+use bizHd\custom\classes\CustomClass;
|
|
|
+use bizHd\custom\classes\HdClass;
|
|
|
+use bizHd\member\classes\MemberLevelClass;
|
|
|
+use bizHd\shop\classes\ShopClass;
|
|
|
+use bizHd\shop\classes\ShopExtClass;
|
|
|
+use bizMall\wx\classes\WxMiniClass;
|
|
|
+use common\components\orderSn;
|
|
|
+use common\components\printUtil;
|
|
|
+use common\components\sms;
|
|
|
+use common\components\stringUtil;
|
|
|
+use common\components\util;
|
|
|
+use PhpAmqpLib\Wire\AMQPTable;
|
|
|
+use Yii;
|
|
|
+use bizHd\base\classes\BaseClass;
|
|
|
+
|
|
|
+class BirthdayGiftClass extends BaseClass
|
|
|
+{
|
|
|
+ public static $baseFile = '\bizHd\birthday\models\BirthdayGift';
|
|
|
+
|
|
|
+ const STATUS_NO_BIRTHDAY = 0;
|
|
|
+ const STATUS_PENDING_NOTIFY = 1;
|
|
|
+ const STATUS_PENDING_CLAIM = 2;
|
|
|
+ const STATUS_COLLECTED = 3;
|
|
|
+ const STATUS_EXPIRED = 4;
|
|
|
+
|
|
|
+ const EXPIRE_SECONDS = 86400;
|
|
|
+
|
|
|
+ public static function getStatusMap()
|
|
|
+ {
|
|
|
+ return [
|
|
|
+ self::STATUS_NO_BIRTHDAY => '未填写',
|
|
|
+ self::STATUS_PENDING_NOTIFY => '待通知',
|
|
|
+ self::STATUS_PENDING_CLAIM => '待领取',
|
|
|
+ self::STATUS_COLLECTED => '已领取',
|
|
|
+ self::STATUS_EXPIRED => '超时放弃',
|
|
|
+ ];
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 等级 -> 生日权益配置
|
|
|
+ */
|
|
|
+ public static function getLevelBenefitMap($mainId, $shopId)
|
|
|
+ {
|
|
|
+ $shop = ShopClass::getById($shopId, true);
|
|
|
+ $memberLevelSet = $shop->memberLevelSet ?? 0;
|
|
|
+ if ($memberLevelSet == 1) {
|
|
|
+ $list = MemberLevelClass::getAllByCondition(['shopId' => $shopId], 'level ASC', '*', null);
|
|
|
+ } else {
|
|
|
+ $list = MemberLevelClass::getAllByCondition(['mainId' => $mainId], 'level ASC', '*', null);
|
|
|
+ if (empty($list)) {
|
|
|
+ $dict = \common\components\dict::getDict('memberLevelMap');
|
|
|
+ $list = [];
|
|
|
+ foreach ($dict as $row) {
|
|
|
+ $list[] = $row;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ $map = [];
|
|
|
+ if (!empty($list)) {
|
|
|
+ foreach ($list as $row) {
|
|
|
+ $level = intval($row['level'] ?? $row->level ?? 0);
|
|
|
+ $map[$level] = [
|
|
|
+ 'name' => $row['name'] ?? $row->name ?? '',
|
|
|
+ 'birthdayBenefit' => trim($row['birthdayBenefit'] ?? $row->birthdayBenefit ?? ''),
|
|
|
+ 'discount' => $row['discount'] ?? $row->discount ?? 10,
|
|
|
+ ];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return $map;
|
|
|
+ }
|
|
|
+
|
|
|
+ public static function getGiftNameForMember($member, $levelMap)
|
|
|
+ {
|
|
|
+ $member = intval($member);
|
|
|
+ if ($member <= 0 || empty($levelMap[$member])) {
|
|
|
+ return '';
|
|
|
+ }
|
|
|
+ return trim($levelMap[$member]['birthdayBenefit'] ?? '');
|
|
|
+ }
|
|
|
+
|
|
|
+ public static function hasBirthdayBenefit($custom, $levelMap)
|
|
|
+ {
|
|
|
+ $member = intval($custom->member ?? $custom['member'] ?? 0);
|
|
|
+ return $member > 0 && !empty(self::getGiftNameForMember($member, $levelMap));
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 当年用于比对的公历月日
|
|
|
+ */
|
|
|
+ public static function getBirthdayMonthDay($custom)
|
|
|
+ {
|
|
|
+ $birthdayTime = intval($custom->birthdayTime ?? $custom['birthdayTime'] ?? 0);
|
|
|
+ if ($birthdayTime <= 0) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ $lunar = intval($custom->lunar ?? $custom['lunar'] ?? 0);
|
|
|
+ $birthday = $custom->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);
|
|
|
+ if ($m > 0 && $d > 0) {
|
|
|
+ return [$m, $d];
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ public static function formatBirthdayDisplay($custom)
|
|
|
+ {
|
|
|
+ $m = intval($custom->birthdayMonth ?? 0);
|
|
|
+ $d = intval($custom->birthdayDate ?? 0);
|
|
|
+ if ($m <= 0 || $d <= 0) {
|
|
|
+ return '';
|
|
|
+ }
|
|
|
+ $prefix = intval($custom->lunar ?? 0) == 1 ? '农历 ' : '';
|
|
|
+ return $prefix . $m . '月' . $d . '日';
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @param int $offsetDays 0今天 1明天
|
|
|
+ */
|
|
|
+ public static function matchesBirthdayOffset($custom, $offsetDays)
|
|
|
+ {
|
|
|
+ $md = self::getBirthdayMonthDay($custom);
|
|
|
+ if (empty($md)) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ $target = strtotime('+' . intval($offsetDays) . ' days');
|
|
|
+ return intval(date('n', $target)) == $md[0] && intval(date('j', $target)) == $md[1];
|
|
|
+ }
|
|
|
+
|
|
|
+ public static function matchesBirthdayWeek($custom)
|
|
|
+ {
|
|
|
+ $md = self::getBirthdayMonthDay($custom);
|
|
|
+ if (empty($md)) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ for ($i = 0; $i < 7; $i++) {
|
|
|
+ $target = strtotime('+' . $i . ' days');
|
|
|
+ if (intval(date('n', $target)) == $md[0] && intval(date('j', $target)) == $md[1]) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ public static function matchesPeriod($custom, $period)
|
|
|
+ {
|
|
|
+ $period = $period ?: 'week';
|
|
|
+ if ($period == 'today') {
|
|
|
+ return self::matchesBirthdayOffset($custom, 0);
|
|
|
+ }
|
|
|
+ if ($period == 'tomorrow') {
|
|
|
+ return self::matchesBirthdayOffset($custom, 1);
|
|
|
+ }
|
|
|
+ return self::matchesBirthdayWeek($custom);
|
|
|
+ }
|
|
|
+
|
|
|
+ public static function getEligibleCustoms($shopId, $mainId)
|
|
|
+ {
|
|
|
+ $levelMap = self::getLevelBenefitMap($mainId, $shopId);
|
|
|
+ $list = CustomClass::getAllByCondition([
|
|
|
+ 'shopId' => $shopId,
|
|
|
+ 'member>' => 0,
|
|
|
+ 'delStatus' => 0,
|
|
|
+ ], 'id ASC', '*', null, true);
|
|
|
+ $result = [];
|
|
|
+ if (!empty($list)) {
|
|
|
+ foreach ($list as $custom) {
|
|
|
+ if (self::hasBirthdayBenefit($custom, $levelMap)) {
|
|
|
+ $result[] = $custom;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return [$result, $levelMap];
|
|
|
+ }
|
|
|
+
|
|
|
+ public static function getWorkbenchSummary($shopId, $mainId)
|
|
|
+ {
|
|
|
+ list($customs,) = self::getEligibleCustoms($shopId, $mainId);
|
|
|
+ $today = 0;
|
|
|
+ $tomorrow = 0;
|
|
|
+ $week = 0;
|
|
|
+ foreach ($customs as $custom) {
|
|
|
+ if (self::getBirthdayMonthDay($custom) === null) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ if (self::matchesBirthdayOffset($custom, 0)) {
|
|
|
+ $today++;
|
|
|
+ }
|
|
|
+ if (self::matchesBirthdayOffset($custom, 1)) {
|
|
|
+ $tomorrow++;
|
|
|
+ }
|
|
|
+ if (self::matchesBirthdayWeek($custom)) {
|
|
|
+ $week++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return [
|
|
|
+ 'today' => $today,
|
|
|
+ 'tomorrow' => $tomorrow,
|
|
|
+ 'week' => $week,
|
|
|
+ ];
|
|
|
+ }
|
|
|
+
|
|
|
+ public static function generateClaimToken()
|
|
|
+ {
|
|
|
+ return md5(uniqid('bg', true) . mt_rand(1000, 9999) . microtime(true));
|
|
|
+ }
|
|
|
+
|
|
|
+ public static function getOrCreateYearRecord($shop, $custom, $levelMap)
|
|
|
+ {
|
|
|
+ $year = intval(date('Y'));
|
|
|
+ $shopId = $shop->id;
|
|
|
+ $mainId = $shop->mainId;
|
|
|
+ $customId = $custom->id;
|
|
|
+ $gift = self::getByCondition(['shopId' => $shopId, 'customId' => $customId, 'year' => $year], true);
|
|
|
+ $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;
|
|
|
+ $data = [
|
|
|
+ 'mainId' => $mainId,
|
|
|
+ 'shopId' => $shopId,
|
|
|
+ 'customId' => $customId,
|
|
|
+ 'hdId' => $hdId,
|
|
|
+ 'userId' => intval($custom->userId),
|
|
|
+ 'year' => $year,
|
|
|
+ 'member' => $member,
|
|
|
+ 'memberName' => $custom->memberName ?? '',
|
|
|
+ 'giftName' => $giftName,
|
|
|
+ 'birthdayMonth' => intval($custom->birthdayMonth),
|
|
|
+ 'birthdayDate' => intval($custom->birthdayDate),
|
|
|
+ 'lunar' => intval($custom->lunar),
|
|
|
+ 'birthdayDisplay' => self::formatBirthdayDisplay($custom),
|
|
|
+ ];
|
|
|
+ if (empty($gift)) {
|
|
|
+ $data['status'] = $status;
|
|
|
+ $data['claimToken'] = self::generateClaimToken();
|
|
|
+ $gift = self::add($data, true);
|
|
|
+ } else {
|
|
|
+ if (intval($gift->status) < self::STATUS_PENDING_CLAIM) {
|
|
|
+ $gift->status = $status;
|
|
|
+ }
|
|
|
+ foreach (['member', 'memberName', 'giftName', 'birthdayMonth', 'birthdayDate', 'lunar', 'birthdayDisplay', 'hdId', 'userId'] as $f) {
|
|
|
+ if (isset($data[$f])) {
|
|
|
+ $gift->$f = $data[$f];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (empty($gift->claimToken)) {
|
|
|
+ $gift->claimToken = self::generateClaimToken();
|
|
|
+ }
|
|
|
+ $gift->save();
|
|
|
+ }
|
|
|
+ return $gift;
|
|
|
+ }
|
|
|
+
|
|
|
+ public static function ensureYearRecords($shop)
|
|
|
+ {
|
|
|
+ list($customs, $levelMap) = self::getEligibleCustoms($shop->id, $shop->mainId);
|
|
|
+ foreach ($customs as $custom) {
|
|
|
+ self::getOrCreateYearRecord($shop, $custom, $levelMap);
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ public static function buildBoardItem($gift, $custom)
|
|
|
+ {
|
|
|
+ $status = intval($gift->status);
|
|
|
+ $statusMap = self::getStatusMap();
|
|
|
+ $mobile = $custom->mobile ?? '';
|
|
|
+ $tail = strlen($mobile) >= 4 ? substr($mobile, -4) : '';
|
|
|
+ return [
|
|
|
+ 'id' => intval($gift->id),
|
|
|
+ 'customId' => intval($gift->customId),
|
|
|
+ 'name' => $custom->name ?? '',
|
|
|
+ 'mobile' => $mobile,
|
|
|
+ 'mobileTail' => $tail,
|
|
|
+ 'avatar' => CustomClass::groupBaseInfo([['avatar' => $custom->avatar ?? '']])[0]['smallAvatar'] ?? '',
|
|
|
+ 'member' => intval($gift->member),
|
|
|
+ 'memberName' => $gift->memberName,
|
|
|
+ 'giftName' => $gift->giftName,
|
|
|
+ 'birthdayDisplay' => $gift->birthdayDisplay,
|
|
|
+ 'status' => $status,
|
|
|
+ 'statusName' => $statusMap[$status] ?? '',
|
|
|
+ 'pickupTime' => $gift->pickupTime ?? '',
|
|
|
+ 'collectTime' => $gift->collectTime ?? '',
|
|
|
+ 'notifyTime' => $gift->notifyTime ?? '',
|
|
|
+ 'expireTime' => $gift->expireTime ?? '',
|
|
|
+ ];
|
|
|
+ }
|
|
|
+
|
|
|
+ public static function getBoardList($shop, $params)
|
|
|
+ {
|
|
|
+ self::ensureYearRecords($shop);
|
|
|
+ $period = $params['period'] ?? 'week';
|
|
|
+ $statusFilter = isset($params['status']) ? intval($params['status']) : -1;
|
|
|
+ $searchText = trim($params['searchText'] ?? $params['keyword'] ?? '');
|
|
|
+ $page = max(1, intval($params['page'] ?? 1));
|
|
|
+ $pageSize = max(1, min(50, intval($params['pageSize'] ?? 20)));
|
|
|
+
|
|
|
+ list($customs, $levelMap) = self::getEligibleCustoms($shop->id, $shop->mainId);
|
|
|
+ $customMap = [];
|
|
|
+ foreach ($customs as $c) {
|
|
|
+ $customMap[$c->id] = $c;
|
|
|
+ }
|
|
|
+
|
|
|
+ $year = intval(date('Y'));
|
|
|
+ $gifts = self::getAllByCondition(['shopId' => $shop->id, 'year' => $year], 'id DESC', '*', null, true);
|
|
|
+ $rows = [];
|
|
|
+ if (!empty($gifts)) {
|
|
|
+ foreach ($gifts as $gift) {
|
|
|
+ $customId = intval($gift->customId);
|
|
|
+ if (empty($customMap[$customId])) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ $custom = $customMap[$customId];
|
|
|
+ if ($statusFilter >= 0 && intval($gift->status) != $statusFilter) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ if ($statusFilter < 0 && intval($gift->status) == self::STATUS_NO_BIRTHDAY) {
|
|
|
+ // 全部 Tab 也展示未填写
|
|
|
+ }
|
|
|
+ if (intval($gift->status) != self::STATUS_NO_BIRTHDAY && !self::matchesPeriod($custom, $period)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ if (intval($gift->status) == self::STATUS_NO_BIRTHDAY && $period != 'week') {
|
|
|
+ // 未填写仅在较宽范围展示:近一周仍显示
|
|
|
+ if ($period != 'week') {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (!empty($searchText)) {
|
|
|
+ $name = $custom->name ?? '';
|
|
|
+ $mobile = $custom->mobile ?? '';
|
|
|
+ if (strpos($name, $searchText) === false && strpos($mobile, $searchText) === false) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ $rows[] = self::buildBoardItem($gift, $custom);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ $total = count($rows);
|
|
|
+ $offset = ($page - 1) * $pageSize;
|
|
|
+ $list = array_slice($rows, $offset, $pageSize);
|
|
|
+ return [
|
|
|
+ 'list' => $list,
|
|
|
+ 'total' => $total,
|
|
|
+ 'page' => $page,
|
|
|
+ 'pageSize' => $pageSize,
|
|
|
+ 'finished' => ($offset + count($list)) >= $total,
|
|
|
+ ];
|
|
|
+ }
|
|
|
+
|
|
|
+ public static function getStatusCounts($shop, $params)
|
|
|
+ {
|
|
|
+ self::ensureYearRecords($shop);
|
|
|
+ $period = $params['period'] ?? 'week';
|
|
|
+ list($customs,) = self::getEligibleCustoms($shop->id, $shop->mainId);
|
|
|
+ $customMap = [];
|
|
|
+ foreach ($customs as $c) {
|
|
|
+ $customMap[$c->id] = $c;
|
|
|
+ }
|
|
|
+ $counts = [
|
|
|
+ 'all' => 0,
|
|
|
+ 'pendingNotify' => 0,
|
|
|
+ 'pendingClaim' => 0,
|
|
|
+ 'collected' => 0,
|
|
|
+ 'noBirthday' => 0,
|
|
|
+ 'expired' => 0,
|
|
|
+ ];
|
|
|
+ $year = intval(date('Y'));
|
|
|
+ $gifts = self::getAllByCondition(['shopId' => $shop->id, 'year' => $year], null, '*', null, true);
|
|
|
+ if (!empty($gifts)) {
|
|
|
+ foreach ($gifts as $gift) {
|
|
|
+ $customId = intval($gift->customId);
|
|
|
+ if (empty($customMap[$customId])) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ $custom = $customMap[$customId];
|
|
|
+ $st = intval($gift->status);
|
|
|
+ if ($st != self::STATUS_NO_BIRTHDAY && !self::matchesPeriod($custom, $period)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ if ($st == self::STATUS_NO_BIRTHDAY && $period != 'week') {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ $counts['all']++;
|
|
|
+ if ($st == self::STATUS_PENDING_NOTIFY) {
|
|
|
+ $counts['pendingNotify']++;
|
|
|
+ } elseif ($st == self::STATUS_PENDING_CLAIM) {
|
|
|
+ $counts['pendingClaim']++;
|
|
|
+ } elseif ($st == self::STATUS_COLLECTED) {
|
|
|
+ $counts['collected']++;
|
|
|
+ } elseif ($st == self::STATUS_NO_BIRTHDAY) {
|
|
|
+ $counts['noBirthday']++;
|
|
|
+ } elseif ($st == self::STATUS_EXPIRED) {
|
|
|
+ $counts['expired']++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return $counts;
|
|
|
+ }
|
|
|
+
|
|
|
+ public static function getGiftStats($shop, $period)
|
|
|
+ {
|
|
|
+ self::ensureYearRecords($shop);
|
|
|
+ list($customs,) = self::getEligibleCustoms($shop->id, $shop->mainId);
|
|
|
+ $customMap = [];
|
|
|
+ foreach ($customs as $c) {
|
|
|
+ $customMap[$c->id] = $c;
|
|
|
+ }
|
|
|
+ $pending = [];
|
|
|
+ $collected = [];
|
|
|
+ $year = intval(date('Y'));
|
|
|
+ $gifts = self::getAllByCondition(['shopId' => $shop->id, 'year' => $year], null, '*', null, true);
|
|
|
+ if (!empty($gifts)) {
|
|
|
+ foreach ($gifts as $gift) {
|
|
|
+ $customId = intval($gift->customId);
|
|
|
+ if (empty($customMap[$customId])) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ if ($period != 'all' && !self::matchesPeriod($customMap[$customId], $period)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ $name = trim($gift->giftName);
|
|
|
+ if (empty($name)) {
|
|
|
+ $name = '未配置礼品';
|
|
|
+ }
|
|
|
+ $st = intval($gift->status);
|
|
|
+ if ($st == self::STATUS_PENDING_CLAIM) {
|
|
|
+ $pending[$name] = ($pending[$name] ?? 0) + 1;
|
|
|
+ } elseif ($st == self::STATUS_COLLECTED) {
|
|
|
+ $collected[$name] = ($collected[$name] ?? 0) + 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ $fmt = function ($map) {
|
|
|
+ $rows = [];
|
|
|
+ foreach ($map as $name => $num) {
|
|
|
+ $rows[] = ['giftName' => $name, 'num' => $num];
|
|
|
+ }
|
|
|
+ return $rows;
|
|
|
+ };
|
|
|
+ return [
|
|
|
+ 'pending' => $fmt($pending),
|
|
|
+ 'collected' => $fmt($collected),
|
|
|
+ ];
|
|
|
+ }
|
|
|
+
|
|
|
+ public static function getShopDisplayName($shop)
|
|
|
+ {
|
|
|
+ $sjId = $shop->sjId ?? 0;
|
|
|
+ $sj = SjClass::getById($sjId, true);
|
|
|
+ $sjName = $sj->name ?? '';
|
|
|
+ $shopName = $shop->shopName ?? '';
|
|
|
+ return $shopName == '首店' ? $sjName : trim($sjName . ' ' . $shopName);
|
|
|
+ }
|
|
|
+
|
|
|
+ public static function buildShortLink($shopId, $token)
|
|
|
+ {
|
|
|
+ $page = 'pages/member/birthdayGift?account=' . $shopId . '&token=' . urlencode($token);
|
|
|
+ $ret = WxMiniClass::getShortLink($page);
|
|
|
+ return $ret['link'] ?? '';
|
|
|
+ }
|
|
|
+
|
|
|
+ public static function scheduleExpireDelay($giftId, $expireAt)
|
|
|
+ {
|
|
|
+ $giftId = intval($giftId);
|
|
|
+ $expireAt = is_numeric($expireAt) ? intval($expireAt) : strtotime($expireAt);
|
|
|
+ $delayMs = max(1000, ($expireAt - time()) * 1000);
|
|
|
+ $message = serialize([
|
|
|
+ 'type' => 'birthday_gift_expire',
|
|
|
+ 'giftId' => $giftId,
|
|
|
+ ]);
|
|
|
+ $producer = Yii::$app->rabbitmq->getProducer('notifyProducer');
|
|
|
+ $producer->publish($message, 'limitBuyDelayExchange', 'birthdayGiftDelayRoute', [
|
|
|
+ 'delivery_mode' => 2,
|
|
|
+ 'content_type' => 'application/octet-stream',
|
|
|
+ 'application_headers' => new AMQPTable([
|
|
|
+ 'x-delay' => intval($delayMs),
|
|
|
+ ]),
|
|
|
+ ]);
|
|
|
+ Yii::info('birthday gift expire delay: giftId=' . $giftId . ' delayMs=' . $delayMs, __METHOD__);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ public static function expireById($giftId)
|
|
|
+ {
|
|
|
+ $gift = self::getById($giftId, true);
|
|
|
+ if (empty($gift)) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ if (intval($gift->status) != self::STATUS_PENDING_CLAIM) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ $expireTime = $gift->expireTime ?? '';
|
|
|
+ if (!empty($expireTime) && strtotime($expireTime) > time()) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ $gift->status = self::STATUS_EXPIRED;
|
|
|
+ $gift->abandonTime = date('Y-m-d H:i:s');
|
|
|
+ $gift->save();
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ public static function sendNotifySms($shop, $gift, $custom)
|
|
|
+ {
|
|
|
+ $sjId = $shop->sjId ?? 0;
|
|
|
+ $merchant = SjClass::getById($sjId);
|
|
|
+ if (empty($merchant)) {
|
|
|
+ return [false, '商家信息不存在'];
|
|
|
+ }
|
|
|
+ $mobile = $custom->mobile ?? '';
|
|
|
+ if (empty($mobile)) {
|
|
|
+ return [false, '客户无手机号'];
|
|
|
+ }
|
|
|
+ $shopName = self::getShopDisplayName($shop);
|
|
|
+ $giftDesc = $gift->giftName ?: '生日礼品';
|
|
|
+ $shortLink = $gift->shortLink;
|
|
|
+ if (empty($shortLink)) {
|
|
|
+ $shortLink = self::buildShortLink($shop->id, $gift->claimToken);
|
|
|
+ $gift->shortLink = $shortLink;
|
|
|
+ }
|
|
|
+ $msg = "{$shopName}:亲爱的会员您好,明天就是您生日啦!这边有份您的vip生日福利礼包{$giftDesc},请您24小时内点击下方链接免费领取{$shortLink}逾期无效、感谢您的配合!祝您生活愉快!天天开心!";
|
|
|
+ sms::merchantSend($mobile, $msg, $merchant);
|
|
|
+ return [true, ''];
|
|
|
+ }
|
|
|
+
|
|
|
+ public static function batchNotifyTomorrow($shop)
|
|
|
+ {
|
|
|
+ self::ensureYearRecords($shop);
|
|
|
+ list($customs, $levelMap) = self::getEligibleCustoms($shop->id, $shop->mainId);
|
|
|
+ $success = 0;
|
|
|
+ $fail = 0;
|
|
|
+ $messages = [];
|
|
|
+ $year = intval(date('Y'));
|
|
|
+ foreach ($customs as $custom) {
|
|
|
+ if (!self::matchesBirthdayOffset($custom, 1)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ $gift = self::getOrCreateYearRecord($shop, $custom, $levelMap);
|
|
|
+ if (intval($gift->status) != self::STATUS_PENDING_NOTIFY) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ list($ok, $err) = self::sendNotifySms($shop, $gift, $custom);
|
|
|
+ if (!$ok) {
|
|
|
+ $fail++;
|
|
|
+ $messages[] = ($custom->name ?? '') . ':' . $err;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ $now = date('Y-m-d H:i:s');
|
|
|
+ $expire = date('Y-m-d H:i:s', time() + self::EXPIRE_SECONDS);
|
|
|
+ $gift->status = self::STATUS_PENDING_CLAIM;
|
|
|
+ $gift->notifyTime = $now;
|
|
|
+ $gift->expireTime = $expire;
|
|
|
+ $gift->smsSent = 1;
|
|
|
+ if (empty($gift->orderSn)) {
|
|
|
+ $gift->orderSn = 'BG' . date('ymdHis') . mt_rand(1000, 9999);
|
|
|
+ }
|
|
|
+ $gift->save();
|
|
|
+ self::scheduleExpireDelay($gift->id, strtotime($expire));
|
|
|
+ $success++;
|
|
|
+ }
|
|
|
+ return [
|
|
|
+ 'success' => $success,
|
|
|
+ 'fail' => $fail,
|
|
|
+ 'messages' => $messages,
|
|
|
+ ];
|
|
|
+ }
|
|
|
+
|
|
|
+ public static function getInfoByToken($shopId, $token)
|
|
|
+ {
|
|
|
+ $gift = self::getByCondition(['shopId' => $shopId, 'claimToken' => $token], true);
|
|
|
+ if (empty($gift)) {
|
|
|
+ util::fail('链接无效或已失效');
|
|
|
+ }
|
|
|
+ $shop = ShopClass::getById($shopId, true);
|
|
|
+ $custom = CustomClass::getById($gift->customId, true);
|
|
|
+ $status = intval($gift->status);
|
|
|
+ $expired = false;
|
|
|
+ if ($status == self::STATUS_PENDING_CLAIM && !empty($gift->expireTime) && strtotime($gift->expireTime) < time()) {
|
|
|
+ self::expireById($gift->id);
|
|
|
+ $gift = self::getById($gift->id, true);
|
|
|
+ $status = intval($gift->status);
|
|
|
+ $expired = true;
|
|
|
+ }
|
|
|
+ $fullAddress = ($shop->city ?? '') . ($shop->address ?? '') . ($shop->floor ?? '');
|
|
|
+ return [
|
|
|
+ 'giftName' => $gift->giftName,
|
|
|
+ 'status' => $status,
|
|
|
+ 'statusName' => self::getStatusMap()[$status] ?? '',
|
|
|
+ 'pickupTime' => $gift->pickupTime ?? '',
|
|
|
+ 'collectTime' => $gift->collectTime ?? '',
|
|
|
+ 'expireTime' => $gift->expireTime ?? '',
|
|
|
+ 'expired' => $expired || $status == self::STATUS_EXPIRED,
|
|
|
+ 'collected' => $status == self::STATUS_COLLECTED,
|
|
|
+ 'canClaim' => $status == self::STATUS_PENDING_CLAIM,
|
|
|
+ 'shopName' => $shop->shopName ?? '',
|
|
|
+ 'fullAddress' => $fullAddress,
|
|
|
+ 'latitude' => $shop->latitude ?? '',
|
|
|
+ 'longitude' => $shop->longitude ?? '',
|
|
|
+ 'customName' => $custom->name ?? '',
|
|
|
+ ];
|
|
|
+ }
|
|
|
+
|
|
|
+ public static function claimByToken($shopId, $token, $pickupTime)
|
|
|
+ {
|
|
|
+ if (empty($pickupTime)) {
|
|
|
+ util::fail('请选择领取时间');
|
|
|
+ }
|
|
|
+ $gift = self::getByCondition(['shopId' => $shopId, 'claimToken' => $token], true);
|
|
|
+ if (empty($gift)) {
|
|
|
+ util::fail('链接无效');
|
|
|
+ }
|
|
|
+ $status = intval($gift->status);
|
|
|
+ if ($status == self::STATUS_COLLECTED) {
|
|
|
+ util::fail('已领取,请勿重复操作');
|
|
|
+ }
|
|
|
+ if ($status == self::STATUS_EXPIRED) {
|
|
|
+ util::fail('领取时间已过,已自动放弃权益');
|
|
|
+ }
|
|
|
+ if ($status != self::STATUS_PENDING_CLAIM) {
|
|
|
+ util::fail('当前状态不可领取');
|
|
|
+ }
|
|
|
+ if (!empty($gift->expireTime) && strtotime($gift->expireTime) < time()) {
|
|
|
+ self::expireById($gift->id);
|
|
|
+ util::fail('领取时间已过,已自动放弃权益');
|
|
|
+ }
|
|
|
+ $gift->pickupTime = $pickupTime;
|
|
|
+ $gift->collectTime = date('Y-m-d H:i:s');
|
|
|
+ $gift->status = self::STATUS_COLLECTED;
|
|
|
+ $gift->save();
|
|
|
+ self::printReceipt($gift);
|
|
|
+ return $gift;
|
|
|
+ }
|
|
|
+
|
|
|
+ public static function buildPrintContent($gift, $shop, $custom)
|
|
|
+ {
|
|
|
+ $shopName = self::getShopDisplayName($shop);
|
|
|
+ $pickup = $gift->pickupTime ?? '';
|
|
|
+ $pickupShort = $pickup ? date('m-d H:i', strtotime($pickup)) : '';
|
|
|
+ $mobile = $custom->mobile ?? '';
|
|
|
+ $tail = strlen($mobile) >= 4 ? substr($mobile, -4) : '';
|
|
|
+ $name = $custom->name ?? '';
|
|
|
+ $balance = floatval($custom->balance ?? 0);
|
|
|
+ $content = '<CB>生日赠礼订单</CB><BR>';
|
|
|
+ $content .= '<BR>';
|
|
|
+ if ($pickupShort) {
|
|
|
+ $content .= $pickupShort . ' 到店自取<BR>';
|
|
|
+ }
|
|
|
+ $content .= '<BR>';
|
|
|
+ $content .= '取花人:<BR>';
|
|
|
+ $content .= $name . ' 尾号 ' . $tail . '<BR>';
|
|
|
+ $content .= $mobile . '<BR>';
|
|
|
+ $content .= '<BR>';
|
|
|
+ $content .= '生日赠礼<BR>';
|
|
|
+ $content .= '<B>' . ($gift->giftName ?: '精美花束一份') . '</B><BR>';
|
|
|
+ $content .= '--------------------------------<BR>';
|
|
|
+ $content .= '会员等级:' . ($gift->memberName ?: '会员') . '<BR>';
|
|
|
+ $content .= '当前账户余额:' . $balance . ' 元<BR>';
|
|
|
+ $content .= '订单日期:' . ($gift->collectTime ?: date('Y-m-d H:i:s')) . '<BR>';
|
|
|
+ $content .= '订单编号:' . ($gift->orderSn ?: $gift->id) . '<BR>';
|
|
|
+ $content .= '门店名称:' . $shopName . '<BR>';
|
|
|
+ $content .= '<BR>';
|
|
|
+ return $content;
|
|
|
+ }
|
|
|
+
|
|
|
+ public static function printReceipt($gift)
|
|
|
+ {
|
|
|
+ $shopId = $gift->shopId ?? 0;
|
|
|
+ $shop = ShopClass::getById($shopId, true);
|
|
|
+ if (empty($shop)) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ $ext = ShopExtClass::getByCondition(['shopId' => $shopId]);
|
|
|
+ $printSn = $ext['printSn'] ?? '';
|
|
|
+ if (empty($printSn)) {
|
|
|
+ Yii::info('birthday gift print: no printSn shopId=' . $shopId, __METHOD__);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ $custom = CustomClass::getById($gift->customId, true);
|
|
|
+ $content = self::buildPrintContent($gift, $shop, $custom);
|
|
|
+ $p = new printUtil($printSn);
|
|
|
+ $p->printMsg($content);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ public static function manualPrint($shopId, $giftId)
|
|
|
+ {
|
|
|
+ $gift = self::getById($giftId, true);
|
|
|
+ if (empty($gift) || intval($gift->shopId) != intval($shopId)) {
|
|
|
+ util::fail('记录不存在');
|
|
|
+ }
|
|
|
+ if (intval($gift->status) != self::STATUS_COLLECTED) {
|
|
|
+ util::fail('仅已领取记录可打印');
|
|
|
+ }
|
|
|
+ self::printReceipt($gift);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+}
|