// +---------------------------------------------------------------------- namespace App\Services\Api; use App\Models\AccountLogModel; use App\Models\CouponModel; use App\Models\MemberCouponModel; use App\Models\MemberModel; use App\Models\OrderCommissionModel; use App\Models\OrderModel; use App\Models\StoreModel; use App\Services\BaseService; use App\Services\ConfigService; use App\Services\RedisService; use Illuminate\Support\Facades\DB; /** * 结算管理-服务类 * @author laravel开发员 * @since 2020/11/11 * @package App\Services\Api */ class SettleService extends BaseService { /** * 构造函数 * @author laravel开发员 * @since 2020/11/11 */ public function __construct() { $this->model = new AccountLogModel(); } /** * 静态入口 * @return static|null */ public static function make() { if (!self::$instance) { self::$instance = (new static()); } return self::$instance; } /** * 佣金奖励计算 * @param $order 订单信息 * @param $orderGoods 订单商品 * @param $userInfo 用户信息 * @param $settle 是否直接结算 */ public function commissionCount($order, $orderGoods, $userInfo, $settle = false) { $userId = isset($order['user_id']) ? $order['user_id'] : 0; $storeId = isset($order['store_id']) ? $order['store_id'] : 0; $orderId = isset($order['id']) ? $order['id'] : 0; $orderNo = isset($order['order_no']) ? $order['order_no'] : ''; $orderTotal = isset($order['pay_total']) ? $order['pay_total'] : 0; $data = [ 'order_id' => $orderId, 'user_id' => $userId, 'order_no' => $orderNo, 'store_id' => $storeId, 'total' => $orderTotal, 'create_time' => time(), 'status' => 2, 'mark' => 1, ]; $errors = []; /* TODO 计算商家佣金 */ if ($storeId > 0) { $storeInfo = StoreModel::where(['id' => $storeId])->first(); $bonusRate = isset($storeInfo['bonus_rate']) ? floatval($storeInfo['bonus_rate']) : 0; $storeBonusRate = ConfigService::make()->getConfigByCode('store_bonus_rate', 0); $storeBonusRate = $storeBonusRate > 0 && $storeBonusRate <= 100 ? $storeBonusRate : 0; $bonusRate = $bonusRate > 0 && $bonusRate <= 100 ? $bonusRate : $storeBonusRate; $bonus = moneyFormat($orderTotal * $bonusRate / 100, 2); $data['bonus'] = $bonus; $data['bonus_rate'] = $bonusRate; } /* TODO 计算分销奖励 */ $parents = isset($userInfo['parents']) ? $userInfo['parents'] : ''; $parents = $parents ? explode(',', $parents) : []; $parents = array_filter($parents); $parents = array_reverse($parents); // 由下到上1-3层 $rewardLevel = ConfigService::make()->getConfigByCode('commission_level', 2); $parents = array_splice($parents, 0, $rewardLevel); // 分销奖励计算 if ($parents) { $userList = MemberModel::with(['levelData'])->whereIn('id', $parents) ->select(['id', 'nickname', 'mobile', 'member_level', 'status', 'mark']) ->orderBy(DB::raw("FIELD(id, " . implode(',', $parents) . ")")) ->get(); $bonusRows = ConfigService::make()->getConfigByGroup(11); foreach ($userList as $k => $user) { // 默认只分2层 $layer = $k + 1; if ($layer > $rewardLevel) { continue; } // 处理奖励数据 $pid = isset($point['id']) ? $point['id'] : 0; $pMark = isset($point['mark']) ? $point['mark'] : 0; $data["bonus_level{$layer}_uid"] = $pid; $bonus = isset($bonusRows['bonus_rate_level' . $layer]) ? $bonusRows['bonus_rate_level' . $layer] : 0; $bonusData = [ 'id' => $pid, 'nickname' => isset($point['nickname']) ? $point['nickname'] : '', 'mobile' => isset($point['mobile']) ? $point['mobile'] : '', 'layer' => $layer, 'bonus' => 0, ]; if ($pMark == 1) { $bonusData['bonus'] = $bonus; } else { $bonusData["error"] = "{$layer}级分销用户不存在"; } // 数据 $data["bonus_level{$layer}_data"] = json_encode($bonusData, 256); } } // 佣金数据入库 if (!$cid = OrderCommissionModel::where(['order_no' => $orderNo])->value('id')) { $cid = OrderCommissionModel::insertGetId($data); } else { OrderCommissionModel::where(['id' => $cid])->update($data); } // 是否直接结算 if($settle){ return $this->commissionSettle($orderId); } $this->error = '佣金计算成功'; $data['id'] = $cid; return $data; } /** * 订单佣金结算 * @param $orderId 订单ID * @return array|false */ public function commissionSettle($orderId) { try { $info = OrderModel::with(['commission', 'user']) ->where(['id' => $orderId, 'mark' => 1]) ->select(['id', 'order_no', 'user_id', 'total', 'pay_total', 'pay_status', 'status', 'refund_status']) ->first(); $info = $info ? $info->toArray() : []; if (empty($info)) { $this->error = '结算订单不存在'; return false; } if ($info['status'] <= 1 || $info['pay_status'] == 10) { $this->error = '订单未支付'; return false; } if (in_array($info['refund_status'], [1, 2, 3])) { $this->error = '订单已退款'; return false; } $orderNo = isset($info['order_no']) ? $info['order_no'] : ''; $orderUserId = isset($info['user_id']) ? $info['user_id'] : 0; $user = isset($info['user']) ? $info['user'] : []; $mobile = isset($user['mobile']) ? $user['mobile'] : $orderUserId; $commission = isset($info['commission']) ? $info['commission'] : []; $commissionId = isset($commission['id']) ? $commission['id'] : 0; if (empty($commission) || $commissionId <= 0) { $this->error = '结算订单收益参数错误'; return false; } if ($commission['status'] == 1) { $this->error = '订单收益已结算'; return false; } $cacheKey = "caches:ordersCommission:{$orderNo}_{$orderUserId}:"; if (RedisService::get("{$cacheKey}lock")) { $this->error = '订单结算中'; return false; } // 创业订单 $logs = []; RedisService::set("{$cacheKey}lock", $info, 300); // TODO 商家结算 $storeInfo = isset($commission['store']) ? $commission['store'] : []; $storeId = isset($commission['store_id']) ? $commission['store_id'] : 0; $storeBonus = isset($commission['bonus']) ? $commission['bonus'] : 0; $storeUserId = isset($storeInfo['user_id']) ? $storeInfo['user_id'] : 0; $storeBalance = isset($storeInfo['balance']) ? $storeInfo['balance'] : 0; if ($storeId > 0 && $storeInfo && $storeBonus > 0) { $updateData = [ 'balance' => DB::raw("balance + {$storeBonus}"), 'income' => DB::raw("income + {$storeBonus}"), 'update_time' => time() ]; if (!StoreModel::where(['id' => $storeId])->update($updateData)) { $this->error = '商家提成结算失败'; RedisService::clear("{$cacheKey}lock"); return false; } $storeBalance = moneyFormat($storeBalance + $storeBonus, 2); $data = [ 'user_id' => $storeUserId, 'store_id' => $storeId, 'source_order_no' => $orderNo, 'user_type' => 2, 'type' => 7, 'bonus_type' => 0, 'money' => $storeBonus, 'after_money' => $storeBalance, 'date' => date('Y-m-d'), 'create_time' => time(), 'remark' => '商家结算', 'remark1' => "用户[{$mobile}]购买商品订单结算", 'status' => 1, 'mark' => 1 ]; $logs[] = $data; } // TODO 分销结算 $layer = 3; $bonusUids = []; for ($i = 1; $i <= $layer; $i++) { $uid = isset($commission["bonus_level{$i}_uid"]) ? $commission["bonus_level{$i}_uid"] : 0; if ($uid) { $bonusUids[] = $uid; } } $bonusUsers = MemberModel::whereIn('id', $bonusUids) ->select(['id', 'openid', 'balance', 'mobile', 'nickname', 'property', 'ls_score', 'status']) ->get() ->keyBy('id'); $bonusUsers = $bonusUsers ? $bonusUsers->toArray() : []; for ($i = 1; $i <= $layer; $i++) { $uid = isset($commission["bonus_level{$i}_uid"]) ? $commission["bonus_level{$i}_uid"] : 0; $bonusData = isset($commission["bonus_level{$i}_data"]) ? $commission["bonus_level{$i}_data"] : ''; $bonusData = $bonusData ? json_decode($bonusData, true) : []; $bonus = isset($bonusData['bonus']) ? $bonusData['bonus'] : 0; $bonusUser = isset($bonusUsers[$uid]) ? $bonusUsers[$uid] : []; $bonusUserBalance = isset($bonusUser['balance']) ? $bonusUser['balance'] : 0; if ($uid && $bonusUser && $bonus > 0) { $updateData = [ 'balance' => DB::raw("balance + {$bonus}"), 'bonus_total' => DB::raw("bonus_total + {$bonus}"), 'update_time' => time() ]; if (!MemberModel::where(['id' => $uid])->update($updateData)) { $this->error = '分销收益结算错误'; RedisService::clear("{$cacheKey}lock"); return false; } if ($bonus > 0) { $bonusUserBalance = moneyFormat($bonusUserBalance + $bonus, 2); $data = [ 'user_id' => $uid, 'source_order_no' => $orderNo, 'user_type' => 1, 'type' => 8, 'bonus_type' => 1, 'money' => $bonus, 'after_money' => $bonusUserBalance, 'date' => date('Y-m-d'), 'create_time' => time() + $i, 'remark' => "分销奖励", 'remark1' => "用户ID:{$orderUserId}购买商品{$i}级分销奖励", 'status' => 1, 'mark' => 1 ]; $logs[] = $data; } } } // TODO 明细入表 RedisService::set("{$cacheKey}logs", $logs, 3600); if ($logs && !AccountLogModel::insert($logs)) { $this->error = '奖励明细结算处理错误'; RedisService::clear("{$cacheKey}lock"); return false; } // 订单结算状态更新 if (!OrderCommissionModel::where(['id' => $commissionId])->update(['status' => 1, 'arrival_at' => date('Y-m-d H:i:s'), 'update_time' => time()])) { $this->error = '订单结算状态更新失败'; return false; } $this->error = '订单结算完成'; RedisService::clear("{$cacheKey}lock"); RedisService::clear("caches:orders:settleList"); RedisService::set("{$cacheKey}result", $info, 3600); $result = ['id' => $orderId, 'user_id' => $orderUserId, 'logs' => $logs, 'commission' => $commission]; RedisService::set("caches:settles:{$orderId}_{$orderNo}_success", $result, 7200); return $result; } catch (\Exception $exception) { RedisService::set("caches:settles:{$orderId}_error", ['error' => $exception->getMessage(), 'trace' => $exception->getTrace()], 7200); return false; } } /** * 新人注册奖励 * @param $userId * @return array|bool */ public function registerReward($userId) { $rewardOpen = ConfigService::make()->getConfigByCode('register_award_coupon', 0); $rewardCouponId = ConfigService::make()->getConfigByCode('register_reward_coupon_id', 0); if ($rewardCouponId <= 0 || $rewardOpen != 1) { $this->error = '未开启或配置注册优惠券奖励'; return true; } $couponInfo = CouponModel::where(['id' => $rewardCouponId, 'mark' => 1]) ->first(); $status = isset($couponInfo['status']) ? $couponInfo['status'] : 0; $num = isset($couponInfo['num']) ? $couponInfo['num'] : 0; $receivedNum = isset($couponInfo['received_num']) ? $couponInfo['received_num'] : 0; if (empty($couponInfo) || $status != 1) { $this->error = '配置的注册奖励优惠券不存在或无效'; return true; } if ($num > 0 && $receivedNum >= $num) { $this->error = '注册奖励优惠券已发放完~'; return true; } $data = [ 'coupon_id' => $rewardCouponId, 'user_id' => $userId, 'store_id' => isset($couponInfo['store_id']) ? $couponInfo['store_id'] : 0, 'name' => isset($couponInfo['name']) ? $couponInfo['name'] : '', 'coupon_type' => isset($couponInfo['coupon_type']) ? $couponInfo['coupon_type'] : 20, 'reduce_price' => isset($couponInfo['reduce_price']) ? $couponInfo['reduce_price'] : 0, 'discount' => isset($couponInfo['discount']) ? $couponInfo['discount'] : 0, 'min_price' => isset($couponInfo['min_price']) ? $couponInfo['min_price'] : 0, 'expire_day' => isset($couponInfo['expire_day']) ? $couponInfo['expire_day'] : 0, 'start_time' => isset($couponInfo['start_time']) ? $couponInfo['start_time'] : 0, 'end_time' => isset($couponInfo['end_time']) ? $couponInfo['end_time'] : 0, 'goods_ids' => isset($couponInfo['goods_ids']) && $couponInfo['goods_ids'] ? $couponInfo['goods_ids'] : '', 'create_time' => time(), 'status' => 1, ]; if (!$id = MemberCouponModel::insertGetId($data)) { $this->error = '奖励注册优惠券失败'; return true; } // 更新发放统计 CouponModel::where(['id' => $id])->update(['received_num' => DB::raw("received_num+1"), 'update_time' => time()]); $data['id'] = $id; $data['discount'] = floatval($data['discount']); $data['reduce_price'] = floatval($data['reduce_price']); unset($data['create_time']); unset($data['status']); unset($data['goods_ids']); $this->error = '奖励注册优惠券成功'; return $data; } }