Showing
3 changed files
with
138 additions
and
77 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, | 59 | $response = $client->post(self::IS_SANDBOX ? self::SANDBOX_URL : self::VERIFY_URL, |
60 | - ['json' => ['receipt-data' => $token, 'password' => self::PASSWORD]])->getBody()->getContents(); | 60 | + ['json' => ['receipt-data' => $token, 'password' => self::PASSWORD]]) |
61 | - $resp = json_decode($response,true); | 61 | + ->getBody()->getContents(); |
62 | - Log::debug($response); | 62 | + $resp = json_decode($response, true); |
63 | - if ($resp['status'] <= 21003) { | 63 | + if ($resp['status'] > 0) { |
64 | - $newToken = str_replace('+', ' ', $token); | 64 | + Log::debug($response); |
65 | - try{ | 65 | + return false; |
66 | - $response = $client->post(self::IS_SANDBOX ? self::SANDBOX_URL : self::VERIFY_URL, | ||
67 | - ['json' => ['receipt-data' => $newToken, 'password' => self::PASSWORD]])->getBody()->getContents(); | ||
68 | - Log::debug('======== 替换+ ========'); | ||
69 | - Log::debug($response); | ||
70 | - }catch (GuzzleException $exception){ | ||
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,80 +98,127 @@ class ApplePayment implements PaymentInterface | ... | @@ -93,80 +98,127 @@ 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]); |
106 | - Log::debug(print_r($responseBodyPayload,true)); | ||
107 | - /**{ | ||
108 | - "notificationType": "SUBSCRIBED" | ||
109 | - "subtype": "RESUBSCRIBE" | ||
110 | - "notificationUUID": "99e65e59-c178-4f49-8b83-ea7d916cb568" | ||
111 | - "data": { | ||
112 | - "bundleId": "ink.parlando.parlando" | ||
113 | - "bundleVersion": "13" | ||
114 | - "environment": "Sandbox" | ||
115 | - "signedTransactionInfo": "xxx" | ||
116 | - "signedRenewalInfo": "xxx" | ||
117 | - } | ||
118 | - "version": "2.0" | ||
119 | - "signedDate": 1671451705697 | ||
120 | - } | ||
121 | - */ | ||
122 | - | ||
123 | $signedTransactionInfoString = $responseBodyPayload->data->signedTransactionInfo; | 105 | $signedTransactionInfoString = $responseBodyPayload->data->signedTransactionInfo; |
124 | $components = explode('.',$signedTransactionInfoString); | 106 | $components = explode('.',$signedTransactionInfoString); |
125 | $header = json_decode(base64_decode($components[0]),true); | 107 | $header = json_decode(base64_decode($components[0]),true); |
126 | - if (count($components) < 3){ | 108 | + $signedTransactionInfo = $this->decodeCertificate($signedTransactionInfoString, $header['x5c'][0]); |
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; | 109 | $responseBodyPayload->data->signedTransactionInfo = $signedTransactionInfo; |
134 | - /**{ | ||
135 | - "transactionId": "2000000231419425" | ||
136 | - "originalTransactionId": "2000000229164150" | ||
137 | - "webOrderLineItemId": "2000000017115109" | ||
138 | - "bundleId": "ink.parlando.parlando" | ||
139 | - "productId": "monthly_yiyan_vip" | ||
140 | - "subscriptionGroupIdentifier": "21080623" | ||
141 | - "purchaseDate": 1671451694000 | ||
142 | - "originalPurchaseDate": 1671123372000 | ||
143 | - "expiresDate": 1671451994000 | ||
144 | - "quantity": 1 | ||
145 | - "type": "Auto-Renewable Subscription" | ||
146 | - "inAppOwnershipType": "PURCHASED" | ||
147 | - "signedDate": 1671451705700 | ||
148 | - "environment": "Sandbox" | ||
149 | - }*/ | ||
150 | $signedRenewalInfoString = $responseBodyPayload->data->signedRenewalInfo; | 110 | $signedRenewalInfoString = $responseBodyPayload->data->signedRenewalInfo; |
151 | $components = explode('.',$signedRenewalInfoString); | 111 | $components = explode('.',$signedRenewalInfoString); |
152 | $header = json_decode(base64_decode($components[0]),true); | 112 | $header = json_decode(base64_decode($components[0]),true); |
153 | - if (count($components) < 3){ | 113 | + $signedRenewalInfo = $this->decodeCertificate($signedRenewalInfoString, $header['x5c'][0]); |
154 | - Log::error("jwt错误"); | ||
155 | - return false; | ||
156 | - } | ||
157 | - $signedRenewalInfo = $this->decodeCertificate($string, $header['x5c'][0]); | ||
158 | - Log::debug(print_r($signedRenewalInfo,true)); | ||
159 | $responseBodyPayload->data->signedRenewalInfo = $signedRenewalInfo; | 114 | $responseBodyPayload->data->signedRenewalInfo = $signedRenewalInfo; |
115 | + | ||
116 | + Log::debug(print_r($responseBodyPayload,true)); | ||
160 | /**{ | 117 | /**{ |
161 | - "originalTransactionId": "2000000229164150" | 118 | + "notificationType": "SUBSCRIBED" |
162 | - "autoRenewProductId": "monthly_yiyan_vip" | 119 | + "subtype": "RESUBSCRIBE" |
163 | - "productId": "monthly_yiyan_vip" | 120 | + "notificationUUID": "99e65e59-c178-4f49-8b83-ea7d916cb568" |
164 | - "autoRenewStatus": 1 | 121 | + "data": { |
165 | - "signedDate": 1671451705673 | 122 | + "bundleId": "ink.parlando.parlando" |
166 | - "environment": "Sandbox" | 123 | + "bundleVersion": "13" |
167 | - "recentSubscriptionStartDate": 1671451694000 | 124 | + "environment": "Sandbox" |
125 | + "signedTransactionInfo": { | ||
126 | + "transactionId": "2000000231419425" | ||
127 | + "originalTransactionId": "2000000229164150" | ||
128 | + "webOrderLineItemId": "2000000017115109" | ||
129 | + "bundleId": "ink.parlando.parlando" | ||
130 | + "productId": "monthly_yiyan_vip" | ||
131 | + "subscriptionGroupIdentifier": "21080623" | ||
132 | + "purchaseDate": 1671451694000 | ||
133 | + "originalPurchaseDate": 1671123372000 | ||
134 | + "expiresDate": 1671451994000 | ||
135 | + "quantity": 1 | ||
136 | + "type": "Auto-Renewable Subscription" | ||
137 | + "inAppOwnershipType": "PURCHASED" | ||
138 | + "signedDate": 1671451705700 | ||
139 | + "environment": "Sandbox" | ||
140 | + } | ||
141 | + "signedRenewalInfo": { | ||
142 | + "originalTransactionId": "2000000229164150" | ||
143 | + "autoRenewProductId": "monthly_yiyan_vip" | ||
144 | + "productId": "monthly_yiyan_vip" | ||
145 | + "autoRenewStatus": 1 | ||
146 | + "signedDate": 1671451705673 | ||
147 | + "environment": "Sandbox" | ||
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