Showing
3 changed files
with
115 additions
and
54 deletions
| ... | @@ -43,12 +43,15 @@ class PayController extends Controller | ... | @@ -43,12 +43,15 @@ class PayController extends Controller |
| 43 | $order_sn = $request->post('order_sn'); | 43 | $order_sn = $request->post('order_sn'); |
| 44 | $pay_type = $request->post('pay_type'); | 44 | $pay_type = $request->post('pay_type'); |
| 45 | $token = $request->post('token'); | 45 | $token = $request->post('token'); |
| 46 | + $others = $request->post('others',[]); | ||
| 47 | + $transactionId = $others['apple']['transactionIdentifier']; | ||
| 48 | + $originalTransactionId = $others['apple']['originalTransactionIdentifier']; | ||
| 46 | 49 | ||
| 47 | $order = Order::query()->where('order_sn', $order_sn)->first(); | 50 | $order = Order::query()->where('order_sn', $order_sn)->first(); |
| 48 | 51 | ||
| 49 | if ($order->status != Order::UNPAID) return Response::fail('订单错误!'); | 52 | if ($order->status != Order::UNPAID) return Response::fail('订单错误!'); |
| 50 | 53 | ||
| 51 | - $payment = $factory->init($pay_type)->verify($order, $token); | 54 | + $payment = $factory->init($pay_type)->verify($order, $token, $transactionId, $originalTransactionId); |
| 52 | 55 | ||
| 53 | if ($payment) return Response::success(['order_sn' => $order_sn], '支付成功'); | 56 | if ($payment) return Response::success(['order_sn' => $order_sn], '支付成功'); |
| 54 | else return Response::fail('订单错误!'); | 57 | else return Response::fail('订单错误!'); | ... | ... |
| ... | @@ -14,6 +14,12 @@ class UserProfile extends Model | ... | @@ -14,6 +14,12 @@ class UserProfile extends Model |
| 14 | 14 | ||
| 15 | protected $fillable = ['user_id','unionid']; | 15 | protected $fillable = ['user_id','unionid']; |
| 16 | 16 | ||
| 17 | + const IS_VIP = 1; | ||
| 18 | + | ||
| 19 | + const NO_VIP = 0; | ||
| 20 | + | ||
| 21 | + const WAIT_VIP = 2; // 已付款,等待处理(回调不及时,需要等待) | ||
| 22 | + | ||
| 17 | public function user() | 23 | public function user() |
| 18 | { | 24 | { |
| 19 | return $this->belongsTo('App\Models\User', 'id', 'user_id'); | 25 | return $this->belongsTo('App\Models\User', 'id', 'user_id'); | ... | ... |
| ... | @@ -55,23 +55,28 @@ class ApplePayment implements PaymentInterface | ... | @@ -55,23 +55,28 @@ class ApplePayment implements PaymentInterface |
| 55 | // 4. 验证成功,返回true | 55 | // 4. 验证成功,返回true |
| 56 | 56 | ||
| 57 | $client = new Client(['headers' => ['Content-Type' => 'application/json']]); | 57 | $client = new Client(['headers' => ['Content-Type' => 'application/json']]); |
| 58 | - try{ | 58 | + try { |
| 59 | - $response = $client->post(self::IS_SANDBOX ? self::SANDBOX_URL : self::VERIFY_URL, | ||
| 60 | - ['json' => ['receipt-data' => $token, 'password' => self::PASSWORD]])->getBody()->getContents(); | ||
| 61 | - $resp = json_decode($response,true); | ||
| 62 | - Log::debug($response); | ||
| 63 | - if ($resp['status'] <= 21003) { | ||
| 64 | - $newToken = str_replace('+', ' ', $token); | ||
| 65 | - try{ | ||
| 66 | $response = $client->post(self::IS_SANDBOX ? self::SANDBOX_URL : self::VERIFY_URL, | 59 | $response = $client->post(self::IS_SANDBOX ? self::SANDBOX_URL : self::VERIFY_URL, |
| 67 | - ['json' => ['receipt-data' => $newToken, 'password' => self::PASSWORD]])->getBody()->getContents(); | 60 | + ['json' => ['receipt-data' => $token, 'password' => self::PASSWORD]]) |
| 68 | - Log::debug('======== 替换+ ========'); | 61 | + ->getBody()->getContents(); |
| 62 | + $resp = json_decode($response, true); | ||
| 63 | + if ($resp['status'] > 0) { | ||
| 69 | Log::debug($response); | 64 | Log::debug($response); |
| 70 | - }catch (GuzzleException $exception){ | 65 | + return false; |
| 71 | - Log::error($exception->getMessage() . 'Line:' . $exception->getLine()); | ||
| 72 | - } | ||
| 73 | } | 66 | } |
| 74 | - }catch (GuzzleException $exception){ | 67 | + $originalTransactionId = $resp['receipt']['pending_renewal_info']['originalTransactionId']; |
| 68 | + | ||
| 69 | + // 绑定order 和 originalTransactionId | ||
| 70 | + $order->pay_number = $originalTransactionId; | ||
| 71 | + $order->status = Order::PAID; | ||
| 72 | + $order->save(); | ||
| 73 | + | ||
| 74 | + // 修改用户状态 | ||
| 75 | + $profile = UserProfile::query()->find($order->user_id); | ||
| 76 | + $profile->is_vip = UserProfile::WAIT_VIP; | ||
| 77 | + $profile->save(); | ||
| 78 | + return true; | ||
| 79 | + } catch (GuzzleException $exception) { | ||
| 75 | Log::error($exception->getMessage() . 'Line:' . $exception->getLine()); | 80 | Log::error($exception->getMessage() . 'Line:' . $exception->getLine()); |
| 76 | } | 81 | } |
| 77 | 82 | ||
| ... | @@ -93,16 +98,21 @@ class ApplePayment implements PaymentInterface | ... | @@ -93,16 +98,21 @@ class ApplePayment implements PaymentInterface |
| 93 | Log::debug('sandbox返回的数据:===================='); | 98 | Log::debug('sandbox返回的数据:===================='); |
| 94 | 99 | ||
| 95 | $components = explode('.',$string); | 100 | $components = explode('.',$string); |
| 96 | - if (count($components) < 3){ | ||
| 97 | - Log::error("jwt错误"); | ||
| 98 | - return false; | ||
| 99 | - } | ||
| 100 | - | ||
| 101 | $header = json_decode(base64_decode($components[0]),true); | 101 | $header = json_decode(base64_decode($components[0]),true); |
| 102 | - | ||
| 103 | // 这一步可以省略,不需要验证根证书 | 102 | // 这一步可以省略,不需要验证根证书 |
| 104 | - $this->validateAppleRootCa($header); | 103 | +// $this->validateAppleRootCa($header); |
| 105 | $responseBodyPayload = $this->decodeCertificate($string, $header['x5c'][0]); | 104 | $responseBodyPayload = $this->decodeCertificate($string, $header['x5c'][0]); |
| 105 | + $signedTransactionInfoString = $responseBodyPayload->data->signedTransactionInfo; | ||
| 106 | + $components = explode('.',$signedTransactionInfoString); | ||
| 107 | + $header = json_decode(base64_decode($components[0]),true); | ||
| 108 | + $signedTransactionInfo = $this->decodeCertificate($signedTransactionInfoString, $header['x5c'][0]); | ||
| 109 | + $responseBodyPayload->data->signedTransactionInfo = $signedTransactionInfo; | ||
| 110 | + $signedRenewalInfoString = $responseBodyPayload->data->signedRenewalInfo; | ||
| 111 | + $components = explode('.',$signedRenewalInfoString); | ||
| 112 | + $header = json_decode(base64_decode($components[0]),true); | ||
| 113 | + $signedRenewalInfo = $this->decodeCertificate($signedRenewalInfoString, $header['x5c'][0]); | ||
| 114 | + $responseBodyPayload->data->signedRenewalInfo = $signedRenewalInfo; | ||
| 115 | + | ||
| 106 | Log::debug(print_r($responseBodyPayload,true)); | 116 | Log::debug(print_r($responseBodyPayload,true)); |
| 107 | /**{ | 117 | /**{ |
| 108 | "notificationType": "SUBSCRIBED" | 118 | "notificationType": "SUBSCRIBED" |
| ... | @@ -112,26 +122,7 @@ class ApplePayment implements PaymentInterface | ... | @@ -112,26 +122,7 @@ class ApplePayment implements PaymentInterface |
| 112 | "bundleId": "ink.parlando.parlando" | 122 | "bundleId": "ink.parlando.parlando" |
| 113 | "bundleVersion": "13" | 123 | "bundleVersion": "13" |
| 114 | "environment": "Sandbox" | 124 | "environment": "Sandbox" |
| 115 | - "signedTransactionInfo": "xxx" | 125 | + "signedTransactionInfo": { |
| 116 | - "signedRenewalInfo": "xxx" | ||
| 117 | - } | ||
| 118 | - "version": "2.0" | ||
| 119 | - "signedDate": 1671451705697 | ||
| 120 | - } | ||
| 121 | - */ | ||
| 122 | - | ||
| 123 | - $signedTransactionInfoString = $responseBodyPayload->data->signedTransactionInfo; | ||
| 124 | - $components = explode('.',$signedTransactionInfoString); | ||
| 125 | - $header = json_decode(base64_decode($components[0]),true); | ||
| 126 | - if (count($components) < 3){ | ||
| 127 | - Log::error("jwt错误"); | ||
| 128 | - return false; | ||
| 129 | - } | ||
| 130 | - $signedTransactionInfo = $this->decodeCertificate($string, $header['x5c'][0]); | ||
| 131 | - Log::debug(print_r($signedTransactionInfo,true)); | ||
| 132 | - | ||
| 133 | - $responseBodyPayload->data->signedTransactionInfo = $signedTransactionInfo; | ||
| 134 | - /**{ | ||
| 135 | "transactionId": "2000000231419425" | 126 | "transactionId": "2000000231419425" |
| 136 | "originalTransactionId": "2000000229164150" | 127 | "originalTransactionId": "2000000229164150" |
| 137 | "webOrderLineItemId": "2000000017115109" | 128 | "webOrderLineItemId": "2000000017115109" |
| ... | @@ -146,18 +137,8 @@ class ApplePayment implements PaymentInterface | ... | @@ -146,18 +137,8 @@ class ApplePayment implements PaymentInterface |
| 146 | "inAppOwnershipType": "PURCHASED" | 137 | "inAppOwnershipType": "PURCHASED" |
| 147 | "signedDate": 1671451705700 | 138 | "signedDate": 1671451705700 |
| 148 | "environment": "Sandbox" | 139 | "environment": "Sandbox" |
| 149 | - }*/ | ||
| 150 | - $signedRenewalInfoString = $responseBodyPayload->data->signedRenewalInfo; | ||
| 151 | - $components = explode('.',$signedRenewalInfoString); | ||
| 152 | - $header = json_decode(base64_decode($components[0]),true); | ||
| 153 | - if (count($components) < 3){ | ||
| 154 | - Log::error("jwt错误"); | ||
| 155 | - return false; | ||
| 156 | } | 140 | } |
| 157 | - $signedRenewalInfo = $this->decodeCertificate($string, $header['x5c'][0]); | 141 | + "signedRenewalInfo": { |
| 158 | - Log::debug(print_r($signedRenewalInfo,true)); | ||
| 159 | - $responseBodyPayload->data->signedRenewalInfo = $signedRenewalInfo; | ||
| 160 | - /**{ | ||
| 161 | "originalTransactionId": "2000000229164150" | 142 | "originalTransactionId": "2000000229164150" |
| 162 | "autoRenewProductId": "monthly_yiyan_vip" | 143 | "autoRenewProductId": "monthly_yiyan_vip" |
| 163 | "productId": "monthly_yiyan_vip" | 144 | "productId": "monthly_yiyan_vip" |
| ... | @@ -165,8 +146,79 @@ class ApplePayment implements PaymentInterface | ... | @@ -165,8 +146,79 @@ class ApplePayment implements PaymentInterface |
| 165 | "signedDate": 1671451705673 | 146 | "signedDate": 1671451705673 |
| 166 | "environment": "Sandbox" | 147 | "environment": "Sandbox" |
| 167 | "recentSubscriptionStartDate": 1671451694000 | 148 | "recentSubscriptionStartDate": 1671451694000 |
| 149 | + } | ||
| 150 | + } | ||
| 151 | + "version": "2.0" | ||
| 152 | + "signedDate": 1671451705697 | ||
| 168 | }*/ | 153 | }*/ |
| 169 | - Log::debug(print_r($responseBodyPayload,true)); | 154 | + |
| 155 | + switch ($responseBodyPayload->notificationType){ | ||
| 156 | + case "SUBSCRIBED": | ||
| 157 | + if ($responseBodyPayload->subtype == 'INITIAL_BUY'){ //首次购买 | ||
| 158 | + | ||
| 159 | + } | ||
| 160 | + | ||
| 161 | + if ($responseBodyPayload->subtype == 'RESUBSCRIBE'){ //重新订阅 | ||
| 162 | + // 应该再创建一个订单。。。 | ||
| 163 | + } | ||
| 164 | + | ||
| 165 | + $originalTransactionId = $responseBodyPayload->data->signedTransactionInfo->originalTransactionId; | ||
| 166 | + | ||
| 167 | + $order = Order::query()->where('pay_number', $originalTransactionId)->first(); | ||
| 168 | + if(!$order) { | ||
| 169 | + Log::error('没有找到对应的订单,说明apple服务端比客户端的回调快!'); | ||
| 170 | + return; | ||
| 171 | + } | ||
| 172 | + | ||
| 173 | + /** 修改订单状态*/ | ||
| 174 | + $order->pay_time = Carbon::now(); | ||
| 175 | + $order->pay_type = $responseBodyPayload->data->signedTransactionInfo->type; | ||
| 176 | + $order->save(); | ||
| 177 | + /** 给用户加会员*/ | ||
| 178 | + $user = UserProfile::query()->find($order->user_id); | ||
| 179 | + $user->is_vip = 1; | ||
| 180 | + $user->create_vip_time = Carbon::createFromTimestampMs($responseBodyPayload->data->signedTransactionInfo->purchaseDate); | ||
| 181 | + $user->expire_vip_time = Carbon::createFromTimestampMs($responseBodyPayload->data->signedTransactionInfo->expiresDate); | ||
| 182 | + $user->buy_number += 1; | ||
| 183 | + $user->buy_amount += $order->pay_amount; | ||
| 184 | + $user->last_buy_time = Carbon::now(); | ||
| 185 | + $user->save(); | ||
| 186 | + break; | ||
| 187 | + case "DID_RENEW": | ||
| 188 | + // 应该再创建一个订单。。。 | ||
| 189 | + $originalTransactionId = $responseBodyPayload->data->signedTransactionInfo->originalTransactionId; | ||
| 190 | + $order = Order::query()->where('pay_number', $originalTransactionId)->first(); | ||
| 191 | + if(!$order) { | ||
| 192 | + Log::error('没有找到对应的订单,说明apple服务端比客户端的回调快!'); | ||
| 193 | + return; | ||
| 194 | + } | ||
| 195 | + /** 给用户加会员*/ | ||
| 196 | + $user = UserProfile::query()->find($order->user_id); | ||
| 197 | + $user->is_vip = 1; | ||
| 198 | + $user->expire_vip_time = Carbon::createFromTimestampMs($responseBodyPayload->data->signedTransactionInfo->expiresDate); | ||
| 199 | + $user->buy_number += 1; | ||
| 200 | + $user->buy_amount += $order->pay_amount; | ||
| 201 | + $user->last_buy_time = Carbon::now(); | ||
| 202 | + $user->save(); | ||
| 203 | + break; | ||
| 204 | + case "EXPIRED": | ||
| 205 | + // 应该再创建一个订单。。。 | ||
| 206 | + $originalTransactionId = $responseBodyPayload->data->signedTransactionInfo->originalTransactionId; | ||
| 207 | + $order = Order::query()->where('pay_number', $originalTransactionId)->first(); | ||
| 208 | + if(!$order) { | ||
| 209 | + Log::error('没有找到对应的订单,说明apple服务端比客户端的回调快!'); | ||
| 210 | + return; | ||
| 211 | + } | ||
| 212 | + /** 给用户取消会员*/ | ||
| 213 | + $user = UserProfile::query()->find($order->user_id); | ||
| 214 | + $user->is_vip = 0; | ||
| 215 | + $user->expire_vip_time = Carbon::createFromTimestampMs($responseBodyPayload->data->signedTransactionInfo->expiresDate); | ||
| 216 | + $user->save(); | ||
| 217 | + break; | ||
| 218 | + default: | ||
| 219 | + Log::debug('特殊通知类型:'.$responseBodyPayload->notificationType.' ===================='); | ||
| 220 | + Log::debug(var_export($responseBodyPayload,true)); | ||
| 221 | + } | ||
| 170 | } | 222 | } |
| 171 | 223 | ||
| 172 | private function validateAppleRootCa($header) | 224 | private function validateAppleRootCa($header) | ... | ... |
-
Please register or login to post a comment