作者 李宇航

合并分支 'master-server' 到 'master'

Master server



查看合并请求 !992
... ... @@ -35,7 +35,7 @@ class PayStripeApi
];
// 构造函数设置密钥
public function __construct($secretKey)
public function __construct()
{
$this->secretKey = 'sk_test_51MyseXIWCYVeLww1tbPZzRe1Qk4lS5d2VLiDjpju7G0ToiX1RJcFinQXNlftq9eCjZE0n2gjaz1mfy1g0mxTusdf00m636Gv62';
}
... ... @@ -79,13 +79,13 @@ class PayStripeApi
* @method :post
* @time :2024/12/24 10:38
*/
public function createPaymentIntent($amount, $currency = 'usd')
public function createPaymentIntent($amount, $currency = 'usd', $paymentMethodTypes = 'card')
{
$url = "https://api.stripe.com/v1/payment_intents";
$data = [
'amount' => $amount,
'currency' => $currency,
'payment_method_types[]' => $this->currency_types[$currency],
'payment_method_types[]' => $paymentMethodTypes,
];
return $this->sendRequest($url, 'POST', $data);
}
... ... @@ -104,87 +104,6 @@ class PayStripeApi
}
/**
* @remark :创建客户
* @name :createCustomer
* @author :lyh
* @method :post
* @time :2024/12/24 10:41
*/
public function createCustomer($name, $email, $description = '')
{
$url = "https://api.stripe.com/v1/customers";
$data = [
'name' => $name,
'email' => $email,
'description' => $description
];
return $this->sendRequest($url, 'POST', $data);
}
/**
* @remark :查询客户
* @name :retrieveCustomer
* @author :lyh
* @method :post
* @time :2024/12/24 10:41
*/
public function retrieveCustomer($customerId)
{
$url = "https://api.stripe.com/v1/customers/{$customerId}";
return $this->sendRequest($url, 'GET');
}
/**
* @remark :删除客户
* @name :deleteCustomer
* @author :lyh
* @method :post
* @time :2024/12/24 10:42
*/
public function deleteCustomer($customerId)
{
$url = "https://api.stripe.com/v1/customers/{$customerId}";
return $this->sendRequest($url, 'DELETE');
}
/**
* @remark :创建支付方法
* @name :createPaymentMethod
* @author :lyh
* @method :post
* @time :2024/12/24 10:42
*/
public function createPaymentMethod($cardNumber, $expMonth, $expYear, $cvc)
{
$url = "https://api.stripe.com/v1/payment_methods";
$data = [
'type' => 'card',
'card[number]' => $cardNumber,
'card[exp_month]' => $expMonth,
'card[exp_year]' => $expYear,
'card[cvc]' => $cvc,
];
return $this->sendRequest($url, 'POST', $data);
}
/**
* @remark :绑定支付方法到客户
* @name :attachPaymentMethodToCustomer
* @author :lyh
* @method :post
* @time :2024/12/24 10:42
*/
public function attachPaymentMethodToCustomer($paymentMethodId, $customerId)
{
$url = "https://api.stripe.com/v1/payment_methods/{$paymentMethodId}/attach";
$data = [
'customer' => $customerId,
];
return $this->sendRequest($url, 'POST', $data);
}
/**
* @remark :创建退款
* @name :createRefund
* @author :lyh
... ... @@ -198,7 +117,6 @@ class PayStripeApi
if ($amount) {
$data['amount'] = $amount;
}
return $this->sendRequest($url, 'POST', $data);
}
... ... @@ -216,50 +134,89 @@ class PayStripeApi
}
/**
* @remark :创建订阅
* @name :createSubscription
* @author :lyh
* @method :post
* @time :2024/12/24 10:42
*/
public function createSubscription($customerId, $priceId)
{
$url = "https://api.stripe.com/v1/subscriptions";
$data = [
'customer' => $customerId,
'items[0][price]' => $priceId,
];
return $this->sendRequest($url, 'POST', $data);
}
/**
* @remark :取消订阅
* @name :cancelSubscription
* @remark :处理 Webhook
* @name :handleWebhook
* @author :lyh
* @method :post
* @time :2024/12/24 10:43
*/
public function cancelSubscription($subscriptionId)
public static function handleWebhook()
{
$url = "https://api.stripe.com/v1/subscriptions/{$subscriptionId}";
return $this->sendRequest($url, 'DELETE');
try {
// Webhook 签名密钥(从 Stripe 仪表盘获取)
$endpointSecret = 'whsec_garhW2TrCIrduyM3rve9mFS2sn69B9Yt';
// 获取原始请求内容
$payload = request()->getContent();
// 获取 Stripe 签名头
$sigHeader = request()->header('Stripe-Signature');
// 验证签名
if (!self::verifySignature($payload, $sigHeader, $endpointSecret)) {
return [
'code' => '201',
'message' => 'Invalid signature',
'details' => [
'payload' => $payload,
'sigHeader' => $sigHeader,
'endpointSecret' => $endpointSecret,
],
]; // 返回 400 Bad Request 状态码;
}
$event = json_decode($payload, true);
// 获取事件类型
$eventType = $event['type'];
$eventData = $event['data']['object'];
// 根据事件类型处理
switch ($eventType) {
case 'payment_intent.succeeded':
// 处理支付成功逻辑
@file_put_contents(storage_path('logs/lyh_error.log'), var_export('success', true) . PHP_EOL, FILE_APPEND);
@file_put_contents(storage_path('logs/lyh_error.log'), var_export($eventType, true) . PHP_EOL, FILE_APPEND);
@file_put_contents(storage_path('logs/lyh_error.log'), var_export($eventData, true) . PHP_EOL, FILE_APPEND);
$paymentIntentId = $eventData['id'];
break;
case 'payment_intent.payment_failed':
// 处理支付失败逻辑
$error = $eventData['last_payment_error'];
break;
case 'charge.refunded':
// 处理退款逻辑
$chargeId = $eventData['id'];
break;
default:
throw new \Exception('Unhandled event type: ' . $eventType);
}
return $event;
} catch (Exception $e) {
throw new \Exception('Webhook Error: ' . $e->getMessage());
}
}
/**
* @remark :处理 Webhook
* @name :handleWebhook
* @remark :验证签名
* @name :verifySignature
* @author :lyh
* @method :post
* @time :2024/12/24 10:43
* @time :2024/12/24 15:55
*/
public static function handleWebhook($payload, $sigHeader, $endpointSecret)
public static function verifySignature($payload, $sigHeader, $endpointSecret)
{
try {
$event = json_decode($payload, true);
// 检查事件类型
return $event; // 返回解析后的事件
} catch (Exception $e) {
throw new Exception('Webhook Error: ' . $e->getMessage());
// 解析 Signature Header,获取 timestamp 和签名
if (!preg_match('/t=(\d+),v1=([a-f0-9]+)/', $sigHeader, $matches)) {
return false; // 签名格式错误
}
$timestamp = $matches[1]; // 提取时间戳
$receivedSignature = $matches[2]; // 提取签名
// 防止重放攻击:检查时间戳是否在 5 分钟以内
$currentTimestamp = time();
if (abs($currentTimestamp - $timestamp) > 300) {
return false; // 签名过期
}
// 计算预期签名
$signedPayload = "{$timestamp}.{$payload}";
$expectedSignature = hash_hmac('sha256', $signedPayload, $endpointSecret);
// 比较签名是否匹配
return hash_equals($expectedSignature, $receivedSignature);
}
}
... ...
<?php
/**
* @remark :
* @name :PayStripeController.php
* @author :lyh
* @method :post
* @time :2024/12/24 16:42
*/
namespace App\Http\Controllers\Api;
use App\Enums\Common\Code;
use App\Helper\PayStripeApi;
class PayStripeController extends BaseController
{
/**
* @remark :回调方法
* @name :handleWebhook
* @author :lyh
* @method :post
* @time :2024/12/24 15:41
*/
public function handleWebhook(){
$pay = new PayStripeApi();
$data = $pay->handleWebhook();
$this->response('success',Code::SUCCESS,$data);
}
}
... ...
<?php
/**
* @remark :
* @name :Extension3059ModuleController.php
* @author :lyh
* @method :post
* @time :2024/12/25 9:44
*/
namespace App\Http\Controllers\Bside\ExtensionModule;
use App\Enums\Common\Code;
use App\Helper\PayStripeApi;
use App\Http\Controllers\Bside\BaseController;
use App\Models\ExtentModule\ExtensionModuleValue;
class Extension3059ModuleController extends BaseController
{
/**
* @remark :获取当前所有的商品列表
* @name :getProductLists
* @author :lyh
* @method :post
* @time :2024/12/25 9:37
*/
public function getProductLists(){
$this->param['module_id'] = $this->param['module_id'] ?? 2;//默认加载商品数据
$searchParam = [
'module_id'=>$this->param['module_id'],
];
$data = [];
$moduleValueModel = new ExtensionModuleValue();
$lists = $moduleValueModel->list($searchParam);
if(!empty($lists)){
foreach ($lists as $k => $v){
$data[$v['uuid']][$v['field_id']] = $v['value'];
$data[$v['uuid']]['created_at'] = $v['created_at'];
}
}
$resultData = [];
foreach ($data as $k => $v){
$v['uuid'] = $k;
$resultData[] = $v;
}
$this->response('success',Code::SUCCESS,$resultData);
}
/**
* @remark :编辑订单详情
* @name :editOrderDetail
* @author :lyh
* @method :post
* @time :2024/12/25 10:26
*/
public function saveOrderDetail(){
$this->request->validate([
'data'=>'required',
'amount'=>'required',
'currency'=>'required',
'payment_method_types'=>'required',
],[
'data.required' => '数据不能为空',
'amount.required' => '金额不能为空',
'currency.required' => '币种不能为空',
'payment_method_types.required' => '支付方式不能为空',
]);
$this->param['module_id'] = 1;//默认订单模块
$moduleValueModel = new ExtensionModuleValue();
$info = $moduleValueModel->where('module_id',$this->param['module_id'])->orderBy('uuid','desc')->first();
if(empty($info)){
$uuid = 1;
}else{
$info = $info->toArray();
$uuid = $info['uuid'] + 1;
}
$saveData = [];
try {
//生成订单id
$saveData[] =['uuid'=>$uuid,'module_id'=>$this->param['module_id'],'field_id'=>1,'value'=>md5(uniqid(mt_rand(), true))];
$data = $this->param['data'];
$moduleValueModel = new ExtensionModuleValue();
foreach ($data as $k => $v){
$saveData[] = [
'uuid'=>$uuid,
'module_id'=>$this->param['module_id'],
'field_id'=>$v['field_id'],
'value'=>$v['value']
];
}
$pay = new PayStripeApi();
$data = $pay->createPaymentIntent($this->param['amount'],$this->param['currency'],$this->param['payment_method_types']);
$saveData[] = ['uuid'=>$uuid,'module_id'=>$this->param['module_id'],'field_id'=>8,'value'=>$data['id'] ?? '未获取到支付意愿,请重新获取'];
$moduleValueModel->insertAll($saveData);
}catch (\Exception $e){
$this->fail('error,请联系管理员');
}
$this->response('success',Code::SUCCESS,['uuid'=>$uuid,'data'=>$data]);
}
}
... ...
... ... @@ -185,13 +185,7 @@ class ExtensionModuleController extends BaseController
foreach ($data as $k => $v){
$info = $moduleValueModel->read(['uuid'=>$this->param['uuid'],'field_id'=>$v['field_id'],'module_id'=>$this->param['module_id']]);
if($info === false){
if($this->user['project_id'] == 2205 && $this->param['module_id'] == 1){
if($v['field_id'] == 12 && !empty($v['value'])){//下拉框数据
if($v['value'] != 'Ordered'){
$this->fail('请从第一个流程开始选择。');
}
}
}
$this->edit2205ModuleValue($v);
$data = [
'uuid'=>$this->param['uuid'],
'module_id'=>$this->param['module_id'],
... ... @@ -200,6 +194,22 @@ class ExtensionModuleController extends BaseController
];
$moduleValueModel->addReturnId($data);
}else{
$this->edit2205ModuleValue($v);
$moduleValueModel->edit(['value'=>$v['value'] ?? ''],['id'=>$info['id']]);
}
}
$this->response('success',Code::SUCCESS,['uuid'=>$this->param['uuid']]);
}
/**
* @remark :2205项目单独处理
* @name :edit2205ModuleValue
* @author :lyh
* @method :post
* @time :2024/12/25 10:12
*/
public function edit2205ModuleValue($v){
if(isset($this->param['id']) && !empty($this->param['id'])){
if($this->user['project_id'] == 2205 && $this->param['module_id'] == 1){
if($v['field_id'] == 12 && (!empty($v['value']) && !empty($info['value']))){//下拉框数据
$filedModel = new ExtensionModuleField();
... ... @@ -221,12 +231,16 @@ class ExtensionModuleController extends BaseController
}
}
}
$moduleValueModel->edit(['value'=>$v['value'] ?? ''],['id'=>$info['id']]);
}else{
if($this->user['project_id'] == 2205 && $this->param['module_id'] == 1){
if($v['field_id'] == 12 && !empty($v['value'])){//下拉框数据
if($v['value'] != 'Ordered'){
$this->fail('请从第一个流程开始选择。');
}
}
}
}
$this->response('success',Code::SUCCESS,['uuid'=>$this->param['uuid']]);
}
/**
* @remark :新增數據
... ... @@ -252,13 +266,7 @@ class ExtensionModuleController extends BaseController
$data = $this->param['data'];
$moduleValueModel = new ExtensionModuleValue();
foreach ($data as $k => $v){
if($this->user['project_id'] == 2205 && $this->param['module_id'] == 1){
if($v['field_id'] == 12 && !empty($v['value'])){//下拉框数据
if($v['value'] != 'Ordered'){
$this->fail('请重第一个流程开始选择');
}
}
}
$this->edit2205ModuleValue($v);
$data = [
'uuid'=>$uuid,
'module_id'=>$this->param['module_id'],
... ...
... ... @@ -36,7 +36,7 @@ class TestController extends BaseController
*/
public function ceshi(){
$pay = new PayStripeApi();
$data = $pay->createPaymentIntent(5000,'cny');
$data = $pay->createPaymentIntent(5000,'cny','alipay');
$this->response('success',Code::SUCCESS,$data);
}
... ...
... ... @@ -32,9 +32,9 @@ class ExtensionModuleFieldLogic extends BaseLogic
public function saveModuleField(){
//先查看当前字段是否存在
if(isset($this->param['id']) && !empty($this->param['id'])){
$info = $this->model->read(['field_name'=>$this->param['field_name'],'id'=>['!=',$this->param['id']]]);
$info = $this->model->read(['field_name'=>$this->param['field_name'],'module_id'=>$this->param['module_id'],'id'=>['!=',$this->param['id']]]);
}else{
$info = $this->model->read(['field_name'=>$this->param['field_name']]);
$info = $this->model->read(['field_name'=>$this->param['field_name'],'module_id'=>$this->param['module_id']]);
}
if($info !== false){
$this->fail('当前字段名已存在');
... ...
... ... @@ -116,6 +116,24 @@ class Base extends Model
}
/**
* @remark :批量添加数据
* @name :addAllReturnId
* @author :lyh
* @method :post
* @time :2024/12/25 11:16
*/
public function insertAll($data){
if(is_array($data)){
foreach ($data as $k => $sonData){
$sonData['created_at'] = date('Y-m-d H:i:s');
$sonData['updated_at'] = $sonData['created_at'];
$data[$k] = $sonData;
}
}
return $this->insert($data);
}
/**
* @remark :统计数量
* @name :count
* @author :lyh
... ...
... ... @@ -17,7 +17,7 @@ use Illuminate\Support\Facades\Route;
Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
return $request->user();
});
Route::any('stripeWebhook', [\App\Http\Controllers\Api\PayStripeController::class, 'handleWebhook'])->name('api.handleWebhook');
Route::any('traffic_visit', [\App\Http\Controllers\Api\NoticeController::class, 'trafficVisit'])->name('api.traffic_visit');
Route::get('optimize_project_list', [\App\Http\Controllers\Api\PrivateController::class, 'optimizeProjectList'])->name('api.optimize_project_list');
Route::get('get_project_route', [\App\Http\Controllers\Api\PrivateController::class, 'getProjectRoute'])->name('api.get_project_route');
... ...