From 17f983bf5cf6173acd3e0ad0d7b46dfd9db0568e Mon Sep 17 00:00:00 2001 From: lqmac Date: Mon, 3 Jun 2024 01:22:24 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=AF=E4=BB=98tiaoz1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/api/controller/Checkout.php | 4 + app/api/service/cashier/Payment.php | 9 +- app/api/service/order/Checkout.php | 1 + app/command/ProfitSharing.php | 87 ++++++------- app/command/ProfitSharingResult.php | 114 +++++++++--------- app/common/library/payment/gateway/Driver.php | 4 + .../library/payment/gateway/driver/Wechat.php | 3 + .../payment/gateway/driver/wechat/V3.php | 88 ++++++++++++-- 8 files changed, 193 insertions(+), 117 deletions(-) diff --git a/app/api/controller/Checkout.php b/app/api/controller/Checkout.php index 09c23e50..a19b3d42 100644 --- a/app/api/controller/Checkout.php +++ b/app/api/controller/Checkout.php @@ -109,6 +109,10 @@ class Checkout extends Controller } // 创建订单 增加订单 $orderInfo['merchantId'] = $merchantId; + if ($merchantId) { + $model = \app\store\model\Merchant::detail($merchantId, $this->storeId); + $orderInfo['commission_ratio'] = $model['commission_ratio']; + } //print_r($orderInfo);die; if (!$Checkout->createOrder($orderInfo)) { return $this->renderError($Checkout->getError() ?: '订单创建失败', ['isCreated' => false]); diff --git a/app/api/service/cashier/Payment.php b/app/api/service/cashier/Payment.php index 9d5e0fc1..2da51432 100644 --- a/app/api/service/cashier/Payment.php +++ b/app/api/service/cashier/Payment.php @@ -123,7 +123,14 @@ class Payment extends BaseService $this->orderInfo = OrderModel::getDetail($this->orderId); // 订单支付事件 $this->orderPayEvent(); - + //判断当前订单是否需要设置为分账订单 + if ($this->orderInfo->commission_ratio > 0) { + $precent = $this->orderInfo->commission_ratio / 1000; + $precentPrice = round($precent * $this->orderInfo->pay_price, 2); + if ($precentPrice > 0) { + $extra['profit_sharing'] = TRUE; + } + } // 构建第三方支付请求的参数 $payment = $this->unifiedorder($extra,$this->orderInfo->merchant_id); // 记录第三方交易信息 diff --git a/app/api/service/order/Checkout.php b/app/api/service/order/Checkout.php index 08bd5172..a2c06cf6 100644 --- a/app/api/service/order/Checkout.php +++ b/app/api/service/order/Checkout.php @@ -876,6 +876,7 @@ class Checkout extends BaseService 'platform' => getPlatform(), 'store_id' => $this->storeId, 'merchant_id' => $order['merchantId'] ?? 0, + 'commission_ratio' => $order['commission_ratio'] ?? 0, 'expect_receive_time' => $this->param['expect_receive_time'],//期待收货时间 'is_street_take' => $this->param['is_street_take'],//是否街边1-在 0-不在 'to_store_time' => $this->param['to_store_time'],//预计到店时间 diff --git a/app/command/ProfitSharing.php b/app/command/ProfitSharing.php index 94a8cef3..30ba0f15 100644 --- a/app/command/ProfitSharing.php +++ b/app/command/ProfitSharing.php @@ -20,6 +20,7 @@ use app\common\model\PaymentTrade; use app\common\model\wxapp\Setting; use app\common\enum\Client as ClientEnum; use app\common\library\payment\Facade as PaymentFacade; +use app\common\library\Log; // /www/server/php/74/bin/php /server/wwwroot/yanzong/think test class ProfitSharing extends Command @@ -49,27 +50,29 @@ class ProfitSharing extends Command } var_dump($stores); foreach ($stores as $store) { - try { - $where = []; - //查询已完成的订单,并且未分账的订单 - $where[] = ['order_status','=', 30]; - $where[] = ['pay_status','=', 20]; - $where[] = ['is_refund','=', 10]; - $where[] = ['is_delete','=', 0]; - $where[] = ['profitsharing_status','=', 0]; - $where[] = ['store_id','=', $store['store_id']]; - $where[] = ['merchant_id','>', 0]; - $orders = Order::where($where) - ->field('order_id,total_price,order_price,pay_price,pay_method,cost_price,merchant_id,store_id,order_status,pay_status,delivery_status,receipt_status,delivery_type,delivery_time,create_time,trade_id') - ->select(); - // var_dump($orders->toArray()); - // exit(); - if ($orders->isEmpty()) { - echo $store['store_id']."没有已完成的订单要分账".PHP_EOL; - continue; - } - //微信支付订单抽佣给平台、余额支付抽佣给平台,把订单金额记录到商户账上 - foreach ($orders as $order) { + + $where = []; + //查询已完成的订单,并且未分账的订单 + $where[] = ['order_status','=', 30]; + $where[] = ['pay_status','=', 20]; + $where[] = ['is_refund','=', 10]; + $where[] = ['is_delete','=', 0]; + $where[] = ['profitsharing_status','=', 0]; + $where[] = ['store_id','=', $store['store_id']]; + $where[] = ['merchant_id','>', 0]; + $where[] = ['commission_ratio','>', 0]; + $orders = Order::where($where) + ->field('order_id,total_price,order_price,pay_price,pay_method,cost_price,merchant_id,store_id,order_status,pay_status,delivery_status,receipt_status,delivery_type,delivery_time,create_time,trade_id') + ->select(); + // var_dump($orders->toArray()); + // exit(); + if ($orders->isEmpty()) { + echo $store['store_id']."没有已完成的订单要分账".PHP_EOL; + continue; + } + //微信支付订单抽佣给平台、余额支付抽佣给平台,把订单金额记录到商户账上 + foreach ($orders as $order) { + try { //余额支付 if ($order->pay_method == PaymentMethodEnum::BALANCE) { //增加商户支付详情 @@ -117,14 +120,11 @@ class ProfitSharing extends Command echo $store['store_id'].$payment->template_id."微信支付模版没有配置11".PHP_EOL; continue; } + //支付信息初始化 $PaymentModel = new Payment; $templateInfo = $PaymentModel->getPaymentInfo(PaymentMethodEnum::WECHAT, ClientEnum::MP_WEIXIN, $order->store_id, $order->merchant_id); - // var_dump($templateInfo); - // exit(); $options = $templateInfo['template']['config'][PaymentMethodEnum::WECHAT]; - $payment = PaymentFacade::store(PaymentMethodEnum::WECHAT)->setOptions($options, ClientEnum::MP_WEIXIN); - var_dump($payment); //平台微信支付配置信息 $platform_payment = Payment::where('store_id', $order->store_id)->where('merchant_id', 0)->where('method',PaymentMethodEnum::WECHAT)->where('is_enable', 1)->find(); @@ -160,14 +160,14 @@ class ProfitSharing extends Command $precent = $model['commission_ratio'] / 1000; $precentPrice = round($precent * $order->pay_price * 100, 2); var_dump($precentPrice); - $precentPrice = 100; + //$precentPrice = 100; if ($precentPrice <= 0) { echo $order->order_id.":当前订单抽佣金额小于等于0".$precentPrice.PHP_EOL; continue; } - var_dump($payment); - $ret = $payment->addReceiver("MERCHANT_ID", $platform_wechat_config['mchId'], "乔善英", "HEADQUARTER"); - exit(); + //var_dump($payment); + $ret = $payment->addReceiver("MERCHANT_ID", $platform_wechat_config['mchId'], "武汉市汉阳区静好电子商务商行(个体工商户)", "HEADQUARTER"); + //exit(); $transaction_id = $payment_trade->trade_no; $out_trade_no = "PS".date("YmdHis").mt_rand(1000,9999); $receivers = [ @@ -175,40 +175,27 @@ class ProfitSharing extends Command "type" => "MERCHANT_ID", "account" => $platform_wechat_config['mchId'], "amount" => $precentPrice, - "description" => "分到商户" + "description" => "分到平台" ] ]; - - - //var_dump($receiver); - //var_dump($ret); var_dump($receivers); - //$sharing = $payment->profit_sharing->share($transaction_id, $out_trade_no, $receivers); $sharing = $payment->profitsharing($transaction_id, $out_trade_no, $receivers); var_dump($sharing); - exit; - if ($sharing['return_code'] != "SUCCESS") { - echo $order->order_id.":".$sharing['return_msg'].PHP_EOL; - continue; - } - if ($sharing['result_code'] != "SUCCESS") { - echo $order->order_id.":".$sharing['err_code_des'].PHP_EOL; - continue; - } - var_dump($sharing); - var_dump($sharing->return_code); - var_dump($sharing->result_code); - exit(); + //更新 $ret = Order::where('order_id',$order->order_id)->update(['profitsharing_status' => 1, 'profitsharing_time' => time(),'out_order_no' => $out_trade_no]); echo "微信支付分账中".PHP_EOL; var_dump($ret); } + } catch (\Exception $e) { + Log::append('微信支付分账失败', [$order->order_id.":".$e->getMessage()]); + echo $order->order_id.":".$e->getMessage(); + $ret = Order::where('order_id',$order->order_id)->update(['profitsharing_status' => 3, 'profitsharing_time' => time(),'out_order_no' => $out_trade_no]); + continue; } - } catch (Exception $e) { - } + } diff --git a/app/command/ProfitSharingResult.php b/app/command/ProfitSharingResult.php index 9c511f5e..cca1ec2b 100644 --- a/app/command/ProfitSharingResult.php +++ b/app/command/ProfitSharingResult.php @@ -18,7 +18,8 @@ use app\common\model\PaymentTemplate; use app\common\model\Payment; use app\common\model\PaymentTrade; use app\common\model\wxapp\Setting; - +use app\common\enum\Client as ClientEnum; +use app\common\library\payment\Facade as PaymentFacade; // /www/server/php/74/bin/php /server/wwwroot/yanzong/think test class ProfitSharingResult extends Command @@ -43,7 +44,7 @@ class ProfitSharingResult extends Command $where[] = ['is_delete','=', 0]; $where[] = ['profitsharing_status','=', 1]; $where[] = ['merchant_id','>', 0]; - $where[] = ['method','=', PaymentMethodEnum::WECHAT]; + $where[] = ['pay_method','=', PaymentMethodEnum::WECHAT]; } $orders = Order::where($where) @@ -52,68 +53,69 @@ class ProfitSharingResult extends Command // var_dump($orders->toArray()); // exit(); if ($orders->isEmpty()) { - echo $store['store_id']."没有已完成的订单要分账".PHP_EOL; + echo "没有已完成的订单要分账".PHP_EOL; return false; } //微信支付订单抽佣给平台、余额支付抽佣给平台,把订单金额记录到商户账上 foreach ($orders as $order) { - //商户微信支付配置 - $payment = Payment::where('store_id', $order->store_id)->where('merchant_id', $order->merchant_id)->where('method',PaymentMethodEnum::WECHAT)->where('is_enable', 1)->find(); - if (!$payment) { - echo $store['store_id']."微信支付方式没有配置".PHP_EOL; - continue; - } - $payment_template = PaymentTemplate::where('template_id', $payment->template_id)->where('is_delete', 1)->find(); - if (!$payment_template) { - echo $store['store_id'].$payment->template_id."微信支付模版没有配置".PHP_EOL; - continue; - } - $wechat_config = $payment_template['config'] ? json_decode($payment_template['config'], true) : []; - if (!$wechat_config) { - echo $store['store_id'].$payment->template_id."微信支付模版没有配置11".PHP_EOL; - continue; - } - $wechat_config = $wechat_config['wechat']['normal'] ?? []; - //小程序配置 - $mini = Setting::where('store_id', $order->store_id)->find(); - if (!$mini) { - echo $store['store_id']."小程序配置没有".PHP_EOL; - continue; - } - $mini_config = $mini['values'] ? json_decode($mini['config'], true) : []; - if (!$mini_config) { - echo $store['store_id'].$payment->template_id."微信支付模版没有配置11".PHP_EOL; - continue; - } - //分账 - $config = [ - 'app_id' => $mini_config['app_id'], - "secret" => $mini_config['app_secret'], - 'mch_id' => $wechat_config['mchId'], - 'key' => $wechat_config['apiKey'], - 'cert_path' => PaymentTemplateModel::realPathCertFile(PaymentMethodEnum::WECHAT, $wechat_config['apiclientCert'], $order->store_id), - 'key_path' => PaymentTemplateModel::realPathCertFile(PaymentMethodEnum::WECHAT, $wechat_config['apiclientKey'], $order->store_id), - 'notify_url' => '', - ]; - $payment = Factory::payment($config); - - + try { + //商户微信支付配置 + $payment = Payment::where('store_id', $order->store_id)->where('merchant_id', $order->merchant_id)->where('method',PaymentMethodEnum::WECHAT)->where('is_enable', 1)->find(); + if (!$payment) { + echo $order['store_id']."微信支付方式没有配置".PHP_EOL; + continue; + } + $payment_template = PaymentTemplate::where('template_id', $payment->template_id)->where('is_delete', 1)->find(); + if (!$payment_template) { + echo $order['store_id'].$payment->template_id."微信支付模版没有配置".PHP_EOL; + continue; + } + $wechat_config = $payment_template['config'] ? json_decode($payment_template['config'], true) : []; + if (!$wechat_config) { + echo $order['store_id'].$payment->template_id."微信支付模版没有配置11".PHP_EOL; + continue; + } + $wechat_config = $wechat_config['wechat']['normal'] ?? []; + //小程序配置 + $mini = Setting::where('store_id', $order->store_id)->find(); + if (!$mini) { + echo $order['store_id']."小程序配置没有".PHP_EOL; + continue; + } + $mini_config = $mini['values'] ? json_decode($mini['config'], true) : []; + if (!$mini_config) { + echo $order['store_id'].$payment->template_id."微信支付模版没有配置11".PHP_EOL; + continue; + } + //分账 + //支付信息初始化 + $PaymentModel = new Payment; + $templateInfo = $PaymentModel->getPaymentInfo(PaymentMethodEnum::WECHAT, ClientEnum::MP_WEIXIN, $order->store_id, $order->merchant_id); + $options = $templateInfo['template']['config'][PaymentMethodEnum::WECHAT]; + $payment = PaymentFacade::store(PaymentMethodEnum::WECHAT)->setOptions($options, ClientEnum::MP_WEIXIN); + + - $payment_trade = PaymentTrade::where('trade_id', $order->trade_id)->field('trade_no')->find(); - if (!$payment_trade) { - echo $store['store_id']."没有交易流水号".PHP_EOL; + $payment_trade = PaymentTrade::where('trade_id', $order->trade_id)->field('trade_no')->find(); + if (!$payment_trade) { + echo $order['store_id']."没有交易流水号".PHP_EOL; + continue; + } + $transaction_id = $payment_trade->trade_no; + $sharing = $payment->profitsharingQuery($order->out_order_no, $transaction_id); + var_dump($sharing); + var_dump($sharing->return_code); + var_dump($sharing->result_code); + //更新 + $ret = Order::where('order_id',$order->order_id)->update(['profitsharing_status' => 2, 'profitsharing_time' => time()]); + echo "微信支付分账结果".PHP_EOL; + var_dump($ret); + } catch (\Exception $e) { + echo $e->getMessage(); continue; } - $transaction_id = $payment_trade->trade_no; - $sharing = $payment->profit_sharing->query($transaction_id,$order->out_order_no); - var_dump($sharing); - var_dump($sharing->return_code); - var_dump($sharing->result_code); - //更新 - $ret = Order::where('order_id',$order->order_id)->update(['profitsharing_status' => 2, 'profitsharing_time' => time()]); - echo "微信支付分账结果".PHP_EOL; - var_dump($ret); + } diff --git a/app/common/library/payment/gateway/Driver.php b/app/common/library/payment/gateway/Driver.php index d37995b4..bb3612c5 100644 --- a/app/common/library/payment/gateway/Driver.php +++ b/app/common/library/payment/gateway/Driver.php @@ -67,6 +67,9 @@ abstract class Driver abstract public function profitsharing(string $transaction_id, string $out_order_no, array $receivers): bool; + abstract public function profitsharingQuery(string $out_order_no, string $transaction_id): ?array; + + abstract public function unify(string $outTradeNo, string $totalFee, array $extra = []): bool; /** @@ -77,6 +80,7 @@ abstract class Driver */ abstract public function tradeQuery(string $outTradeNo): ?array; + /** * 获取异步回调的请求参数 * @return array diff --git a/app/common/library/payment/gateway/driver/Wechat.php b/app/common/library/payment/gateway/driver/Wechat.php index fa516eb3..ee2eaebe 100644 --- a/app/common/library/payment/gateway/driver/Wechat.php +++ b/app/common/library/payment/gateway/driver/Wechat.php @@ -80,6 +80,9 @@ class Wechat extends Driver } return true; } + public function profitsharingQuery(string $out_order_no, string $transaction_id): ?array{ + return $this->getApp()->profitsharingQuery($out_order_no, $transaction_id); + } /** * 统一下单API * @param string $outTradeNo 交易订单号 diff --git a/app/common/library/payment/gateway/driver/wechat/V3.php b/app/common/library/payment/gateway/driver/wechat/V3.php index c28c24b7..e5b93aa6 100644 --- a/app/common/library/payment/gateway/driver/wechat/V3.php +++ b/app/common/library/payment/gateway/driver/wechat/V3.php @@ -63,6 +63,15 @@ class V3 $this->config = $this->getConfig($options); return $this; } + /** + * 微信分账-添加分账人 + * [addReceiver description] + * @param string $type [description] + * @param string $account [description] + * @param string $name [description] + * @param string $relation_type [description] + * @param string $custom_relation [description] + */ public function addReceiver(string $type, string $account, string $name, string $relation_type = "HEADQUARTER", string $custom_relation = ""): bool{ //是否解冻剩余未分资金,暂时请求分账即解冻,后续可看需求调整 $unfreeze_unsplit = true; @@ -70,7 +79,7 @@ class V3 $params = [ 'type' => $type, 'account' => $account, - 'name' => $name, + 'name' => $this->getEncrypt($name), 'relation_type' => $relation_type, //'custom_relation' => $custom_relation, ]; @@ -83,7 +92,7 @@ class V3 $params['sub_mchid'] = $this->config['sub_mchid']; } else { $params['appid'] = $this->config['app_id']; - $params['mchid'] = $this->config['mch_id']; + //$params['mchid'] = $this->config['mch_id']; } try { @@ -91,10 +100,10 @@ class V3 // Doc: https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_1.shtml $resp = $this->getApp() ->chain($this->getAddReceiverUrl()) - ->post(['json' => $params]); + ->post(['json' => $params,'headers' => ['Accept' => 'application/json','Wechatpay-Serial' => $this->platformCertificateSerial]]); // 记录api返回的数据 $unifyResult = helper::jsonDecode((string)$resp->getBody()); - var_dump($unifyResult);exit; + //var_dump($unifyResult);exit; return true; } catch (\Throwable $e) { // 异常处理 @@ -103,15 +112,21 @@ class V3 } return false; } + /** + * 微信发起分账 + * [profitsharing description] + * @param string $transaction_id [description] + * @param string $out_order_no [description] + * @param array $receivers [description] + * @return [type] [description] + */ public function profitsharing(string $transaction_id, string $out_order_no, array $receivers): bool{ - //是否解冻剩余未分资金,暂时请求分账即解冻,后续可看需求调整 - $unfreeze_unsplit = true; // 下单的参数 $params = [ 'out_order_no' => $out_order_no, 'transaction_id' => $transaction_id, 'receivers' => $receivers, - 'unfreeze_unsplit' => $unfreeze_unsplit, + 'unfreeze_unsplit' => true, ]; // 普通商户参数和服务商支付参数 @@ -133,7 +148,8 @@ class V3 ->post(['json' => $params]); // 记录api返回的数据 $unifyResult = helper::jsonDecode((string)$resp->getBody()); - var_dump($unifyResult);exit; + var_dump($unifyResult); + //exit; return true; } catch (\Throwable $e) { // 异常处理 @@ -142,6 +158,34 @@ class V3 } return false; } + /** + * 分账查询 + * [profitsharingQuery description] + * @param string $out_order_no [description] + * @param string $transaction_id [description] + * @return [type] [description] + */ + public function profitsharingQuery(string $out_order_no, string $transaction_id): ?array + { + // 下单的参数 + $params = ['transaction_id' => $transaction_id]; + + try { + $resp = $this->getApp() + ->chain($this->getProfitUrl()."/".$out_order_no) + ->get(['query' => $params]); + // 记录api返回的数据 + $result = helper::jsonDecode((string)$resp->getBody()); + var_dump($result); + // 判断订单支付成功 + return $result; + } catch (\Throwable $e) { + // 异常处理 + $message = $this->getThrowMessage($e); + $this->throwError('tradeQuery', "微信支付交易查询失败:{$message}"); + } + return null; + } /** * 统一下单API * @param string $outTradeNo 交易订单号 @@ -158,8 +202,11 @@ class V3 'description' => '线上商城商品', 'notify_url' => $this->notifyUrl(), // 支付结果异步通知地址 'amount' => ['total' => (int)helper::bcmul($totalFee, 100), 'currency' => 'CNY'], - 'scene_info' => ['payer_client_ip' => \request()->ip()] + 'scene_info' => ['payer_client_ip' => \request()->ip()], + 'settle_info' => ['profit_sharing' => $extra['profit_sharing'] ?? false],//是否指定分账 ]; + // var_dump($params); + // exit(); // 普通商户参数和服务商支付参数 if ($this->isProvider()) { $params['sp_appid'] = $this->config['app_id']; @@ -511,7 +558,9 @@ class V3 // 从「微信支付平台证书」中获取「证书序列号」 $platformCertificateSerial = PemUtil::parseCertificateSerialNo($platformCertificateFilePath); - + //设置类属性 + $this->platformCertificateSerial = $platformCertificateSerial; + // 构造一个 APIv3 客户端实例 return Builder::factory([ // 微信支付商户号 @@ -585,6 +634,25 @@ class V3 ]; } } + /** + * 平台私密信息加密算法 + * [getEncrypt description] + * @param [type] $str [description] + * @return [type] [description] + */ + private function getEncrypt($str) { + //$str是待加密字符串 + $public_key_path = $this->config['platform_cert_path']; + $public_key = file_get_contents($public_key_path); + $encrypted = ''; + if (openssl_public_encrypt($str, $encrypted, $public_key, OPENSSL_PKCS1_OAEP_PADDING)) { + //base64编码 + $sign = base64_encode($encrypted); + } else { + throw new Exception('encrypt failed'); + } + return $sign; + } /** * 异步回调地址