Skip to content

微信分账

此功能基于yansongda插件

详细文档参阅: https://pay.yansongda.cn/docs/v3/

use addons\epay\library\Service;

use Yansongda\Pay\Pay;
use Yansongda\Pay\Plugin\Wechat\V3\Extend\ProfitSharing\AddReceiverPlugin;
use Yansongda\Pay\Plugin\Wechat\V3\Extend\ProfitSharing\DeleteReceiverPlugin;
use Yansongda\Pay\Plugin\Wechat\V3\Extend\ProfitSharing\CreatePlugin;
use Yansongda\Pay\Plugin\Wechat\V3\Extend\ProfitSharing\UnfreezePlugin;
use Yansongda\Pay\Plugin\Wechat\V3\Extend\ProfitSharing\QueryPlugin;


// 微信支付相关
class WxPay(){

    const MINIAPPID = 'wxxxxx'; // 小程序ID

    /**
     * 添加分账接收方
     * @return void
     */
    public function addReceiverPlugin($openid) {
        $config = Service::getConfig("wechat");
        Pay::config($config);
        $list = [
            "appid" => self::MINIAPPID,
            "type" => "PERSONAL_OPENID",
            "account" => $openid,   // 用户的OPENID
            "relation_type" => "USER",
            "custom_relation" => "用户"
        ];

        $allPlugins = Pay::wechat()->mergeCommonPlugins([AddReceiverPlugin::class]);
        $result = Pay::wechat()->pay($allPlugins, $list)->toArray();
    }

    /**
     * 删除分账接收方
     * @return void
     */
    public function delReceiverPlugin() {
        $config = Service::getConfig("wechat");
        Pay::config($config);
        $list = [
            "appid" => self::MINIAPPID,
            "type" => "PERSONAL_OPENID",
            "account" => $openid,
        ];
        $allPlugins = Pay::wechat()->mergeCommonPlugins([DeleteReceiverPlugin::class]);
        $result = Pay::wechat()->pay($allPlugins, $list)->toArray();
    }


    /**
     * 执行分账
     * @return void
     */
    public function createPlugin($sn) {
        $orderInfo = Db::name('recharge')->where('sn', $sn)->find();

        $config = Service::getConfig("wechat");
        Pay::config($config);
        $receivers = [
            [
                "type" => "PERSONAL_OPENID",
                "account" => "oTGw91ydkvD8-kny1nVzt4JEPV-M",
                "amount" => intval($orderInfo['amount'] * 0.08),
                "description" => "分给浩浩-8%"
            ],
            [
                "type" => "PERSONAL_OPENID",
                "account" => "oTGw919vumgdtNR201D9HcfSuv3E",
                "amount" => intval($orderInfo['amount'] * 0.06),
                "description" => "分给晶晶-6%"
            ]
        ];
        $receivers[] = [
            "type" => "PERSONAL_OPENID",
            "account" => $orderInfo['openid'],
            "amount" => intval($orderInfo['amount'] * 0.12),
            "description" => "用户支付返还-12%"
        ];
        $req = [
            'transaction_id' => $orderInfo['transaction_id'],
            'out_order_no' => $orderInfo['sn'],
            "receivers" => $receivers,
            'unfreeze_unsplit' => true,
        ];
        $allPlugins = Pay::wechat()->mergeCommonPlugins([CreatePlugin::class]);
        $result = Pay::wechat()->pay($allPlugins, $req)->toArray();

        // 订单维度记录分账详情
        $log[0]['request'] = $req;
        Db::name('recharge')->where('sn', $orderInfo['sn'])->update([
            'share_detail' => json_encode($log, 512)
        ]);

        // 人员维度 记录分账人
        foreach ($receivers as $v) {
            $insert = [
                'sn' => $orderInfo['sn'],
                'transaction_id' => $orderInfo['transaction_id'],
                'session' => 1,
                'account' => $v['account'],
                'account_type' => $v['type'],
                'amount' => $v['amount'],
                'description' => $v['description'],
            ];
            Db::name('sharing_log')->insert($insert, true);
        }
        \think\Log::record("发起分账:");
        \think\Log::record($result);
    }

    /**
     * 获取分账结果
     * @return void
     */
    public function queryPlugin($sn) {
        $orderInfo = Db::name('recharge')->where('sn', $sn)->find();

        $config = Service::getConfig("wechat");
        Pay::config($config);
        $requset = [
            'transaction_id' => $orderInfo['transaction_id'],
            'out_order_no' => $orderInfo['sn'], // 首次分账即业务单号  二次分账为首次返回的 order_id
        ];

        $allPlugins = Pay::wechat()->mergeCommonPlugins([QueryPlugin::class]);
        $result = Pay::wechat()->pay($allPlugins, $requset)->toArray();
        \think\Log::record("获取分账:");
        \think\Log::record($result);
        foreach ($result['receivers'] as $v) {
            $insert = [
                'sn' => $orderInfo['sn'],
                'transaction_id' => $orderInfo['transaction_id'],
                'session' => 1,
                'account' => $v['account'],
                'account_type' => $v['type'],
                'amount' => $v['amount'],
                'description' => $v['description'],
                'detail_id' => $v['detail_id'],
                'finish_time' => date('Y-m-d H:i:s', strtotime($v['finish_time'])),
                'result' => $v['result'],
            ];
            // 替换式更新
            Db::name('sharing_log')->insert($insert, true);
        }

        $log = json_decode($orderInfo['share_detail'], true);
        $log[0]['response'] = $result;
        Db::name('recharge')->where('sn', $orderInfo['sn'])->update([
            'share_detail' => json_encode($log, 512)
        ]);
    }


    /**
     * 查询支付订单详情
     * @return void
     */
    public function findOrder() {
        $config = Service::getConfig("wechat");
        Pay::config($config);
        $order = [
            'out_trade_no' => 'SN202509301747346676'
        ];
        $result = Pay::wechat()->query($order)->toArray();
    }



    /**
     * 发起支付
     * @return void
     */
    public function pay() {
        $user_id = $this->auth->id;
        $openId = $this->auth->username;

        $sn = "SN" . date("YmdHis") . mt_rand(1000, 9999);
        $orderInfo = [
            "user_id" => $user_id,
            "openid" => $openId,
            "sn" => $sn,
            "amount" => mt_rand(100, 1000),
            "status" => "to_pay"
        ];

        Db::name('recharge')->insert($orderInfo);

        $notifyurl = $this->request->root(true) . '/addons/exam/question/callbackV3';
        $returnurl = $this->request->root(true);
        $order = [
            'amount' => $orderInfo['amount'] / 100,
            'orderid' => $orderInfo['sn'],
            'type' => "wechat",
            'title' => "普通充值-无分账",
            'notifyurl' => $notifyurl,
            'returnurl' => $returnurl,
            'method' => "miniapp",
            'openid' => $openId
        ];
        $pay = \addons\epay\library\Service::submitOrder($order);
        Db::name('recharge')->where('sn', $sn)->update([
            'req_detail' => json_encode($order)
        ]);
        $this->success('成功', $pay);
    }

    /**
     * 支付回调
     */
    public function callbackV3() {
        $insert = [
            'sn' => '',
            'log' => json_encode($this->request->param(), 512),
        ];
        Db::name('log')->insert($insert);

        $paytype = 'wechat';
        $pay = Service::checkNotify($paytype);
        $data = $pay->callback();
        try {
            //微信支付V3返回和V2不同
            if (Service::isVersionV3() && $paytype === 'wechat') {
                $data = $data['resource']['ciphertext'];
                $data['total_fee'] = $data['amount']['total'];
            }

            \think\Log::record($data);
            //获取支付金额、订单号
            $payamount = $paytype == 'alipay' ? $data['total_amount'] : $data['total_fee'] / 100;
            $out_trade_no = $data['out_trade_no'];
            \think\Log::record("回调成功,订单号:{$out_trade_no},金额:{$payamount}");

            //你可以在此编写订单逻辑
            $orderInfo = Db::name('recharge')->where('sn', $out_trade_no)->find();
            if ($orderInfo['status'] == 'to_pay') {
                $insert['sn'] = $orderInfo['sn'];
                Db::name('log')->insert($insert);
                Db::name('recharge')->where('sn', $out_trade_no)->update([
                    'status' => 'paid',
                    'transaction_id' => $data['transaction_id'],
                    'resp_detail' => json_encode($data)
                ]);
            }

        } catch (Exception $e) {
            \think\Log::record("回调逻辑处理错误:" . $e->getMessage(), "error");
        }

        //下面这句必须要执行,且在此之前不能有任何输出
        if (Service::isVersionV3()) {
            return $pay->success()->getBody()->getContents();
        } else {
            return $pay->success()->send();
        }
    }

}