<?php namespace App\Models; use App\Command\Log; use EasyWeChat\Factory; use Illuminate\Support\Facades\DB; use App\Models\Good as GoodModel; use App\Models\GoodSku; use Exception; use NwVVVS\AdapayCore\AdaPay\Payment; use App\Models\OrderGoods; use App\Models\OrderInfo; use App\Models\UserPointChangeRec; class Adapay { public const APP_ID = 'app_c383f483-3c2a-41b6-8d21-7f597dde4c50'; public function __construct() { /** * 商户接入AdaPay SDK时需要设置的初始化参数 * 设置配置从配置文件读取 */ \NwVVVS\AdapayCore\AdaPay::init(dirname(__FILE__) . "/../../config/merchantConfig.json", "test"); } //支付 public function pay($order_title, $order_sn, $order_amount, $openid) { $payment = new \NwVVVS\AdapaySdk\Payment(); # 支付设置 $payment_params = [ "app_id" => Adapay::APP_ID, "order_no" => $order_sn, "pay_channel" => "wx_lite", "pay_mode" => "delay", "time_expire" => date('YmdHis', time() + 300), "pay_amt" => $order_amount, "goods_title" => $order_title, "goods_desc" => $order_title, "description" => "", "notify_url" => env('API_URL') . '/pay-notify', "expend" => [ "open_id" => $openid ] ]; # 发起支付 $payment->create($payment_params); # 对支付结果进行处理 Log::add('--调起支付--', $payment->result); if ($payment->isError()) { //失败处理 throw new \Exception($payment->result['error_msg']); } else { //成功处理 Log::add('--支付参数--', json_decode($payment->result['expend']['pay_info'], true)); $item = json_decode($payment->result['expend']['pay_info'], true); $item['timestamp'] = $item['timeStamp']; return $item; } } //支付回调-分账--》改成冻结,7天后解冻分账 public function payNotify($params = []) { $adapay_tools = new \NwVVVS\AdapaySdk\AdapayTools(); //验证签名 $post_data = json_decode($params['data'], 1); $post_data_str = json_encode($post_data, JSON_UNESCAPED_UNICODE); $post_sign_str = isset($params['sign']) ? $params['sign'] : ''; # 先校验签名和返回的数据的签名的数据是否一致 $sign_flag = $adapay_tools->verifySign($post_data_str, $post_sign_str); if (!$sign_flag) { Log::add('支付签名验证失败', []); return false; } $message = $post_data; $order_no = $message['order_no']; $orderObj = OrderInfo::where(['order_sn' => $order_no])->first(); if (!$orderObj) { Log::add('订单不存在', [$order_no]); return false; } //支付完成后通知 if ($message['status'] == "succeeded" && $orderObj->pay_status == 0) { DB::beginTransaction(); try { //更新订单 if ($orderObj->pay_status == 0) { $orderObj->order_status = 1; $orderObj->pay_status = 1; $orderObj->freeze_stat = $message['freeze_stat']; if ($orderObj->save()) { if ($orderObj->pay_type=1) {//纯现金支付才返积分 //创建直推分积分记录 $this->createPointRecordByOrder($orderObj->id); } //更新商品销量、库存 $this->updateGoodsStock($orderObj); // //更新商品销量、库存 // $goodsList = OrderGoods::where("order_id", $orderObj->id)->get(); // foreach ($goodsList as $item) { // //Log::add('--订单商品对象--', $item); // $gid = $item->goods_id; // $attr_id = $item->attr_id; // $mer_id = $item->merchant_id; // $goods_number = $item->goods_number; // //更新此商品支付状态 // $item->is_pay = 1; // $item->save(); // $goodsObj = GoodModel::find($gid); // //更新商品规格库存 // $attrObj = GoodSku::find($attr_id); // $attr_stock = ($attrObj->stock - $goods_number) >= 0 ? $attrObj->stock - $goods_number : 0; // $attrObj->stock = $attr_stock; // $attrObj->save(); // //更新商品sku // $skuArr = json_decode($goodsObj->sku, true); // if ($skuArr['sku']) { // foreach ($skuArr['sku'] as $kk => $vv) { // if (isset($vv['attr_sn']) && $vv['attr_sn'] == $attrObj->attr_sn) { // $skuArr['sku'][$kk]['stock'] = $attr_stock; // } // } // $goodsObj->sku = json_encode($skuArr, JSON_UNESCAPED_UNICODE); // $goodsObj->save(); // } // //商户规格库存 // $mgsObj = MerchantGoodSku::where(['goods_id' => $gid, 'attr_id' => $attr_id, 'merchant_id' => $mer_id])->first(); // if ($mer_id && $mgsObj) { // $changeStock = ($mgsObj->stock >= $goods_number) ? $mgsObj->stock - $goods_number : 0; // $mgsObj->stock = $changeStock; // $mgsObj->save(); // } // } } } //支付记录 // 创建新的PaymentRecord对象 $pay_cord = new PaymentRecord(); // 查询是否已存在相同order_sn的支付记录 $cordLog = $pay_cord->where(['order_sn' => $message['order_no']])->first(); // 如果不存在记录,则创建新记录 if (!$cordLog) { // 设置支付记录的各项属性 $pay_cord->order_sn = $message['order_no']; // 订单号 $pay_cord->other_order = $message['out_trans_id']; // 外部交易ID $pay_cord->payment_id = $message['id']; // 支付ID $pay_cord->party_order_id = $message['party_order_id']; // 合作方订单ID $pay_cord->money = $message['real_amt']; // 实际支付金额 $pay_cord->uid = $orderObj->user_id; // 用户ID // 保存支付记录到数据库 $pay_cord->save(); } DB::commit(); } catch (\Exception $e) { Log::add('付款回调失败', $e); DB::rollBack(); return false; } } //解冻通知 $freeze_stat = $message['freeze_stat'] ?? ''; if ($message['status'] == "succeeded" && $orderObj->freeze_stat == 'FREEZE') { if ($freeze_stat != 'UNFREEZE') { return false; } $orderObj->freeze_stat = 'UNFREEZE'; $orderObj->save(); // 调用汇付接口分账-6天后在解冻分账--》【改到updateOrderStatusToDiv里面去了】 //$this->handlePaymentConfirmAndDivide($order_no, $orderObj, $payment_confirm); } return true; } //创建支付确认 public function createPaymentConfirm($payment_params) { $payment = new \NwVVVS\AdapaySdk\PaymentConfirm(); # 发起支付确认创建 $payment->create($payment_params); # 对支付确认创建结果进行处理 if ($payment->isError()) { //失败处理 Log::add('支付确认返回结果,失败', $payment->result); throw new Exception($payment->result['error_msg']); } else { //成功处理 Log::add('支付确认返回结果,成功', $payment->result); return $payment->result; } } //查询支付对象列表 public function queryList($payment_params) { $payment = new \NwVVVS\AdapaySdk\Payment(); $payment->queryList($payment_params); # 对支付结果进行处理 if ($payment->isError()) { //失败处理 echo "<pre>"; print_r($payment->result); } else { //成功处理 echo "<pre>"; print_r($payment->result); die; } } //退款 public function refund($order_sn, $refund_no) { #初始化退款对象 $payment = new \NwVVVS\AdapaySdk\PaymentReverse(); $payLog = PaymentRecord::where('order_sn', $order_sn)->first(); $payment_params = array( # 支付对象ID "payment_id" => $payLog->payment_id, # 商户app_id "app_id" => Adapay::APP_ID, # 撤销订单号 "order_no" => $refund_no, # 撤销金额 "reverse_amt" => $payLog->money, # 通知地址 "notify_url" => env('API_URL') . '/refund-notify', # 撤销原因 "reason" => "取消订单", # 扩展域 "expand" => "", # 设备信息 "device_info" => "", ); # 发起支付撤销 $payment->create($payment_params); # 对支付撤销结果进行处理 if ($payment->isError()) { //失败处理 Log::add('撤销失败', $payment->result); $msg = isset($payment->result['error_msg']) ? $payment->result['error_msg'] : '撤销失败'; throw new \Exception($msg); } $result = $payment->result; Log::add('撤销成功', $result); //系统订单信息 $orderObj = OrderInfo::where("order_sn", $order_sn)->first(); //退款记录 $refund_cord = new RefundRecord(); $cordLog = $refund_cord->where(['refund_no' => $result['order_no']])->first(); if (!$cordLog) { $refund_cord->order_sn = $order_sn; $refund_cord->refund_no = $result['order_no']; $refund_cord->payment_id = $result['id']; $refund_cord->money = $result['reverse_amt']; $refund_cord->uid = $orderObj->user_id; $refund_cord->save(); } return true; } //退款回调 public function refundNotify($params) { $adapay_tools = new \NwVVVS\AdapaySdk\AdapayTools(); $post_data = json_decode($params['data'], 1); $post_data_str = json_encode($post_data, JSON_UNESCAPED_UNICODE); $post_sign_str = isset($params['sign']) ? $params['sign'] : ''; # 先校验签名和返回的数据的签名的数据是否一致 $sign_flag = $adapay_tools->verifySign($post_data_str, $post_sign_str); if (!$sign_flag) { //Log::add('退款签名验证失败', []); //return false; } $message = $post_data; $recordObj = RefundRecord::where(['refund_no' => $message['order_no'], 'payment_id' => $message['id']])->first(); if (!$recordObj) { Log::add('退单记录不存在', [$message['order_no']]); return false; } if ($message['status'] == 'succeeded') { $recordObj->status = 1; $recordObj->save(); return true; } return false; } //创建个人用户 public function createMember($uid, $phone) { $member = new \NwVVVS\AdapaySdk\Member(); $member_params = array( # app_id "app_id" => Adapay::APP_ID, # 用户id "member_id" => "mm_" . $uid, # 用户手机号 "tel_no" => $phone, ); # 创建 $member->create($member_params); # 对创建用户对象结果进行处理 if ($member->isError()) { //失败处理 Log::add('创建用户失败-' . $uid, $member->result); return $member->result; } else { //成功处理 Log::add('创建用户成功', $member->result); return $member->result; } } //创建企业用户 public function createCompany($member_params) { $member = new \NwVVVS\AdapaySdk\CorpMember(); # 创建企业用户 $member->create($member_params); # 对创建企业用户结果进行处理 if ($member->isError()) { //失败处理 return $member->result; } else { //成功处理 return $member->result; } } //创建结算对象 public function createMemberSettleAccount($account_params) { $account = new \NwVVVS\AdapaySdk\SettleAccount(); # 创建结算账户 $account->create($account_params); # 对创建结算账户结果进行处理 if ($account->isError()) { //失败处理 Log::add('创建用户结算账户失败', $account->result); return $account->result; } else { //成功处理 Log::add('创建用户结算账户成功', $account->result); return $account->result; } } //删除结算账户 public function deleteSettleAccount($account_params) { $account = new \NwVVVS\AdapaySdk\SettleAccount(); # 结算账户 $account->delete($account_params); # 对删除结算账户结果进行处理 if ($account->isError()) { //失败处理 return $account->result; } else { //成功处理 return $account->result; } } //查询账户余额 public function queryBalance($account_params) { $account = new \NwVVVS\AdapaySdk\SettleAccount(); # 查询账户余额 $account->balance($account_params); # 对查询账户余额结果进行处理 if ($account->isError()) { //失败处理 return $account->result; } else { //成功处理 return $account->result; } } // //手动分账修复错误数据--【转移到:OrderDivideRecordController::manualDivide】 // public function queryBalance($account_params) // { // $account = new \NwVVVS\AdapaySdk\SettleAccount(); // # 查询账户余额 // $account->balance($account_params); // # 对查询账户余额结果进行处理 // if ($account->isError()) { // //失败处理 // return $account->result; // } else { // //成功处理 // return $account->result; // } // } /** * 处理支付确认和分账逻辑 * @param string $order_no 订单号 * @param OrderInfo $orderObj 订单对象 * @param \NwVVVS\AdapaySdk\PaymentConfirm $payment_confirm 支付确认对象 * @return bool 处理结果 * @throws Exception 处理失败时抛出异常 */ public static function handlePaymentConfirmAndDivide($order_no, $order_id) { $payment_confirm = new \NwVVVS\AdapaySdk\PaymentConfirm(); //支付确认 //交易记录 $prObj = PaymentRecord::where('order_sn', $order_no)->first(); # 支付确认参数设置 $payment_params = array( "payment_id" => $prObj->payment_id, "order_no" => 'payconfirm_' . date("YmdHis") . rand(100000, 999999), "confirm_amt" => $prObj->money, "description" => "", "div_members" => "" //分账参数列表 默认是数组List ); DB::beginTransaction(); try { //分账列表 $divResult = OrderDivideRecord::divide($order_id, $payment_params['order_no']); //返回分账参数列表 $payment_params['div_members'] = $divResult['div_members']; $payment_params['confirm_amt'] = $divResult['confirm_amt']; Log::add('发起分账支付确认-向汇付' . $order_no, $payment_params); # 发起支付确认创建 $payment_confirm->create($payment_params); # 对支付确认创建结果进行处理 if ($payment_confirm->isError()) { //失败处理 Log::add('支付确认失败', $payment_confirm->result); $result = $payment_confirm->result; throw new Exception($result['error_msg']); } else { //成功处理 Log::add('支付确认成功', $payment_confirm->result); $result = $payment_confirm->result; if ($result['status'] == 'succeeded') { Log::add('分账成功', ['order_sn' => $order_no]); //写入支付确认信息 (new HfPayconfirm())->add($payment_params, $result['fee_amt']); } } DB::commit(); return true; } catch (\Exception $e) { Log::add('支付确认对象失败', $e->getMessage()); DB::rollBack(); return false; } } /** * 根据订单ID生成积分记录 * @param int $order_id 订单ID * @return bool 处理结果 * @throws Exception 处理失败时抛出异常 * * 功能说明: * 1. 根据订单ID获取订单信息 * 2. 获取订单关联的用户信息 * 3. 获取用户的直推和间推关系 * 4. 为相关用户创建积分记录 * * 使用示例: * Adapay::createPointRecordByOrder(123); * * 注意事项: * 1. 需要先创建UserPointRec模型类 * 2. 积分计算逻辑需要根据业务需求调整 */ public static function createPointRecordByOrder($order_id) { DB::beginTransaction(); try { // 获取订单信息 $orderObj = OrderInfo::find($order_id); if (!$orderObj) { throw new Exception('订单不存在'); } // 获取用户信息 $userObj = User::find($orderObj->user_id); if (!$userObj) { throw new Exception('用户不存在'); } // 获取直推和间推用户 $spuid = $userObj->spuid; // 直推用户ID $second_spuid = $userObj->second_spuid; // 间推用户ID //获取订单商品积分 $goodsObjList = DB::select(' SELECT log.id, log.goods_id, loi.order_amount, log.goods_price, log.goods_number, lg.first_commission, lg.second_commission, -- 计算总的一级佣金 (log.goods_number*log.goods_price * lg.first_commission)/100 AS total_first_commission, -- 计算总的二级佣金 (log.goods_number*log.goods_price * lg.second_commission)/100 AS total_second_commission FROM li_order_goods log LEFT JOIN li_order_info loi ON loi.id = log.order_id LEFT JOIN li_goods lg ON lg.id = log.goods_id WHERE loi.pay_type=1 and log.order_id = ?; ', [$order_id]); if (!$goodsObjList) { Log::add('积分记录创建失败', [ 'error' => '搜索为空', 'order_id' => $order_id ]); } // 购物车结算会有多个商品,多笔分佣,遍历商品列表,为每个商品创建积分记录 foreach ($goodsObjList as $goodsObj) { //判断直推是否存在 if ($spuid) { // 计算直推用户的积分 $total_first_commission = $goodsObj->total_first_commission; // 为直推用户创建积分记录 UserPointChangeRec::pointChangeRecord($spuid, $total_first_commission, 1, 1, 3, $order_id); // } //判断间推是否存在 if ($second_spuid) { // 计算间推用户的积分 $total_second_commission = $goodsObj->total_second_commission; // 为间推用户创建积分记录 UserPointChangeRec::pointChangeRecord($second_spuid, $total_second_commission, 1, 2, 3, $order_id); // } } DB::commit(); return true; } catch (\Exception $e) { Log::add('积分记录创建失败', [ 'error' => $e->getMessage(), 'order_id' => $order_id ]); DB::rollBack(); return false; } } /** * 根据订单对象更新商品库存 * * 功能说明: * 1. 根据订单对象获取订单商品列表 * 2. 遍历订单商品,更新商品规格库存、商品SKU库存和商户规格库存 * * 参数说明: * @param OrderInfo $orderObj 订单对象 * * 返回值说明: * @return bool 更新成功返回true,失败返回false * * 异常说明: * @throws Exception 当订单对象无效或商品不存在时抛出异常 * * 使用示例: * $order = OrderInfo::find(123); * Adapay::updateGoodsStock($order); * * 注意事项: * 1. 需要在事务中调用此方法 * 2. 会同时更新商品规格库存、商品SKU和商户规格库存 */ public static function updateGoodsStock($orderObj) { if (!$orderObj || !$orderObj->id) { throw new Exception('订单对象无效'); } $orderGoods = OrderGoods::where('order_id', $orderObj->id)->get(); if ($orderGoods->isEmpty()) { throw new Exception('订单商品不存在'); } foreach ($orderGoods as $item) { $goodsObj = GoodModel::find($item->goods_id); if (!$goodsObj) { Log::add('商品不存在', ['goods_id' => $item->goods_id]); continue; } //更新商品规格库存 $attrObj = GoodSku::find($item->attr_id); if (!$attrObj) { Log::add('商品规格不存在', ['attr_id' => $item->attr_id]); continue; } $attr_stock = ($attrObj->stock - $item->goods_number) >= 0 ? $attrObj->stock - $item->goods_number : 0; $attrObj->stock = $attr_stock; $attrObj->save(); //更新商品sku $skuArr = json_decode($goodsObj->sku, true); if ($skuArr['sku']) { foreach ($skuArr['sku'] as $kk => $vv) { if (isset($vv['attr_sn']) && $vv['attr_sn'] == $attrObj->attr_sn) { $skuArr['sku'][$kk]['stock'] = $attr_stock; } } $goodsObj->sku = json_encode($skuArr, JSON_UNESCAPED_UNICODE); $goodsObj->save(); } //商户规格库存 $mgsObj = MerchantGoodSku::where([ 'goods_id' => $item->goods_id, 'attr_id' => $item->attr_id, 'merchant_id' => $orderObj->merchant_id ])->first(); if ($orderObj->merchant_id && $mgsObj) { $changeStock = ($mgsObj->stock >= $item->goods_number) ? $mgsObj->stock - $item->goods_number : 0; $mgsObj->stock = $changeStock; $mgsObj->save(); } } return true; } }