|
|
@@ -0,0 +1,593 @@
|
|
|
+<?php
|
|
|
+
|
|
|
+namespace bizHd\groupBuy\classes;
|
|
|
+
|
|
|
+use bizHd\base\classes\BaseClass;
|
|
|
+use bizHd\custom\classes\CustomClass;
|
|
|
+use bizHd\order\classes\OrderClass;
|
|
|
+use bizHd\order\classes\OrderGoodsClass;
|
|
|
+use bizHd\refund\classes\HdRefundClass;
|
|
|
+use bizHd\refund\services\HdRefundService;
|
|
|
+use bizHd\shop\classes\ShopClass;
|
|
|
+use common\components\noticeUtil;
|
|
|
+use common\components\util;
|
|
|
+use PhpAmqpLib\Wire\AMQPTable;
|
|
|
+use Yii;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 拼团单核心业务类
|
|
|
+ * 职责:开团/参团校验、支付成功入团计数、到期虚拟成团或失败自动退款
|
|
|
+ * 订单与拼团解耦:订单只记 groupBuyId,人数由 xhGroupBuyMember 维护
|
|
|
+ */
|
|
|
+class GroupBuyClass extends BaseClass
|
|
|
+{
|
|
|
+ public static $baseFile = '\bizHd\groupBuy\models\GroupBuy';
|
|
|
+
|
|
|
+ /** 拼团中 */
|
|
|
+ const STATUS_ONGOING = 1;
|
|
|
+ /** 拼团成功 */
|
|
|
+ const STATUS_SUCCESS = 2;
|
|
|
+ /** 拼团失败 */
|
|
|
+ const STATUS_FAIL = 3;
|
|
|
+ /** 已取消(从未成团,如团长未支付超时) */
|
|
|
+ const STATUS_CANCEL = 4;
|
|
|
+
|
|
|
+ /** 非虚拟成团默认有效期:24 小时 */
|
|
|
+ const DEFAULT_DEADLINE_SECONDS = 86400;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 开团:创建拼团单(currentNum=0),成员与订单由 Controller 在下单后挂接
|
|
|
+ *
|
|
|
+ * @param int $mainId
|
|
|
+ * @param int $shopId
|
|
|
+ * @param int $customId 团长
|
|
|
+ * @param array $activityGoodsRow getActiveGoodsRowById 结果
|
|
|
+ * @return \yii\db\ActiveRecord
|
|
|
+ */
|
|
|
+ public static function createGroup($mainId, $shopId, $customId, $activityGoodsRow)
|
|
|
+ {
|
|
|
+ $mainId = intval($mainId);
|
|
|
+ $shopId = intval($shopId);
|
|
|
+ $customId = intval($customId);
|
|
|
+ if ($mainId <= 0 || $customId <= 0 || empty($activityGoodsRow)) {
|
|
|
+ util::fail('开团参数无效');
|
|
|
+ }
|
|
|
+ $needNum = intval($activityGoodsRow['groupSize'] ?? 0);
|
|
|
+ if (!in_array($needNum, [2, 3, 5], true)) {
|
|
|
+ util::fail('成团人数无效');
|
|
|
+ }
|
|
|
+ $virtualGroup = !empty($activityGoodsRow['virtualGroup']) ? 1 : 0;
|
|
|
+ $virtualMinutes = intval($activityGoodsRow['virtualMinutes'] ?? 0);
|
|
|
+ $now = time();
|
|
|
+ if ($virtualGroup && $virtualMinutes > 0) {
|
|
|
+ $deadline = $now + $virtualMinutes * 60;
|
|
|
+ } else {
|
|
|
+ $deadline = $now + self::DEFAULT_DEADLINE_SECONDS;
|
|
|
+ }
|
|
|
+ // 团截止不得超过活动结束时间
|
|
|
+ $activityEnd = intval($activityGoodsRow['endTime'] ?? 0);
|
|
|
+ if ($activityEnd > 0 && $deadline > $activityEnd) {
|
|
|
+ $deadline = $activityEnd;
|
|
|
+ }
|
|
|
+ if ($deadline <= $now) {
|
|
|
+ util::fail('活动即将结束,无法开团');
|
|
|
+ }
|
|
|
+
|
|
|
+ $group = self::add([
|
|
|
+ 'mainId' => $mainId,
|
|
|
+ 'shopId' => $shopId,
|
|
|
+ 'activityId' => intval($activityGoodsRow['activityId'] ?? 0),
|
|
|
+ 'activityGoodsId' => intval($activityGoodsRow['activityGoodsId'] ?? $activityGoodsRow['id'] ?? 0),
|
|
|
+ 'goodsId' => intval($activityGoodsRow['goodsId'] ?? 0),
|
|
|
+ 'leaderCustomId' => $customId,
|
|
|
+ 'needNum' => $needNum,
|
|
|
+ 'currentNum' => 0,
|
|
|
+ 'price' => floatval($activityGoodsRow['price'] ?? 0),
|
|
|
+ 'status' => self::STATUS_ONGOING,
|
|
|
+ 'virtualGroup' => $virtualGroup,
|
|
|
+ 'deadline' => $deadline,
|
|
|
+ ]);
|
|
|
+ $groupBuyId = intval($group['id']);
|
|
|
+ if ($groupBuyId > 0) {
|
|
|
+ self::scheduleExpireDelay($groupBuyId, $deadline);
|
|
|
+ }
|
|
|
+ return $group;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 参团前校验:团存在、拼团中、未过期、未满、客户未重复加入
|
|
|
+ *
|
|
|
+ * @param int $mainId
|
|
|
+ * @param int $groupBuyId
|
|
|
+ * @param int $customId
|
|
|
+ * @return object 拼团单 AR
|
|
|
+ */
|
|
|
+ public static function assertCanJoin($mainId, $groupBuyId, $customId)
|
|
|
+ {
|
|
|
+ $mainId = intval($mainId);
|
|
|
+ $groupBuyId = intval($groupBuyId);
|
|
|
+ $customId = intval($customId);
|
|
|
+ $group = self::getLockById($groupBuyId);
|
|
|
+ if (empty($group) || intval($group->mainId) !== $mainId) {
|
|
|
+ util::fail('拼团不存在');
|
|
|
+ }
|
|
|
+ if (intval($group->status) !== self::STATUS_ONGOING) {
|
|
|
+ util::fail('该团已结束,无法参团');
|
|
|
+ }
|
|
|
+ if (intval($group->deadline) > 0 && intval($group->deadline) <= time()) {
|
|
|
+ util::fail('该团已到期,无法参团');
|
|
|
+ }
|
|
|
+ if (intval($group->currentNum) >= intval($group->needNum)) {
|
|
|
+ util::fail('该团已满员');
|
|
|
+ }
|
|
|
+ $existMember = GroupBuyMemberClass::getByCondition([
|
|
|
+ 'groupBuyId' => $groupBuyId,
|
|
|
+ 'customId' => $customId,
|
|
|
+ 'status' => ['in', [
|
|
|
+ GroupBuyMemberClass::STATUS_WAIT_PAY,
|
|
|
+ GroupBuyMemberClass::STATUS_PAID,
|
|
|
+ ]],
|
|
|
+ ], true);
|
|
|
+ if (!empty($existMember)) {
|
|
|
+ util::fail('您已在该团中,请勿重复参团');
|
|
|
+ }
|
|
|
+ return $group;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 支付成功钩子:成员置已支付、currentNum+1、判定满团
|
|
|
+ * 由 OrderClass::payAfter 在 groupBuyId>0 时调用
|
|
|
+ *
|
|
|
+ * @param object $order
|
|
|
+ * @return bool
|
|
|
+ */
|
|
|
+ public static function onOrderPaid($order)
|
|
|
+ {
|
|
|
+ if (empty($order)) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ $groupBuyId = intval($order->groupBuyId ?? 0);
|
|
|
+ if ($groupBuyId <= 0) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ $orderId = intval($order->id ?? 0);
|
|
|
+ $customId = intval($order->customId ?? 0);
|
|
|
+ $orderSn = strval($order->orderSn ?? '');
|
|
|
+
|
|
|
+ $group = self::getLockById($groupBuyId);
|
|
|
+ if (empty($group)) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ $member = GroupBuyMemberClass::getByCondition([
|
|
|
+ 'groupBuyId' => $groupBuyId,
|
|
|
+ 'customId' => $customId,
|
|
|
+ ], true);
|
|
|
+ if (empty($member)) {
|
|
|
+ // 兜底:支付成功但成员记录缺失时补建
|
|
|
+ GroupBuyMemberClass::add([
|
|
|
+ 'groupBuyId' => $groupBuyId,
|
|
|
+ 'mainId' => intval($group->mainId),
|
|
|
+ 'orderId' => $orderId,
|
|
|
+ 'orderSn' => $orderSn,
|
|
|
+ 'customId' => $customId,
|
|
|
+ 'role' => intval($group->leaderCustomId) === $customId
|
|
|
+ ? GroupBuyMemberClass::ROLE_LEADER
|
|
|
+ : GroupBuyMemberClass::ROLE_MEMBER,
|
|
|
+ 'status' => GroupBuyMemberClass::STATUS_PAID,
|
|
|
+ 'joinTime' => date('Y-m-d H:i:s'),
|
|
|
+ ]);
|
|
|
+ } else {
|
|
|
+ if (intval($member->status) === GroupBuyMemberClass::STATUS_PAID) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ GroupBuyMemberClass::updateById(intval($member->id), [
|
|
|
+ 'status' => GroupBuyMemberClass::STATUS_PAID,
|
|
|
+ 'orderId' => $orderId,
|
|
|
+ 'orderSn' => $orderSn,
|
|
|
+ 'joinTime' => date('Y-m-d H:i:s'),
|
|
|
+ ]);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 仅拼团中才累加人数;已成功/失败的团不再变更
|
|
|
+ if (intval($group->status) !== self::STATUS_ONGOING) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ $currentNum = intval($group->currentNum) + 1;
|
|
|
+ $needNum = intval($group->needNum);
|
|
|
+ $update = ['currentNum' => $currentNum];
|
|
|
+ if ($currentNum >= $needNum) {
|
|
|
+ $update['status'] = self::STATUS_SUCCESS;
|
|
|
+ $update['successTime'] = date('Y-m-d H:i:s');
|
|
|
+ $update['currentNum'] = $needNum;
|
|
|
+ }
|
|
|
+ self::updateById($groupBuyId, $update);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 订单超时取消时:成员置失效;若团无人支付则取消团
|
|
|
+ *
|
|
|
+ * @param object $order
|
|
|
+ * @return bool
|
|
|
+ */
|
|
|
+ public static function onOrderExpired($order)
|
|
|
+ {
|
|
|
+ if (empty($order)) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ $groupBuyId = intval($order->groupBuyId ?? 0);
|
|
|
+ $customId = intval($order->customId ?? 0);
|
|
|
+ if ($groupBuyId <= 0 || $customId <= 0) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ $member = GroupBuyMemberClass::getByCondition([
|
|
|
+ 'groupBuyId' => $groupBuyId,
|
|
|
+ 'customId' => $customId,
|
|
|
+ ], true);
|
|
|
+ if (!empty($member) && intval($member->status) === GroupBuyMemberClass::STATUS_WAIT_PAY) {
|
|
|
+ GroupBuyMemberClass::updateById(intval($member->id), [
|
|
|
+ 'status' => GroupBuyMemberClass::STATUS_INVALID,
|
|
|
+ ]);
|
|
|
+ }
|
|
|
+ $group = self::getLockById($groupBuyId);
|
|
|
+ if (empty($group) || intval($group->status) !== self::STATUS_ONGOING) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ if (intval($group->currentNum) <= 0) {
|
|
|
+ self::updateById($groupBuyId, [
|
|
|
+ 'status' => self::STATUS_CANCEL,
|
|
|
+ 'failTime' => date('Y-m-d H:i:s'),
|
|
|
+ ]);
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 幂等到期判定:虚拟成团 → 成功;非虚拟 → 失败并批量退款
|
|
|
+ *
|
|
|
+ * @param int $groupBuyId
|
|
|
+ * @return bool
|
|
|
+ */
|
|
|
+ public static function expireById($groupBuyId)
|
|
|
+ {
|
|
|
+ $groupBuyId = intval($groupBuyId);
|
|
|
+ if ($groupBuyId <= 0) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ $connection = Yii::$app->db;
|
|
|
+ $transaction = $connection->beginTransaction();
|
|
|
+ try {
|
|
|
+ $group = self::getLockById($groupBuyId);
|
|
|
+ if (empty($group)) {
|
|
|
+ $transaction->commit();
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ if (intval($group->status) !== self::STATUS_ONGOING) {
|
|
|
+ $transaction->commit();
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ $deadline = intval($group->deadline);
|
|
|
+ if ($deadline > time()) {
|
|
|
+ $transaction->commit();
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ $currentNum = intval($group->currentNum);
|
|
|
+ $needNum = intval($group->needNum);
|
|
|
+ if ($currentNum >= $needNum) {
|
|
|
+ self::updateById($groupBuyId, [
|
|
|
+ 'status' => self::STATUS_SUCCESS,
|
|
|
+ 'successTime' => date('Y-m-d H:i:s'),
|
|
|
+ 'currentNum' => $needNum,
|
|
|
+ ]);
|
|
|
+ $transaction->commit();
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 无人支付:直接取消,无需退款
|
|
|
+ if ($currentNum <= 0) {
|
|
|
+ self::updateById($groupBuyId, [
|
|
|
+ 'status' => self::STATUS_CANCEL,
|
|
|
+ 'failTime' => date('Y-m-d H:i:s'),
|
|
|
+ ]);
|
|
|
+ GroupBuyMemberClass::updateByCondition(
|
|
|
+ [
|
|
|
+ 'groupBuyId' => $groupBuyId,
|
|
|
+ 'status' => GroupBuyMemberClass::STATUS_WAIT_PAY,
|
|
|
+ ],
|
|
|
+ ['status' => GroupBuyMemberClass::STATUS_INVALID]
|
|
|
+ );
|
|
|
+ $transaction->commit();
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!empty($group->virtualGroup)) {
|
|
|
+ // 虚拟成团:不伪造成员,直接判定成功
|
|
|
+ self::updateById($groupBuyId, [
|
|
|
+ 'status' => self::STATUS_SUCCESS,
|
|
|
+ 'successTime' => date('Y-m-d H:i:s'),
|
|
|
+ 'currentNum' => $needNum,
|
|
|
+ ]);
|
|
|
+ $transaction->commit();
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ self::updateById($groupBuyId, [
|
|
|
+ 'status' => self::STATUS_FAIL,
|
|
|
+ 'failTime' => date('Y-m-d H:i:s'),
|
|
|
+ ]);
|
|
|
+ GroupBuyMemberClass::updateByCondition(
|
|
|
+ [
|
|
|
+ 'groupBuyId' => $groupBuyId,
|
|
|
+ 'status' => GroupBuyMemberClass::STATUS_WAIT_PAY,
|
|
|
+ ],
|
|
|
+ ['status' => GroupBuyMemberClass::STATUS_INVALID]
|
|
|
+ );
|
|
|
+ $transaction->commit();
|
|
|
+ } catch (\Exception $e) {
|
|
|
+ $transaction->rollBack();
|
|
|
+ noticeUtil::push('拼团到期判定失败 groupBuyId=' . $groupBuyId . ' ' . $e->getMessage(), '15280215347');
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 退款放在主事务外,单条失败不影响其它成员
|
|
|
+ self::refundPaidMembers($groupBuyId);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 对已支付成员逐单自动退款(复用 HdRefundService::addRefund)
|
|
|
+ *
|
|
|
+ * @param int $groupBuyId
|
|
|
+ * @return bool
|
|
|
+ */
|
|
|
+ public static function refundPaidMembers($groupBuyId)
|
|
|
+ {
|
|
|
+ $groupBuyId = intval($groupBuyId);
|
|
|
+ $members = GroupBuyMemberClass::getAllByCondition([
|
|
|
+ 'groupBuyId' => $groupBuyId,
|
|
|
+ 'status' => GroupBuyMemberClass::STATUS_PAID,
|
|
|
+ ], null, '*', null);
|
|
|
+ if (empty($members)) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ foreach ($members as $member) {
|
|
|
+ $orderId = intval($member['orderId'] ?? 0);
|
|
|
+ if ($orderId <= 0) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ $connection = Yii::$app->db;
|
|
|
+ $transaction = $connection->beginTransaction();
|
|
|
+ try {
|
|
|
+ $order = OrderClass::getLockById($orderId);
|
|
|
+ if (empty($order) || intval($order->payStatus) !== 1) {
|
|
|
+ $transaction->commit();
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ // 已有退款则跳过
|
|
|
+ if (intval($order->refund ?? 0) === OrderClass::REFUND_YES) {
|
|
|
+ $transaction->commit();
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ $shopId = intval($order->shopId);
|
|
|
+ $shop = ShopClass::getById($shopId, true);
|
|
|
+ if (empty($shop)) {
|
|
|
+ util::fail('没有找到门店');
|
|
|
+ }
|
|
|
+ $orderSn = strval($order->orderSn ?? '');
|
|
|
+ $orderGoods = OrderGoodsClass::getAllByCondition(['orderSn' => $orderSn], null, '*', null, true);
|
|
|
+ $productData = [];
|
|
|
+ if (!empty($orderGoods)) {
|
|
|
+ foreach ($orderGoods as $goodsItem) {
|
|
|
+ $productData[] = [
|
|
|
+ 'productId' => $goodsItem->goodsId,
|
|
|
+ 'num' => $goodsItem->num,
|
|
|
+ 'unitPrice' => $goodsItem->unitPrice,
|
|
|
+ 'property' => 0,
|
|
|
+ ];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ $post = [
|
|
|
+ 'price' => $order->actPrice ?? 0,
|
|
|
+ 'refundType' => HdRefundClass::REFUND_TYPE_MONEY_GOOD,
|
|
|
+ 'id' => $orderId,
|
|
|
+ 'shopId' => $shopId,
|
|
|
+ 'sjId' => intval($shop->sjId ?? 0),
|
|
|
+ 'shopAdminId' => 0,
|
|
|
+ 'mainId' => intval($order->mainId ?? 0),
|
|
|
+ 'shopAdminName' => '系统自动退款(拼团失败)',
|
|
|
+ 'product' => $productData,
|
|
|
+ 'remark' => '拼团失败自动退款',
|
|
|
+ ];
|
|
|
+ HdRefundService::addRefund($post, $order);
|
|
|
+ $transaction->commit();
|
|
|
+ } catch (\Exception $e) {
|
|
|
+ $transaction->rollBack();
|
|
|
+ noticeUtil::push(
|
|
|
+ '拼团失败退款异常 groupBuyId=' . $groupBuyId . ' orderId=' . $orderId . ' ' . $e->getMessage(),
|
|
|
+ '15280215347'
|
|
|
+ );
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 投递拼团到期延迟消息(复用 limitBuyDelayExchange)
|
|
|
+ *
|
|
|
+ * @param int $groupBuyId
|
|
|
+ * @param int $deadline unix
|
|
|
+ * @return bool
|
|
|
+ */
|
|
|
+ public static function scheduleExpireDelay($groupBuyId, $deadline)
|
|
|
+ {
|
|
|
+ $groupBuyId = intval($groupBuyId);
|
|
|
+ $deadline = intval($deadline);
|
|
|
+ if ($groupBuyId <= 0 || $deadline <= 0) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ $delayMs = max(1000, ($deadline - time()) * 1000);
|
|
|
+ $message = serialize([
|
|
|
+ 'type' => 'group_buy_expire',
|
|
|
+ 'groupBuyId' => $groupBuyId,
|
|
|
+ ]);
|
|
|
+ $producer = Yii::$app->rabbitmq->getProducer('notifyProducer');
|
|
|
+ $producer->publish($message, 'limitBuyDelayExchange', 'groupBuyDelayRoute', [
|
|
|
+ 'delivery_mode' => 2,
|
|
|
+ 'content_type' => 'application/octet-stream',
|
|
|
+ 'application_headers' => new AMQPTable([
|
|
|
+ 'x-delay' => intval($delayMs),
|
|
|
+ ]),
|
|
|
+ ]);
|
|
|
+ Yii::info('group buy expire delay: groupBuyId=' . $groupBuyId . ' delayMs=' . $delayMs, __METHOD__);
|
|
|
+ } catch (\Exception $e) {
|
|
|
+ // 延迟消息失败不阻断开团,依赖 console 兜底扫描
|
|
|
+ Yii::error('group buy scheduleExpireDelay fail: ' . $e->getMessage(), __METHOD__);
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 团详情(含成员头像)
|
|
|
+ *
|
|
|
+ * @param int $mainId
|
|
|
+ * @param int $groupBuyId
|
|
|
+ * @return array
|
|
|
+ */
|
|
|
+ public static function getDetail($mainId, $groupBuyId)
|
|
|
+ {
|
|
|
+ $mainId = intval($mainId);
|
|
|
+ $groupBuyId = intval($groupBuyId);
|
|
|
+ $group = self::getById($groupBuyId, true);
|
|
|
+ if (empty($group) || intval($group->mainId) !== $mainId) {
|
|
|
+ util::fail('拼团不存在');
|
|
|
+ }
|
|
|
+ $activityGoods = GroupBuyGoodsClass::getById(intval($group->activityGoodsId), true);
|
|
|
+ $members = GroupBuyMemberClass::getAllByCondition([
|
|
|
+ 'groupBuyId' => $groupBuyId,
|
|
|
+ 'status' => GroupBuyMemberClass::STATUS_PAID,
|
|
|
+ ], 'role ASC,id ASC', '*', null);
|
|
|
+ $memberList = [];
|
|
|
+ if (!empty($members)) {
|
|
|
+ $customIds = array_column($members, 'customId');
|
|
|
+ $customs = CustomClass::getCustomByIds($customIds);
|
|
|
+ $customMap = [];
|
|
|
+ if (!empty($customs)) {
|
|
|
+ foreach ($customs as $c) {
|
|
|
+ $customMap[intval($c['id'] ?? 0)] = $c;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ foreach ($members as $m) {
|
|
|
+ $cid = intval($m['customId']);
|
|
|
+ $custom = $customMap[$cid] ?? null;
|
|
|
+ $memberList[] = [
|
|
|
+ 'customId' => $cid,
|
|
|
+ 'role' => intval($m['role']),
|
|
|
+ 'avatar' => is_array($custom)
|
|
|
+ ? ($custom['smallAvatar'] ?? ($custom['avatar'] ?? ''))
|
|
|
+ : '',
|
|
|
+ 'name' => is_array($custom) ? ($custom['name'] ?? '') : '',
|
|
|
+ ];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ $needNum = intval($group->needNum);
|
|
|
+ $currentNum = intval($group->currentNum);
|
|
|
+ $remain = max(0, $needNum - $currentNum);
|
|
|
+ return [
|
|
|
+ 'id' => intval($group->id),
|
|
|
+ 'status' => intval($group->status),
|
|
|
+ 'needNum' => $needNum,
|
|
|
+ 'currentNum' => $currentNum,
|
|
|
+ 'remainNum' => $remain,
|
|
|
+ 'deadline' => intval($group->deadline),
|
|
|
+ 'virtualGroup' => intval($group->virtualGroup),
|
|
|
+ 'price' => floatval($group->price),
|
|
|
+ 'goodsId' => intval($group->goodsId),
|
|
|
+ 'activityGoodsId' => intval($group->activityGoodsId),
|
|
|
+ 'leaderCustomId' => intval($group->leaderCustomId),
|
|
|
+ 'members' => $memberList,
|
|
|
+ 'goods' => [
|
|
|
+ 'goodsId' => intval($group->goodsId),
|
|
|
+ 'name' => $activityGoods ? strval($activityGoods->name) : '',
|
|
|
+ 'cover' => $activityGoods ? strval($activityGoods->cover) : '',
|
|
|
+ 'price' => floatval($group->price),
|
|
|
+ 'originPrice' => $activityGoods ? floatval($activityGoods->originPrice) : 0,
|
|
|
+ 'groupSize' => $needNum,
|
|
|
+ ],
|
|
|
+ ];
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 某商品当前「最快成团」的进行中开放团(还差人数最少,其次即将到期)
|
|
|
+ *
|
|
|
+ * @param int $mainId
|
|
|
+ * @param int $goodsId
|
|
|
+ * @param int $activityGoodsId
|
|
|
+ * @return array|null
|
|
|
+ */
|
|
|
+ public static function getHottestOpenGroup($mainId, $goodsId, $activityGoodsId = 0)
|
|
|
+ {
|
|
|
+ $mainId = intval($mainId);
|
|
|
+ $goodsId = intval($goodsId);
|
|
|
+ $activityGoodsId = intval($activityGoodsId);
|
|
|
+ $condition = [
|
|
|
+ 'mainId' => $mainId,
|
|
|
+ 'goodsId' => $goodsId,
|
|
|
+ 'status' => self::STATUS_ONGOING,
|
|
|
+ 'deadline>' => time(),
|
|
|
+ ];
|
|
|
+ if ($activityGoodsId > 0) {
|
|
|
+ $condition['activityGoodsId'] = $activityGoodsId;
|
|
|
+ }
|
|
|
+ $list = self::getAllByCondition($condition, 'currentNum DESC,deadline ASC', '*', null);
|
|
|
+ if (empty($list)) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ foreach ($list as $row) {
|
|
|
+ if (intval($row['currentNum']) >= intval($row['needNum'])) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ if (intval($row['currentNum']) <= 0) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ return self::getDetail($mainId, intval($row['id']));
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 我的拼团列表
|
|
|
+ *
|
|
|
+ * @param int $mainId
|
|
|
+ * @param int $customId
|
|
|
+ * @return array
|
|
|
+ */
|
|
|
+ public static function getMyList($mainId, $customId)
|
|
|
+ {
|
|
|
+ $mainId = intval($mainId);
|
|
|
+ $customId = intval($customId);
|
|
|
+ $members = GroupBuyMemberClass::getAllByCondition([
|
|
|
+ 'mainId' => $mainId,
|
|
|
+ 'customId' => $customId,
|
|
|
+ 'status' => ['in', [
|
|
|
+ GroupBuyMemberClass::STATUS_WAIT_PAY,
|
|
|
+ GroupBuyMemberClass::STATUS_PAID,
|
|
|
+ ]],
|
|
|
+ ], 'id DESC', '*', null);
|
|
|
+ if (empty($members)) {
|
|
|
+ return [];
|
|
|
+ }
|
|
|
+ $result = [];
|
|
|
+ foreach ($members as $m) {
|
|
|
+ $detail = self::getDetail($mainId, intval($m['groupBuyId']));
|
|
|
+ $detail['myRole'] = intval($m['role']);
|
|
|
+ $detail['myMemberStatus'] = intval($m['status']);
|
|
|
+ $detail['orderId'] = intval($m['orderId']);
|
|
|
+ $detail['orderSn'] = strval($m['orderSn']);
|
|
|
+ $result[] = $detail;
|
|
|
+ }
|
|
|
+ return $result;
|
|
|
+ }
|
|
|
+}
|