TimestampBehavior::class ] ]; } public function attributeLabels() { return [ 'id' => '', 'sort_key' => '序号', 'name' => '期数', 'dividends_trigger_money' => '分红触发金额', 'dividends_money' => '当前分红统计金额(订单金额*让利)', 'dividends_user_num' => '分红用户人数', 'league_price' => '预计/累计发放联盟券数量', 'is_send' => '是否发放', 'created_at' => '创建时间', 'updated_at' => '修改时间', ]; } //有用户下单 获取配置信息 判断之前是否存在活动奖池 public static function setDividendsCycle($order) { $tran = \Yii::$app->db->beginTransaction(); try { //获取订单类型以及让利比例 $store = Store::findOne($order->store_id); $transfer_profit = $store->transfer_profit; $order_type = StoreDividendsCycleSub::ORDER_TYPE_MALL; if ($order instanceof \app\plugins\scanCodePay\models\Order) { $order_type = StoreDividendsCycleSub::ORDER_TYPE_FACE; $transfer_profit = $store->scan_transfer_profit; $order->pay_price = bcsub($order->total_price, $order->coupon_sub_price, 2); } if (isset($order->food_flag_id) && intval($order->food_flag_id) > 0) { $order_type = StoreDividendsCycleSub::ORDER_TYPE_FOOD; $transfer_profit = $store->food_transfer_profit;; } // 收银台判断 判断收银订单中是否存在当前订单 if (isset($order->hanging_order_id) && intval($order->hanging_order_id) > 0) { $order_type = StoreDividendsCycleSub::ORDER_TYPE_CASHIER; $transfer_profit = $store->cashier_transfer_profit; } //获取当前订单的分红值 订单支付金额 * 让利比例 $store_dividends_money = bcdiv(bcmul($order->pay_price, $transfer_profit, 2), 100, 2); //获取配置项 $store_dividends_setting = Option::get('store_dividends_setting', 0, 'store_dividends')['value']; $store_dividends_setting = json_decode($store_dividends_setting, true); if (empty($store_dividends_setting)) { throw new \Exception('请先配置分红设置'); } //判断订单是否已经加入 $order_is_join = StoreDividendsCycleSub::findOne(['order_id' => $order->id, 'order_type' => $order_type]); if ($order_is_join) { throw new \Exception('订单已经加入'); } //获取当前分红周期 $storeDividendsCycleArray = self::find()->where(['is_send' => self::IS_SEND_NO])->orderBy('id desc') ->select('id, sort_key')->asArray()->one(); //添加分红用户 $storeDividendsStore = StoreDividendsUser::addUser(StoreDividendsUser::ROLE_STORE, $store->id, $storeDividendsCycleArray['sort_key'] ?: 1); $storeDividendsUser = null; $user = User::findOne($order->user_id); if ($user) { $saasUser = SaasUser::findOne(['mobile' => $user->binding, 'is_delete' => 0]); $storeDividendsUser = StoreDividendsUser::addUser(StoreDividendsUser::ROLE_USER, $saasUser->id, $storeDividendsCycleArray['sort_key'] ?: 1); } if (!$storeDividendsStore || !$storeDividendsUser) { throw new \Exception('添加分红用户失败'); } $user_dividends_integral = bcdiv(bcmul($store_dividends_money, $store_dividends_setting['store_dividends_give_user_integral_rate'], 2), 100, 2); $store_dividends_integral = bcdiv(bcmul($store_dividends_money, $store_dividends_setting['store_dividends_give_store_integral_rate'], 2), 100, 2); //添加用户积分记录 START //商城记录 $storeDividendsIntegralStore = new StoreDividendsUserIntegralLog(); $storeDividendsIntegralStore->dividends_user_id = $storeDividendsStore->id; $storeDividendsIntegralStore->order_id = $order->id; $storeDividendsIntegralStore->order_type = $order_type; $storeDividendsIntegralStore->dividends_integral = $store_dividends_integral; $storeDividendsIntegralStore->save(); $storeDividendsStore->updateCounters(['dividends_integral' => $store_dividends_integral]); //用户记录 $storeDividendsIntegralUser = new StoreDividendsUserIntegralLog(); $storeDividendsIntegralUser->dividends_user_id = $storeDividendsUser->id; $storeDividendsIntegralUser->order_id = $order->id; $storeDividendsIntegralUser->order_type = $order_type; $storeDividendsIntegralUser->dividends_integral = $user_dividends_integral; $storeDividendsIntegralUser->save(); $storeDividendsUser->updateCounters(['dividends_integral' => $user_dividends_integral]); //添加用户积分记录 END //查询未结束的分红周期(在额定分红范围内 没有达到最高层) $storeDividends = StoreDividends::findOne(['is_finish' => StoreDividends::IS_FINISH_NO]); if ($storeDividends) { $storeDividendsCycleId = $storeDividendsCycleArray['id']; $storeDividendsCycle = self::findOne($storeDividendsCycleId); if ($storeDividendsCycle) { $storeDividends->updateCounters(['dividends_money' => $store_dividends_money]); $current_money = $store_dividends_money; //判断 带上这次这期是否会结束 $is_finish = false; $current_dividends_money = bcadd($storeDividendsCycle->dividends_money, $store_dividends_money, 2); if ($current_dividends_money >= $storeDividendsCycle->dividends_trigger_money) { //计算一下当前周期还查多少到达预计值 然后将差值放入当前周期池的来源表中 $current_money = bcsub($storeDividendsCycle->dividends_trigger_money, $storeDividendsCycle->dividends_money, 2); //计算一下多出的值 然后计算一下当前周期需要多少 剩余多出来的增加到下一周期附表上 $storeDividendsCycle->dividends_money = $storeDividendsCycle->dividends_trigger_money; $storeDividendsCycle->save(); $is_finish = true; //添加期数用户记录 } else { $storeDividendsCycle->updateCounters(['dividends_money' => $store_dividends_money]); //添加期数用户记录 } StoreDividendsCycleUserSub::addCycleUserSub($storeDividendsCycle->id); $storeDividendsCycleSub = new StoreDividendsCycleSub(); $storeDividendsCycleSub->dividends_cycle_id = $storeDividendsCycle->id; $storeDividendsCycleSub->order_id = $order->id; $storeDividendsCycleSub->order_type = $order_type; $storeDividendsCycleSub->order_no = $order->order_no; $storeDividendsCycleSub->store_profit = $transfer_profit; $storeDividendsCycleSub->money = $current_money; $storeDividendsCycleSub->user_dividends_integral = $user_dividends_integral; $storeDividendsCycleSub->store_dividends_integral = $store_dividends_integral; if (!$storeDividendsCycleSub->save()) { throw new \Exception('添加分红周期失败【' . implode(';', array_values($storeDividendsCycleSub->firstErrors)) . '】'); }; //先给附表中数据写入一下 //如果结束 就先计算一下 用户以及商城可以拿取多少联盟券 if ($is_finish) { // $num = 0; // $total_league_price = 0; // $result = self::handleSendLeague($order, $storeDividendsCycle->id, $num, $total_league_price); // if ($result['code']) { // throw new \Exception($result['msg']); // } // $storeDividendsCycle->is_send = self::IS_SEND_YES; // $storeDividendsCycle->dividends_user_num = $num; // $storeDividendsCycle->league_price = $total_league_price; // $storeDividendsCycle->save(); //然后执行下一轮的分期 $result = self::handleOutDividends( $order, $order_type, $transfer_profit, $storeDividendsCycle->sort_key, $current_dividends_money, $storeDividendsCycle->dividends_trigger_money, $store_dividends_setting['store_dividends_pool_profit_rate'], $storeDividendsUser->id, $storeDividendsStore->id, $user_dividends_integral, $store_dividends_integral ); if ($result['code']) { throw new \Exception($result['msg']); } } } else { $storeDividendsCycle = self::find()->where(['is_send' => 1])->orderBy('sort_key DESC')->asArray()->all(); $current_dividends_money = bcadd($storeDividendsCycle['dividends_money'], $store_dividends_money, 2); //然后执行下一轮的分期 $result = self::handleOutDividends( $order, $order_type, $transfer_profit, $storeDividendsCycle['sort_key'], $current_dividends_money, $storeDividendsCycle['dividends_trigger_money'], $store_dividends_setting['store_dividends_pool_profit_rate'], $storeDividendsUser->id, $storeDividendsStore->id, $user_dividends_integral, $store_dividends_integral ); if ($result['code']) { throw new \Exception($result['msg']); } } } else { $storeDividends = new StoreDividends(); $storeDividends->max_cycle = $store_dividends_setting['store_dividends_max_cycle']; $storeDividends->current_cycle = 1; $storeDividends->dividends_money = $store_dividends_money; $storeDividends->is_finish = StoreDividends::IS_FINISH_NO; if (!$storeDividends->save()) { throw new \Exception('添加分红周期失败【' . implode(';', array_values($storeDividends->firstErrors)) . '】'); }; $is_finish = false; $current_money = $store_dividends_money; if ($store_dividends_money >= $store_dividends_setting['store_dividends_init_profit']) { $current_money = $store_dividends_setting['store_dividends_init_profit']; $is_finish = true; } $storeDividendsCycle = new self(); $storeDividendsCycle->sort_key = 1; $storeDividendsCycle->name = '第一期'; $storeDividendsCycle->dividends_trigger_money = $store_dividends_setting['store_dividends_init_profit']; $storeDividendsCycle->dividends_money = $current_money; $storeDividendsCycle->dividends_user_num = 0; $storeDividendsCycle->is_send = self::IS_SEND_NO; if (!$storeDividendsCycle->save()) { throw new \Exception('添加分红周期失败【' . implode(';', array_values($storeDividendsCycle->firstErrors)) . '】'); }; //添加期数用户记录 StoreDividendsCycleUserSub::addCycleUserSub($storeDividendsCycle->id); $storeDividendsCycleSub = new StoreDividendsCycleSub(); $storeDividendsCycleSub->dividends_cycle_id = $storeDividendsCycle->id; $storeDividendsCycleSub->order_id = $order->id; $storeDividendsCycleSub->order_type = $order_type; $storeDividendsCycleSub->order_no = $order->order_no; $storeDividendsCycleSub->store_profit = $transfer_profit; $storeDividendsCycleSub->money = $current_money; $storeDividendsCycleSub->user_dividends_integral = $user_dividends_integral; $storeDividendsCycleSub->store_dividends_integral = $store_dividends_integral; if (!$storeDividendsCycleSub->save()) { throw new \Exception('添加分红周期失败【' . implode(';', array_values($storeDividendsCycleSub->firstErrors)) . '】'); }; if ($is_finish) { // $num = 0; // $total_league_price = 0; // $result = self::handleSendLeague($order, $storeDividendsCycle->id, $num, $total_league_price); // if ($result['code']) { // throw new \Exception($result['msg']); // } // $storeDividendsCycle->is_send = self::IS_SEND_YES; // $storeDividendsCycle->dividends_user_num = $num; // $storeDividendsCycle->league_price = $total_league_price; // $storeDividendsCycle->save(); //然后执行下一轮的分期 $result = self::handleOutDividends( $order, $order_type, $transfer_profit, $storeDividendsCycle->sort_key, $store_dividends_money, $storeDividendsCycle->dividends_trigger_money, $store_dividends_setting['store_dividends_pool_profit_rate'], $storeDividendsUser->id, $storeDividendsStore->id, $user_dividends_integral, $store_dividends_integral ); if ($result['code']) { throw new \Exception($result['msg']); } } } $tran->commit(); return [ 'code' => 0, 'msg' => '操作成功' ]; } catch (\Exception $e) { $tran->rollBack(); return [ 'code' => 1, 'msg' => $e->getMessage() ]; } } /** * @param $order Order | \app\plugins\scanCodePay\models\Order 上次分红结束后的分期数 * @param $order_type integer 订单类型 * @param $transfer_profit float 让利比例 * @param $sort_key integer 上次分红结束后的分期数 * @param $store_dividends_money float 累计的分红金额 * @param $dividends_trigger_money float 上次分红触发金额 * @param $store_dividends_pool_profit_rate float 分红池分红触发增长比例 * @param $storeDividendsUserId integer 某店分红用户ID * @param $storeDividendsStoreId integer 某店分红商家ID * @param $user_dividends_integral float 某店分红当期用户积分数量 * @param $store_dividends_integral float 某店分红当期商家积分数量 * 处理超出部分的分红 如果上次超出的分红只是等于0 那么就添加一期分红 不做其他处理 */ public static function handleOutDividends( $order, $order_type, $transfer_profit, $sort_key, $store_dividends_money, $prev_dividends_trigger_money, $store_dividends_pool_profit_rate, $storeDividendsUserId, $storeDividendsStoreId, $user_dividends_integral, $store_dividends_integral ) { try { $store_dividends_setting = Option::get('store_dividends_setting', 0, 'store_dividends')['value']; $store_dividends_setting = json_decode($store_dividends_setting, true); //计算当前的分红池触发金额 $dividends_trigger_money = bcadd($prev_dividends_trigger_money, bcdiv(bcmul($prev_dividends_trigger_money, $store_dividends_pool_profit_rate, 2), 100, 2), 2); $is_finish = false; $next_store_dividends_money = $store_dividends_money; $current_money = bcsub($next_store_dividends_money, $dividends_trigger_money, 2); //如果当前分红值直接超过分红池触发金额 就再开始考虑下一次期分红 if ($store_dividends_money >= $dividends_trigger_money) { $current_money = bcsub($dividends_trigger_money, $prev_dividends_trigger_money, 2);//计算一下当前的分红值 $next_store_dividends_money = $dividends_trigger_money; $is_finish = true; } $nextStoreDividendsCycle = new self(); $nextStoreDividendsCycle->sort_key = $sort_key + 1; $nextStoreDividendsCycle->name = '第' . self::numberToChinese($nextStoreDividendsCycle->sort_key) . '期'; $nextStoreDividendsCycle->dividends_trigger_money = $dividends_trigger_money; $nextStoreDividendsCycle->dividends_money = $next_store_dividends_money; $nextStoreDividendsCycle->dividends_user_num = 0; $nextStoreDividendsCycle->is_send = self::IS_SEND_NO; if (!$nextStoreDividendsCycle->save()) { throw new \Exception('添加分红周期失败【' . implode(';', array_values($nextStoreDividendsCycle->firstErrors)) . '】'); }; //添加期数用户记录 StoreDividendsCycleUserSub::addCycleUserSub($nextStoreDividendsCycle->id); if ($current_money > 0) { $storeDividendsCycleSub = new StoreDividendsCycleSub(); $storeDividendsCycleSub->dividends_cycle_id = $nextStoreDividendsCycle->id; $storeDividendsCycleSub->order_id = $order->id; $storeDividendsCycleSub->order_type = $order_type; $storeDividendsCycleSub->order_no = $order->order_no; $storeDividendsCycleSub->store_profit = $transfer_profit; $storeDividendsCycleSub->money = $current_money; $storeDividendsCycleSub->user_dividends_integral = 0; $storeDividendsCycleSub->store_dividends_integral = 0; if (!$storeDividendsCycleSub->save()) { throw new \Exception('添加分红周期失败【' . implode(';', array_values($storeDividendsCycleSub->firstErrors)) . '】'); }; if ($is_finish) { // $num = 0; // $total_league_price = 0; // $result = self::handleSendLeague($order, $nextStoreDividendsCycle->id, $num, $total_league_price); // if ($result['code']) { // return $result; // } // // $nextStoreDividendsCycle->is_send = self::IS_SEND_YES; // $nextStoreDividendsCycle->dividends_user_num = $num; // $nextStoreDividendsCycle->league_price = $total_league_price; // $nextStoreDividendsCycle->save(); //然后执行下一轮的分期 $result = self::handleOutDividends( $order, $order_type, $transfer_profit, $nextStoreDividendsCycle->sort_key, $store_dividends_money, $nextStoreDividendsCycle->dividends_trigger_money, $store_dividends_setting['store_dividends_pool_profit_rate'], $storeDividendsUserId, $storeDividendsStoreId, $user_dividends_integral, $store_dividends_integral ); if ($result['code']) { return $result; } } } return [ 'code' => 0, 'msg' => '操作成功' ]; } catch (\Exception $e) { return [ 'code' => 1, 'msg' => $e->getMessage() ]; } } /** * 分红时候给商家和用户发放联盟券 */ public static function handleSendLeague($order, $cycle_id, &$num = 0, &$total_league_price = 0, &$total_integral_price = 0) { try { $store_dividends_setting = Option::get('store_dividends_setting', 0, 'store_dividends')['value']; $store_dividends_setting = json_decode($store_dividends_setting, true); if (empty($store_dividends_setting)) { throw new \Exception('请先配置分红设置'); } $single_integral_profit = $store_dividends_setting['store_dividends_single_integral_profit']; $cycle = StoreDividendsCycle::findOne($cycle_id); // $userList = StoreDividendsCycleUserSub::find()->alias('cus') // ->leftJoin(['u' => StoreDividendsUser::tableName()], 'cus.dividends_user_id = u.id') // ->where(['>', 'cus.dividends_integral', 0]) // ->andWhere(['cus.dividends_cycle_id' => $cycle->id]) // ->select('u.id, u.role, u.role_id, cus.dividends_integral')->asArray()->all(); $userList = StoreDividendsUser::find()->where(['>', 'dividends_integral', 0]) ->andWhere(['<=', 'join_cycle_key', $cycle->sort_key]) ->select('id, role, role_id, dividends_integral')->asArray()->all(); foreach ($userList as $item) { $total_integral_price = bcadd($total_integral_price, $item['dividends_integral'], 2); $league_price = bcdiv(bcmul($item['dividends_integral'], $single_integral_profit, 2), 100, 2); $model = Store::findOne($item['role_id']); if (intval($item['role']) === StoreDividendsUser::ROLE_USER) { $model = SaasUser::findOne($item['role_id']); } if (!$model) { continue; } $storeDividendsUser = StoreDividendsUser::addUser($item['role'], $item['role_id']); $storeDividendsLeagueLog = new StoreDividendsUserLeagueLog(); $storeDividendsLeagueLog->dividends_cycle_id = $cycle_id; $storeDividendsLeagueLog->dividends_user_id = $item['id']; $storeDividendsLeagueLog->dividends_integral = $item['dividends_integral']; $storeDividendsLeagueLog->league_price = $league_price; $storeDividendsLeagueLog->save(); $before = $model->league_price; $model->updateCounters(['league_price' => $league_price]); $storeDividendsUser->updateCounters(['league_price' => $league_price]); //给商城增加联盟券 SaaSLeaguePriceLog::setLeaguePriceLog( intval($item['role']) === StoreDividendsUser::ROLE_STORE ? $item['role_id'] : 0, intval($item['role']) === StoreDividendsUser::ROLE_USER ? $item['role_id'] : 0, $league_price, $before, SaaSLeaguePriceLog::TYPE_STORE_DIVIDENDS_CYCLE, SaaSLeaguePriceLog::SEND_TYPE, intval($item['role']), $order->id); $total_league_price += $league_price; } $num = count($userList); return [ 'code' => 0, 'msg' => '' ]; } catch (\Exception $e) { return [ 'code' => 1, 'msg' => $e->getMessage() ]; } } /** * 将数字转换为中文大写形式(支持整数) * @param int $number 需要转换的数字 * @return string */ public static function numberToChinese($number) { if ($number < 0 || $number > 99999999) { return '暂不支持超出范围的数字'; } // 定义中文字符 $char = ['零', '一', '二', '三', '四', '五', '六', '七', '八', '九']; $unit = ['', '十', '百', '千']; $sectionUnit = ['', '万', '亿', '万亿']; // 拆分数字为每四位一组处理 $sections = []; while ($number > 0) { $sections[] = $number % 10000; $number = intval($number / 10000); } $result = ''; for ($i = count($sections) - 1; $i >= 0; $i--) { $n = $sections[$i]; if ($n == 0) { continue; // 当前节全为0时跳过 } $str = ''; $zeroCount = 0; for ($j = 0; $j < 4; $j++) { $digit = $n % 10; $n = intval($n / 10); if ($digit == 0) { $zeroCount++; } else { if ($zeroCount > 0) { $str = $char[0] . $str; $zeroCount = 0; } $str = $char[$digit] . $unit[$j] . $str; } } $result .= $str . $sectionUnit[$i]; } // 处理特殊情况 $result = str_replace(['一十', '零万'], ['十', '万'], $result); return $result ?: '零'; } }