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