Files
tougao/application/api/controller/Order.php
wangjinlei 3c7e25ec65 支付bug
2025-11-27 10:03:35 +08:00

463 lines
19 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
namespace app\api\controller;
use app\api\controller\Base;
use PaypalServerSdkLib\Authentication\ClientCredentialsAuthCredentialsBuilder;
use PaypalServerSdkLib\Environment;
use PaypalServerSdkLib\Models\Builders\AmountWithBreakdownBuilder;
use PaypalServerSdkLib\Models\Builders\ExperienceContextBuilder;
use PaypalServerSdkLib\Models\Builders\OrderApplicationContextBuilder;
use PaypalServerSdkLib\Models\Builders\OrderRequestBuilder;
use PaypalServerSdkLib\Models\Builders\PaymentSourceBuilder;
use PaypalServerSdkLib\Models\Builders\PaypalWalletBuilder;
use PaypalServerSdkLib\Models\Builders\PaypalWalletExperienceContextBuilder;
use PaypalServerSdkLib\Models\Builders\PurchaseUnitRequestBuilder;
use PaypalServerSdkLib\Models\PaymentSource;
use PaypalServerSdkLib\PaypalServerSdkClientBuilder;
use think\Db;
use think\db\exception\DataNotFoundException;
use think\Env;
use think\db\exception\ModelNotFoundException;
use think\Exception;
use think\Request;
use think\exception\DbException;
use think\exception\PDOException;
use think\Queue;
use think\Validate;
use think\log;
class Order extends base{
protected $PAYPAL_CLIENT_ID="ATqBigrhcNdqR8J83aDjTOoJHsAVz0U45JRY4H0stcEcv0mQrMDHQmyrydQInYd1w4lJ1ee3Wsblm2WP";
protected $PAYPAL_CLIENT_SECRET="EJL5CtykvRiMZ1apKrX4zDX03d01CuxgrUi6-D7K45NgNQAGGY0Kj0Du9tL04Zc3aDBgxgZ4JLErSQp3";
public function __construct(\think\Request $request = null)
{
parent::__construct($request);
}
public function paystationTest(){
$sn = 'TMR'.date('Ymd') . strtoupper(bin2hex(random_bytes(8)));
$accessToken = createPayStationToken();
$data_array = [
'paystation_id' => Env::get("paystation.client_id"),
'gateway_id' => "PAYSTATION",//GATEWAY_ID,
"merchant_session" => $sn,
"merchant_reference"=>$sn,
"amount" =>100,
"return_url"=>"https://www.tmrjournals.com/",
"response_url"=>"http://api.tmrjournals.com/public/index.php/api/Order/completePaystation"
];
$data = json_encode($data_array);
$purchase = postPayStationQuery('v1/hosted/purchases', $accessToken, $data);
$paystation_res = object_to_array(json_decode($purchase));
return jsonSuccess($paystation_res);
}
public function completePaystation(){
Log::log("payStation:act ".date("Y-m-d H:i:s"));
$data = $this->request->post();
if(!isset($data['transaction_id'])|| !$data['result']['success']){
return jsonError("Paystation responds with no results or result fail");
}
$tid = $data['transaction_id'];
Log::log("payStation:".$tid);
$paystation_info = $this->paystation_obj->where("transaction_id",$tid)->find();
if (!$paystation_info){
return jsonSuccess([]);
}
$order_info = $this->order_obj->where("ps_id",$paystation_info['ps_id'])->find();
$this->article_obj->where("article_id",$order_info['article_id'])->update(['is_buy'=>1]);
$this->order_obj->where("order_id",$order_info['order_id'])->update(['state'=>1]);
return jsonSuccess([]);
}
public function PaystationLookup(){
$data = $this->request->post();
$rule = new Validate([
"article_id"=>"require"
]);
if(!$rule->check($data)){
return jsonError($rule->getError());
}
$article_info = $this->article_obj->where("article_id",$data['article_id'])->find();
$order_info = $this->order_obj->where("article_id",$article_info['article_id'])->whereIn("state",[0,1])->find();
if($order_info==null){
return jsonError("no order");
}
sleep(2);
$paystation_info = $this->paystation_obj->where("ps_id",$order_info['ps_id'])->find();
$response = paystationLookup($paystation_info["merchant_session"]);
$res = xml_to_array($response);
if(isset($res['PaystationQuickLookup']['LookupResponse']['Authentication']['auth_Status'])&&$res['PaystationQuickLookup']['LookupResponse']['Authentication']['auth_Status']=="Y"){
$this->article_obj->where("article_id",$order_info['article_id'])->update(['is_buy'=>1]);
$this->order_obj->where("order_id",$order_info['order_id'])->update(['state'=>1]);
return jsonSuccess(["result"=>"success","paystation"=>$paystation_info]);
}else{
return jsonSuccess(['result'=>"fail"]);
}
}
public function testPays(){
$data = $this->request->post();
$rule = new Validate([
"ms"=>"require"
]);
if(!$rule->check($data)){
return jsonError($rule->getError());
}
$url = "https://payments.paystation.co.nz/lookup/";
$time = time();
$params = [
"pi" => "616562",
"ms" => $data['ms'],
"pstn_HMACTimestamp" => $time
];
$secret_key = Env::get("paystation.hmac");// 使用提供的HMAC认证密钥
// function calculate_hmac($key, $message) {
// return hash_hmac('sha256', $message, $key);
// }
$query_string = http_build_query($params);
$hmac_signature = hash_hmac('sha256', $time."paystation".$query_string,$secret_key);
$params["pstn_HMAC"] = $hmac_signature;
$url_with_params = $url . '?' . http_build_query($params);
// echo $url_with_params;
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url_with_params);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$response = curl_exec($ch);
if(curl_errno($ch)) {
echo 'Error:' . curl_error($ch);
} else {
echo "Response: " . $response;
}
curl_close($ch);
return jsonSuccess($response);
}
public function getPreOrderDetail(){
$data = $this->request->post();
$rule = new Validate([
"article_id"=>"require"
]);
if(!$rule->check($data)){
return jsonError($rule->getError());
}
$order_info = $this->order_obj->where("article_id",$data['article_id'])->whereIn("state",[0,1])->find();
if(!$order_info){
return jsonError("order not find");
}
if($order_info['pay_type']==2){
$paystation = $this->paystation_obj->where("ps_id",$order_info['ps_id'])->find();
if($order_info['state']==0){
$res = xml_to_array(paystationLookup($paystation['merchant_session']));
if(isset($res['PaystationQuickLookup']['LookupResponse']['PaystationErrorMessage'])&&$res['PaystationQuickLookup']['LookupResponse']['PaystationErrorMessage']=='Transaction successful'){
$this->article_obj->where("article_id",$order_info['article_id'])->update(['is_buy'=>1]);
$this->order_obj->where("order_id",$order_info['order_id'])->update(['state'=>1]);
}
}
$order_info['paystation'] = $paystation;
$re['detail'] = $order_info;
return jsonSuccess($re);
}else{
return jsonError("Payment type error");
}
}
/**
* 修改文章价格
*
* 该函数用于编辑者修改指定文章的费用信息,包括费用金额和费用备注。
* 同时会同步更新相关的订单信息(如果存在未完成的订单)。
*
* @return \think\response\Json 返回JSON格式的结果成功时返回成功状态失败时返回错误信息
*/
public function changePrice(){
// 获取POST请求数据
$data = $this->request->post();
// 验证必要字段
$rule = new Validate([
"editor_id"=>"require",
"article_id"=>"require",
"fee"=>"require",
"fee_remark"=>"require"
]);
if(!$rule->check($data)){
return jsonError($rule->getError());
}
// 查询文章、期刊和编辑者信息
$article_info = $this->article_obj->where("article_id",$data['article_id'])->find();
$journal_info = $this->journal_obj->where("journal_id",$article_info['journal_id'])->find();
$editor_info = $this->user_obj->where("user_id",$data['editor_id'])->find();
// 验证编辑者权限
if($journal_info['editor_id']!=$editor_info['user_id']){
return jsonError("You are not the editor of this journal");
}
// 更新文章费用信息
$article_update['fee']=$data['fee'];
$article_update['fee_remark']=$data['fee_remark'];
if(intval($data['fee'])==0) {
$article_update['is_buy']=1;
}
$this->article_obj->where("article_id",$data['article_id'])->update($article_update);
// 如果存在未完成的订单,则同步更新订单费用
$order_info = $this->order_obj->where("article_id",$data['article_id'])->whereIn("state",[0,1])->find();
if($order_info){
if(intval($data['fee'])==0){
$this->order_obj->where("order_id",$order_info['order_id'])->update(['state'=>2]);
}else{
$update1['order_fee']=$data['fee'];
$this->order_obj->where("order_id",$order_info['order_id'])->update($update1);
}
}
return jsonSuccess();
}
/**
* @throws DataNotFoundException
* @throws ModelNotFoundException
* @throws DbException
* @throws PDOException
* @throws Exception
* @throws \Exception
*/
public function creatArticleOrder(){
$data = $this->request->post();
$rule = new Validate([
"article_id"=>"require"
]);
if(!$rule->check($data)){
return jsonError($rule->getError());
}
$frag = [];
$article_info = $this->article_obj->where("article_id",$data['article_id'])->find();
if($article_info['is_buy']==1){
return jsonError("paid");
}
// $journal_info = $this->journal_obj->where("journal_id",$article_info['journal_id'])->find();
$check = $this->order_obj->where("user_id",$article_info['user_id'])->where("article_id",$data['article_id'])->whereIn("state",[0,1])->find();
if($check){
$re['paypal'] = null;
$paystation_res = $this->creatPaystation($article_info['article_id']);
$ps_insert['transaction_id'] = $paystation_res['transaction_id'];
$ps_insert['session_id'] = $paystation_res['session_id'];
$ps_insert['paystation_id'] = $paystation_res['paystation_id'];
$ps_insert['currency'] = $paystation_res['currency'];
$ps_insert['amount'] = $paystation_res['amount'];
$ps_insert['merchant_session'] = $paystation_res['merchant_session'];
$ps_insert['request_time'] = $paystation_res['request_time'];
$ps_insert['payment_url'] = $paystation_res['payment_url'];
$ps_insert['data'] = json_encode($paystation_res);
$ps_id = $this->paystation_obj->insertGetId($ps_insert);
$this->order_obj->where("order_id",$check['order_id'])->update(['ps_id'=>$ps_id,"paystation_url"=>$paystation_res['payment_url']]);
$re['paystation'] = $this->paystation_obj->where("ps_id",$ps_id)->find();
$re['detail'] =$this->order_obj->where("order_id",$check['order_id'])->find();
return jsonSuccess($re);
}
$ca_sn = 'TMR'.date('Ymd') . strtoupper(bin2hex(random_bytes(8)));
$insert1['order_sn'] = $ca_sn;
$insert1['user_id'] = $article_info['user_id'];
$insert1['pay_type'] = 2;
$insert1["article_id"] = $data['article_id'];
$insert1["currency"] = "USD";
$insert1['order_fee'] = $article_info['fee'];
$insert1['real_fee'] = $article_info['fee'];
$accessToken = createPayStationToken();
$data_array = [
'paystation_id' => Env::get("paystation.client_id"),
'gateway_id' => "PAYSTATION",//GATEWAY_ID,
"merchant_session" => $ca_sn,
"merchant_reference"=>$ca_sn,
"amount" =>(int)(prin($article_info['fee'])*100),//(int)((((int)$journal_info['fee'])*726/416)*100),
// "amount" =>100,
// "currency"=>"USD",//目前paystation仅支持nzd
"return_url"=>"https://submission.tmrjournals.com/success?id=".$article_info['article_id'],
"response_url"=>"http://api.tmrjournals.com/public/index.php/api/Order/completePaystation"
];
$data = json_encode($data_array);
$purchase = postPayStationQuery('v1/hosted/purchases', $accessToken, $data);
$paystation_res = object_to_array(json_decode($purchase));
// return jsonSuccess($paystation_res);
$ps_insert['transaction_id'] = $paystation_res['transaction_id'];
$ps_insert['session_id'] = $paystation_res['session_id'];
$ps_insert['paystation_id'] = $paystation_res['paystation_id'];
$ps_insert['currency'] = $paystation_res['currency'];
$ps_insert['amount'] = $paystation_res['amount'];
$ps_insert['merchant_session'] = $paystation_res['merchant_session'];
$ps_insert['request_time'] = $paystation_res['request_time'];
$ps_insert['payment_url'] = $paystation_res['payment_url'];
$ps_insert['data'] = json_encode($paystation_res);
$ps_id = $this->paystation_obj->insertGetId($ps_insert);
$insert1['ps_id'] = $ps_id;
$insert1['paystation_url'] = $paystation_res['payment_url'];
$insert1['ctime'] = time();
$id = $this->order_obj->insertGetId($insert1);
$frag['paystation'] = $paystation_res;
$frag["paypal"] = null;
$frag['detail'] = $this->order_obj->where("order_id",$id)->find();
return jsonSuccess($frag);
}
private function creatPaystation($article_id){
$article_info = $this->article_obj->where("article_id",$article_id)->find();
$ca_sn = 'TMR'.date('Ymd') . strtoupper(bin2hex(random_bytes(8)));
$accessToken = createPayStationToken();
$data_array = [
'paystation_id' => Env::get("paystation.client_id"),
'gateway_id' => "PAYSTATION",//GATEWAY_ID,
"merchant_session" => $ca_sn,
"merchant_reference"=>$ca_sn,
"amount" =>(int)(prin($article_info['fee'])*100),
"return_url"=>"https://submission.tmrjournals.com/success?id=".$article_info['article_id'],
"response_url"=>"http://api.tmrjournals.com/public/index.php/api/Order/completePaystation"
];
$data = json_encode($data_array);
$purchase = postPayStationQuery('v1/hosted/purchases', $accessToken, $data);
$paystation_res = object_to_array(json_decode($purchase));
return $paystation_res;
}
public function getUserOrder(){
$data = $this->request->post();
$rule = new Validate([
"user_id"=>"require",
"state"=>"require"
]);
if(!$rule->check($data)){
return jsonError($rule->getError());
}
$list = $this->order_obj->where("user_id",$data['user_id'])->where("state",$data['state'])->select();
foreach ($list as $k=>$v){
$article = $this->article_obj->where("article_id",$v['article_id'])->find();
$list[$k]['article_detail'] = $article;
$list[$k]['journal_detail'] = $this->journal_obj->where("journal_id",$article['journal_id'])->find();
}
$re['list'] = $list;
return jsonSuccess($re);
}
private function handleResponse($response)
{
$jsonResponse = json_decode($response->getBody(), true);
return [
"jsonResponse" => $jsonResponse,
"httpStatusCode" => $response->getStatusCode(),
];
}
public function preOrderDetail(){
$data = $this->request->post();
$rule = new Validate([
"article_id"=>"require"
]);
if(!$rule->check($data)){
return jsonError($rule->getError());
}
$article_info = $this->article_obj->where("article_id",$data['article_id'])->find();
$journal_info = $this->journal_obj->where("journal_id",$article_info['journal_id'])->find();
$user_info = $this->user_obj->where("user_id",$article_info['user_id'])->find();
$re['article_detail'] = $article_info;
$re['journal_detail'] = $journal_info;
$re['user_detail'] = $user_info;
return jsonSuccess($re);
}
private function createPaypalOrder($fee)
{
$client = $this->createClient();
$orderBody = [
"body" => OrderRequestBuilder::init("CAPTURE", [
PurchaseUnitRequestBuilder::init(
AmountWithBreakdownBuilder::init("USD", $fee)->build()
)->build(),
])
->paymentSource(
PaymentSourceBuilder::init()->paypal(
PaypalWalletBuilder::init()->experienceContext(
PaypalWalletExperienceContextBuilder::init()->returnUrl("https://www.baidu.com")->build()
)->build()
)->build()
)
->build(),
];
$apiResponse = $client->getOrdersController()->ordersCreate($orderBody);
return $this->handleResponse($apiResponse);
}
public function completeOrder(){
$data = $this->request->post();
$rule = new Validate([
"order_id"=>"require"
]);
if(!$rule->check($data)){
return jsonError($rule->getError());
}
$order_info = $this->order_obj->where("order_id",$data['order_id'])->find();
$this->captureOrder($order_info['paypal_order_id']);
$this->article_obj->where("article_id",$order_info['article_id'])->update(['is_buy'=>1]);
$this->order_obj->where("order_id",$data['order_id'])->update(['state'=>1]);
return jsonSuccess([]);
}
private function getOrderStatus($orderId){
$client = $this->createClient();
return $client->getOrdersController()->ordersGet(["id"=>$orderId]);
}
private function createClient(){
return PaypalServerSdkClientBuilder::init()
->clientCredentialsAuthCredentials(
ClientCredentialsAuthCredentialsBuilder::init(
$this->PAYPAL_CLIENT_ID,
$this->PAYPAL_CLIENT_SECRET
)
)
->environment(Environment::SANDBOX)
->build();
}
private function captureOrder($orderID)
{
$client = $this->createClient();
$captureBody = [
"id" => $orderID,
];
$apiResponse = $client->getOrdersController()->ordersCapture($captureBody);
return $this->handleResponse($apiResponse);
}
}