uniacid = $u->uniacid; Setting::$uniqueAccountId = $u->uniacid; $this->setLog = Setting::get(self::SET_LOG_NAME);//生成红包记录时间 $set = Setting::get('plugin.red-packet'); $red_packet = $this->getOrder($set); $isCreate = $this->validateCreateRedPacketConditions($set);//验证创建红包条件 if (!$isCreate) { continue; } \Log::info("--每日红包基数--"); $this->getData($red_packet, $set); } } /** * 获取前一天订单(平台,门店,供应商,酒店) */ public function getOrder($set) { $range = [strtotime(date("Y-m-d 00:00:00", strtotime("-1 day"))), strtotime(date("Y-m-d 00:00:00", time()))]; if ($set['is_open_red_packet'] == 1) { if ($set['self_order_after'] == 3) { $price = \Yunshop\RedPacket\common\models\Order::uniacid()->select('price') ->pluginId() ->where('status', $set['self_order_after']) ->whereBetween('finish_time', $range) ->sum('price'); return $price; } else { $price = \Yunshop\RedPacket\common\models\Order::uniacid()->select('price') ->pluginId() ->where('status', '>=', $set['self_order_after']) ->whereBetween('pay_time', $range) ->sum('price'); return $price; } } return ''; } /** * 每日红包参数 */ public function getData($red_packet, $set) { $uniacid = \YunShop::app()->uniacid; if (!$uniacid) { \Log::info('未接入公众号'); return; } if (!empty($red_packet)) { $amount = self::settlement($set); $min_money = 0.01; $mim_amount = $set['number_sum'] * $min_money; if ($amount < $mim_amount) { \Log::info('每日产生红包低于平均人数红包值---', $mim_amount); return; } $data = array( 'uniacid' => \YunShop::app()->uniacid, 'results_amount' => $red_packet, 'amount' => $amount, 'percentage' => $set['proportion'], 'number_sum' => $set['number_sum'], 'receive_amount' => 0, 'receive' => 0, ); $redPacketLogsId = RedPacketLogsModel::create($data)->id; } if (!empty($redPacketLogsId)) { \Log::info('生成随机红包数量',$set); //开启了红包梯度 独一套生成红包方式,领取红包也是独一套领取 if ($set['is_grads']) { $this->redPacketSum($amount, $set['number_sum']);//同时生成原红包,用作领取中途关闭功能,不带红包最高限制 $this->gradsCreateRedPacket($amount, $set['number_sum'],$set['grads']); } else { //开启了红包最高限制 if ($set['is_red_packet_max'] == 1) { $this->redPacketSum2($set['red_packet_max'], $amount, $set['number_sum']); } else { $this->redPacketSum($amount, $set['number_sum']); } } $this->getBonus($amount, $set['number_sum'], $set, $redPacketLogsId);//额外奖励 } } /** * 每日红包结算 * @param $set */ public function settlement($set) { \Log::debug('每日红包统计'); \Log::info('分部结算前一天订单红包池'); $range = [strtotime(date("Y-m-d 00:00:00", strtotime("-1 day"))), strtotime(date("Y-m-d 00:00:00", time()))]; \Log::debug('时间区间:' . json_encode($range)); \Log::debug('结算订单模式:' . $set['self_order_after']); \Log::info('结算订单模式', $set['self_order_after']); //门店订单 $storeOrder = $this->getStoreOrder($set, $range); //收银台订单 $cashierOrder = $this->getCashierOrder($set, $range); //cps订单 $cpsOrder = $this->getCpsOrder($set, $range); //平台,供应商,酒店,拼团订单 if (!$storeOrder->isEmpty()) { $store = $storeOrder->toArray(); \Log::info('今日门店订单', $store); $store_price = ''; foreach ($store as $key => $value) { $setting = StoreSetting::select('value') ->where('store_id', $value['has_one_store_order']['store_id']) ->where('key', 'red_packet') ->first(); $casts = $setting['value']; \Log::info('门店比例', $casts['store_proportion']); \Log::info('门店订单金额', $value['price']); if ($setting) { if ($casts['is_store'] == 1 && $casts['store_proportion'] != 0) { $store_price += $value['price'] * $casts['store_proportion']; } else { $store_price += $value['price'] * $set['proportion']; } } } \Log::debug('门店订单金额:' . $store_price); } if (!$cashierOrder->isEmpty()) { $cashier_price = ''; $cashier = $cashierOrder->toArray(); \Log::info('今日收银台订单', $cashier); foreach ($cashier as $key => $value) { $setting = RedPacketGoodsModel::where('goods_id', $value['has_one_cashier_order']['cashier_id']) ->where('is_cashier', 1) ->first(); \Log::info('收银台比例', $setting['cashier_proportion']); \Log::info('收银台订单金额', $value['price']); if ($setting['is_cashier'] == 1 && $setting['cashier_proportion'] != 0) { $cashier_price += $value['price'] * $setting['cashier_proportion']; } else if ($setting['is_cashier'] == 1 && $setting['cashier_proportion'] == 0) { $cashier_price += $value['price'] * $set['proportion']; } } \Log::debug('收银台订单金额:' . $cashier_price); } if (!$cpsOrder->isEmpty()) { $cps_price = ''; $cps = $cpsOrder->toArray(); foreach ($cps as $key => $value) { $goods = Goods::uniacid()->where('plugin_id', 70)->first(); $setting = RedPacketGoodsModel::where('goods_id', $goods->id) ->where('is_cps', 1) ->first(); if ($setting['is_cps'] == 1 && $setting['cps_proportion'] != 0) { $cps_price += round(($value['price'] * $setting['cps_proportion']) / 100, 2); } else if ($setting['is_cps'] == 1 && $setting['cps_proportion'] == 0) { $cps_price += round(($value['price'] * $set['proportion']) / 100, 2); } } \Log::debug('cps订单金额:' . $cps_price); } // 商城结算金额计算 \Log::debug('红包比例:' . $set['proportion']); // $order = $this->getOrders($set, $range); // $amount = $order * $set['proportion']; $amount = $this->getOrdersV2($set, $range);// 2023-9-13 修改 兼容商品独立计算规则 \Log::debug('(平台,供应商,酒店,拼团)订单统计结果:' . $amount); // 门店余额充值订单 $balancePriceTotal = $this->getBalanceOrderPriceTotal($set, $range); \Log::debug('门店余额充值订单结算金额/100', $balancePriceTotal); //保留两位小数并且不四舍五入 $data = sprintf("%.2f", substr(sprintf("%.3f", (($store_price + $cashier_price + $amount + $cps_price) / 100)), 0, -1)); $data += $balancePriceTotal; \Log::debug('商城结算金额', $amount); \Log::debug('门店结算金额', $store_price); \Log::debug('收银台结算金额', $cashier_price); \Log::debug('cps结算金额', $cps_price); \Log::debug('结算总金额/100', $data); return $data; } /** * @param string $amount * @param string $number_sum * 红包 */ private function redPacketSum($amount = '', $number_sum = '') { $min_money = 0.01; $mim_amount = $number_sum * $min_money; $uniacid = \YunShop::app()->uniacid; if ($amount < $mim_amount) { \Log::debug('每日产生红包低于平均人数红包值'); $red_Packet = storage_path('app/redPacket' . '/' . $uniacid); app(Filesystem::class)->makeDirectory($red_Packet, 0777, 1); $path = $red_Packet . '/redPacket.txt'; $arr_redPacket = ''; file_put_contents($path, $arr_redPacket); } else { if ($amount == '') { $arr_redPacket = ''; } else { for ($i = 1; $i < $number_sum; $i++) { $safe_total = ($amount - ($number_sum - $i) * $min_money) / ($number_sum - $i);//随机安全上限 $money = round((mt_rand($min_money * 100, $safe_total * 100) / 100), 2); $amount = $amount - $money; //红包数据 $readPack[] = [ 'money' => round($money, 2), ]; } //最后一个红包,不用随机 $readPack[] = [ 'money' => round($amount, 2) ]; shuffle($readPack);//乱序 \Log::debug('删除每日红包1'); Redis::del('today_redpacket' . $uniacid); foreach ($readPack as $key => $val) { $redPacket[$key] = $val['money']; Redis::lPush('today_redpacket' . $uniacid, $val['money']); } $arr_redPacket = serialize($redPacket); } \Log::debug('当天红包池额度', $amount); \Log::debug('当天红包数量', $number_sum); \Log::debug('当天红包池', $arr_redPacket); $red_Packet = storage_path('app/redPacket' . '/' . $uniacid); app(Filesystem::class)->makeDirectory($red_Packet, 0777, 1); $path = $red_Packet . '/redPacket.txt'; file_put_contents($path, $arr_redPacket); } } //门店订单 public function getStoreOrder($set, $range) { $storeOrder = \Yunshop\RedPacket\common\models\Order::uniacid() ->select('id', 'uid', 'order_sn', 'created_at', 'price') ->with([ 'hasOneStoreOrder' => function ($q) { return $q->select('id', 'order_id', 'store_id'); } ]); $storeOrder = $this->getStatus($set, $storeOrder, $range); $storeOrder = $storeOrder->where('plugin_id', '32') ->get(); return $storeOrder; } // 门店余额充值订单 public function getBalanceOrderPriceTotal($set, $range) { $priceTotal = 0; if (app('plugins')->isEnabled('store-cashier')) { if ($set['self_order_after'] == 3) { $orderIds = Order::select()->where('status', $set['self_order_after'])->whereBetween('finish_time', $range)->where('plugin_id', 39)->pluck('id'); } else { $orderIds = Order::select()->where('status', '>=', $set['self_order_after'])->whereBetween('pay_time', $range)->where('plugin_id', 39)->pluck('id'); } $balacneOrders = PluginBalanceOrder::with([ 'hasOneShopOrder' ])->whereIn('order_id', $orderIds)->get(); if (!$balacneOrders->isEmpty()) { foreach ($balacneOrders as $balacneOrder) { $setting = RedPacketGoodsModel::where('goods_id', $balacneOrder->balance_id) ->where('is_cashier', 1) ->first(); $itemRes = proportionMath($balacneOrder->hasOneShopOrder->price, $set['proportion']); if ($setting['is_cashier'] == 1 && $setting['cashier_proportion'] != 0) { $itemRes = proportionMath($balacneOrder->hasOneShopOrder->price, $setting['cashier_proportion']); } $priceTotal += $itemRes; } } } return $priceTotal; } //收银台订单 public function getCashierOrder($set, $range) { $cashierOrder = \Yunshop\RedPacket\common\models\Order::uniacid() ->select('id', 'uid', 'order_sn', 'created_at', 'price') ->with([ 'hasOneCashierOrder' => function ($q) { return $q->select('id', 'order_id', 'cashier_id'); } ]); $cashierOrder = $this->getStatus($set, $cashierOrder, $range); $cashierOrder = $cashierOrder->where('plugin_id', '31') ->orderBy('id', 'DESC') ->get(); return $cashierOrder; } //cps订单 public function getCpsOrder($set, $range) { $cpsOrder = \Yunshop\RedPacket\common\models\Order::uniacid() ->select('id', 'uid', 'order_sn', 'created_at', 'price') ->with([ 'hasOneCpsOrder' => function ($q) { return $q->select('id', 'order_id'); } ]); $cpsOrder = $this->getStatus($set, $cpsOrder, $range); $cpsOrder = $cpsOrder->where('plugin_id', '70') ->orderBy('id', 'DESC') ->get(); return $cpsOrder; } //(平台,供应商,酒店,拼团)订单 public function getOrders($set, $range) { $order = \Yunshop\RedPacket\common\models\Order::uniacid() ->select('price'); $order = $this->getStatus($set, $order, $range); $order = $order->whereIn('plugin_id', [0, 33, 92, 54]) ->orderBy('id', 'DESC') ->sum('price'); \Log::debug('(平台,供应商,酒店,拼团)订单统计:' . $order); return $order; } /** * Common: 2023-9-13 修改 兼容商品独立计算规则 * Author: wu-hui * Time: 2023/09/14 10:18 * @param $set * @param $range * @return float|int */ public function getOrdersV2($set, $range){ $order = \Yunshop\RedPacket\common\models\Order::uniacid(); $order = $this->getStatus($set, $order, $range); $orderIds = $order->whereIn('plugin_id', [0, 33, 92, 54])->orderBy('id', 'DESC')->pluck('id')->toArray(); $orderGoodsList = OrderGoods::uniacid() ->with(['redPacketGoods'=>function($query){ $query->select(['goods_id','is_open','scale_all']); }]) ->select(['id','goods_id','payment_amount']) ->whereIn('order_id',$orderIds) ->get() ->toArray(); // 循环处理 获取商城结算金额 (float)$amount = 0; foreach($orderGoodsList as $goodsItem){ if((int)$goodsItem['red_packet_goods']['is_open'] == 1){ $proportion = (float)$goodsItem['red_packet_goods']['scale_all'] > 0 ? (float)$goodsItem['red_packet_goods']['scale_all'] : (float)$set['proportion']; $amount += $goodsItem['payment_amount'] * $proportion; } } return $amount; } //读取订单状态 public function getStatus($set, $order, $range) { if ($set['self_order_after'] == 3) { $order = $order->where('status', $set['self_order_after'])->whereBetween('finish_time', $range); } else { $order = $order->where('status', '>=', $set['self_order_after'])->whereBetween('pay_time', $range); } return $order; } //单独修改红包池 public function handless($uniacid) { date_default_timezone_set('PRC'); $set = Setting::get('plugin.red-packet'); \YunShop::app()->uniacid = $uniacid; Setting::$uniqueAccountId = $uniacid; $red_packet = $this->getOrder($set); if ($set['is_open_red_packet'] == 1) { $this->getData($red_packet, $set); } } /** * @param int $red_packet_max * @param string $amount * @param string $number_sum * 生成红包 封顶规则 */ private function redPacketSum2($red_packet_max, $amount = '', $number_sum = '') { $min_money = 0.01; $mim_amount = $number_sum * $min_money; $uniacid = \YunShop::app()->uniacid; //红包数*上限 > 总红包金额 $maxRedPacket = bcmul($number_sum, $red_packet_max, 2); $max_money = $red_packet_max; if ($maxRedPacket > $amount) { $max_money = bcdiv($amount, $number_sum, 2);//取平均值为上限 } if ($amount < $mim_amount) { \Log::debug('每日产生红包低于平均人数红包值'); $red_Packet = storage_path('app/redPacket' . '/' . $uniacid); app(Filesystem::class)->makeDirectory($red_Packet, 0777, 1); $path = $red_Packet . '/redPacket.txt'; $arr_redPacket = ''; file_put_contents($path, $arr_redPacket); } else { if ($amount == '') { $arr_redPacket = ''; } else { for ($i = 0; $i < $number_sum; $i++) { $safe_total = $max_money; $money = round((mt_rand($min_money * 100, $safe_total * 100) / 100), 2); $amount = $amount - $money; //红包数据 $readPack[] = [ 'money' => round($money, 2), ]; } \Log::debug('删除每日红包2'); Redis::del('today_redpacket' . $uniacid); foreach ($readPack as $key => $val) { $redPacket[$key] = $val['money']; Redis::lPush('today_redpacket' . $uniacid, $val['money']); } $arr_redPacket = serialize($redPacket); } \Log::debug('当天红包池额度', $amount); \Log::debug('当天红包数量', $number_sum); \Log::debug('当天红包池', $arr_redPacket); $red_Packet = storage_path('app/redPacket' . '/' . $uniacid); app(Filesystem::class)->makeDirectory($red_Packet, 0777, 1); $path = $red_Packet . '/redPacket.txt'; file_put_contents($path, $arr_redPacket); } } //额外奖励 protected function getBonus($redPackData, $number_sum, $set, $redPacketLogsId) { if (empty($redPackData) || $set['is_bonus'] == 0) { return; } $uniacid = \YunShop::app()->uniacid; //奖励金额是固定还是百分比 if ($set['bonus_type'] == 1) { $reward = round($set['bonus_amount'], 2);//固定金额 } else { $reward = round(proportionMath($redPackData, $set['bonus_amount']), 2);//红包池的百分比 } if (!empty($reward)) { //删除额外红包,生成新额外奖励红包 Redis::del('today_redpacket_bonus' . $uniacid); for ($i = 0; $i < $number_sum; $i++) { Redis::lPush('today_redpacket_bonus' . $uniacid, $reward); } //生成额外奖励记录 BonusCreateLogsModel::create([ 'uniacid' => $uniacid, 'amount' => bcmul($number_sum, $reward, 2), 'number_sum' => $number_sum, 'create_type' => $set['bonus_type'], 'create_amount' => $reward, 'red_packet_logs_id' => $redPacketLogsId ]); } } /** * @param array $set * @return bool */ protected function validateCreateRedPacketConditions($set) { // 红包工具 基础设置 开启, 不执行每日红包业务逻辑 if (app('plugins')->isEnabled('redpack-tool')) { $toolSetting = Setting::get('plugin.redpack_tool'); if ($toolSetting['is_open']) { \Log::debug('红包工具基础设置开启,不执行每日红包业务逻辑'); return false; } } //当天是否已生成红包 if ($this->setLog['current_d'] == date('d')) { \Log::debug('每日红包-' . date('d') . '号已生成红包,当前不可生成'); return false; } //未开启 if ($set['is_open_red_packet'] != 1) { return false; } //设置当前日期 $this->setLog['current_d'] = date('d'); Setting::set(self::SET_LOG_NAME, $this->setLog); return true; } /** * @param string $amount 每日生成红包金额 * @param string $number_sum 最大红包数量 * @param array $grads 梯度设置 * 梯度生成红包(随机生成,不可用于判断是否超限,实际领取的时候再判断不可超限) */ protected function gradsCreateRedPacket($red_packet_amount,$number_sum,$grads) { $uniacid = \YunShop::app()->uniacid; //获取梯度设置 $quota = array_column($grads,'amount','quota'); foreach ($quota as $key => $value) { $amount_section = explode('_',$value);//金额区间 \Log::debug('删除旧梯度:' . 'grads_redpacket_' . $uniacid . '_' . $key); Redis::del('grads_redpacket_' . $uniacid . '_' . $key);//删除旧梯度 $total = $breakSign = 0; for ($i = 1;$i <= $number_sum;$i++) { $amount = (float)sprintf("%.2f",mt_rand($amount_section[0]*100,$amount_section[1]*100)/100);//随机生成范围内浮点 //第一次生成 todo 后续优化成领取的时候实时生成 if ($i === 1 && bccomp($amount,$red_packet_amount,2) == 1) { Redis::lPush('grads_redpacket_' . $uniacid . '_' . $key, $red_packet_amount);//最大金额 $total += $amount; continue; } //此次生成的金额大于总额,结束生成 if (bccomp($total+$amount,$red_packet_amount,2) == 1) { \Log::debug('grads_redpacket_' . $uniacid . '_' . $key . ':超总额不生成',[$total+$amount,$red_packet_amount]); break; } $total += $amount; Redis::lPush('grads_redpacket_' . $uniacid . '_' . $key, $amount);//list放入当前梯度 } } } }