283 lines
8.9 KiB
PHP
283 lines
8.9 KiB
PHP
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
use App\Enums\PayWay;
|
|
use App\Enums\SocialiteType;
|
|
use App\Exceptions\BizException;
|
|
use App\Exceptions\WeChatPayException;
|
|
use App\Models\{User, Order, SalesValueLog, Agent, OrderProfit, SocialiteUser};
|
|
use App\Services\Payment\WxpayService;
|
|
use Illuminate\Database\Eloquent\Builder;
|
|
use Illuminate\Support\Collection;
|
|
|
|
/**
|
|
* 分销模块
|
|
*/
|
|
class DistributeService
|
|
{
|
|
/**
|
|
* 根据订单, 更新成长值
|
|
*
|
|
* @param \App\Models\Order $order
|
|
*
|
|
* @return boolean
|
|
*/
|
|
public function incrementGrowthValue(Order $order)
|
|
{
|
|
if (!$this->canDistribute($order)) {
|
|
return false;
|
|
}
|
|
// 订单成长值
|
|
$sales_value = $order->sales_value;
|
|
$user = $order->user;
|
|
$userAgent = $user->agent;
|
|
// 已经处理过订单成长值
|
|
if ($user->salesValueLogs()->where('order_id', $order->id)->exists()) {
|
|
return false;
|
|
}
|
|
|
|
// 用户获得成长值
|
|
$user->salesValueLogs()->create([
|
|
'order_id' => $order->id,
|
|
'order_user_id' => $order->user_id,
|
|
'type' => SalesValueLog::TYPE_INDIVIDUAL,
|
|
'change_sales_value' => $sales_value
|
|
]);
|
|
$user->userInfo()->increment('growth_value', $sales_value);
|
|
|
|
if (!$userAgent || $userAgent->type !== Agent::TYPE_AGENT) {
|
|
// 自动升级代理
|
|
$levels = Agent::where('slug', Agent::TYPE_FAVOITE)->orderBy('sort')->get();
|
|
$levelUp = '';
|
|
foreach($levels->reverse() as $item) {
|
|
if ($user->userInfo->growth_value >= $item->growth_value) {
|
|
$levelUp = $item;
|
|
}
|
|
}
|
|
// 如果当前等级, 比升级之后的要高, 则不升级
|
|
if ($levelUp && (!$userAgent || $levelUp->sort < $userAgent->sort)) {
|
|
$user->update([
|
|
'agent_id' => $levelUp->id,
|
|
]);
|
|
$userAgent = $levelUp;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* 根据订单, 添加返现记录
|
|
*
|
|
* @param Order $order
|
|
*
|
|
* @return \Illuminate\Database\Eloquent\Collection
|
|
*/
|
|
public function storeByOrder(Order $order)
|
|
{
|
|
// 使用积分抵扣的订单不返利
|
|
if ($order->point_discount_amount > 0) {
|
|
return;
|
|
}
|
|
|
|
$sales_value = $order->sales_value;
|
|
$user = $order->user;
|
|
|
|
// 上级返利
|
|
$parentIds = array_reverse($user->userInfo->parent_ids);
|
|
// 按照推荐的顺序, 第一位是直属推荐人
|
|
$parents = User::with(['userInfo', 'agent'])->whereIn('id', $parentIds)->get()->sortBy(fn($item) => array_search($item->id, $parentIds));
|
|
// 过滤掉 不是代理身份 的用户
|
|
// 过滤掉 相同等级 的 后者 用户
|
|
// 过滤掉等级 低于 上一个分钱 的用户(sort = 1 为最高级, slug 要相同)
|
|
$existsList = [];
|
|
$lastAgent = null;
|
|
$filtered = collect();
|
|
foreach($parents as $item) {
|
|
if (!$item->agent) {
|
|
continue;
|
|
}
|
|
|
|
if (in_array($item->agent->sort, $existsList)) {
|
|
continue;
|
|
}
|
|
|
|
if ($lastAgent && $item->agent->sort > $lastAgent->sort && $item->agent->slug === $lastAgent->slug) {
|
|
continue;
|
|
}
|
|
$lastAgent = $item->agent;
|
|
|
|
array_push($existsList, $item->agent->sort);
|
|
|
|
$filtered->push($item);
|
|
}
|
|
// 生成返利记录
|
|
$profit_list = [];
|
|
$money_sum = 0;
|
|
foreach($filtered as $item) {
|
|
$agent = $item->agent??'';
|
|
if (!$agent) {
|
|
continue;
|
|
}
|
|
$money = floor($sales_value * $agent->ratio) / 100 - $money_sum;
|
|
if ($money <= 0) {
|
|
continue;
|
|
}
|
|
array_unshift($profit_list, [
|
|
'from_user_id' => $user->id,
|
|
'user_id' => $item->id,
|
|
'role' => $agent->slug . '-' . $agent->sort,
|
|
'role_name' => $agent->name,
|
|
'ratio' => $agent->ratio,
|
|
'growth_value' => $sales_value,
|
|
'money' => $money,
|
|
'sub_money' => $money_sum,
|
|
]);
|
|
$money_sum += $money;
|
|
}
|
|
// 订单保存返利金额
|
|
$order->update([
|
|
'profit' => $money_sum
|
|
]);
|
|
return $order->profits()->createMany($profit_list);
|
|
}
|
|
|
|
/**
|
|
* 判断订单是否可以生成返利
|
|
*
|
|
* @param \App\Models\Order $order
|
|
*
|
|
* @return boolean
|
|
*/
|
|
public function canDistribute(Order $order)
|
|
{
|
|
// 订单已取消, 换货后生成的新订单
|
|
if ($order->isCancelled() || $order->is_change) {
|
|
return false;
|
|
}
|
|
// 订单确认收货
|
|
if (!$order->isCompleted()) {
|
|
return false;
|
|
}
|
|
// 订单超过售后期限
|
|
$value = app_settings('app.sale_after_expire_days');
|
|
if ($value && $order->completed_at) {
|
|
$diff_day = $order->completed_at->diffInDays();
|
|
return $diff_day > $value;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* 批量支付
|
|
* 使用微信企业付款, 支付返利金额
|
|
* 支付的金额必须大于 1, 并且是同一个人的
|
|
*/
|
|
public function wechatTransfers(Collection $list)
|
|
{
|
|
if ($list->count() === 0) {
|
|
throw new BizException('记录数必须大于 0');
|
|
}
|
|
$filtered = collect();
|
|
$money = 0;
|
|
$userId = $list->first()->user_id;
|
|
// 商户订单号
|
|
$sn = serial_number();
|
|
foreach($list as $item) {
|
|
// 待付款, 同一收款用户, 金额 > 0, 代理等级: Agent::TYPE_FAVOITE
|
|
if ($item->status === 4 &&
|
|
$item->user_id === $userId &&
|
|
$item->money > 0 &&
|
|
$item->isRole(Agent::TYPE_FAVOITE)
|
|
) {
|
|
$item->update([
|
|
'status' => 1,
|
|
'pay_no' => $sn
|
|
]);
|
|
$money += $item->money;
|
|
|
|
if ($money > 200) {
|
|
break;
|
|
}
|
|
|
|
$filtered->push($item);
|
|
}
|
|
}
|
|
if ($money < 1) {
|
|
throw new BizException('金额小于 1, 无法打款');
|
|
}
|
|
$openid = SocialiteUser::where('socialite_type', SocialiteType::WechatMiniProgram->value)->where('user_id', $userId)->value('socialite_id');
|
|
if (!$openid) {
|
|
throw new BizException('用户 '.$userId.' 没有 openid');
|
|
}
|
|
|
|
$result = (new WxpayService())->transfer([
|
|
'partner_trade_no' => $sn,
|
|
'openid' => $openid,
|
|
'check_name' => 'NO_CHECK',
|
|
'amount' => $money * 100,
|
|
'desc' => '推荐返利',
|
|
]);
|
|
|
|
$this->success($filtered, $result);
|
|
}
|
|
|
|
/**
|
|
* 微信分账
|
|
*
|
|
* @return void
|
|
*/
|
|
public function wechatShare(Order $order)
|
|
{
|
|
$receivers = [];
|
|
$sn = serial_number();
|
|
$list = $order->profits;
|
|
foreach ($list as $item) {
|
|
$openid = SocialiteUser::where('socialite_type', SocialiteType::WechatMiniProgram->value)->where('user_id', $item->user_id)->value('socialite_id');
|
|
if (!$openid) {
|
|
throw new BizException('用户 '.$item->user_id.' 没有 openid');
|
|
}
|
|
$item->update(['pay_way' => PayWay::WxPayShare, 'pay_no' => $sn, 'status' => 1]);
|
|
if ($item->money > 0) {
|
|
array_push($receivers, [
|
|
"type" => "PERSONAL_SUB_OPENID",
|
|
"account" => $openid,
|
|
"amount" => floor($item->money * 100),
|
|
"description" => "推荐返利"
|
|
]);
|
|
}
|
|
}
|
|
$status = 'FINISHED';
|
|
if (count($receivers) > 0) {
|
|
$result = (new WxpayService())->share($order->out_trade_no, $sn, $receivers);
|
|
$status = data_get($result, 'status');
|
|
logger('DistributeService@wechatShare, order:' . $order->id, $result);
|
|
}
|
|
if ($status == 'FINISHED') {
|
|
$attributes = ['share_sn' => $sn, 'status' => 'N'];
|
|
$order->update([
|
|
'wx_share' => $order->wx_share ? array_merge($order->wx_share, $attributes) : $attributes,
|
|
'profit_paid' => now(),
|
|
]);
|
|
$this->success($list, $result);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 支付成功
|
|
*
|
|
* @param Collection $list 提成记录
|
|
* @param array $result [paid_at, remarks]
|
|
*/
|
|
public function success(Collection $list, $result = [])
|
|
{
|
|
OrderProfit::whereIn('id', $list->pluck('id'))->update([
|
|
'status' => 2,
|
|
'paid_at' => data_get($result, 'paid_at', now()),
|
|
'pay_data' => $result,
|
|
'remarks' => data_get($result, 'remarks'),
|
|
]);
|
|
}
|
|
}
|