From c322ddd122743da689a56298192fb8357f9e694f Mon Sep 17 00:00:00 2001 From: Tyler King Date: Wed, 25 Apr 2018 13:32:57 -0230 Subject: [PATCH 1/4] Usage support built in to the plan init --- src/ShopifyApp/Libraries/BillingPlan.php | 37 ++++++++++++------- .../Traits/BillingControllerTrait.php | 10 ++++- .../resources/config/shopify-app.php | 22 +++++++++++ tests/Controllers/BillingControllerTest.php | 25 ++++++++++++- 4 files changed, 78 insertions(+), 16 deletions(-) diff --git a/src/ShopifyApp/Libraries/BillingPlan.php b/src/ShopifyApp/Libraries/BillingPlan.php index fa6dc802..4575a6b1 100644 --- a/src/ShopifyApp/Libraries/BillingPlan.php +++ b/src/ShopifyApp/Libraries/BillingPlan.php @@ -56,11 +56,13 @@ public function __construct(Shop $shop, string $chargeType = 'recurring') * * @param array $plan The plan details. * $plan = [ - * 'name' => (string) Plan name. - * 'price' => (float) Plan price. Required. - * 'test' => (boolean) Test mode or not. - * 'trial_days' => (int) Plan trial period in days. - * 'return_url' => (string) URL to handle response for acceptance or decline or billing. Required. + * 'name' => (string) Plan name. + * 'price' => (float) Plan price. Required. + * 'test' => (boolean) Test mode or not. + * 'trial_days' => (int) Plan trial period in days. + * 'return_url' => (string) URL to handle response for acceptance or decline or billing. Required. + * 'capped_amount' => (float) Capped price if using UsageCharge API. + * 'terms' => (string) Terms for the usage. Required if using capped_amount. * ] * * @return $this @@ -143,19 +145,26 @@ public function getConfirmationUrl() throw new Exception('Plan details are missing for confirmation URL request.'); } + // Build the charge array + $chargeDetails = [ + 'test' => isset($this->details['test']) ? $this->details['test'] : false, + 'trial_days' => isset($this->details['trial_days']) ? $this->details['trial_days'] : 0, + 'name' => $this->details['name'], + 'price' => $this->details['price'], + 'return_url' => $this->details['return_url'] + ]; + + // Handle capped amounts for UsageCharge API + if (isset($this->details['capped_amount'])) { + $chargeDetails['capped_amount'] = $this->details['capped_amount']; + $chargeDetails['terms'] = $this->details['terms']; + } + // Begin the charge request $charge = $this->shop->api()->request( 'POST', "/admin/{$this->chargeType}s.json", - [ - "{$this->chargeType}" => [ - 'test' => isset($this->details['test']) ? $this->details['test'] : false, - 'trial_days' => isset($this->details['trial_days']) ? $this->details['trial_days'] : 0, - 'name' => $this->details['name'], - 'price' => $this->details['price'], - 'return_url' => $this->details['return_url'], - ], - ] + ["{$this->chargeType}" => $chargeDetails] )->body->{$this->chargeType}; return $charge->confirmation_url; diff --git a/src/ShopifyApp/Traits/BillingControllerTrait.php b/src/ShopifyApp/Traits/BillingControllerTrait.php index 499ffbb0..82102185 100644 --- a/src/ShopifyApp/Traits/BillingControllerTrait.php +++ b/src/ShopifyApp/Traits/BillingControllerTrait.php @@ -65,13 +65,21 @@ public function process() */ protected function planDetails() { - return [ + $plan = [ 'name' => config('shopify-app.billing_plan'), 'price' => config('shopify-app.billing_price'), 'test' => config('shopify-app.billing_test'), 'trial_days' => config('shopify-app.billing_trial_days'), 'return_url' => url(config('shopify-app.billing_redirect')), ]; + + // Handle capped amounts for UsageCharge API + if (config('shopify-app.billing_capped_amount')) { + $plan['capped_amount'] = config('shopify-app.billing_capped_amount'); + $plan['terms'] = config('shopify-app.billing_terms'); + } + + return $plan; } /** diff --git a/src/ShopifyApp/resources/config/shopify-app.php b/src/ShopifyApp/resources/config/shopify-app.php index fa33d81f..728026d3 100644 --- a/src/ShopifyApp/resources/config/shopify-app.php +++ b/src/ShopifyApp/resources/config/shopify-app.php @@ -184,6 +184,28 @@ 'billing_redirect' => env('SHOPIFY_BILLING_REDIRECT', '/billing/process'), + /* + |-------------------------------------------------------------------------- + | Billing Capped Amount + |-------------------------------------------------------------------------- + | + | The capped price for charging a customer when using the UsageCharge API. + | + */ + + 'billing_capped_amount' => env('SHOPIFY_BILLING_CAPPED_AMOUNT'), + + /* + |-------------------------------------------------------------------------- + | Billing Terms + |-------------------------------------------------------------------------- + | + | Terms for the usage. Required if using capped amount. + | + */ + + 'billing_terms' => env('SHOPIFY_BILLING_TERMS'), + /* |-------------------------------------------------------------------------- | Shopify Webhooks diff --git a/tests/Controllers/BillingControllerTest.php b/tests/Controllers/BillingControllerTest.php index 66de9568..54e520c8 100644 --- a/tests/Controllers/BillingControllerTest.php +++ b/tests/Controllers/BillingControllerTest.php @@ -66,8 +66,31 @@ public function testReturnsBasePlanDetails() 'price' => config('shopify-app.billing_price'), 'test' => config('shopify-app.billing_test'), 'trial_days' => config('shopify-app.billing_trial_days'), - 'return_url' => url(config('shopify-app.billing_redirect')), + 'return_url' => url(config('shopify-app.billing_redirect')) + ], + $method->invoke($controller, 'planDetails') + ); + } + public function testReturnsBasePlanDetailsWithUsage() + { + config(['shopify-app.billing_capped_amount' => 100.00]); + config(['shopify-app.billing_terms' => '$1 for 100 emails.']); + + $controller = new BillingController(); + $method = new ReflectionMethod(BillingController::class, 'planDetails'); + $method->setAccessible(true); + + // Based on default config + $this->assertEquals( + [ + 'name' => config('shopify-app.billing_plan'), + 'price' => config('shopify-app.billing_price'), + 'test' => config('shopify-app.billing_test'), + 'trial_days' => config('shopify-app.billing_trial_days'), + 'capped_amount' => config('shopify-app.billing_capped_amount'), + 'terms' => config('shopify-app.billing_terms'), + 'return_url' => url(config('shopify-app.billing_redirect')) ], $method->invoke($controller, 'planDetails') ); From 41f35824a93d340939e9cbceef49bc2457dd1db0 Mon Sep 17 00:00:00 2001 From: Tyler King Date: Wed, 25 Apr 2018 13:38:42 -0230 Subject: [PATCH 2/4] StyleCI fixes --- src/ShopifyApp/Libraries/BillingPlan.php | 2 +- tests/Controllers/BillingControllerTest.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ShopifyApp/Libraries/BillingPlan.php b/src/ShopifyApp/Libraries/BillingPlan.php index 4575a6b1..7e1bad98 100644 --- a/src/ShopifyApp/Libraries/BillingPlan.php +++ b/src/ShopifyApp/Libraries/BillingPlan.php @@ -151,7 +151,7 @@ public function getConfirmationUrl() 'trial_days' => isset($this->details['trial_days']) ? $this->details['trial_days'] : 0, 'name' => $this->details['name'], 'price' => $this->details['price'], - 'return_url' => $this->details['return_url'] + 'return_url' => $this->details['return_url'], ]; // Handle capped amounts for UsageCharge API diff --git a/tests/Controllers/BillingControllerTest.php b/tests/Controllers/BillingControllerTest.php index 54e520c8..20bcf47c 100644 --- a/tests/Controllers/BillingControllerTest.php +++ b/tests/Controllers/BillingControllerTest.php @@ -66,7 +66,7 @@ public function testReturnsBasePlanDetails() 'price' => config('shopify-app.billing_price'), 'test' => config('shopify-app.billing_test'), 'trial_days' => config('shopify-app.billing_trial_days'), - 'return_url' => url(config('shopify-app.billing_redirect')) + 'return_url' => url(config('shopify-app.billing_redirect')), ], $method->invoke($controller, 'planDetails') ); @@ -90,7 +90,7 @@ public function testReturnsBasePlanDetailsWithUsage() 'trial_days' => config('shopify-app.billing_trial_days'), 'capped_amount' => config('shopify-app.billing_capped_amount'), 'terms' => config('shopify-app.billing_terms'), - 'return_url' => url(config('shopify-app.billing_redirect')) + 'return_url' => url(config('shopify-app.billing_redirect')), ], $method->invoke($controller, 'planDetails') ); From 4e9364b1d400f1b99c1ba03a119a89a483c96be7 Mon Sep 17 00:00:00 2001 From: Tyler King Date: Wed, 25 Apr 2018 14:10:26 -0230 Subject: [PATCH 3/4] Test fix --- tests/Libraries/BillingPlanTest.php | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/Libraries/BillingPlanTest.php b/tests/Libraries/BillingPlanTest.php index 4ffbc8e4..58fc7124 100644 --- a/tests/Libraries/BillingPlanTest.php +++ b/tests/Libraries/BillingPlanTest.php @@ -36,6 +36,20 @@ public function testShouldReturnConfirmationUrl() ); } + public function testShouldReturnConfirmationUrlWhenUsageIsEnabled() + { + $plan = array_merge($this->plan, [ + 'capped_amount' => 100.00, + 'terms' => '$1 for 500 emails', + ]); + $url = (new BillingPlan($this->shop))->setDetails($plan)->getConfirmationUrl(); + + $this->assertEquals( + 'https://example.myshopify.com/admin/charges/1029266947/confirm_recurring_application_charge?signature=BAhpBANeWT0%3D--64de8739eb1e63a8f848382bb757b20343eb414f', + $url + ); + } + /** * @expectedException \Exception * @expectedExceptionMessage Plan details are missing for confirmation URL request. From eb17d513c4635bfd0ec1b1557cfc0177e0441957 Mon Sep 17 00:00:00 2001 From: Tyler King Date: Wed, 25 Apr 2018 14:12:05 -0230 Subject: [PATCH 4/4] StyleCI fix --- tests/Libraries/BillingPlanTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Libraries/BillingPlanTest.php b/tests/Libraries/BillingPlanTest.php index 58fc7124..16be9d53 100644 --- a/tests/Libraries/BillingPlanTest.php +++ b/tests/Libraries/BillingPlanTest.php @@ -40,7 +40,7 @@ public function testShouldReturnConfirmationUrlWhenUsageIsEnabled() { $plan = array_merge($this->plan, [ 'capped_amount' => 100.00, - 'terms' => '$1 for 500 emails', + 'terms' => '$1 for 500 emails', ]); $url = (new BillingPlan($this->shop))->setDetails($plan)->getConfirmationUrl();