Showing
3 changed files
with
146 additions
and
93 deletions
... | @@ -3,6 +3,7 @@ | ... | @@ -3,6 +3,7 @@ |
3 | namespace App\Console\Commands; | 3 | namespace App\Console\Commands; |
4 | 4 | ||
5 | use App\Payment\GooglePayment; | 5 | use App\Payment\GooglePayment; |
6 | +use Carbon\Carbon; | ||
6 | use Illuminate\Console\Command; | 7 | use Illuminate\Console\Command; |
7 | 8 | ||
8 | class DevGoogle extends Command | 9 | class DevGoogle extends Command |
... | @@ -38,21 +39,27 @@ class DevGoogle extends Command | ... | @@ -38,21 +39,27 @@ class DevGoogle extends Command |
38 | */ | 39 | */ |
39 | public function handle() | 40 | public function handle() |
40 | { | 41 | { |
42 | +// | ||
43 | +// $credentials_file = public_path().'/pc-api-7482901338487549764-603-566eccf76b91.json'; | ||
44 | +// $client = new \Google_Client(); | ||
45 | +// $client->setAuthConfig($credentials_file); | ||
46 | +// $client->setApplicationName("Client_Library_Examples"); | ||
47 | +// $client->setScopes( | ||
48 | +// [ | ||
49 | +// \Google_Service_AndroidPublisher::ANDROIDPUBLISHER, | ||
50 | +// ] | ||
51 | +// ); | ||
52 | +// | ||
53 | +// $validator =new \Google_Service_AndroidPublisher($client); | ||
54 | +// $resp = $validator->purchases_subscriptions->get('pub.yiyan.parlando.Parlando', 'monthly_yiyan_vip', 'aa'); | ||
55 | +// dd($resp); | ||
41 | 56 | ||
42 | - $credentials_file = public_path().'/pc-api-7482901338487549764-603-566eccf76b91.json'; | 57 | + $time = 1668186646527; |
43 | - $client = new \Google_Client(); | 58 | + $startTime = 1668184557316; |
44 | - $client->setAuthConfig($credentials_file); | 59 | + echo date('Y-m-d H:i:s',$startTime/1000) . PHP_EOL; |
45 | - $client->setApplicationName("Client_Library_Examples"); | 60 | + echo date('Y-m-d H:i:s',$time/1000) . PHP_EOL; |
46 | - $client->setScopes( | ||
47 | - [ | ||
48 | - \Google_Service_AndroidPublisher::ANDROIDPUBLISHER, | ||
49 | - ] | ||
50 | - ); | ||
51 | - | ||
52 | - $validator =new \Google_Service_AndroidPublisher($client); | ||
53 | - $resp = $validator->purchases_subscriptions->get('pub.yiyan.parlando.Parlando', 'monthly_yiyan_vip', 'aa'); | ||
54 | - dd($resp); | ||
55 | 61 | ||
62 | + echo Carbon::createFromTimestampMs($time)->toDateTimeString(); | ||
56 | return 0; | 63 | return 0; |
57 | } | 64 | } |
58 | } | 65 | } | ... | ... |
... | @@ -25,6 +25,12 @@ class Controller extends BaseController | ... | @@ -25,6 +25,12 @@ class Controller extends BaseController |
25 | { | 25 | { |
26 | $ua = request()->header('user-agent'); | 26 | $ua = request()->header('user-agent'); |
27 | 27 | ||
28 | + if (strpos($ua, 'iPhone') || strpos($ua, 'iPad') || strpos($ua,'Mac OS X')) { | ||
28 | return 'ios'; | 29 | return 'ios'; |
30 | + }else if (strpos($ua, 'Android') || strpos($ua, 'android')){ | ||
31 | + return 'android'; | ||
32 | + }else{ | ||
33 | + return 'unkown'; | ||
34 | + } | ||
29 | } | 35 | } |
30 | } | 36 | } | ... | ... |
... | @@ -23,6 +23,23 @@ class GooglePayment implements PaymentInterface | ... | @@ -23,6 +23,23 @@ class GooglePayment implements PaymentInterface |
23 | 23 | ||
24 | const IS_SANDBOX = true; | 24 | const IS_SANDBOX = true; |
25 | 25 | ||
26 | + const SUBSCRIPTION_RECOVERED = 1; //- 从帐号保留状态恢复了订阅。 | ||
27 | + const SUBSCRIPTION_RENEWED = 2; // 续订了处于活动状态的订阅。 | ||
28 | + const SUBSCRIPTION_CANCELED = 3; // 自愿或非自愿地取消了订阅。如果是自愿取消,在用户取消时发送。 | ||
29 | + const SUBSCRIPTION_PURCHASED = 4; // 购买了新的订阅。 | ||
30 | + const SUBSCRIPTION_ON_HOLD = 5; // 订阅已进入帐号保留状态(如果已启用)。 | ||
31 | + const SUBSCRIPTION_IN_GRACE_PERIOD = 6; // 订阅已进入宽限期(如果已启用)。 | ||
32 | + const SUBSCRIPTION_RESTARTED = 7; // 用户已通过 Play > 帐号 > 订阅重新激活其订阅(需要选择使用订阅恢复功能)。 | ||
33 | + const SUBSCRIPTION_PRICE_CHANGE_CONFIRMED = 8; // 用户已成功确认订阅价格变动。 | ||
34 | + const SUBSCRIPTION_DEFERRED = 9; // 订阅的续订时间点已延期。 | ||
35 | + const SUBSCRIPTION_PAUSED = 10; // 订阅已暂停。 | ||
36 | + const SUBSCRIPTION_PAUSE_SCHEDULE_CHANGED = 11; // 订阅暂停计划已更改。 | ||
37 | + const SUBSCRIPTION_REVOKED = 12; // 用户在到期时间之前已撤消订阅。 | ||
38 | + const SUBSCRIPTION_EXPIRED = 13; // 订阅已到期。 | ||
39 | + | ||
40 | + const ONE_TIME_PRODUCT_PURCHASED = 1; //用户成功购买了一次性商品。 | ||
41 | + const ONE_TIME_PRODUCT_CANCELED = 2; // 用户已取消待处理的一次性商品购买交易。 | ||
42 | + | ||
26 | public $client; | 43 | public $client; |
27 | 44 | ||
28 | public function __construct() | 45 | public function __construct() |
... | @@ -30,8 +47,6 @@ class GooglePayment implements PaymentInterface | ... | @@ -30,8 +47,6 @@ class GooglePayment implements PaymentInterface |
30 | $this->client = $this->getGoogleClient(); | 47 | $this->client = $this->getGoogleClient(); |
31 | } | 48 | } |
32 | 49 | ||
33 | - | ||
34 | - | ||
35 | public function prepare(Order $order) | 50 | public function prepare(Order $order) |
36 | { | 51 | { |
37 | // 查询订单对应的产品id | 52 | // 查询订单对应的产品id |
... | @@ -143,100 +158,125 @@ class GooglePayment implements PaymentInterface | ... | @@ -143,100 +158,125 @@ class GooglePayment implements PaymentInterface |
143 | 158 | ||
144 | public function notify($string) | 159 | public function notify($string) |
145 | { | 160 | { |
146 | - //subscriptionNotification(订阅相关)、oneTimeProductNotification(一次性购买相关)testNotification(测试发布相关) 三个不会同时存在任意2个 | ||
147 | - //subscriptionNotification说明 | ||
148 | - | ||
149 | //参数名 说明 | 161 | //参数名 说明 |
150 | //version 此通知的版本。最初,此值为“1.0”。此版本与其他版本字段不同。 | 162 | //version 此通知的版本。最初,此值为“1.0”。此版本与其他版本字段不同。 |
151 | //notificationType int 订阅的 notificationType 可以参考下面的表 | 163 | //notificationType int 订阅的 notificationType 可以参考下面的表 |
152 | //purchaseToken 购买订阅时向用户设备提供的令牌 | 164 | //purchaseToken 购买订阅时向用户设备提供的令牌 |
153 | //subscriptionId 所购买订阅的 ID(例如“monthly001”) | 165 | //subscriptionId 所购买订阅的 ID(例如“monthly001”) |
154 | - | ||
155 | - //SUBSCRIPTION_RECOVERED - 从帐号保留状态恢复了订阅。 | ||
156 | - //SUBSCRIPTION_RENEWED - 续订了处于活动状态的订阅。 | ||
157 | - //SUBSCRIPTION_CANCELED - 自愿或非自愿地取消了订阅。如果是自愿取消,在用户取消时发送。 | ||
158 | - //SUBSCRIPTION_PURCHASED - 购买了新的订阅。 | ||
159 | - //SUBSCRIPTION_ON_HOLD - 订阅已进入帐号保留状态(如果已启用)。 | ||
160 | - //SUBSCRIPTION_IN_GRACE_PERIOD - 订阅已进入宽限期(如果已启用)。 | ||
161 | - //SUBSCRIPTION_RESTARTED - 用户已通过 Play > 帐号 > 订阅重新激活其订阅(需要选择使用订阅恢复功能)。 | ||
162 | - //SUBSCRIPTION_PRICE_CHANGE_CONFIRMED - 用户已成功确认订阅价格变动。 | ||
163 | - //SUBSCRIPTION_DEFERRED - 订阅的续订时间点已延期。 | ||
164 | - //SUBSCRIPTION_PAUSED - 订阅已暂停。 | ||
165 | - //SUBSCRIPTION_PAUSE_SCHEDULE_CHANGED - 订阅暂停计划已更改。 | ||
166 | - //SUBSCRIPTION_REVOKED - 用户在到期时间之前已撤消订阅。 | ||
167 | - //SUBSCRIPTION_EXPIRED - 订阅已到期。 | ||
168 | - | ||
169 | - | ||
170 | - // 'acknowledgementState' => 1, | ||
171 | - // 'autoRenewing' => false, // 设置是否在订阅到期时自动续订。 | ||
172 | - // 'autoResumeTimeMillis' => NULL, | ||
173 | - // 'cancelReason' => 1, //订阅被取消或未自动续订的原因。可能的值包括:0.用户取消了订阅 1.由于结算问题 2.系统取消了订阅 2. 订阅被新的订阅取代了。3.开发者已取消订阅 | ||
174 | - // 'cancelSurveyResultType' => 'Google\\Service\\AndroidPublisher\\SubscriptionCancelSurveyResult', | ||
175 | - // 'cancelSurveyResultDataType' => '', | ||
176 | - // 'countryCode' => 'CA', | ||
177 | - // 'developerPayload' => '', | ||
178 | - // 'emailAddress' => NULL, | ||
179 | - // 'expiryTimeMillis' => '1668023054641', // 订阅的到期时间 | ||
180 | - // 'externalAccountId' => NULL, | ||
181 | - // 'familyName' => NULL, | ||
182 | - // 'givenName' => NULL, | ||
183 | - // 'introductoryPriceInfoType' => 'Google\\Service\\AndroidPublisher\\IntroductoryPriceInfo', | ||
184 | - // 'introductoryPriceInfoDataType' => '', | ||
185 | - // 'kind' => 'androidpublisher#subscriptionPurchase', | ||
186 | - // 'linkedPurchaseToken' => NULL, | ||
187 | - // 'obfuscatedExternalAccountId' => 'osnB10209503106007', //我们系统的订单号 | ||
188 | - // 'obfuscatedExternalProfileId' => NULL, | ||
189 | - // 'orderId' => 'GPA.3390-9999-6519-16223..5', | ||
190 | - // 'paymentState' => NULL, //订阅的付款状态。可能的值包括:0=待处理付款,1=付款已收讫,2=免费试用,3=延迟升级/降级.已取消、已过期的订阅不会显示。 | ||
191 | - // 'priceAmountMicros' => '5490000', // 订阅价格。例如,如果订阅价格为 1.99 欧元,priceAmountMicros 为 1990000。 | ||
192 | - // 'priceChangeType' => 'Google\\Service\\AndroidPublisher\\SubscriptionPriceChange', | ||
193 | - // 'priceChangeDataType' => '', | ||
194 | - // 'priceCurrencyCode' => 'CAD', | ||
195 | - // 'profileId' => NULL, | ||
196 | - // 'profileName' => NULL, | ||
197 | - // 'promotionCode' => NULL, | ||
198 | - // 'promotionType' => NULL, | ||
199 | - // 'purchaseType' => 0, // 订阅的购买类型 0=测试,1=促销,当购买交易不是使用标准的应用内购买结算流程时,系统才会设置此字段。 | ||
200 | - // 'startTimeMillis' => '1668020958362', | ||
201 | - // 'userCancellationTimeMillis' => NULL, | ||
202 | - // 'internal_gapi_mappings' => | ||
203 | - | ||
204 | - | ||
205 | $data = json_decode(base64_decode($string),true); | 166 | $data = json_decode(base64_decode($string),true); |
206 | Log::debug('返回的数据:===================='); | 167 | Log::debug('返回的数据:===================='); |
207 | Log::debug(print_r($data,true)); | 168 | Log::debug(print_r($data,true)); |
169 | + | ||
208 | $packageName = $data['packageName']; | 170 | $packageName = $data['packageName']; |
209 | if (isset($data['subscriptionNotification'])) { | 171 | if (isset($data['subscriptionNotification'])) { |
210 | $subscriptionId = $data['subscriptionNotification']['subscriptionId']; | 172 | $subscriptionId = $data['subscriptionNotification']['subscriptionId']; |
211 | $purchaseToken = $data['subscriptionNotification']['purchaseToken']; | 173 | $purchaseToken = $data['subscriptionNotification']['purchaseToken']; |
212 | - | 174 | + try{ |
213 | - | ||
214 | - //1.3. 根据解密后的内容去google接口做查询校验并发货(关键参数expiryTimeMillis) | ||
215 | - //根据解密后的内容去google接口做校验 | ||
216 | - //Google文档地址 | ||
217 | - //请求域名(Get/form): | ||
218 | - //https://androidpublisher.googleapis.com/androidpublisher/v3/applications/{packageName}/purchases/subscriptions/{subscriptionId}/tokens/{token} | ||
219 | $validator =new \Google_Service_AndroidPublisher($this->client); | 175 | $validator =new \Google_Service_AndroidPublisher($this->client); |
220 | $resp = $validator->purchases_subscriptions->get($packageName, $subscriptionId, $purchaseToken); | 176 | $resp = $validator->purchases_subscriptions->get($packageName, $subscriptionId, $purchaseToken); |
221 | - | 177 | + }catch (\Exception $exception){ |
222 | - Log::debug('新订阅人员:===================='); | 178 | + Log::error("查询订阅出错了:=================="); |
179 | + Log::error("packageName:".$packageName); | ||
180 | + Log::error("subscriptionId:". $subscriptionId); | ||
181 | + Log::error("purchaseToken:".$purchaseToken); | ||
182 | + Log::error("==============================="); | ||
183 | + return false; | ||
184 | + } | ||
185 | + $orderSn = $resp->getObfuscatedExternalAccountId(); | ||
186 | + $order = Order::query()->where('order_sn',$orderSn)->first(); | ||
187 | + if (!$order) { | ||
188 | + Log::error("查无此订单"); | ||
189 | + return false; | ||
190 | + } | ||
191 | + switch ($data['notificationType']){ | ||
192 | + case self::SUBSCRIPTION_PURCHASED: | ||
193 | + if ($resp->getPaymentState() == 1) $order->status = Order::DONE; | ||
194 | + /** 修改订单状态*/ | ||
195 | + $order->pay_time = Carbon::now(); | ||
196 | + $order->pay_number = $resp->getOrderId(); | ||
197 | + $order->pay_type = $resp->getKind(); | ||
198 | + $order->callback = $string; | ||
199 | + $order->save(); | ||
200 | + /** 给用户加会员*/ | ||
201 | + $user = UserProfile::query()->find($order->user_id); | ||
202 | + $user->is_vip = 1; | ||
203 | + $user->create_vip_time = Carbon::createFromTimestampMs($resp->getStartTimeMillis()); | ||
204 | + $user->expire_vip_time = Carbon::createFromTimestampMs($resp->getExpiryTimeMillis()); | ||
205 | + $user->buy_number += 1; | ||
206 | + $user->buy_amount += $order->pay_amount; | ||
207 | + $user->last_buy_time = Carbon::now(); | ||
208 | + $user->save(); | ||
209 | + break; | ||
210 | + case self::SUBSCRIPTION_RENEWED : | ||
211 | + case self::SUBSCRIPTION_RESTARTED: | ||
212 | + /** 给用户加会员*/ | ||
213 | + $user = UserProfile::query()->find($order->user_id); | ||
214 | + $user->is_vip = 1; | ||
215 | + $user->expire_vip_time = Carbon::createFromTimestampMs($resp->getExpiryTimeMillis()); | ||
216 | + $user->buy_number += 1; | ||
217 | + $user->buy_amount += $order->pay_amount; | ||
218 | + $user->last_buy_time = Carbon::now(); | ||
219 | + $user->save(); | ||
220 | + break; | ||
221 | + case self::SUBSCRIPTION_CANCELED: | ||
222 | + case self::SUBSCRIPTION_EXPIRED: | ||
223 | + /** 给用户取消会员*/ | ||
224 | + $user = UserProfile::query()->find($order->user_id); | ||
225 | + $user->is_vip = 0; | ||
226 | + $user->expire_vip_time = Carbon::createFromTimestampMs($resp->getExpiryTimeMillis()); | ||
227 | + $user->save(); | ||
228 | + break; | ||
229 | + default: | ||
230 | + Log::debug('特殊通知类型:'.$data['notificationType'].' ===================='); | ||
223 | Log::debug(var_export($resp,true)); | 231 | Log::debug(var_export($resp,true)); |
224 | - Log::debug("购买状态" . $resp->getAcknowledgementState()); //0。待确认 1. 已确认 | 232 | + } |
225 | - | 233 | + }elseif (isset($data['subscriptionNotification'])){ |
226 | - //1.4. 消耗该笔订单 | 234 | + // oneTimeProductNotification 一次性购买相关 |
227 | - //Google文档地址 | 235 | + /** |
228 | - //请求域名(Post/form) | 236 | + * 成功会返回返回字段解释 https://developers.google.com/android-publisher/api-ref/purchases/products |
229 | - //https://androidpublisher.googleapis.com/androidpublisher/v3/applications/{packageName}/purchases/subscriptions/{subscriptionId}/tokens/{token}:acknowledge | 237 | + * 返回字段解释 中文翻译 |
230 | - | 238 | + * consumptionState int 消费类产品的消费状态 0有待消费1已消耗 |
231 | -// $acknowledge = new SubscriptionPurchasesAcknowledgeRequest(); | 239 | + * developerPayload string onyx系统生成的唯一ID |
232 | -// $acknowledge->developerPayload = ''; // todo 可以将我们系统的订单号、用户支付金额等存入谷歌订单里 | 240 | + * kind sgring 购买的对象 |
233 | -// $resp = $validator->purchases_subscriptions->acknowledge($packageName, $subscriptionId, $purchaseToken,$acknowledge); | 241 | + * orderId sgring 客户支付订单ID(google play 订单ID) |
234 | -// | 242 | + * purchaseState int 订单的采购状态 0购买1取消 |
235 | -// Log::debug('消耗结果:===================='); | 243 | + * purchaseTimeMillis int 时间戳 |
236 | -// Log::debug(var_export($resp,true)); | 244 | + * purchaseType int 扩展字段 0 测试 1促销 |
237 | - | 245 | + * Array( |
238 | - // todo 发货 | 246 | + * [consumptionState] => 1 |
247 | + * [developerPayload] => 你的订单号 | ||
248 | + * [kind] => androidpublisher#productPurchase | ||
249 | + * [orderId] => google play 订单号 | ||
250 | + * [purchaseState] => 0 | ||
251 | + * [purchaseTimeMillis] => 1542187625018 | ||
252 | + * [purchaseType] => | ||
253 | + * ) | ||
254 | + */ | ||
239 | 255 | ||
256 | + $productId = $data['OneTimeProductNotification']['purchaseToken']; | ||
257 | + $purchaseToken = $data['OneTimeProductNotification']['purchaseToken']; | ||
258 | + try { | ||
259 | + $validator =new \Google_Service_AndroidPublisher($this->client); | ||
260 | + $resp = $validator->purchases_products->get($packageName, $productId, $purchaseToken); | ||
261 | + } catch (\Exception $e) { | ||
262 | + Log::error("查询订阅出错了:=================="); | ||
263 | + Log::error("packageName:".$packageName); | ||
264 | + Log::error("productId:". $productId); | ||
265 | + Log::error("purchaseToken:".$purchaseToken); | ||
266 | + Log::error("==============================="); | ||
267 | + return false; | ||
268 | + } | ||
269 | + // ... | ||
270 | + switch ($data['notificationType']){ | ||
271 | + case self::ONE_TIME_PRODUCT_PURCHASED : | ||
272 | + case self::ONE_TIME_PRODUCT_CANCELED : | ||
273 | + default: | ||
274 | + Log::debug('特殊通知类型:'.$data['notificationType'].' ===================='); | ||
275 | + Log::debug(var_export($resp,true)); | ||
276 | + break; | ||
277 | + } | ||
278 | + }else{ | ||
279 | + Log::debug("收到测试通知信息 version:" . $data['testNotification']['version']); | ||
240 | } | 280 | } |
241 | 281 | ||
242 | } | 282 | } | ... | ... |
-
Please register or login to post a comment