| 
						 | 
						<?php
namespace App\Http\Controllers\Api;use App\Common\PayType;use App\Jobs\BalanceDue;use App\Jobs\OrderTimeout;use App\Models\AdminSetting;use App\Models\Agent;use App\Models\AgentProduct;use App\Models\AgentSetting;use App\Models\Order;use App\Models\Product;use App\Models\UserMoneyLog;use EasyWeChat\Factory;use EasyWeChat\Kernel\Exceptions\Exception;use EasyWeChat\Payment\Kernel\Exceptions\InvalidSignException;use Illuminate\Support\Facades\DB;use App\Common\OrderStatus;
class WxpayController{	//微信支付 支付结果通知网址
	public function notify()	{		$agent_id = request()->route('agent_id');//		$agent = Agent::find($agent_id);
		$setting = AdminSetting::val(['payee_appid', 'payee_mchid', 'payee_mchkey']);		if (!isset($setting['payee_appid'], $setting['payee_mchid'], $setting['payee_mchkey'])) {			return '获取系统配置失败';		}
		$config = config('wechat.payment.default');		$config = array_merge($config, [			'app_id' => $setting['payee_appid'],			'mch_id' => $setting['payee_mchid'],			'key' => $setting['payee_mchkey'],		]);		$app = Factory::payment($config);		try {			$response = $app->handlePaidNotify(function ($message, $fail) use ($agent_id) {				//仅测试用,回调记录
				DB::table('pay_debugs')->insert(['agent_id' => $agent_id, 'type' => 1, 'content' => json_encode($message)]);
//				$this->log($message);
				// 请求成功
				if ($message['return_code'] === 'SUCCESS') {					//主要是为了区分定金支付和尾款支付,订单号带有-status后缀,分割后前面才是真正的订单号
					$order_no = explode('-', $message['out_trade_no'])[0];					$order = Order::query()						->where(['order_no' => $order_no])						->first();
					//已经处理过的订单直接返回true
					if ($order && in_array($order->status, [OrderStatus::PAID, OrderStatus::PAID_RETAINAGE, OrderStatus::SUCCESS])) {						return true;					}
					//判断该微信支付订单号有没有处理过
					$exist_log = UserMoneyLog::where([						'user_id' => $order->user_id,						'order_id' => $order->id,						'type' => 1,						'transaction_id' => $message['transaction_id'],					])->first();					if ($exist_log) {						return true;					}
					// 支付成功
					if ($message['result_code'] === 'SUCCESS') {						DB::beginTransaction();						try {							//增加销量,库存在拍下时已经减了
							$agent_product = AgentProduct::find($order->agent_product_id);							$agent_product->increment('sale', $order->num);
							Product::query()								->where('id', $order->product_id)								->increment('sale', $order->num);
							$status = $order->status;							$pay_type = $order->pay_type;							$money = $message['total_fee'] / 100;							//定金支付和首付款支付
							if (in_array($pay_type, [PayType::DEPOSIT_PAY, PayType::EARNEST_PAY, PayType::DOWN_PAYMENT])) {								if ($status == OrderStatus::UNPAID) {									$order->status = OrderStatus::PAY_EARNEST;								} else if ($status == OrderStatus::PAY_EARNEST) {									$order->status = OrderStatus::PAID_RETAINAGE;									$order->verify_code = uniqid(); //生成核销码
								}							} else if ($pay_type == PayType::ONLINE) {								$order->status = OrderStatus::PAID;								$order->verify_code = uniqid(); //生成核销码
							}
							$order->paid_at = now();							$order->paid_money = DB::raw('`paid_money` + ' . $money);							//如果是已付定金,重新设置超时时间,否则清除超时时间
							if ($order->status == OrderStatus::PAY_EARNEST) {								if ($pay_type == PayType::DEPOSIT_PAY || $pay_type == PayType::EARNEST_PAY) { //订金超时
									$time = $order->prepay_timeout * 60;								}								if (empty($time)) { //默认订单超时
									$time = (AgentSetting::val($agent_id, 'order_timeout') ?? 60) * 60;								}								$order->timeout = date('Y-m-d H:i:s', time() + $time);								//订单超时
								OrderTimeout::dispatch($order->order_no,$time);								//尾款通知时间 默认为剩余三小时自动通知
								$smsEarnest = env('SMS_EARNEST',60*60*24*3);								//短信通知
								if(env('SMS_SWITCH' , '') == true && $time > $smsEarnest) {									//如果剩余时间大于三小时 在订单到期前三小时给用户发短信
									if ($time > $smsEarnest) {										BalanceDue::dispatch($order->order_no,$time - $smsEarnest);									}								}							} else {								$order->timeout = null;							}							$order->save();
							//资金流水
							UserMoneyLog::query()->create([								'user_id' => $order->user_id,								'agent_id' => $order->agent_id,								'money' => $money,								'order_id' => $order->id,								'type' => 1,								'desc' => DB::raw("LEFT('购买产品:{$order->title}', 250)"),								'transaction_id' => $message['transaction_id'], //微信支付订单号
								'created_at' => now(), //模型没有updated_at,无法自动写入时间
								'out_trade_no' => $message['out_trade_no'] ?? '',							]);
							DB::commit();							return true;						} catch (Exception $e) {							DB::rollBack();							$fail('Unknown error');						}					} // 支付失败
					else if ($message['result_code'] === 'FAIL') {						return true;					}				}
				// 希望微信重试
				$fail('Unknown error 2');			});		} catch (InvalidSignException | Exception $e) {			$this->log($e->getMessage() . $e->getFile() . $e->getLine());			return 'error';		}
		return $response;	}
	//退款通知
	public function refund()	{		$agent_id = request()->route('agent_id');//		$agent = Agent::find($agent_id);
		$setting = AdminSetting::val(['payee_appid', 'payee_mchid', 'payee_mchkey']);		if (!isset($setting['payee_appid'], $setting['payee_mchid'], $setting['payee_mchkey'])) {			return '获取系统配置失败';		}
		$config = config('wechat.payment.default');		$config = array_merge($config, [			'app_id' => $setting['payee_appid'],			'mch_id' => $setting['payee_mchid'],			'key' => $setting['payee_mchkey'],		]);		$app = Factory::payment($config);		try {			$response = $app->handleRefundedNotify(function ($message, $reqInfo, $fail) use ($agent_id) {				//仅测试用,回调记录
				DB::table('pay_debugs')->insert(['agent_id' => $agent_id, 'type' => 2, 'content' => json_encode($message)]);
				// 记录一下本地调试
//				$this->log(['message' => $message, 'reqInfo' => $reqInfo], 'refund');
				// 请求成功
				if ($message['return_code'] === 'SUCCESS') {					//主要是为了区分定金支付和尾款支付,订单号带有-status后缀,分割后前面才是真正的订单号
					$order_no = explode('-', $reqInfo['out_trade_no'])[0];					$order = Order::query()						->where(['order_no' => $order_no])						->first();
					//如果已经处理过则不再处理
					if ($order->status == OrderStatus::REFUNDED) {						return true;					}
					//如果已经存在相关的退款记录,也不再处理
					$exist_log = UserMoneyLog::where([						'user_id' => $order->user_id,						'order_id' => $order->id,						'type' => 2,						'transaction_id' => $reqInfo['transaction_id'],					])->first();					if ($exist_log) {						return true;					}
					$log = UserMoneyLog::query()						->where([							'user_id' => $order->user_id,							'order_id' => $order->id,							'type' => 1,							'transaction_id' => $reqInfo['transaction_id'],						])->first();
					if (!$log) {						$fail('找不到交易信息');					}
					// 退款成功
					if ($reqInfo['refund_status'] === 'SUCCESS') {						DB::beginTransaction();						try {							//更新订单状态为退款成功
							$order->status = OrderStatus::REFUNDED;							$order->save();							//记录日志
							UserMoneyLog::create([								'user_id' => $order->user_id,								'agent_id' => $order->agent_id,								'money' => -$reqInfo['settlement_refund_fee'] / 100,								'order_id' => $order->id,								'type' => 2,								'desc' => DB::raw("LEFT('退款:{$order->title}', 250)"),								'transaction_id' => $reqInfo['transaction_id'],								'created_at' => now(), //模型没有updated_at,无法自动写入时间
							]);
							// 退库存
							Product::query()								->where('id', $order->product_id)								->increment('stock', $order->num);
							DB::commit();							return true;						} catch (\Exception $e) {							DB::rollBack();							$fail('Unknown error');						}					}				}
				$fail('Unknown error 2');			});		} catch (Exception $e) {			$this->log($e->getMessage() . $e->getFile() . $e->getLine());			return 'error';		}
		return $response;	}
	//保存消息,用于调试
	private function log($write_data, $type = 'notify')	{		$dir = storage_path('wxpay');		if (!is_dir($dir)) {			mkdir($dir);		}		$filename = $dir . '/' . $type . '_' . date('Y-m-d-H') . '.log';		$data = '[' . date('Y-m-d H:i:s') . ']' . PHP_EOL;		$data .= '[message]: ' . (is_array($write_data) ? json_encode($write_data) : $write_data) . PHP_EOL . PHP_EOL;		file_put_contents($filename, $data, FILE_APPEND);	}}
  |