李帅

1.使用谷歌服务账号进行验证

...@@ -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 - return 'ios'; 28 + if (strpos($ua, 'iPhone') || strpos($ua, 'iPad') || strpos($ua,'Mac OS X')) {
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'];
174 + try{
175 + $validator =new \Google_Service_AndroidPublisher($this->client);
176 + $resp = $validator->purchases_subscriptions->get($packageName, $subscriptionId, $purchaseToken);
177 + }catch (\Exception $exception){
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'].' ====================');
231 + Log::debug(var_export($resp,true));
232 + }
233 + }elseif (isset($data['subscriptionNotification'])){
234 + // oneTimeProductNotification 一次性购买相关
235 + /**
236 + * 成功会返回返回字段解释 https://developers.google.com/android-publisher/api-ref/purchases/products
237 + * 返回字段解释 中文翻译
238 + * consumptionState int 消费类产品的消费状态 0有待消费1已消耗
239 + * developerPayload string onyx系统生成的唯一ID
240 + * kind sgring 购买的对象
241 + * orderId sgring 客户支付订单ID(google play 订单ID)
242 + * purchaseState int 订单的采购状态 0购买1取消
243 + * purchaseTimeMillis int 时间戳
244 + * purchaseType int 扩展字段 0 测试 1促销
245 + * Array(
246 + * [consumptionState] => 1
247 + * [developerPayload] => 你的订单号
248 + * [kind] => androidpublisher#productPurchase
249 + * [orderId] => google play 订单号
250 + * [purchaseState] => 0
251 + * [purchaseTimeMillis] => 1542187625018
252 + * [purchaseType] =>
253 + * )
254 + */
212 255
213 - 256 + $productId = $data['OneTimeProductNotification']['purchaseToken'];
214 - //1.3. 根据解密后的内容去google接口做查询校验并发货(关键参数expiryTimeMillis) 257 + $purchaseToken = $data['OneTimeProductNotification']['purchaseToken'];
215 - //根据解密后的内容去google接口做校验 258 + try {
216 - //Google文档地址 259 + $validator =new \Google_Service_AndroidPublisher($this->client);
217 - //请求域名(Get/form): 260 + $resp = $validator->purchases_products->get($packageName, $productId, $purchaseToken);
218 - //https://androidpublisher.googleapis.com/androidpublisher/v3/applications/{packageName}/purchases/subscriptions/{subscriptionId}/tokens/{token} 261 + } catch (\Exception $e) {
219 - $validator =new \Google_Service_AndroidPublisher($this->client); 262 + Log::error("查询订阅出错了:==================");
220 - $resp = $validator->purchases_subscriptions->get($packageName, $subscriptionId, $purchaseToken); 263 + Log::error("packageName:".$packageName);
221 - 264 + Log::error("productId:". $productId);
222 - Log::debug('新订阅人员:===================='); 265 + Log::error("purchaseToken:".$purchaseToken);
223 - Log::debug(var_export($resp,true)); 266 + Log::error("===============================");
224 - Log::debug("购买状态" . $resp->getAcknowledgementState()); //0。待确认 1. 已确认 267 + return false;
225 - 268 + }
226 - //1.4. 消耗该笔订单 269 + // ...
227 - //Google文档地址 270 + switch ($data['notificationType']){
228 - //请求域名(Post/form) 271 + case self::ONE_TIME_PRODUCT_PURCHASED :
229 - //https://androidpublisher.googleapis.com/androidpublisher/v3/applications/{packageName}/purchases/subscriptions/{subscriptionId}/tokens/{token}:acknowledge 272 + case self::ONE_TIME_PRODUCT_CANCELED :
230 - 273 + default:
231 -// $acknowledge = new SubscriptionPurchasesAcknowledgeRequest(); 274 + Log::debug('特殊通知类型:'.$data['notificationType'].' ====================');
232 -// $acknowledge->developerPayload = ''; // todo 可以将我们系统的订单号、用户支付金额等存入谷歌订单里 275 + Log::debug(var_export($resp,true));
233 -// $resp = $validator->purchases_subscriptions->acknowledge($packageName, $subscriptionId, $purchaseToken,$acknowledge); 276 + break;
234 -// 277 + }
235 -// Log::debug('消耗结果:===================='); 278 + }else{
236 -// Log::debug(var_export($resp,true)); 279 + Log::debug("收到测试通知信息 version:" . $data['testNotification']['version']);
237 -
238 - // todo 发货
239 -
240 } 280 }
241 281
242 } 282 }
......