wesmiler 1 день тому
батько
коміт
1a78be273b
2 змінених файлів з 529 додано та 0 видалено
  1. 412 0
      app/Services/Common/BalanceLogService.php
  2. 117 0
      app/Services/PaymentService.php

+ 412 - 0
app/Services/Common/BalanceLogService.php

@@ -0,0 +1,412 @@
+<?php
+// +----------------------------------------------------------------------
+// | LARAVEL8.0 框架 [ LARAVEL ][ RXThinkCMF ]
+// +----------------------------------------------------------------------
+// | 版权所有 2017~2021 LARAVEL研发中心
+// +----------------------------------------------------------------------
+// | 官方网站: http://www.laravel.cn
+// +----------------------------------------------------------------------
+// | Author: laravel开发员 <laravel.qq.com>
+// +----------------------------------------------------------------------
+
+namespace App\Services\Common;
+
+use App\Models\AccountLogModel;
+use App\Models\ActionLogModel;
+use App\Models\BalanceLogModel;
+use App\Models\MemberModel;
+use App\Services\BaseService;
+use App\Services\PaymentService;
+use App\Services\RedisService;
+use Illuminate\Support\Facades\DB;
+
+/**
+ * 余额管理-服务类
+ * @author laravel开发员
+ * @since 2020/11/11
+ * @package App\Services\Common
+ */
+class BalanceLogService extends BaseService
+{
+    public static $instance = null;
+
+    /**
+     * 构造函数
+     * @author laravel开发员
+     * @since 2020/11/11
+     * AccountService constructor.
+     */
+    public function __construct()
+    {
+        $this->model = new BalanceLogModel();
+    }
+
+    /**
+     * 静态入口
+     * @return static|null
+     */
+    public static function make()
+    {
+        if (!self::$instance) {
+            self::$instance = (new static());
+        }
+        return self::$instance;
+    }
+
+    /**
+     * @param $params
+     * @param int $pageSize
+     * @return array
+     */
+    public function getDataList($params, $pageSize = 15)
+    {
+        $query = $this->getQuery($params);
+
+        $model = clone $query;
+        $counts = [
+            'count' => $model->count('a.id'),
+            'total' => $model->sum('a.money'),
+        ];
+
+        $list = $query->select(['a.*'])
+            ->orderBy('a.create_time', 'desc')
+            ->orderBy('a.id', 'desc')
+            ->paginate($pageSize > 0 ? $pageSize : 9999999);
+        $list = $list ? $list->toArray() : [];
+        if ($list) {
+            foreach ($list['data'] as &$item) {
+                $item['create_time'] = $item['create_time'] ? datetime($item['create_time'], 'Y-m-d H.i.s') : '';
+                $item['pay_img'] = $item['pay_img'] ? get_image_url($item['pay_img']) : '';
+                $item['member'] = isset($item['member']) ? $item['member'] : [];
+            }
+        }
+
+        return [
+            'pageSize' => $pageSize,
+            'total' => isset($list['total']) ? $list['total'] : 0,
+            'counts' => $counts,
+            'list' => isset($list['data']) ? $list['data'] : []
+        ];
+    }
+
+    /**
+     * 查询
+     * @param $params
+     * @return \Illuminate\Database\Eloquent\Builder
+     */
+    public function getQuery($params)
+    {
+        $where = ['a.mark' => 1];
+        $type = isset($params['type']) ? $params['type'] : 0;
+        if ($type > 0) {
+            $where['a.type'] = $type;
+        }
+
+        $accountType = isset($params['account_type']) ? $params['account_type'] : 0;
+        if ($accountType > 0) {
+            $where['a.account_type'] = $accountType;
+        }
+
+        return $this->model->with(['member'])->from("balance_logs as a")
+            ->leftJoin('member as b', 'b.id', '=', 'a.user_id')
+            ->where($where)
+            ->where(function ($query) use ($params) {
+                $keyword = isset($params['keyword']) ? $params['keyword'] : '';
+                $userId = isset($params['user_id']) ? $params['user_id'] : 0;
+                if ($userId) {
+                    $query->where('a.user_id', $userId);
+                }
+
+                if ($keyword) {
+                    $query->where(function ($query) use ($keyword) {
+                        $query->where('b.nickname', 'like', "%{$keyword}%")
+                            ->orWhere('b.mobile', 'like', "%{$keyword}%");
+                    });
+                }
+
+                $orderNo = isset($params['order_no']) ? trim($params['order_no']) : '';
+                if ($orderNo) {
+                    $query->where(function ($query) use ($orderNo) {
+                        $query->where('a.order_no', 'like', "%{$orderNo}%");
+                    });
+                }
+
+                $status = isset($params['status']) ? $params['status'] : 0;
+                if ($status < 0) {
+                    $query->whereIn('a.status', [1, 3]);
+                } else if ($status > 0) {
+                    $query->where('a.status', $status);
+                }
+            })
+            ->where(function ($query) use ($params) {
+
+                // 日期
+                $date = isset($params['date']) ? $params['date'] : [];
+                $start = isset($date[0]) ? $date[0] : '';
+                $end = isset($date[1]) ? $date[1] : '';
+                $end = $start >= $end ? '' : $end;
+                if ($start) {
+                    $query->where('a.create_time', '>=', strtotime($start));
+                }
+                if ($end) {
+                    $query->where('a.create_time', '<=', strtotime($end));
+                }
+            });
+    }
+
+
+    /**
+     * 添加或编辑
+     * @return array
+     * @since 2020/11/11
+     * @author laravel开发员
+     */
+    public function edit()
+    {
+        $data = request()->all();
+        return parent::edit($data); // TODO: Change the autogenerated stub
+    }
+
+    /**
+     * 审核
+     * @param $adminId
+     * @param $params
+     * @return array|false
+     */
+    public function confirm($adminId, $params)
+    {
+        $id = isset($params['id']) ? intval($params['id']) : 0;
+        $status = isset($params['status']) ? intval($params['status']) : 0;
+        $payStatus = isset($params['pay_status']) ? intval($params['pay_status']) : 0;
+        $confirmRemark = isset($params['confirm_remark']) ? trim($params['confirm_remark']) : '';
+        $payImg = isset($params['pay_img']) ? trim($params['pay_img']) : '';
+        $payImg = $payImg ? get_image_path($payImg) : '';
+
+        $info = $this->model->with(['member'])->where(['id' => $id, 'mark' => 1])->first();
+        $userInfo = isset($info['member']) ? $info['member'] : [];
+        $openid = isset($userInfo['openid']) ? $userInfo['openid'] : '';
+        $realname = isset($userInfo['realname']) ? $userInfo['realname'] : '';
+        $orderStatus = isset($info['status']) ? $info['status'] : 0;
+        $accountType = isset($info['account_type']) ? $info['account_type'] : 0;
+        $payType = isset($info['pay_type']) ? $info['pay_type'] : 10;
+        $orderUserId = isset($info['user_id']) ? $info['user_id'] : 0;
+        $orderNo = isset($info['order_no']) ? $info['order_no'] : '';
+        $money = isset($info['money']) ? $info['money'] : 0;
+        $actualMoney = isset($info['actual_money']) ? $info['actual_money'] : 0;
+        $fields = [1 => 'balance', 2 => 'property', 4 => 'ls_score'];
+        $field = isset($fields[$accountType]) ? $fields[$accountType] : 'balance';
+        $balance = isset($userInfo[$field]) ? $userInfo[$field] : 0;
+        if (empty($info) || empty($userInfo) || $orderUserId <= 0 || $money <= 0) {
+            $this->error = '提现信息不存在或参数错误';
+            return false;
+        }
+
+        if ($orderStatus != 1) {
+            $this->error = '提现订单状态不可操作';
+            return false;
+        }
+
+        if (!in_array($status, [2, 3])) {
+            $this->error = '审核状态错误';
+            return false;
+        }
+
+        if ($status == 3 && empty($confirmRemark)) {
+            $this->error = '请填写审核驳回备注';
+            return false;
+        }
+
+        DB::beginTransaction();
+        $status = $payStatus == 20 && $status == 2 && $payType!=10 ? 4 : $status;
+        $updateData = ['status' => $status, 'pay_status' => $payStatus, 'pay_img' => $payImg, 'confirm_admin_id' => $adminId, 'update_time' => time(), 'confirm_remark' => $confirmRemark];
+        if (!$this->model->where(['id' => $id])->update($updateData)) {
+            DB::rollBack();
+            $this->error = '提现审核失败';
+            return false;
+        }
+
+        // 如果驳回
+        if ($status == 3) {
+            $updateData = ["{$field}" => DB::raw("{$field} + {$money}"), 'update_time' => time()];
+            if (!MemberModel::where(['id' => $orderUserId])->update($updateData)) {
+                DB::rollBack();
+                $this->error = '提现审核处理失败';
+                return false;
+            }
+
+            $log = [
+                'user_id' => $orderUserId,
+                'source_order_no' => isset($info['order_no']) ? $info['order_no'] : '',
+                'user_type' => isset($info['user_type']) ? $info['user_type'] : 1,
+                'type' => 5,
+                'money' => $money,
+                'after_money' => moneyFormat($balance + $money, 2),
+                'date' => date('Y-m-d'),
+                'create_time' => time(),
+                'remark' => '提现驳回',
+                'status' => 1,
+                'mark' => 1,
+            ];
+            if (!AccountLogModel::insertGetId($log)) {
+                DB::rollBack();
+                $this->error = '提现审核处理失败';
+                return false;
+            }
+        } else if ($status == 2) {
+            // 微信打款
+            $result = [];
+            if ($payStatus == 20) {
+                $order = [
+                    'order_no' => $orderNo,
+                    'pay_money' => $actualMoney,
+                    'account' => $openid,
+                    'real_name' => $realname,
+                    'body' => '余额提现',
+                ];
+
+                if (!$result = PaymentService::make()->transfer($order)) {
+                    DB::rollBack();
+                    $this->error = PaymentService::make()->getError();
+                    return false;
+                }
+
+                $batchId = isset($result['batch_id']) ? $result['batch_id'] : '';
+                $mchId = isset($result['mch_id']) ? $result['mch_id'] : '';
+                $packageInfo = isset($result['package_info']) ? $result['package_info'] : '';
+                $updateData = ['pay_status' => 20, 'pay_at' => date('Y-m-d H:i:s'), 'package_info' => $packageInfo, 'mch_id' => $mchId, 'batch_id' => $batchId, 'receive_status' => 2, 'update_time' => time()];
+                if (!$this->model->where(['id' => $id])->update($updateData)) {
+                    DB::rollBack();
+                    $this->error = '提现打款处理失败';
+                    return false;
+                }
+            }
+        }
+
+
+        DB::commit();
+        $this->error = '提现审核成功';
+        return ['id' => $id, 'money' => $money, 'status' => $status];
+    }
+
+    /**
+     * 打款
+     * @param $adminId
+     * @param $params
+     * @return array|false
+     */
+    public function payment($adminId, $params)
+    {
+        $id = isset($params['id']) ? intval($params['id']) : 0;
+        $payStatus = isset($params['pay_status']) ? intval($params['pay_status']) : 0;
+        $payImg = isset($params['pay_img']) ? trim($params['pay_img']) : '';
+        $payImg = $payImg ? get_image_path($payImg) : '';
+
+        $info = $this->model->with(['member'])->where(['id' => $id, 'mark' => 1])->first();
+        $userInfo = isset($info['member']) ? $info['member'] : [];
+        $openid = isset($userInfo['openid']) ? $userInfo['openid'] : '';
+        $realname = isset($userInfo['realname']) ? $userInfo['realname'] : '';
+        $orderStatus = isset($info['status']) ? $info['status'] : 0;
+        $accountType = isset($info['account_type']) ? $info['account_type'] : 0;
+        $orderUserId = isset($info['user_id']) ? $info['user_id'] : 0;
+        $orderNo = isset($info['order_no']) ? $info['order_no'] : '';
+        $money = isset($info['money']) ? $info['money'] : 0;
+        $actualMoney = isset($info['actual_money']) ? $info['actual_money'] : 0;
+        $fields = [1 => 'balance', 2 => 'property', 4 => 'ls_score'];
+        $field = isset($fields[$accountType]) ? $fields[$accountType] : 'balance';
+        if (empty($info) || empty($userInfo) || $orderUserId <= 0 || $money <= 0) {
+            $this->error = '提现信息不存在或参数错误';
+            return false;
+        }
+
+        if ($orderStatus != 2) {
+            $this->error = '提现订单状态不可操作';
+            return false;
+        }
+
+        if ($payStatus != 20) {
+            $this->error = '请选择已打款';
+            return false;
+        }
+
+
+        DB::beginTransaction();
+        $updateData = ['pay_status' => $payStatus, 'pay_img' => $payImg, 'update_time' => time()];
+        if ($payStatus == 20) {
+            $updateData['status'] = 4;
+        }
+        if (!$this->model->where(['id' => $id])->update($updateData)) {
+            DB::rollBack();
+            $this->error = '提现打款处理失败';
+            return false;
+        }
+
+        // 线上打款逻辑
+        $order = [
+            'order_no' => $orderNo,
+            'pay_money' => $actualMoney,
+            'account' => $openid,
+            'real_name' => $realname,
+            'body' => '余额提现',
+        ];
+
+        if (!$result = PaymentService::make()->transfer($order)) {
+            DB::rollBack();
+            $this->error = PaymentService::make()->getError();
+            return false;
+        }
+
+        $batchId = isset($result['batch_id']) ? $result['batch_id'] : '';
+        $mchId = isset($result['mch_id']) ? $result['mch_id'] : '';
+        $packageInfo = isset($result['package_info']) ? $result['package_info'] : '';
+        $updateData = ['pay_status' => 20, 'pay_at' => date('Y-m-d H:i:s'), 'package_info' => $packageInfo, 'mch_id' => $mchId, 'batch_id' => $batchId, 'receive_status' => 2, 'update_time' => time()];
+        if (!$this->model->where(['id' => $id])->update($updateData)) {
+            DB::rollBack();
+            $this->error = '提现打款处理失败';
+            return false;
+        }
+
+        DB::commit();
+        $this->error = '在线打款处理成功';
+        return ['id' => $id, 'money' => $money, 'status' => $payStatus];
+    }
+
+    /**
+     * 删除
+     * @return array
+     */
+    public function delete()
+    {
+        // 设置日志标题
+        ActionLogModel::setRecord(session('userId'), ['type' => 1, 'title' => "删除余额明细", 'content' => json_encode(request()->post(), 256), 'module' => 'admin']);
+        ActionLogModel::record();
+        $this->model->where('mark', 0)->where('update_time', '<=', time() - 7 * 86400)->delete();
+        return parent::delete(); // TODO: Change the autogenerated stub
+    }
+
+    /*\提现统计
+     * @param int $type
+     * @return array|mixed
+     */
+    public function getTotal($type = 1)
+    {
+        $cacheKey = "caches:balances:total_{$type}";
+        $data = RedisService::get($cacheKey);
+        if ($data) {
+            return $data;
+        }
+
+        $data = $this->model->where(['mark' => 1])
+            ->where(function ($query) use ($type) {
+                if ($type == 1) {
+                    $query->where(['type' => 2])->whereIn('status', [2, 4]);
+                } else {
+                    $query->where(['type' => 2]);
+                }
+            })->sum('money');
+        if ($data) {
+            RedisService::set($cacheKey, $data, rand(300, 600));
+        }
+
+        return $data;
+    }
+}

+ 117 - 0
app/Services/PaymentService.php

@@ -683,6 +683,123 @@ class PaymentService extends BaseService
     }
 
     /**
+     * 企业打款到零钱(商家转账)
+     * @param $order 订单参数:order_no-单号,pay_money-打款金额,account-打款账号(微信openid或支付宝账号),body-打款备注
+     * @param string $scene
+     * @param int $payType
+     * @return bool
+     */
+    public function transfer($order, $scene='withdraw', $payType=10)
+    {
+        $outTradeNo = isset($order['order_no']) && $order['order_no'] ? $order['order_no'] : get_order_num('WD');
+        $body = isset($order['body']) ? $order['body'] : '';
+        $amount = isset($order['pay_money']) ? $order['pay_money'] : 0;
+        $account = isset($order['account']) ? $order['account'] : '';  // 微信openid或支付宝账号
+        $realName = isset($order['real_name']) ? $order['real_name'] : '';  // 实名
+        if ($amount < 0) {
+            $this->error = '打款金额错误';
+            return false;
+        }
+
+        if(empty($account)){
+            $this->error = $payType == 10? '缺少微信OPENID' : '支付宝账户不为空';
+            return false;
+        }
+
+        // 创建支付
+        $result = [];
+        try {
+
+            $config = ConfigService::make()->getConfigOptionByGroup(6);
+            if ($payType == 10) {
+                $appid = isset($config['wxpay_appid']) ? $config['wxpay_appid'] : '';
+                $payData = [
+                    '_action' => 'mch_transfer', // 微信官方老版本下线后,此部分可省略
+                    'appid' => $appid,
+                    'out_bill_no' => $outTradeNo,
+                    'transfer_scene_id' => '1000',
+                    'openid' => $account,
+                    'transfer_amount' => intval($amount * 100),
+                    'transfer_remark' => $body?$body:'收益结算',
+                    'user_recv_perception' => '现金奖励',
+                    "transfer_scene_report_infos"=> [
+                        [
+                            "info_type" => "活动名称",
+                            "info_content" => "收益结算"
+                        ],
+                        [
+                            "info_type" => "奖励说明",
+                            "info_content" => "数字资产提现"
+                        ]
+                    ],
+                ];
+
+                $pay = $this->createPay($scene, $payType);
+                RedisService::set("caches:payments:wechat:{$scene}_{$outTradeNo}_pay", ['order' => $order,'params'=>$payData,'pay'=>$pay, 'config' => $this->config], 7200);
+                if (empty($pay)) {
+                    $this->error = '微信打款失败';
+                    return false;
+                }
+
+                $result = $pay->transfer($payData);
+                RedisService::set("caches:payments:wechat:{$scene}_{$outTradeNo}_result", ['order' => $order,'params'=>$payData,'result'=> $result, 'config' => $this->config], 7200);
+                $msg = isset($result['message'])? trim($result['message']) : '';
+                $batchId = isset($result['transfer_bill_no'])? trim($result['transfer_bill_no']) : '';
+                $packageInfo = isset($result['package_info'])? trim($result['package_info']) : '';
+                if(empty($batchId) || empty($packageInfo)){
+                    $this->error = $msg? $msg : '微信打款失败';
+                    return false;
+                }
+
+                $this->error = '微信打款成功';
+                return ['order_no'=> $outTradeNo,'mch_id'=>$config['wxpay_mchd'],'batch_id'=> $batchId,'package_info'=>$packageInfo,'result'=>$result];
+            }else if ($payType == 20){
+                $payData = [
+                    'out_biz_no'   => $outTradeNo,//商户订单号,内部订单号
+                    'trans_amount' => $amount,  //订单总金额,单位为元,精确到小数点后两位,
+                    'biz_scene'    => 'DIRECT_TRANSFER',  //描述特定的业务场景,可传的参数如下:DIRECT_TRANSFER:单笔无密转账到支付宝,B2C现金红包PERSONAL_COLLECTION:C2C现金红包-领红包
+                    'product_code' => 'TRANS_ACCOUNT_NO_PWD',  //业务产品码,单笔无密转账到支付宝账户固定为:TRANS_ACCOUNT_NO_PWD;收发现金红包固定为:STD_RED_PACKET;
+                    'remark'       => $body? $body : '提现',//业务备注
+                    'order_title'  => $body? $body : '提现',//转账业务的标题,用于在支付宝用户的账单里显示
+                    'payee_info'   => [
+                        'identity'      => $account,//参与方的唯一标识'208823395231'
+                        'name'      => $realName,//参与方的唯一标识'208823395231'
+                        'identity_type' => 'ALIPAY_LOGON_ID',//参与方的标识类型,目前支持如下类型:1、ALIPAY_USER_ID 支付宝的会员ID2、ALIPAY_LOGON_ID:支付宝登录号,支持邮箱和手机号格式3、ALIPAY_OPEN_ID:支付宝openid
+                    ],//收款方信息
+                ];
+                $pay = $this->createPay($scene, $payType);
+                RedisService::set("caches:payments:alipay:{$scene}_{$outTradeNo}_pay", ['order' => $order,'params'=>$payData, 'config' => $this->config], 7200);
+                if (empty($pay)) {
+                    $this->error = '支付宝打款失败';
+                    return false;
+                }
+
+
+                $result = $pay->transfer($payData);
+                RedisService::set("caches:payments:alipay:{$scene}_{$outTradeNo}_result", ['order' => $order,'params'=>$payData,'result'=> $result, 'config' => $this->config], 7200);
+                $code = isset($result['code'])? intval($result['code']) : '';
+                $msg = isset($result['sub_msg'])? trim($result['sub_msg']) : '';
+                if($code != 10000){
+                    $this->error = $msg? $msg : '支付宝打款失败';
+                    return false;
+                }
+                $this->error = '支付宝打款成功';
+                return $result;
+            }else if($payType == 50){
+                $this->error = '银行卡打款未开通';
+                return false;
+            }
+
+            $this->error = '打款失败';
+            return false;
+        } catch (\Exception $exception) {
+            RedisService::set("caches:payments:trabsfer:{$scene}_{$outTradeNo}_error", ['order' => $order,'msg'=>$exception->getMessage(),'error'=>$exception->getTrace(), 'config' => $this->config], 7200);
+            $this->error = '打款失败:'.$exception->getMessage().'或运营账户资金是否充足';
+            return false;
+        }
+    }
+
+    /**
      * 分账
      * @param $openid
      * @param $order