From 1aabb8caa1399aa2a9c73db044c553df6d2817e0 Mon Sep 17 00:00:00 2001 From: Florent Blaison Date: Mon, 13 Jan 2020 12:04:21 +0100 Subject: [PATCH 1/4] [ADD] fix error on acknowledgement of an already acknowledged purchase --- src/GooglePlay/Acknowledger.php | 36 +++++-- .../GooglePlay/GooglePlayAcknowledgerTest.php | 100 ++++++++++++++++-- 2 files changed, 118 insertions(+), 18 deletions(-) diff --git a/src/GooglePlay/Acknowledger.php b/src/GooglePlay/Acknowledger.php index 44fb667..5f560c6 100644 --- a/src/GooglePlay/Acknowledger.php +++ b/src/GooglePlay/Acknowledger.php @@ -58,24 +58,38 @@ public function acknowledge(string $type = self::SUBSCRIPTION, string $developer try { switch ($type) { case self::SUBSCRIPTION: - $this->androidPublisherService->purchases_subscriptions->acknowledge( + $subscriptionPurchase = $this->androidPublisherService->purchases_subscriptions->get( $this->packageName, $this->productId, - $this->purchaseToken, - new \Google_Service_AndroidPublisher_SubscriptionPurchasesAcknowledgeRequest( - ['developerPayload' => $developerPayload] - ) + $this->purchaseToken ); + if ($subscriptionPurchase->getAcknowledgementState() != 1) { + $this->androidPublisherService->purchases_subscriptions->acknowledge( + $this->packageName, + $this->productId, + $this->purchaseToken, + new \Google_Service_AndroidPublisher_SubscriptionPurchasesAcknowledgeRequest( + ['developerPayload' => $developerPayload] + ) + ); + } break; case self::PRODUCT: - $this->androidPublisherService->purchases_products->acknowledge( + $productPurchase = $this->androidPublisherService->purchases_products->get( $this->packageName, $this->productId, - $this->purchaseToken, - new \Google_Service_AndroidPublisher_ProductPurchasesAcknowledgeRequest( - ['developerPayload' => $developerPayload] - ) + $this->purchaseToken ); + if ($productPurchase->getAcknowledgementState() != 1) { + $this->androidPublisherService->purchases_products->acknowledge( + $this->packageName, + $this->productId, + $this->purchaseToken, + new \Google_Service_AndroidPublisher_ProductPurchasesAcknowledgeRequest( + ['developerPayload' => $developerPayload] + ) + ); + } break; default: throw new \RuntimeException( @@ -89,7 +103,7 @@ public function acknowledge(string $type = self::SUBSCRIPTION, string $developer return true; } catch (\Exception $e) { - throw new \RuntimeException($e->getMessage(), $e); + throw new \RuntimeException($e->getMessage(), $e->getCode(), $e); } } } diff --git a/tests/GooglePlay/GooglePlayAcknowledgerTest.php b/tests/GooglePlay/GooglePlayAcknowledgerTest.php index 6a4eda7..5516797 100755 --- a/tests/GooglePlay/GooglePlayAcknowledgerTest.php +++ b/tests/GooglePlay/GooglePlayAcknowledgerTest.php @@ -3,8 +3,10 @@ namespace ReceiptValidator\Tests; use Google_Service_AndroidPublisher; +use Google_Service_AndroidPublisher_ProductPurchase; use Google_Service_AndroidPublisher_Resource_PurchasesProducts; use Google_Service_AndroidPublisher_Resource_PurchasesSubscriptions; +use Google_Service_AndroidPublisher_SubscriptionPurchase; use PHPUnit\Framework\TestCase; use ReceiptValidator\GooglePlay\Acknowledger; @@ -13,7 +15,7 @@ */ class GooglePlayAcknowledgerTest extends TestCase { - public function testValidate(): void + public function testValidateWithNonAcknowledgedPurchase(): void { $packageName = 'testPackage'; $productId = '15'; @@ -22,16 +24,32 @@ public function testValidate(): void // mock objects $googleServiceAndroidPublisherMock = $this->getMockBuilder(Google_Service_AndroidPublisher::class) ->disableOriginalConstructor()->getMock(); - $productPurchaseMock = $this->getMockBuilder(Google_Service_AndroidPublisher_Resource_PurchasesProducts::class) + + // products + $purchasesProductsMock = $this->getMockBuilder(Google_Service_AndroidPublisher_Resource_PurchasesProducts::class) + ->disableOriginalConstructor()->getMock(); + $productPurchaseMock = $this->getMockBuilder(Google_Service_AndroidPublisher_ProductPurchase::class) ->disableOriginalConstructor()->getMock(); - $subscriptionPurchaseMock = $this->getMockBuilder(Google_Service_AndroidPublisher_Resource_PurchasesSubscriptions::class) + $productPurchaseMock->expects($this->any())->method('getAcknowledgementState')->willReturn(0); + + // subscriptions + $purchasesSubscriptionsMock = $this->getMockBuilder(Google_Service_AndroidPublisher_Resource_PurchasesSubscriptions::class) ->disableOriginalConstructor()->getMock(); + $subscriptionPurchaseMock = $this->getMockBuilder(Google_Service_AndroidPublisher_SubscriptionPurchase::class) + ->disableOriginalConstructor()->getMock(); + $subscriptionPurchaseMock->expects($this->any())->method('getAcknowledgementState')->willReturn(0); // mock expectations - $googleServiceAndroidPublisherMock->purchases_products = $productPurchaseMock; - $googleServiceAndroidPublisherMock->purchases_subscriptions = $subscriptionPurchaseMock; + $googleServiceAndroidPublisherMock->purchases_products = $purchasesProductsMock; + $googleServiceAndroidPublisherMock->purchases_subscriptions = $purchasesSubscriptionsMock; - $productPurchaseMock->expects($this->once())->method('acknowledge') + $purchasesProductsMock->expects($this->once())->method('get') + ->with( + $packageName, + $productId, + $purchaseToken + )->willReturn($productPurchaseMock); + $purchasesProductsMock->expects($this->once())->method('acknowledge') ->with( $packageName, $productId, @@ -39,7 +57,13 @@ public function testValidate(): void new \Google_Service_AndroidPublisher_ProductPurchasesAcknowledgeRequest(['developerPayload' => 'bar']) ); - $subscriptionPurchaseMock->expects($this->once())->method('acknowledge') + $purchasesSubscriptionsMock->expects($this->once())->method('get') + ->with( + $packageName, + $productId, + $purchaseToken + )->willReturn($subscriptionPurchaseMock); + $purchasesSubscriptionsMock->expects($this->once())->method('acknowledge') ->with( $packageName, $productId, @@ -52,4 +76,66 @@ public function testValidate(): void $googlePlayAcknowledger->acknowledge(Acknowledger::SUBSCRIPTION, 'foo'); $googlePlayAcknowledger->acknowledge(Acknowledger::PRODUCT, 'bar'); } + + public function testValidateWithAcknowledgedPurchase(): void + { + $packageName = 'testPackage'; + $productId = '15'; + $purchaseToken = 'testPurchaseToken'; + + // mock objects + $googleServiceAndroidPublisherMock = $this->getMockBuilder(Google_Service_AndroidPublisher::class) + ->disableOriginalConstructor()->getMock(); + + // products + $purchasesProductsMock = $this->getMockBuilder(Google_Service_AndroidPublisher_Resource_PurchasesProducts::class) + ->disableOriginalConstructor()->getMock(); + $productPurchaseMock = $this->getMockBuilder(Google_Service_AndroidPublisher_ProductPurchase::class) + ->disableOriginalConstructor()->getMock(); + $productPurchaseMock->expects($this->any())->method('getAcknowledgementState')->willReturn(1); + + // subscriptions + $purchasesSubscriptionsMock = $this->getMockBuilder(Google_Service_AndroidPublisher_Resource_PurchasesSubscriptions::class) + ->disableOriginalConstructor()->getMock(); + $subscriptionPurchaseMock = $this->getMockBuilder(Google_Service_AndroidPublisher_SubscriptionPurchase::class) + ->disableOriginalConstructor()->getMock(); + $subscriptionPurchaseMock->expects($this->any())->method('getAcknowledgementState')->willReturn(1); + + // mock expectations + $googleServiceAndroidPublisherMock->purchases_products = $purchasesProductsMock; + $googleServiceAndroidPublisherMock->purchases_subscriptions = $purchasesSubscriptionsMock; + + $purchasesProductsMock->expects($this->once())->method('get') + ->with( + $packageName, + $productId, + $purchaseToken + )->willReturn($productPurchaseMock); + $purchasesProductsMock->expects($this->never())->method('acknowledge') + ->with( + $packageName, + $productId, + $purchaseToken, + new \Google_Service_AndroidPublisher_ProductPurchasesAcknowledgeRequest(['developerPayload' => 'bar']) + ); + + $purchasesSubscriptionsMock->expects($this->once())->method('get') + ->with( + $packageName, + $productId, + $purchaseToken + )->willReturn($subscriptionPurchaseMock); + $purchasesSubscriptionsMock->expects($this->never())->method('acknowledge') + ->with( + $packageName, + $productId, + $purchaseToken, + new \Google_Service_AndroidPublisher_SubscriptionPurchasesAcknowledgeRequest(['developerPayload' => 'foo']) + ); + + $googlePlayAcknowledger = new Acknowledger($googleServiceAndroidPublisherMock, $packageName, $productId, $purchaseToken); + + $googlePlayAcknowledger->acknowledge(Acknowledger::SUBSCRIPTION, 'foo'); + $googlePlayAcknowledger->acknowledge(Acknowledger::PRODUCT, 'bar'); + } } From 503e3d527e29f5d235bc766c13b9f9c78c58ce96 Mon Sep 17 00:00:00 2001 From: Florent Blaison Date: Tue, 14 Jan 2020 12:20:49 +0100 Subject: [PATCH 2/4] [ADD] strategy for acknowledger --- src/GooglePlay/Acknowledger.php | 117 +++++++---- .../Exception/AlreadyAcknowledgeException.php | 29 +++ .../GooglePlay/GooglePlayAcknowledgerTest.php | 198 ++++++++++++++---- 3 files changed, 266 insertions(+), 78 deletions(-) create mode 100644 src/GooglePlay/Exception/AlreadyAcknowledgeException.php diff --git a/src/GooglePlay/Acknowledger.php b/src/GooglePlay/Acknowledger.php index 5f560c6..e888ac8 100644 --- a/src/GooglePlay/Acknowledger.php +++ b/src/GooglePlay/Acknowledger.php @@ -2,11 +2,19 @@ namespace ReceiptValidator\GooglePlay; +use ReceiptValidator\GooglePlay\Exception\AlreadyAcknowledgeException; +use ReceiptValidator\RunTimeException; + /** * Class Acknowledger. */ class Acknowledger { + // Do acknowledge only in case if it have not done + const ACKNOWLEDGE_STRATEGY_IMPLICIT = 'strategy_implicit'; + // Try to do acknowledge directly (exception will be returned in case when acknowledge already was done) + const ACKNOWLEDGE_STRATEGY_EXPLICIT = 'strategy_explicit'; + const SUBSCRIPTION = 'SUBSCRIPTION'; const PRODUCT = 'PRODUCT'; @@ -26,6 +34,10 @@ class Acknowledger * @var string */ protected $productId; + /** + * @var string + */ + protected $strategy; /** * Acknowledger constructor. @@ -34,76 +46,95 @@ class Acknowledger * @param string $packageName * @param string $purchaseToken * @param string $productId + * @param string $strategy + * + * @throws RunTimeException */ public function __construct( \Google_Service_AndroidPublisher $googleServiceAndroidPublisher, $packageName, $productId, - $purchaseToken + $purchaseToken, + $strategy = self::ACKNOWLEDGE_STRATEGY_EXPLICIT ) { + if (!\in_array($strategy, [self::ACKNOWLEDGE_STRATEGY_EXPLICIT, self::ACKNOWLEDGE_STRATEGY_IMPLICIT])) { + throw new RuntimeException(\sprintf('Invalid strategy provided %s', $strategy)); + } + $this->androidPublisherService = $googleServiceAndroidPublisher; $this->packageName = $packageName; $this->purchaseToken = $purchaseToken; $this->productId = $productId; + $this->strategy = $strategy; } /** * @param string $type * @param string $developerPayload * + * @throws RunTimeException + * * @return bool */ public function acknowledge(string $type = self::SUBSCRIPTION, string $developerPayload = '') { - try { - switch ($type) { - case self::SUBSCRIPTION: - $subscriptionPurchase = $this->androidPublisherService->purchases_subscriptions->get( + switch ($type) { + case self::SUBSCRIPTION: + $subscriptionPurchase = $this->androidPublisherService->purchases_subscriptions->get( + $this->packageName, + $this->productId, + $this->purchaseToken + ); + + if ($this->strategy === self::ACKNOWLEDGE_STRATEGY_EXPLICIT + && $subscriptionPurchase->getAcknowledgementState() === 1) { + throw AlreadyAcknowledgeException::fromSubscriptionPurchase($subscriptionPurchase); + } + + if ($subscriptionPurchase->getAcknowledgementState() != 1) { + $this->androidPublisherService->purchases_subscriptions->acknowledge( $this->packageName, $this->productId, - $this->purchaseToken + $this->purchaseToken, + new \Google_Service_AndroidPublisher_SubscriptionPurchasesAcknowledgeRequest( + ['developerPayload' => $developerPayload] + ) ); - if ($subscriptionPurchase->getAcknowledgementState() != 1) { - $this->androidPublisherService->purchases_subscriptions->acknowledge( - $this->packageName, - $this->productId, - $this->purchaseToken, - new \Google_Service_AndroidPublisher_SubscriptionPurchasesAcknowledgeRequest( - ['developerPayload' => $developerPayload] - ) - ); - } - break; - case self::PRODUCT: - $productPurchase = $this->androidPublisherService->purchases_products->get( + } + break; + case self::PRODUCT: + $productPurchase = $this->androidPublisherService->purchases_products->get( + $this->packageName, + $this->productId, + $this->purchaseToken + ); + + if ($this->strategy === self::ACKNOWLEDGE_STRATEGY_EXPLICIT + && $productPurchase->getAcknowledgementState() === 1) { + throw AlreadyAcknowledgeException::fromProductPurchase($productPurchase); + } + + if ($productPurchase->getAcknowledgementState() != 1) { + $this->androidPublisherService->purchases_products->acknowledge( $this->packageName, $this->productId, - $this->purchaseToken - ); - if ($productPurchase->getAcknowledgementState() != 1) { - $this->androidPublisherService->purchases_products->acknowledge( - $this->packageName, - $this->productId, - $this->purchaseToken, - new \Google_Service_AndroidPublisher_ProductPurchasesAcknowledgeRequest( - ['developerPayload' => $developerPayload] - ) - ); - } - break; - default: - throw new \RuntimeException( - \sprintf( - 'Invalid type provided : %s expected %s', - $type, - implode(',', [self::PRODUCT, self::SUBSCRIPTION]) + $this->purchaseToken, + new \Google_Service_AndroidPublisher_ProductPurchasesAcknowledgeRequest( + ['developerPayload' => $developerPayload] ) ); - } - - return true; - } catch (\Exception $e) { - throw new \RuntimeException($e->getMessage(), $e->getCode(), $e); + } + break; + default: + throw new RuntimeException( + \sprintf( + 'Invalid type provided : %s expected %s', + $type, + implode(',', [self::PRODUCT, self::SUBSCRIPTION]) + ) + ); } + + return true; } } diff --git a/src/GooglePlay/Exception/AlreadyAcknowledgeException.php b/src/GooglePlay/Exception/AlreadyAcknowledgeException.php new file mode 100644 index 0000000..066a41e --- /dev/null +++ b/src/GooglePlay/Exception/AlreadyAcknowledgeException.php @@ -0,0 +1,29 @@ +getOrderId()) + ); + } + + public static function fromProductPurchase( + \Google_Service_AndroidPublisher_ProductPurchase $productPurchase + ) { + return new static( + \sprintf('Product purchase %s already acknowledged', $productPurchase->getOrderId()) + ); + } +} diff --git a/tests/GooglePlay/GooglePlayAcknowledgerTest.php b/tests/GooglePlay/GooglePlayAcknowledgerTest.php index 5516797..6da35c9 100755 --- a/tests/GooglePlay/GooglePlayAcknowledgerTest.php +++ b/tests/GooglePlay/GooglePlayAcknowledgerTest.php @@ -9,6 +9,7 @@ use Google_Service_AndroidPublisher_SubscriptionPurchase; use PHPUnit\Framework\TestCase; use ReceiptValidator\GooglePlay\Acknowledger; +use ReceiptValidator\GooglePlay\Exception\AlreadyAcknowledgeException; /** * @group library @@ -23,20 +24,24 @@ public function testValidateWithNonAcknowledgedPurchase(): void // mock objects $googleServiceAndroidPublisherMock = $this->getMockBuilder(Google_Service_AndroidPublisher::class) - ->disableOriginalConstructor()->getMock(); + ->disableOriginalConstructor()->getMock(); // products - $purchasesProductsMock = $this->getMockBuilder(Google_Service_AndroidPublisher_Resource_PurchasesProducts::class) - ->disableOriginalConstructor()->getMock(); + $purchasesProductsMock = $this->getMockBuilder( + Google_Service_AndroidPublisher_Resource_PurchasesProducts::class + ) + ->disableOriginalConstructor()->getMock(); $productPurchaseMock = $this->getMockBuilder(Google_Service_AndroidPublisher_ProductPurchase::class) - ->disableOriginalConstructor()->getMock(); + ->disableOriginalConstructor()->getMock(); $productPurchaseMock->expects($this->any())->method('getAcknowledgementState')->willReturn(0); // subscriptions - $purchasesSubscriptionsMock = $this->getMockBuilder(Google_Service_AndroidPublisher_Resource_PurchasesSubscriptions::class) - ->disableOriginalConstructor()->getMock(); + $purchasesSubscriptionsMock = $this->getMockBuilder( + Google_Service_AndroidPublisher_Resource_PurchasesSubscriptions::class + ) + ->disableOriginalConstructor()->getMock(); $subscriptionPurchaseMock = $this->getMockBuilder(Google_Service_AndroidPublisher_SubscriptionPurchase::class) - ->disableOriginalConstructor()->getMock(); + ->disableOriginalConstructor()->getMock(); $subscriptionPurchaseMock->expects($this->any())->method('getAcknowledgementState')->willReturn(0); // mock expectations @@ -44,40 +49,49 @@ public function testValidateWithNonAcknowledgedPurchase(): void $googleServiceAndroidPublisherMock->purchases_subscriptions = $purchasesSubscriptionsMock; $purchasesProductsMock->expects($this->once())->method('get') - ->with( - $packageName, - $productId, - $purchaseToken - )->willReturn($productPurchaseMock); - $purchasesProductsMock->expects($this->once())->method('acknowledge') - ->with( - $packageName, - $productId, - $purchaseToken, - new \Google_Service_AndroidPublisher_ProductPurchasesAcknowledgeRequest(['developerPayload' => 'bar']) - ); - - $purchasesSubscriptionsMock->expects($this->once())->method('get') ->with( $packageName, $productId, $purchaseToken - )->willReturn($subscriptionPurchaseMock); + )->willReturn($productPurchaseMock); + $purchasesProductsMock->expects($this->once())->method('acknowledge') + ->with( + $packageName, + $productId, + $purchaseToken, + new \Google_Service_AndroidPublisher_ProductPurchasesAcknowledgeRequest( + ['developerPayload' => 'bar'] + ) + ); + + $purchasesSubscriptionsMock->expects($this->once())->method('get') + ->with( + $packageName, + $productId, + $purchaseToken + )->willReturn($subscriptionPurchaseMock); $purchasesSubscriptionsMock->expects($this->once())->method('acknowledge') - ->with( - $packageName, - $productId, - $purchaseToken, - new \Google_Service_AndroidPublisher_SubscriptionPurchasesAcknowledgeRequest(['developerPayload' => 'foo']) - ); + ->with( + $packageName, + $productId, + $purchaseToken, + new \Google_Service_AndroidPublisher_SubscriptionPurchasesAcknowledgeRequest( + ['developerPayload' => 'foo'] + ) + ); - $googlePlayAcknowledger = new Acknowledger($googleServiceAndroidPublisherMock, $packageName, $productId, $purchaseToken); + $googlePlayAcknowledger = new Acknowledger( + $googleServiceAndroidPublisherMock, + $packageName, + $productId, + $purchaseToken + ); $googlePlayAcknowledger->acknowledge(Acknowledger::SUBSCRIPTION, 'foo'); $googlePlayAcknowledger->acknowledge(Acknowledger::PRODUCT, 'bar'); } - public function testValidateWithAcknowledgedPurchase(): void + public function testValidateWithAcknowledgedPurchaseAndImplicitStrategy(): void { $packageName = 'testPackage'; $productId = '15'; @@ -88,14 +102,18 @@ public function testValidateWithAcknowledgedPurchase(): void ->disableOriginalConstructor()->getMock(); // products - $purchasesProductsMock = $this->getMockBuilder(Google_Service_AndroidPublisher_Resource_PurchasesProducts::class) + $purchasesProductsMock = $this->getMockBuilder( + Google_Service_AndroidPublisher_Resource_PurchasesProducts::class + ) ->disableOriginalConstructor()->getMock(); $productPurchaseMock = $this->getMockBuilder(Google_Service_AndroidPublisher_ProductPurchase::class) ->disableOriginalConstructor()->getMock(); $productPurchaseMock->expects($this->any())->method('getAcknowledgementState')->willReturn(1); // subscriptions - $purchasesSubscriptionsMock = $this->getMockBuilder(Google_Service_AndroidPublisher_Resource_PurchasesSubscriptions::class) + $purchasesSubscriptionsMock = $this->getMockBuilder( + Google_Service_AndroidPublisher_Resource_PurchasesSubscriptions::class + ) ->disableOriginalConstructor()->getMock(); $subscriptionPurchaseMock = $this->getMockBuilder(Google_Service_AndroidPublisher_SubscriptionPurchase::class) ->disableOriginalConstructor()->getMock(); @@ -116,7 +134,9 @@ public function testValidateWithAcknowledgedPurchase(): void $packageName, $productId, $purchaseToken, - new \Google_Service_AndroidPublisher_ProductPurchasesAcknowledgeRequest(['developerPayload' => 'bar']) + new \Google_Service_AndroidPublisher_ProductPurchasesAcknowledgeRequest( + ['developerPayload' => 'bar'] + ) ); $purchasesSubscriptionsMock->expects($this->once())->method('get') @@ -130,12 +150,120 @@ public function testValidateWithAcknowledgedPurchase(): void $packageName, $productId, $purchaseToken, - new \Google_Service_AndroidPublisher_SubscriptionPurchasesAcknowledgeRequest(['developerPayload' => 'foo']) + new \Google_Service_AndroidPublisher_SubscriptionPurchasesAcknowledgeRequest( + ['developerPayload' => 'foo'] + ) + ); + + $googlePlayAcknowledger = new Acknowledger( + $googleServiceAndroidPublisherMock, + $packageName, + $productId, + $purchaseToken, + Acknowledger::ACKNOWLEDGE_STRATEGY_IMPLICIT + ); + + $googlePlayAcknowledger->acknowledge(Acknowledger::SUBSCRIPTION, 'foo'); + $googlePlayAcknowledger->acknowledge(Acknowledger::PRODUCT, 'bar'); + } + + public function testValidateWithAcknowledgedPurchaseAndExplicitStrategyForSubscription(): void + { + $this->expectException(AlreadyAcknowledgeException::class); + + $packageName = 'testPackage'; + $productId = '15'; + $purchaseToken = 'testPurchaseToken'; + + // mock objects + $googleServiceAndroidPublisherMock = $this->getMockBuilder(Google_Service_AndroidPublisher::class) + ->disableOriginalConstructor()->getMock(); + + // subscriptions + $purchasesSubscriptionsMock = $this->getMockBuilder( + Google_Service_AndroidPublisher_Resource_PurchasesSubscriptions::class + ) + ->disableOriginalConstructor()->getMock(); + $subscriptionPurchaseMock = $this->getMockBuilder(Google_Service_AndroidPublisher_SubscriptionPurchase::class) + ->disableOriginalConstructor()->getMock(); + $subscriptionPurchaseMock->expects($this->any())->method('getAcknowledgementState')->willReturn(1); + + // mock expectations + $googleServiceAndroidPublisherMock->purchases_subscriptions = $purchasesSubscriptionsMock; + + $purchasesSubscriptionsMock->expects($this->once())->method('get') + ->with( + $packageName, + $productId, + $purchaseToken + )->willReturn($subscriptionPurchaseMock); + $purchasesSubscriptionsMock->expects($this->never())->method('acknowledge') + ->with( + $packageName, + $productId, + $purchaseToken, + new \Google_Service_AndroidPublisher_SubscriptionPurchasesAcknowledgeRequest( + ['developerPayload' => 'foo'] + ) ); - $googlePlayAcknowledger = new Acknowledger($googleServiceAndroidPublisherMock, $packageName, $productId, $purchaseToken); + $googlePlayAcknowledger = new Acknowledger( + $googleServiceAndroidPublisherMock, + $packageName, + $productId, + $purchaseToken + ); $googlePlayAcknowledger->acknowledge(Acknowledger::SUBSCRIPTION, 'foo'); + } + + public function testValidateWithAcknowledgedPurchaseAndExplicitStrategyForProduct(): void + { + $this->expectException(AlreadyAcknowledgeException::class); + + $packageName = 'testPackage'; + $productId = '15'; + $purchaseToken = 'testPurchaseToken'; + + // mock objects + $googleServiceAndroidPublisherMock = $this->getMockBuilder(Google_Service_AndroidPublisher::class) + ->disableOriginalConstructor()->getMock(); + + // products + $purchasesProductsMock = $this->getMockBuilder( + Google_Service_AndroidPublisher_Resource_PurchasesProducts::class + ) + ->disableOriginalConstructor()->getMock(); + $productPurchaseMock = $this->getMockBuilder(Google_Service_AndroidPublisher_ProductPurchase::class) + ->disableOriginalConstructor()->getMock(); + $productPurchaseMock->expects($this->any())->method('getAcknowledgementState')->willReturn(1); + + // mock expectations + $googleServiceAndroidPublisherMock->purchases_products = $purchasesProductsMock; + + $purchasesProductsMock->expects($this->once())->method('get') + ->with( + $packageName, + $productId, + $purchaseToken + )->willReturn($productPurchaseMock); + $purchasesProductsMock->expects($this->never())->method('acknowledge') + ->with( + $packageName, + $productId, + $purchaseToken, + new \Google_Service_AndroidPublisher_ProductPurchasesAcknowledgeRequest( + ['developerPayload' => 'bar'] + ) + ); + + $googlePlayAcknowledger = new Acknowledger( + $googleServiceAndroidPublisherMock, + $packageName, + $productId, + $purchaseToken + ); + $googlePlayAcknowledger->acknowledge(Acknowledger::PRODUCT, 'bar'); } } From 06f2fb4ea95b4fb10898da9292e6ae6f8d668466 Mon Sep 17 00:00:00 2001 From: Florent Blaison Date: Mon, 3 Aug 2020 15:34:10 +0200 Subject: [PATCH 3/4] lint --- src/GooglePlay/Acknowledger.php | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/GooglePlay/Acknowledger.php b/src/GooglePlay/Acknowledger.php index 26c0078..0d01c8f 100644 --- a/src/GooglePlay/Acknowledger.php +++ b/src/GooglePlay/Acknowledger.php @@ -8,8 +8,6 @@ use Google_Service_AndroidPublisher_SubscriptionPurchasesAcknowledgeRequest; use ReceiptValidator\GooglePlay\Exception\AlreadyAcknowledgeException; use ReceiptValidator\RunTimeException; -use function in_array; -use function sprintf; /** * Class Acknowledger. @@ -49,10 +47,10 @@ class Acknowledger * Acknowledger constructor. * * @param Google_Service_AndroidPublisher $googleServiceAndroidPublisher - * @param string $packageName - * @param string $purchaseToken - * @param string $productId - * @param string $strategy + * @param string $packageName + * @param string $purchaseToken + * @param string $productId + * @param string $strategy * * @throws RunTimeException */ @@ -78,9 +76,9 @@ public function __construct( * @param string $type * @param string $developerPayload * + * @return bool * @throws RunTimeException * - * @return bool */ public function acknowledge(string $type = self::SUBSCRIPTION, string $developerPayload = '') { From efe7bf02f68bbf42090be1029141965fbd4f91b9 Mon Sep 17 00:00:00 2001 From: Florent Blaison Date: Mon, 3 Aug 2020 15:47:09 +0200 Subject: [PATCH 4/4] refactor from code review --- src/GooglePlay/Acknowledger.php | 73 +++++++++++-------- .../Exception/AlreadyAcknowledgeException.php | 29 -------- .../GooglePlay/GooglePlayAcknowledgerTest.php | 42 ++--------- 3 files changed, 50 insertions(+), 94 deletions(-) delete mode 100644 src/GooglePlay/Exception/AlreadyAcknowledgeException.php diff --git a/src/GooglePlay/Acknowledger.php b/src/GooglePlay/Acknowledger.php index 0d01c8f..c464b92 100644 --- a/src/GooglePlay/Acknowledger.php +++ b/src/GooglePlay/Acknowledger.php @@ -4,9 +4,6 @@ use Exception; use Google_Service_AndroidPublisher; -use Google_Service_AndroidPublisher_ProductPurchasesAcknowledgeRequest; -use Google_Service_AndroidPublisher_SubscriptionPurchasesAcknowledgeRequest; -use ReceiptValidator\GooglePlay\Exception\AlreadyAcknowledgeException; use ReceiptValidator\RunTimeException; /** @@ -61,7 +58,7 @@ public function __construct( $purchaseToken, $strategy = self::ACKNOWLEDGE_STRATEGY_EXPLICIT ) { - if (! in_array($strategy, [self::ACKNOWLEDGE_STRATEGY_EXPLICIT, self::ACKNOWLEDGE_STRATEGY_IMPLICIT])) { + if (!in_array($strategy, [self::ACKNOWLEDGE_STRATEGY_EXPLICIT, self::ACKNOWLEDGE_STRATEGY_IMPLICIT])) { throw new RuntimeException(sprintf('Invalid strategy provided %s', $strategy)); } @@ -76,58 +73,72 @@ public function __construct( * @param string $type * @param string $developerPayload * - * @return bool * @throws RunTimeException * + * @return bool */ public function acknowledge(string $type = self::SUBSCRIPTION, string $developerPayload = '') { try { switch ($type) { case self::SUBSCRIPTION: - $subscriptionPurchase = $this->androidPublisherService->purchases_subscriptions->get( - $this->packageName, - $this->productId, - $this->purchaseToken - ); - - if ($this->strategy === self::ACKNOWLEDGE_STRATEGY_EXPLICIT - && $subscriptionPurchase->getAcknowledgementState() === 1) { - throw AlreadyAcknowledgeException::fromSubscriptionPurchase($subscriptionPurchase); - } - - if ($subscriptionPurchase->getAcknowledgementState() != 1) { + if ($this->strategy === self::ACKNOWLEDGE_STRATEGY_EXPLICIT) { + // Here exception might be thrown as previously, so no BC break here $this->androidPublisherService->purchases_subscriptions->acknowledge( $this->packageName, $this->productId, $this->purchaseToken, - new Google_Service_AndroidPublisher_SubscriptionPurchasesAcknowledgeRequest( + new \Google_Service_AndroidPublisher_SubscriptionPurchasesAcknowledgeRequest( ['developerPayload' => $developerPayload] ) ); + } elseif ($this->strategy === self::ACKNOWLEDGE_STRATEGY_IMPLICIT) { + $subscriptionPurchase = $this->androidPublisherService->purchases_subscriptions->get( + $this->packageName, + $this->productId, + $this->purchaseToken + ); + + if ($subscriptionPurchase->getAcknowledgementState() !== AbstractResponse::ACKNOWLEDGEMENT_STATE_DONE) { + $this->androidPublisherService->purchases_subscriptions->acknowledge( + $this->packageName, + $this->productId, + $this->purchaseToken, + new \Google_Service_AndroidPublisher_SubscriptionPurchasesAcknowledgeRequest( + ['developerPayload' => $developerPayload] + ) + ); + } } break; case self::PRODUCT: - $productPurchase = $this->androidPublisherService->purchases_products->get( - $this->packageName, - $this->productId, - $this->purchaseToken - ); - - if ($this->strategy === self::ACKNOWLEDGE_STRATEGY_EXPLICIT - && $productPurchase->getAcknowledgementState() === 1) { - throw AlreadyAcknowledgeException::fromProductPurchase($productPurchase); - } - - if ($productPurchase->getAcknowledgementState() != 1) { + if ($this->strategy === self::ACKNOWLEDGE_STRATEGY_EXPLICIT) { + // Here exception might be thrown as previously, so no BC break here $this->androidPublisherService->purchases_products->acknowledge( $this->packageName, $this->productId, $this->purchaseToken, - new Google_Service_AndroidPublisher_ProductPurchasesAcknowledgeRequest( + new \Google_Service_AndroidPublisher_ProductPurchasesAcknowledgeRequest( ['developerPayload' => $developerPayload] ) ); + } elseif ($this->strategy === self::ACKNOWLEDGE_STRATEGY_IMPLICIT) { + $productPurchase = $this->androidPublisherService->purchases_products->get( + $this->packageName, + $this->productId, + $this->purchaseToken + ); + + if ($productPurchase->getAcknowledgementState() !== AbstractResponse::ACKNOWLEDGEMENT_STATE_DONE) { + $this->androidPublisherService->purchases_products->acknowledge( + $this->packageName, + $this->productId, + $this->purchaseToken, + new \Google_Service_AndroidPublisher_ProductPurchasesAcknowledgeRequest( + ['developerPayload' => $developerPayload] + ) + ); + } } break; default: diff --git a/src/GooglePlay/Exception/AlreadyAcknowledgeException.php b/src/GooglePlay/Exception/AlreadyAcknowledgeException.php deleted file mode 100644 index 066a41e..0000000 --- a/src/GooglePlay/Exception/AlreadyAcknowledgeException.php +++ /dev/null @@ -1,29 +0,0 @@ -getOrderId()) - ); - } - - public static function fromProductPurchase( - \Google_Service_AndroidPublisher_ProductPurchase $productPurchase - ) { - return new static( - \sprintf('Product purchase %s already acknowledged', $productPurchase->getOrderId()) - ); - } -} diff --git a/tests/GooglePlay/GooglePlayAcknowledgerTest.php b/tests/GooglePlay/GooglePlayAcknowledgerTest.php index 6da35c9..f5d10b0 100755 --- a/tests/GooglePlay/GooglePlayAcknowledgerTest.php +++ b/tests/GooglePlay/GooglePlayAcknowledgerTest.php @@ -9,7 +9,6 @@ use Google_Service_AndroidPublisher_SubscriptionPurchase; use PHPUnit\Framework\TestCase; use ReceiptValidator\GooglePlay\Acknowledger; -use ReceiptValidator\GooglePlay\Exception\AlreadyAcknowledgeException; /** * @group library @@ -48,12 +47,6 @@ public function testValidateWithNonAcknowledgedPurchase(): void $googleServiceAndroidPublisherMock->purchases_products = $purchasesProductsMock; $googleServiceAndroidPublisherMock->purchases_subscriptions = $purchasesSubscriptionsMock; - $purchasesProductsMock->expects($this->once())->method('get') - ->with( - $packageName, - $productId, - $purchaseToken - )->willReturn($productPurchaseMock); $purchasesProductsMock->expects($this->once())->method('acknowledge') ->with( $packageName, @@ -64,12 +57,6 @@ public function testValidateWithNonAcknowledgedPurchase(): void ) ); - $purchasesSubscriptionsMock->expects($this->once())->method('get') - ->with( - $packageName, - $productId, - $purchaseToken - )->willReturn($subscriptionPurchaseMock); $purchasesSubscriptionsMock->expects($this->once())->method('acknowledge') ->with( $packageName, @@ -169,35 +156,30 @@ public function testValidateWithAcknowledgedPurchaseAndImplicitStrategy(): void public function testValidateWithAcknowledgedPurchaseAndExplicitStrategyForSubscription(): void { - $this->expectException(AlreadyAcknowledgeException::class); - $packageName = 'testPackage'; $productId = '15'; $purchaseToken = 'testPurchaseToken'; // mock objects $googleServiceAndroidPublisherMock = $this->getMockBuilder(Google_Service_AndroidPublisher::class) - ->disableOriginalConstructor()->getMock(); + ->disableOriginalConstructor() + ->getMock(); // subscriptions $purchasesSubscriptionsMock = $this->getMockBuilder( Google_Service_AndroidPublisher_Resource_PurchasesSubscriptions::class ) - ->disableOriginalConstructor()->getMock(); + ->disableOriginalConstructor() + ->getMock(); $subscriptionPurchaseMock = $this->getMockBuilder(Google_Service_AndroidPublisher_SubscriptionPurchase::class) - ->disableOriginalConstructor()->getMock(); + ->disableOriginalConstructor() + ->getMock(); $subscriptionPurchaseMock->expects($this->any())->method('getAcknowledgementState')->willReturn(1); // mock expectations $googleServiceAndroidPublisherMock->purchases_subscriptions = $purchasesSubscriptionsMock; - $purchasesSubscriptionsMock->expects($this->once())->method('get') - ->with( - $packageName, - $productId, - $purchaseToken - )->willReturn($subscriptionPurchaseMock); - $purchasesSubscriptionsMock->expects($this->never())->method('acknowledge') + $purchasesSubscriptionsMock->expects($this->once())->method('acknowledge') ->with( $packageName, $productId, @@ -219,8 +201,6 @@ public function testValidateWithAcknowledgedPurchaseAndExplicitStrategyForSubscr public function testValidateWithAcknowledgedPurchaseAndExplicitStrategyForProduct(): void { - $this->expectException(AlreadyAcknowledgeException::class); - $packageName = 'testPackage'; $productId = '15'; $purchaseToken = 'testPurchaseToken'; @@ -241,13 +221,7 @@ public function testValidateWithAcknowledgedPurchaseAndExplicitStrategyForProduc // mock expectations $googleServiceAndroidPublisherMock->purchases_products = $purchasesProductsMock; - $purchasesProductsMock->expects($this->once())->method('get') - ->with( - $packageName, - $productId, - $purchaseToken - )->willReturn($productPurchaseMock); - $purchasesProductsMock->expects($this->never())->method('acknowledge') + $purchasesProductsMock->expects($this->once())->method('acknowledge') ->with( $packageName, $productId,