From 8d566a38135e9227891f7d80b9abaebc97cbac9d Mon Sep 17 00:00:00 2001 From: k15 Date: Thu, 15 Feb 2024 11:26:29 +0700 Subject: [PATCH 1/6] fix : add billing_plan_id and product_id after creating recurring subscriptions --- .../PayPalAPI/Subscriptions/Helpers.php | 44 ++++++++++--------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/src/Traits/PayPalAPI/Subscriptions/Helpers.php b/src/Traits/PayPalAPI/Subscriptions/Helpers.php index 8b65faa2..cd444235 100644 --- a/src/Traits/PayPalAPI/Subscriptions/Helpers.php +++ b/src/Traits/PayPalAPI/Subscriptions/Helpers.php @@ -93,7 +93,9 @@ public function setupSubscription(string $customer_name, string $customer_email, $body['taxes'] = $this->taxes; } - $subscription = $this->createSubscription($body); + $subscription = $this->createSubscription($body); + $subscription['billing_plan_id'] = $this->billing_plan['id']; + $subscription['product_id'] = $this->product['id']; unset($this->product); unset($this->billing_plan); @@ -139,7 +141,7 @@ public function addDailyPlan(string $name, string $description, float $price, in return $this; } - $plan_pricing = $this->addPlanBillingCycle('DAY', 1, $price, $total_cycles); + $plan_pricing = $this->addPlanBillingCycle('DAY', 1, $price, $total_cycles); $billing_cycles = empty($this->trial_pricing) ? [$plan_pricing] : collect([$this->trial_pricing, $plan_pricing])->filter()->toArray(); $this->addBillingPlan($name, $description, $billing_cycles); @@ -165,7 +167,7 @@ public function addWeeklyPlan(string $name, string $description, float $price, i return $this; } - $plan_pricing = $this->addPlanBillingCycle('WEEK', 1, $price, $total_cycles); + $plan_pricing = $this->addPlanBillingCycle('WEEK', 1, $price, $total_cycles); $billing_cycles = empty($this->trial_pricing) ? [$plan_pricing] : collect([$this->trial_pricing, $plan_pricing])->filter()->toArray(); $this->addBillingPlan($name, $description, $billing_cycles); @@ -191,7 +193,7 @@ public function addMonthlyPlan(string $name, string $description, float $price, return $this; } - $plan_pricing = $this->addPlanBillingCycle('MONTH', 1, $price, $total_cycles); + $plan_pricing = $this->addPlanBillingCycle('MONTH', 1, $price, $total_cycles); $billing_cycles = empty($this->trial_pricing) ? [$plan_pricing] : collect([$this->trial_pricing, $plan_pricing])->filter()->toArray(); $this->addBillingPlan($name, $description, $billing_cycles); @@ -217,7 +219,7 @@ public function addAnnualPlan(string $name, string $description, float $price, i return $this; } - $plan_pricing = $this->addPlanBillingCycle('YEAR', 1, $price, $total_cycles); + $plan_pricing = $this->addPlanBillingCycle('YEAR', 1, $price, $total_cycles); $billing_cycles = empty($this->trial_pricing) ? [$plan_pricing] : collect([$this->trial_pricing, $plan_pricing])->filter()->toArray(); $this->addBillingPlan($name, $description, $billing_cycles); @@ -248,10 +250,10 @@ public function addCustomPlan(string $name, string $description, float $price, s } if (!in_array($interval_unit, $billing_intervals)) { - throw new \RuntimeException('Billing intervals should either be '.implode(', ', $billing_intervals)); + throw new \RuntimeException('Billing intervals should either be ' . implode(', ', $billing_intervals)); } - $plan_pricing = $this->addPlanBillingCycle($interval_unit, $interval_count, $price, $total_cycles); + $plan_pricing = $this->addPlanBillingCycle($interval_unit, $interval_count, $price, $total_cycles); $billing_cycles = empty($this->trial_pricing) ? [$plan_pricing] : collect([$this->trial_pricing, $plan_pricing])->filter()->toArray(); $this->addBillingPlan($name, $description, $billing_cycles); @@ -286,7 +288,7 @@ protected function addPlanBillingCycle(string $interval_unit, int $interval_coun } return [ - 'frequency' => [ + 'frequency' => [ 'interval_unit' => $interval_unit, 'interval_count' => $interval_count, ], @@ -318,10 +320,10 @@ public function addProduct(string $name, string $description, string $type, stri $request_id = Str::random(); $this->product = $this->createProduct([ - 'name' => $name, - 'description' => $description, - 'type' => $type, - 'category' => $category, + 'name' => $name, + 'description' => $description, + 'type' => $type, + 'category' => $category, ], $request_id); return $this; @@ -413,7 +415,7 @@ public function addPaymentFailureThreshold(int $threshold): \Srmklive\PayPal\Ser */ public function addSetupFee(float $price): \Srmklive\PayPal\Services\PayPal { - $this->has_setup_fee = true; + $this->has_setup_fee = true; $this->payment_preferences = [ 'auto_bill_outstanding' => true, 'setup_fee' => [ @@ -443,16 +445,16 @@ public function addSetupFee(float $price): \Srmklive\PayPal\Services\PayPal public function addShippingAddress(string $full_name, string $address_line_1, string $address_line_2, string $admin_area_2, string $admin_area_1, string $postal_code, string $country_code): \Srmklive\PayPal\Services\PayPal { $this->shipping_address = [ - 'name' => [ + 'name' => [ 'full_name' => $full_name, ], 'address' => [ - 'address_line_1' => $address_line_1, - 'address_line_2' => $address_line_2, - 'admin_area_2' => $admin_area_2, - 'admin_area_1' => $admin_area_1, - 'postal_code' => $postal_code, - 'country_code' => $country_code, + 'address_line_1' => $address_line_1, + 'address_line_2' => $address_line_2, + 'admin_area_2' => $admin_area_2, + 'admin_area_1' => $admin_area_1, + 'postal_code' => $postal_code, + 'country_code' => $country_code, ], ]; @@ -475,4 +477,4 @@ public function addTaxes(float $percentage) return $this; } -} +} \ No newline at end of file From 45eba7c47054e182291ecba02ab6b66687e2f7e1 Mon Sep 17 00:00:00 2001 From: Kris Date: Thu, 15 Feb 2024 11:45:45 +0700 Subject: [PATCH 2/6] Update Helpers.php add white space end of file --- src/Traits/PayPalAPI/Subscriptions/Helpers.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Traits/PayPalAPI/Subscriptions/Helpers.php b/src/Traits/PayPalAPI/Subscriptions/Helpers.php index cd444235..00d70752 100644 --- a/src/Traits/PayPalAPI/Subscriptions/Helpers.php +++ b/src/Traits/PayPalAPI/Subscriptions/Helpers.php @@ -477,4 +477,4 @@ public function addTaxes(float $percentage) return $this; } -} \ No newline at end of file +} From 51f0ec3a8625116cc260aebdd07d56dd0ae271a2 Mon Sep 17 00:00:00 2001 From: k15 Date: Wed, 21 Feb 2024 10:09:48 +0700 Subject: [PATCH 3/6] fix : adjust the writing style --- src/Traits/PayPalAPI/Subscriptions/Helpers.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Traits/PayPalAPI/Subscriptions/Helpers.php b/src/Traits/PayPalAPI/Subscriptions/Helpers.php index cb00d668..0b5333f9 100644 --- a/src/Traits/PayPalAPI/Subscriptions/Helpers.php +++ b/src/Traits/PayPalAPI/Subscriptions/Helpers.php @@ -104,7 +104,7 @@ public function setupSubscription(string $customer_name, string $customer_email, $subscription = $this->createSubscription($body); $subscription['billing_plan_id'] = $this->billing_plan['id']; - $subscription['product_id'] = $this->product['id']; + $subscription['product_id'] = $this->product['id']; unset($this->product); unset($this->billing_plan); @@ -150,7 +150,7 @@ public function addDailyPlan(string $name, string $description, float $price, in return $this; } - $plan_pricing = $this->addPlanBillingCycle('DAY', 1, $price, $total_cycles); + $plan_pricing = $this->addPlanBillingCycle('DAY', 1, $price, $total_cycles); $billing_cycles = empty($this->trial_pricing) ? [$plan_pricing] : collect([$this->trial_pricing, $plan_pricing])->filter()->toArray(); $this->addBillingPlan($name, $description, $billing_cycles); @@ -176,7 +176,7 @@ public function addWeeklyPlan(string $name, string $description, float $price, i return $this; } - $plan_pricing = $this->addPlanBillingCycle('WEEK', 1, $price, $total_cycles); + $plan_pricing = $this->addPlanBillingCycle('WEEK', 1, $price, $total_cycles); $billing_cycles = empty($this->trial_pricing) ? [$plan_pricing] : collect([$this->trial_pricing, $plan_pricing])->filter()->toArray(); $this->addBillingPlan($name, $description, $billing_cycles); @@ -202,7 +202,7 @@ public function addMonthlyPlan(string $name, string $description, float $price, return $this; } - $plan_pricing = $this->addPlanBillingCycle('MONTH', 1, $price, $total_cycles); + $plan_pricing = $this->addPlanBillingCycle('MONTH', 1, $price, $total_cycles); $billing_cycles = empty($this->trial_pricing) ? [$plan_pricing] : collect([$this->trial_pricing, $plan_pricing])->filter()->toArray(); $this->addBillingPlan($name, $description, $billing_cycles); @@ -228,7 +228,7 @@ public function addAnnualPlan(string $name, string $description, float $price, i return $this; } - $plan_pricing = $this->addPlanBillingCycle('YEAR', 1, $price, $total_cycles); + $plan_pricing = $this->addPlanBillingCycle('YEAR', 1, $price, $total_cycles); $billing_cycles = empty($this->trial_pricing) ? [$plan_pricing] : collect([$this->trial_pricing, $plan_pricing])->filter()->toArray(); $this->addBillingPlan($name, $description, $billing_cycles); @@ -259,10 +259,10 @@ public function addCustomPlan(string $name, string $description, float $price, s } if (!in_array($interval_unit, $billing_intervals)) { - throw new \RuntimeException('Billing intervals should either be ' . implode(', ', $billing_intervals)); + throw new \RuntimeException('Billing intervals should either be '.implode(', ', $billing_intervals)); } - $plan_pricing = $this->addPlanBillingCycle($interval_unit, $interval_count, $price, $total_cycles); + $plan_pricing = $this->addPlanBillingCycle($interval_unit, $interval_count, $price, $total_cycles); $billing_cycles = empty($this->trial_pricing) ? [$plan_pricing] : collect([$this->trial_pricing, $plan_pricing])->filter()->toArray(); $this->addBillingPlan($name, $description, $billing_cycles); @@ -424,7 +424,7 @@ public function addPaymentFailureThreshold(int $threshold): \Srmklive\PayPal\Ser */ public function addSetupFee(float $price): \Srmklive\PayPal\Services\PayPal { - $this->has_setup_fee = true; + $this->has_setup_fee = true; $this->payment_preferences = [ 'auto_bill_outstanding' => true, 'setup_fee' => [ From c24b18141b62e885d913e3f5794d0fa34312fecd Mon Sep 17 00:00:00 2001 From: k15 Date: Fri, 23 Feb 2024 10:11:48 +0700 Subject: [PATCH 4/6] fix : added a condition whether create billing from subscription helper was successful or not. --- src/Traits/PayPalAPI/Subscriptions/Helpers.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Traits/PayPalAPI/Subscriptions/Helpers.php b/src/Traits/PayPalAPI/Subscriptions/Helpers.php index 0b5333f9..4cd49eb0 100644 --- a/src/Traits/PayPalAPI/Subscriptions/Helpers.php +++ b/src/Traits/PayPalAPI/Subscriptions/Helpers.php @@ -398,7 +398,11 @@ protected function addBillingPlan(string $name, string $description, array $bill ], ]; - $this->billing_plan = $this->createPlan($plan_params, $request_id); + $billingPlan = $this->createPlan($plan_params, $request_id); + if ($error = data_get($billingPlan, 'error', false)) { + throw new \RuntimeException(data_get($error, 'details.0.description', 'Failed to add billing plan')); + } + $this->billing_plan = $billingPlan; } /** From 20d8187e887c98d4df5982b7ec1b69d2af57c2d0 Mon Sep 17 00:00:00 2001 From: k15 Date: Fri, 23 Feb 2024 10:20:37 +0700 Subject: [PATCH 5/6] fix : added an error handler whether product creation from subscription helper was successful or not. --- src/Traits/PayPalAPI/Subscriptions/Helpers.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Traits/PayPalAPI/Subscriptions/Helpers.php b/src/Traits/PayPalAPI/Subscriptions/Helpers.php index 4cd49eb0..a617453a 100644 --- a/src/Traits/PayPalAPI/Subscriptions/Helpers.php +++ b/src/Traits/PayPalAPI/Subscriptions/Helpers.php @@ -328,13 +328,18 @@ public function addProduct(string $name, string $description, string $type, stri $request_id = Str::random(); - $this->product = $this->createProduct([ + $product = $this->createProduct([ 'name' => $name, 'description' => $description, 'type' => $type, 'category' => $category, ], $request_id); + if ($error = data_get($product, 'error', false)) { + throw new \RuntimeException(data_get($error, 'details.0.description', 'Failed to add product')); + } + $this->product = $product; + return $this; } From 5098de18dbb4cc209d011939a06644b80a45bfad Mon Sep 17 00:00:00 2001 From: k15 Date: Fri, 23 Feb 2024 11:33:47 +0700 Subject: [PATCH 6/6] fix : add test it_throws_exception_when_get_error_for_creating_a_billing_plan and it_throws_exception_when_get_error_for_creating_a_product --- .../AdapterCreateSubscriptionHelpersTest.php | 46 +++++++++++++++++++ tests/Mocks/Responses/BillingPlans.php | 27 +++++++++++ tests/Mocks/Responses/CatalogProducts.php | 29 ++++++++++++ 3 files changed, 102 insertions(+) diff --git a/tests/Feature/AdapterCreateSubscriptionHelpersTest.php b/tests/Feature/AdapterCreateSubscriptionHelpersTest.php index bbe51211..550fa520 100644 --- a/tests/Feature/AdapterCreateSubscriptionHelpersTest.php +++ b/tests/Feature/AdapterCreateSubscriptionHelpersTest.php @@ -255,6 +255,52 @@ public function it_throws_exception_when_invalid_interval_is_provided_for_creati $this->client = $this->client->addCustomPlan('Demo Plan', 'Demo Plan', 100, 'MONTHLY', 3); } + /** @test */ + public function it_throws_exception_when_get_error_for_creating_a_billing_plan() + { + $this->client->setAccessToken([ + 'access_token' => self::$access_token, + 'token_type' => 'Bearer', + ]); + + $this->client->setClient( + $this->mock_http_client( + $this->mockCreateCatalogProductsResponse() + ) + ); + + $this->client = $this->client->addProduct('Demo Product', 'Demo Product', 'SERVICE', 'SOFTWARE'); + + $this->client->setClient( + $this->mock_http_client( + $this->mockCreatePlansErrorResponse() + ) + ); + + $this->expectException(\RuntimeException::class); + + $this->client = $this->client->addMonthlyPlan('Demo Plan', 'Demo Plan', 100); + } + + /** @test */ + public function it_throws_exception_when_get_error_for_creating_a_product() + { + $this->client->setAccessToken([ + 'access_token' => self::$access_token, + 'token_type' => 'Bearer', + ]); + + $this->client->setClient( + $this->mock_http_client( + $this->mockGetCatalogProductsErrorResponse() + ) + ); + + $this->expectException(\RuntimeException::class); + + $this->client = $this->client->addProduct('Demo Product', 'Demo Product', 'SERVICE', 'SOFTWARE'); + } + /** @test */ public function it_can_create_a_subscription_without_trial() { diff --git a/tests/Mocks/Responses/BillingPlans.php b/tests/Mocks/Responses/BillingPlans.php index 3cec7e41..02fb3eb4 100644 --- a/tests/Mocks/Responses/BillingPlans.php +++ b/tests/Mocks/Responses/BillingPlans.php @@ -274,6 +274,33 @@ private function mockGetPlansResponse(): array "method": "POST" } ] +}', true); + } + + /** + * @return array + */ + private function mockCreatePlansErrorResponse(): array + { + return Utils::jsonDecode('{ + "error": { + "name" : "UNPROCESSABLE_ENTITY", + "message" : "The requested action could not be performed, semantically incorrect, or failed business validation.", + "debug_id" : "7a944631e76bf", + "details" : [ + { + "issue" : "CURRENCY_NOT_SUPPORTED_FOR_RECEIVER", + "description" : "This currency cannot be accepted for this recipient\'s account." + } + ], + "links" : [ + { + "href" : "https://developer.paypal.com/docs/api/v1/billing/subscriptions#UNPROCESSABLE_ENTITY", + "rel" : "information_link", + "method" : "GET" + } + ] + } }', true); } } diff --git a/tests/Mocks/Responses/CatalogProducts.php b/tests/Mocks/Responses/CatalogProducts.php index cb0fa70e..45fbdf9f 100644 --- a/tests/Mocks/Responses/CatalogProducts.php +++ b/tests/Mocks/Responses/CatalogProducts.php @@ -119,6 +119,35 @@ private function mockGetCatalogProductsResponse(): array "method": "PATCH" } ] +}', true); + } + + /** + * @return array + */ + private function mockGetCatalogProductsErrorResponse(): array + { + return Utils::jsonDecode('{ + "error": { + "name": "INVALID_REQUEST", + "message": "Request is not well-formed, syntactically incorrect, or violates schema.", + "debug_id": "b2aaac7fe91d1", + "details": [ + { + "field": "\/type", + "location": "body", + "issue": "MISSING_REQUIRED_PARAMETER", + "description": "A required field is missing." + } + ], + "links": [ + { + "href": "https:\/\/developer.paypal.com\/docs\/api\/v1\/billing\/subscriptions#INVALID_REQUEST", + "rel": "information_link", + "method": "GET" + } + ] + } }', true); } }