' . implode(', ', $mall_ids) . PHP_EOL; foreach ($mall_ids as $mall_id) { echo '开始更新商城的门店优惠券:mall_id => ' . $mall_id . PHP_EOL; $obj = new AddonConfig(); $name = ($obj->info)['name']; // 更新门店优惠券主表 $lock_name_main = 'qimall:update_store_coupon_status:main:mall_id:' . $mall_id; $lock_val_main = md5($lock_name_main); $lock_main = LockHelper::lock($lock_name_main, $lock_val_main, 60); $lock_main && self::updateMainCoupons($mall_id); LockHelper::uLock($lock_name_main, $lock_val_main); // 更新会员已经领取的门店优惠券的状态 $lock_name_user = 'qimall:update_store_coupon_status:user:mall_id:' . $mall_id; $lock_val_user = md5($lock_name_user); $lock_user = LockHelper::lock($lock_name_user, $lock_val_user, 60); $lock_user && self::updateUserCoupons($mall_id); LockHelper::uLock($lock_name_user, $lock_val_user); } echo ' 自动更新门店优惠券状态任务执行完毕 ... ' . PHP_EOL; return ExitCode::OK; } catch (\Exception $e) { LockHelper::uLock($lock_name_main, $lock_val_main); LockHelper::uLock($lock_name_user, $lock_val_user); $errmsg = ' 自动更新门店优惠券状态任务执行出错, errmsg => ' . $e->getMessage() . ', file: ' . $e->getFile() . ', line: ' . $e->getLine(); echo $errmsg . PHP_EOL; \Yii::error($errmsg); \Yii::getLogger()->flush(true); return false; } } /** * 门店优惠券相关统计,定时器调用执行 * */ // 0 */3 * * * * public function actionCouponStatistics() { // \Yii::error('门店优惠券相关统计任务开始执行 ... '); // \Yii::getLogger()->flush(true); try { echo ' 门店优惠券相关统计任务开始执行 ... ' . PHP_EOL; // 获取当前系统所有可用的 mall_id $malls = Mall::getEnableMallList(); $mall_ids = array_column($malls, 'id'); echo ' 获取到的 mall_id => ' . implode(', ', $mall_ids) . PHP_EOL; // foreach ($mall_ids as $mall_id) { $mall_id = 5; echo '开始更新商城的门店优惠券:mall_id => ' . $mall_id . PHP_EOL; $obj = new AddonConfig(); $name = ($obj->info)['name']; $is_install = MallAddons::isInstall($mall_id, $name); // if (!$is_install) continue; $lock_name = 'qimall:coupon_statistics:mall_id:' . $mall_id; $lock_val = md5($lock_name); // $lock = LockHelper::lock($lock_name, $lock_val, 60); // if ($lock) { // 门店优惠券相关数量 self::statNumber($mall_id); // 订单使用相关统计 self::statOrder($mall_id); // 计算门店优惠券使用率 self::calUseProbability($mall_id); // } // LockHelper::uLock($lock_name, $lock_val); // } echo ' 门店优惠券相关统计任务执行完毕' . PHP_EOL; return ExitCode::OK; } catch (\Exception $e) { // LockHelper::uLock($lock_name, $lock_val); $errmsg = $e->getMessage() . ', file: ' . $e->getFile() . ', line: ' . $e->getLine(); \Yii::error($errmsg); \Yii::getLogger()->flush(true); return false; } } /** * 统计商品使用门店优惠券相关数据,定时器调用执行 * */ // 0 */3 * * * * public function actionCouponGoodStat() { // \Yii::error('统计商品使用门店优惠券相关数据任务开始执行 ...'); // \Yii::getLogger()->flush(true); try { echo ' 统计商品使用门店优惠券相关数据任务开始执行 ... ' . PHP_EOL; // 获取当前系统所有可用的 mall_id $malls = Mall::getEnableMallList(); $mall_ids = array_column($malls, 'id'); echo ' 获取到的 mall_id => ' . implode(', ', $mall_ids) . PHP_EOL; foreach ($mall_ids as $mall_id) { echo ' 开始更新商城的门店优惠券:mall_id => ' . $mall_id . PHP_EOL; // $mall_id = 5; $obj = new AddonConfig(); $name = ($obj->info)['name']; $is_install = MallAddons::isInstall($mall_id, $name); if (!$is_install) { echo ' 未安装门店优惠券应用' . PHP_EOL; continue; } $lock_name = 'qimall:coupon_good_stat:mall_id:' . $mall_id; $lock_val = md5($lock_name); $lock = LockHelper::lock($lock_name, $lock_val, 60); if ($lock) { // 统计使用门店优惠券购买商品相关数量 self::statBookNumber($mall_id); } else { echo ' 获取锁失败' . PHP_EOL; } LockHelper::uLock($lock_name, $lock_val); } echo ' 统计商品使用门店优惠券相关数据任务执行完毕' . PHP_EOL; return ExitCode::OK; } catch (\Exception $e) { LockHelper::uLock($lock_name, $lock_val); $errmsg = $e->getMessage() . ', file: ' . $e->getFile() . ', line: ' . $e->getLine(); \Yii::error($errmsg); \Yii::getLogger()->flush(true); return false; } } /** * 门店优惠券过期前提醒,定时器调用执行 */ // 0 0 */4 * * * public function actionExpireRemind() { try { // 获取当前系统所有可用的 mall_id $malls = Mall::getEnableMallList(); $mall_ids = array_column($malls, 'id'); echo ' 获取到的 mall_id => ' . implode(', ', $mall_ids) . PHP_EOL; foreach ($mall_ids as $mall_id) { echo '开始更新商城的门店优惠券:mall_id => ' . $mall_id . PHP_EOL; // $mall_id = 5; $obj = new AddonConfig(); $name = ($obj->info)['name']; $is_install = MallAddons::isInstall($mall_id, $name); if (!$is_install) continue; $page = 1; $limit = 500; do { $offset = ($page - 1) * $limit; $page++; $reminds = AddonsCouponRemind::find() ->where(['mall_id' => $mall_id, 'status' => StatusEnum::ENABLED, 'send_status' => 1]) ->limit($limit) ->offset($offset) ->all(); if (!empty($reminds)) { foreach ($reminds as $remind) { $coupon = AddonsCoupon::findOne(['id' => $remind->coupon_id, 'mall_id' => $mall_id, 'is_remind' => 1]); if (empty($coupon)) continue; $time_node = $remind->remind_days * 86400; if ($time_node > $remind->expire_time) { // 现在到门店优惠券过期的时间小于三天,发消息提醒 $params = [ 'mall_id' => $mall_id, 'user_id' => $remind->user_id, 'first' => '您已经领取的门店优惠券', 'keywords' => [ 'keyword1' => $coupon->name, ], 'remark' => '即将过期,请尽快使用。' ]; // self::sendWechatMessage($params); } // 睡眠 1s,防止腾讯封禁 sleep(1); } } } while ($reminds); } echo ' 发送过期提醒任务执行完毕 ... ' . PHP_EOL; return true; } catch (\Exception $e) { $errmsg = $e->getMessage() . ', file: ' . $e->getFile() . ', line: ' . $e->getLine(); \Yii::error($errmsg); \Yii::getLogger()->flush(true); return false; } } //更新门店优惠券主表中的状态 private static function updateMainCoupons(int $mall_id) { $curr_time = time(); $receiving_ids = []; $finished_receive_ids = []; $page = 1; $limit = 500; do { $offset = ($page - 1) * $limit; $page++; $coupons = StoreCoupon::find() ->where(['mall_id' => $mall_id, 'status' => 1, 'expire_type' => 2]) ->andWhere(['!=', 'coupon_status', 4]) ->limit($limit) ->offset($offset) ->all(); if (!empty($coupons)) { foreach ($coupons as $coupon) { if ($coupon['begin_at'] <= $curr_time && $coupon['end_at'] > $curr_time) { // 门店优惠券领取中 $receiving_ids[] = $coupon['id']; } elseif ($coupon['end_at'] <= $curr_time) { $finished_receive_ids[] = $coupon['id']; } } } } while ($coupons); if (!empty($receiving_ids)) { $res = StoreCoupon::updateAll(['coupon_status' => 2], ['id' => $receiving_ids, 'mall_id' => $mall_id]); if ($res === false) { \Yii::error('更新门店优惠券状态失败:res => ' . var_export($res, true) . ', mall_id => ' . $mall_id . ', receiving_ids => ' . var_export($receiving_ids, true) . ', errmsg => ' . AddonsCoupon::getStaticError()); \Yii::getLogger()->flush(true); } } if (!empty($finished_receive_ids)) { $res = StoreCoupon::updateAll(['coupon_status' => 3], ['id' => $finished_receive_ids, 'mall_id' => $mall_id]); $res_remaind = StoreCouponRemind::updateAll(['send_status' => 3], ['coupon_id' => $finished_receive_ids, 'mall_id' => $mall_id]); $res_uc = StoreCouponUserRelate::updateAll(['coupon_status' => 3], ['coupon_id' => $finished_receive_ids, 'mall_id' => $mall_id]); if ($res === false || $res_remaind === false || $res_uc === false) { \Yii::error('更新门店优惠券状态失败:res => ' . var_export($res, true) . ', res_remaind => ' . var_export($res_remaind, true) . ', res_uc => ' . var_export($res_uc, true) . ', mall_id => ' . $mall_id . ', finished_receive_ids => ' . var_export($finished_receive_ids, true) . ', ac_errmsg => ' . StoreCoupon::getStaticCodeError() . ', cr_errmsg => ' . StoreCouponRemind::getStaticError() . ', cu_errmsg => ' . StoreCouponUserRelate::getStaticError()); \Yii::getLogger()->flush(true); } } } /** * @name: * @msg: 更新会员已经领取的门店优惠券的状态 * @param {int} $mall_id * @return {*} */ private static function updateUserCoupons(int $mall_id) { $time = time(); $page = 1; $limit = 500; do { $offset = ($page - 1) * $limit; $page++; $user_coupons = StoreCouponUserRelate::find() ->where(['mall_id' => $mall_id, 'is_use' => 0, 'status' => 1, 'is_force_failure' => 0, 'coupon_status' => StoreEnum::STATUS_RECEIVING]) ->andWhere(['or', ['is_giving' => 0], ['is_giving' => 1, 'giving_status' => 1]]) ->andWhere(['<=', 'end_time', $time]) ->limit($limit) ->offset($offset) ->all(); if (!empty($user_coupons)) { foreach ($user_coupons as $user_coupon) { $user_coupon->coupon_status = StoreEnum::STATUS_EXPIRED; $user_coupon->updated_at = $time; $res = $user_coupon->save(); if (!$res) { $errmsg = ' 更新门店优惠券状态失败:res => ' . var_export($res, true) . ', mall_id => ' . $mall_id . ', id => ' . $user_coupon->id; echo $errmsg . PHP_EOL; \Yii::error($errmsg); \Yii::getLogger()->flush(true); } } } } while ($user_coupons); } /** * @name: * @msg: 统计商品使用门店优惠券相关数据 * @param {int} $mall_id * @param {string} $type * @param {string} $field * @return {*} */ private static function statBookNumber(int $mall_id) { $stat_datas = $booking_users = $payed_users = $booking_number = []; $page = 1; $limit = 500; do { $offset = ($page - 1) * $limit; $page++; $coupons = StoreCoupon::find()->where(['mall_id' => $mall_id, 'status' => 1])->limit($limit)->offset($offset)->all(); if (!empty($coupons)) { $coupon_ids = array_column($coupons, 'id'); if (empty($coupon_ids)) continue; $coupon_use_log = StoreCouponUseLog::find() ->select('order_id,coupon_id,user_coupon_id') ->where(['mall_id' => $mall_id, 'status' => StatusEnum::ENABLED, 'coupon_id' => $coupon_ids]) ->asArray() ->indexBy('order_id') ->all(); $order_ids = array_column($coupon_use_log, 'order_id'); $orders = StoreOrder::find() ->where(['id' => $order_ids, 'status' => StatusEnum::ENABLED]) ->asArray() ->indexBy('id') ->all(); if (empty($orders)) continue; $order_details = StoreOrderDetail::find() ->where(['mall_id' => $mall_id, 'status' => StatusEnum::ENABLED, 'order_id' => array_column($orders, 'id')]) ->all(); foreach ($order_details as $detail) { $coupon_id = $coupon_use_log[$detail->order_id]['coupon_id'] ?? 0; $key_order_number = $coupon_id . '_' . $detail['goods_id']; // 下单数量 $booking_number[$key_order_number][] = $detail->order_id; // 支付数量 $pay_status = $orders[$detail->order_id]['pay_status'] ?? OrderStatusEnum::NOT_PAY; if ($pay_status == OrderStatusEnum::PAY) $payed_number[$key_order_number][] = $detail->order_id; // 下单总人数 $booking_users[$key_order_number][] = $detail->user_id; // 购买总人数 if ($pay_status == OrderStatusEnum::PAY) $payed_users[$key_order_number][] = $detail->user_id; } } } while ($coupons); if (!empty($booking_number)) { foreach ($booking_number as $key => $order_ids) { $stat_datas[$key]['booking_number'] = count(array_values(array_unique($order_ids))); } } if (!empty($payed_number)) { foreach ($payed_number as $key => $order_ids) { $stat_datas[$key]['payed_number'] = count(array_values(array_unique($order_ids))); } } if (!empty($booking_users)) { foreach ($booking_users as $key => $users) { $stat_datas[$key]['booking_user_number'] = count(array_values(array_unique($users))); } } if (!empty($payed_users)) { foreach ($payed_users as $key => $users) { $stat_datas[$key]['buyed_user_number'] = count(array_values(array_unique($users))); } } if (empty($stat_datas)) { echo ' stat_datas is empty, stat_datas => ' . var_export($stat_datas, true) . PHP_EOL; return; } // self::updateCouponGoodStat($stat_datas, $mall_id); } /** * @name: * @msg: 更新门店优惠券商品统计表 * @param {array} $data * @param {int} $mall_id * @param {*} $field * @return {*} */ private static function updateCouponGoodStat(array $data, int $mall_id) { if (!empty($data)) { foreach ($data as $key => $dv) { $keys = explode('_', $key); $coupon_good_stat = StoreCouponGoodStatistics::findOne(['mall_id' => $mall_id, 'coupon_id' => $keys[0], 'good_id' => $keys[1]]); if (empty($coupon_good_stat)) { $coupon_good_stat = new StoreCouponGoodStatistics(); $data = [ 'mall_id' => $mall_id, 'coupon_id' => $keys[0] ?? 0, 'good_id' => $keys[1] ?? 0, 'created_at' => time(), ]; $coupon_good_stat->attributes = $data; } foreach ($dv as $dk => $val) { $coupon_good_stat->$dk = $val; } $res = $coupon_good_stat->save(); if (!$res) { var_dump($coupon_good_stat->getErrorMessage()); $errmsg = ' 插入/更新已领取数量失败, res => ' . $res . ', data => ' . var_export($data, true); echo $errmsg . PHP_EOL; \Yii::error($errmsg); \Yii::getLogger()->flush(true); } } } } /** * @name: * @msg: 统计数量 * @param {int} $mall_id * @param {array} $conditions * @param {string} $field * @return {*} */ private static function statNumber(int $mall_id) { echo ' 统计相关数量 ... ' . PHP_EOL; $user_coupons = []; $page = 1; $limit = 500; do { $offset = ($page - 1) * $limit; $page++; $use_coupons = StoreCouponUserRelate::find()->where(['mall_id' => $mall_id, 'status' => 1,'from_type'=>2])->limit($limit)->offset($offset)->all(); if (!empty($use_coupons)) { foreach ($use_coupons as $key => $use_coupon) { $coupon_id = $use_coupon->coupon_id; // 统计已领取数量 if (!isset($user_coupons[$coupon_id]['received_number'])) $user_coupons[$coupon_id]['received_number'] = 0; $user_coupons[$coupon_id]['received_number'] += 1; $user_coupons[$coupon_id]['store_id'] = $use_coupon['store_id']; // 统计已使用数量 if (!isset($user_coupons[$coupon_id]['used_number'])) $user_coupons[$coupon_id]['used_number'] = 0; $use_coupon->is_use == 1 && $user_coupons[$coupon_id]['used_number'] += 1; // 统计门店优惠券被转赠的次数 if (!isset($user_coupons[$coupon_id]['giveing_times'])) $user_coupons[$coupon_id]['giveing_times'] = 0; $use_coupon->is_giving == 1 && $user_coupons[$coupon_id]['giveing_times'] += 1; // 记录领取会员id $received_user_ids[$coupon_id][] = $use_coupon->user_id; // 记录使用会员id $use_coupon->is_use == 1 && $used_user_ids[$coupon_id][] = $use_coupon->user_id; // 记录转赠门店优惠券的会员id $use_coupon->is_giving == 1 && $giving_user_ids[$coupon_id][] = $use_coupon->user_id; } } } while ($use_coupons); // 统计领取会员数量 if (!empty($received_user_ids)) { foreach ($received_user_ids as $coupon_id => $user_ids) { $counts = count(array_flip(array_flip($user_ids))); $user_coupons[$coupon_id]['receive_user_number'] = $counts; } } // 统计用券会员数量 if (!empty($used_user_ids)) { foreach ($used_user_ids as $coupon_id => $user_ids) { $counts = count(array_flip(array_flip($user_ids))); $user_coupons[$coupon_id]['use_user_number'] = $counts; } } // 统计转赠门店优惠券的会员数量 if (!empty($giving_user_ids)) { foreach ($giving_user_ids as $coupon_id => $user_ids) { $counts = count(array_flip(array_flip($user_ids))); $user_coupons[$coupon_id]['giving_user_number'] = $counts; } } !empty($user_coupons) && self::updateCouponStat($user_coupons, $mall_id); echo ' 统计相关数量完成 ... ' . PHP_EOL; } /** * @name: * @msg: 更新 jxmall_coupon_statistics 表数据 * @param {array} $data 统计得到的结果 * @param {int} $mall_id * @param {string} $field 更新字段名 * @return {*} */ private static function updateCouponStat(array $data, int $mall_id) { if (!empty($data)) { foreach ($data as $coupon_id => $dv) { $coupon_stat = StoreCouponStatistics::findOne(['mall_id' => $mall_id, 'coupon_id' => $coupon_id]); if (empty($coupon_stat)) { $coupon_stat = new StoreCouponStatistics(); $data = [ 'mall_id' => $mall_id, 'coupon_id' => $coupon_id, 'store_id' => $dv['store_id'], 'created_at' => time() ]; $coupon_stat->attributes = $data; } foreach ($dv as $key => $value) { $coupon_stat->$key = $value; } // var_dump($coupon_stat); $res = $coupon_stat->save(); if (!$res) { $errmsg = ' 插入/更新已领取数量失败, res => ' . $res . ', data => ' . var_export($data, true); echo $errmsg . PHP_EOL; \Yii::error($errmsg); \Yii::getLogger()->flush(true); } } } } /** * @name: * @msg: 计算门店优惠券使用率 * @param {int} $mall_id * @return {*} */ private static function calUseProbability(int $mall_id) { $page = 1; $limit = 500; do { $offset = ($page - 1) * $limit; $page++; $coupon_stats = StoreCouponStatistics::find()->where(['mall_id' => $mall_id])->limit($limit)->offset($offset)->all(); if (!empty($coupon_stats)) { foreach ($coupon_stats as $coupon_stat) { if (empty($coupon_stat->received_number)) continue; $coupon_stat->use_probability = bcdiv($coupon_stat->used_number, $coupon_stat->received_number, 2); $res = $coupon_stat->save(); if (!$res) { $errmsg = ' 计算&更新门店优惠券使用率出错:res => ' . var_export($res, true) . ', errmsg => ' . $coupon_stat->getErrorMessage() . ', mall_id => ' . $mall_id . ', coupon_id => ' . $coupon_stat->coupon_id; echo $errmsg . PHP_EOL; \Yii::error($errmsg); \Yii::getLogger()->flush(true); } } } } while ($coupon_stats); } // private static function sendWechatMessage(array $params) // { // $wechat = new WechatTemplate($params['mall_id']); // //商城是否开启推送模板消息 // if ($wechat->is_logging() === false) { // return; // } // //用户是否开启模板消息 // if ($wechat->is_notice($params['user_id']) === false) { // return; // } // //是否公众号用户 // if ($wechat->is_platform_wechat($params['user_id']) === false) { // return; // } // $platform = $wechat->getPlatForm(); // // $h5_domain = \Yii::$app->services->setting->mall->get($params['mall_id'], 'basic.web_url'); // if (empty($h5_domain)) { // $h5_domain = \Yii::$app->request->hostInfo; // } else { // $h5_domain = substr($h5_domain, 0, strpos($h5_domain, '?')); // } // $url = 'pages/user/coupon/coupon'; // $h5_url = $h5_domain . $url; // $send_data = [ // 'first' => $params['first'], // 'remark' => $params['remark'], // ]; // if (!empty($params['keywords'])) { // foreach ($params['keywords'] as $key => $val) { // $send_data[$key] = $val; // } // } // $temp_key = WechatTemplate::ORDER_CREATE; // $wechat->sendTemplate($params['user_id'], $temp_key, $h5_url, $send_data, $platform, $url); // } }