From 9785a3f13eaf1cf2498c4ca03b6a6ac02e4a48c4 Mon Sep 17 00:00:00 2001 From: Gringiemar Felix Date: Thu, 15 Dec 2022 20:37:36 +0800 Subject: [PATCH 01/17] test: fix failing tests - removed token related tests - moved createdPaymentMethod() from PaymentMethodTest to Pest --- tests/PaymentMethodTest.php | 28 +------------- tests/PaymentTest.php | 57 ++++------------------------ tests/Pest.php | 38 +++++++++++++++++++ tests/RefundTest.php | 14 +++---- tests/TokenTest.php | 75 ------------------------------------- 5 files changed, 52 insertions(+), 160 deletions(-) delete mode 100644 tests/TokenTest.php diff --git a/tests/PaymentMethodTest.php b/tests/PaymentMethodTest.php index 798a6f2..d75b2bd 100644 --- a/tests/PaymentMethodTest.php +++ b/tests/PaymentMethodTest.php @@ -56,30 +56,4 @@ ->toBeInstanceOf(PaymentMethod::class) ->type->toBe('payment_method') ->payment_method_type->toBe('paymaya'); -}); - -function createPaymentMethod() -{ - return Paymongo::paymentMethod() - ->create([ - 'type' => 'card', - 'details' => [ - 'card_number' => getTestCardWithout3dSecure(), - 'exp_month' => 12, - 'exp_year' => 25, - 'cvc' => '123', - ], - 'billing' => [ - 'address' => [ - 'line1' => 'Somewhere there', - 'city' => 'Cebu City', - 'state' => 'Cebu', - 'country' => 'PH', - 'postal_code' => '6000', - ], - 'name' => 'Rigel Kent Carbonel', - 'email' => 'rigel20.kent@gmail.com', - 'phone' => '0935454875545', - ], - ]); -} +}); \ No newline at end of file diff --git a/tests/PaymentTest.php b/tests/PaymentTest.php index 6a33dbd..564c24a 100644 --- a/tests/PaymentTest.php +++ b/tests/PaymentTest.php @@ -20,64 +20,21 @@ }); it('can retrieve a payment', function () { - $token = createToken(); - - $createdPayment = createPayment($token); + $cardPayment = createCardPayment(); $payment = Paymongo::payment() - ->find($createdPayment->id); - - expect($payment->id)->toBe($createdPayment->id); -}); - -it('cannot create payment when token is not valid', function () { - $this->expectException(BadRequestException::class); + ->find($cardPayment->id); - $token = Paymongo::token()->create([ - 'number' => '5100000000000198', - 'exp_month' => 12, - 'exp_year' => 25, - 'cvc' => '123', - 'billing' => [ - 'address' => [ - 'line1' => 'Test Address', - 'city' => 'Cebu City', - 'postal_code' => '6000', - 'country' => 'PH', - ], - 'name' => 'Rigel Kent Carbonel', - 'email' => 'rigel20.kent@gmail.com', - 'phone' => '928392893', - ], - ]); - - createPayment($token); -}); - -it('cannot create payment when token is used more than once', function () { - $this->expectException(BadRequestException::class); - - $token = createToken(); - $payment = createPayment($token); - - expect($payment) - ->amount->toBe(100.00) - ->currency->toBe('PHP') - ->statement_descriptor->toBe('Test Paymongo') - ->status->toBe('paid'); - - createPayment($token); + expect($cardPayment->id)->toBe($payment->id); }); it('can create payment', function () { - $token = createToken(); - - $payment = createPayment($token); + $cardPayment = createCardPayment(); - expect($payment) + expect($cardPayment) ->toBeInstanceOf(Payment::class) ->amount->toBe(100.00) ->currency->toBe('PHP') - ->statement_descriptor->toBe('Test Paymongo') + ->statement_descriptor->toBe('LUIGEL STORE') ->status->toBe('paid'); -}); +}); \ No newline at end of file diff --git a/tests/Pest.php b/tests/Pest.php index eefa1d5..227b54a 100644 --- a/tests/Pest.php +++ b/tests/Pest.php @@ -3,6 +3,7 @@ use Luigel\Paymongo\Facades\Paymongo; use Luigel\Paymongo\Models\Payment; use Luigel\Paymongo\Models\PaymentIntent; +use Luigel\Paymongo\Models\PaymentMethod; use Luigel\Paymongo\Models\Source; use Luigel\Paymongo\Models\Token; use Luigel\Paymongo\Tests\BaseTestCase; @@ -71,6 +72,32 @@ function createPaymentIntent(): PaymentIntent ]); } +function createPaymentMethod(): PaymentMethod +{ + return Paymongo::paymentMethod() + ->create([ + 'type' => 'card', + 'details' => [ + 'card_number' => getTestCardWithout3dSecure(), + 'exp_month' => 12, + 'exp_year' => 25, + 'cvc' => '123', + ], + 'billing' => [ + 'address' => [ + 'line1' => 'Somewhere there', + 'city' => 'Cebu City', + 'state' => 'Cebu', + 'country' => 'PH', + 'postal_code' => '6000', + ], + 'name' => 'Rigel Kent Carbonel', + 'email' => 'rigel20.kent@gmail.com', + 'phone' => '0935454875545', + ], + ]); +} + function createSource($type = 'gcash'): Source { return Paymongo::source()->create([ @@ -99,6 +126,17 @@ function createPayment(Source|Token $source): Payment ]); } +function createCardPayment(): Payment +{ + $paymentIntent = createPaymentIntent(); + $paymentMethod = createPaymentMethod(); + $attachedPaymentIntent = $paymentIntent->attach($paymentMethod->id, 'http://example.com/success'); + $cardPayment = new Payment(); + $cardPayment = $cardPayment->setData($attachedPaymentIntent->payments[0]); + + return $cardPayment; +} + function createRequest( $method, $content, diff --git a/tests/RefundTest.php b/tests/RefundTest.php index 7d0ed5b..4437188 100644 --- a/tests/RefundTest.php +++ b/tests/RefundTest.php @@ -5,13 +5,12 @@ use Luigel\Paymongo\Models\Refund; it('can create refund', function (string $reason) { - $token = createToken(); - $payment = createPayment($token); + $cardPayment = createCardPayment(); $refund = Paymongo::refund()->create([ 'amount' => 10, 'notes' => 'test refund', - 'payment_id' => $payment->id, + 'payment_id' => $cardPayment->id, 'reason' => $reason, ]); @@ -19,7 +18,7 @@ ->type->toBe('refund') ->amount->toBe(10.0) ->notes->toBe('test refund') - ->payment_id->toBe($payment->id) + ->payment_id->toBe($cardPayment->id) ->reason->toBe($reason) ->status->toBe('pending'); })->with([ @@ -30,13 +29,12 @@ ]); it('can retrieve a refund', function () { - $token = createToken(); - $payment = createPayment($token); + $cardPayment = createCardPayment(); $refund = Paymongo::refund()->create([ 'amount' => 10, 'notes' => 'test refund', - 'payment_id' => $payment->id, + 'payment_id' => $cardPayment->id, 'reason' => Refund::REASON_DUPLICATE, ]); @@ -46,7 +44,7 @@ ->type->toBe('refund') ->amount->toBe(10.0) ->notes->toBe('test refund') - ->payment_id->toBe($payment->id) + ->payment_id->toBe($cardPayment->id) ->reason->toBe(Refund::REASON_DUPLICATE) ->status->toBe('succeeded'); }); diff --git a/tests/TokenTest.php b/tests/TokenTest.php deleted file mode 100644 index 95fcc8e..0000000 --- a/tests/TokenTest.php +++ /dev/null @@ -1,75 +0,0 @@ -create([ - 'number' => getTestCardWithout3dSecure(), - 'exp_month' => 12, - 'exp_year' => 25, - 'cvc' => '123', - 'billing' => [ - 'address' => [ - 'line1' => 'Test Address', - 'city' => 'Cebu City', - 'postal_code' => '6000', - 'country' => 'PH', - ], - 'name' => 'Rigel Kent Carbonel', - 'email' => 'rigel20.kent@gmail.com', - 'phone' => '928392893', - ], - ]); - - expect($token) - ->toBeInstanceOf(Token::class) - ->card->toBeArray()->toMatchArray([ - 'last4' => '4345', - 'exp_month' => 12, - ]) - ->billing->toBeArray()->toMatchArray([ - 'name' => 'Rigel Kent Carbonel', - ]); -}); - -it('can retrieve token', function () { - $createdToken = Paymongo::token() - ->create([ - 'number' => getTestCardWithout3dSecure(), - 'exp_month' => 12, - 'exp_year' => 25, - 'cvc' => '123', - 'billing' => [ - 'address' => [ - 'line1' => 'Test Address', - 'city' => 'Cebu City', - 'postal_code' => '6000', - 'country' => 'PH', - ], - 'name' => 'Rigel Kent Carbonel', - 'email' => 'rigel20.kent@gmail.com', - 'phone' => '928392893', - ], - ]); - - $token = Paymongo::token()->find($createdToken->id); - - $this->assertEquals($createdToken, $token); -}); - -it('cannot create token with invalid data', function () { - $this->expectException(BadRequestException::class); - - Paymongo::token() - ->create([ - 'number' => '424242424242424222', - 'exp_month' => 12, - 'exp_year' => 25, - 'cvc' => '123', - ]); -}); From c2a8c3689713273f38f590014f16a06f704cefef Mon Sep 17 00:00:00 2001 From: Gringiemar Felix Date: Thu, 15 Dec 2022 21:28:15 +0800 Subject: [PATCH 02/17] feat: added links api --- src/Models/Link.php | 18 ++++++++++++++ src/Paymongo.php | 20 ++++++++++++---- src/Traits/Request.php | 39 ++++++++++++++++++++++++++++++ tests/LinkTest.php | 54 ++++++++++++++++++++++++++++++++++++++++++ tests/Pest.php | 20 ++++++++++++---- 5 files changed, 141 insertions(+), 10 deletions(-) create mode 100644 src/Models/Link.php create mode 100644 tests/LinkTest.php diff --git a/src/Models/Link.php b/src/Models/Link.php new file mode 100644 index 0000000..0fecef8 --- /dev/null +++ b/src/Models/Link.php @@ -0,0 +1,18 @@ +link()->archive($this); + } + + public function unarchive(): BaseModel + { + return (new Paymongo)->link()->unarchive($this); + } +} diff --git a/src/Paymongo.php b/src/Paymongo.php index b42d58e..dd90dcf 100644 --- a/src/Paymongo.php +++ b/src/Paymongo.php @@ -2,15 +2,16 @@ namespace Luigel\Paymongo; -use Luigel\Paymongo\Models\Payment; -use Luigel\Paymongo\Models\PaymentIntent; -use Luigel\Paymongo\Models\PaymentMethod; +use Luigel\Paymongo\Models\Link; +use Luigel\Paymongo\Models\Token; use Luigel\Paymongo\Models\Refund; use Luigel\Paymongo\Models\Source; -use Luigel\Paymongo\Models\Token; +use Luigel\Paymongo\Models\Payment; use Luigel\Paymongo\Models\Webhook; -use Luigel\Paymongo\Traits\HasToggleWebhook; use Luigel\Paymongo\Traits\Request; +use Luigel\Paymongo\Models\PaymentIntent; +use Luigel\Paymongo\Models\PaymentMethod; +use Luigel\Paymongo\Traits\HasToggleWebhook; class Paymongo { @@ -28,6 +29,7 @@ class Paymongo protected const ENDPOINT_PAYMENT = 'payments/'; protected const ENDPOINT_TOKEN = 'tokens/'; protected const ENDPOINT_REFUND = 'refunds/'; + protected const ENDPOINT_LINK = 'links/'; public const SOURCE_GCASH = 'gcash'; public const SOURCE_GRAB_PAY = 'grab_pay'; public const AMOUNT_TYPE_FLOAT = 'float'; @@ -108,4 +110,12 @@ public function refund(): self return $this; } + + public function link(): self + { + $this->apiUrl = self::BASE_API.self::ENDPOINT_LINK; + $this->returnModel = Link::class; + + return $this; + } } diff --git a/src/Traits/Request.php b/src/Traits/Request.php index b9fb889..8368cc4 100644 --- a/src/Traits/Request.php +++ b/src/Traits/Request.php @@ -12,6 +12,7 @@ use Luigel\Paymongo\Exceptions\PaymentErrorException; use Luigel\Paymongo\Exceptions\UnauthorizedException; use Luigel\Paymongo\Models\BaseModel; +use Luigel\Paymongo\Models\Link; use Luigel\Paymongo\Models\PaymentIntent; use Luigel\Paymongo\Models\Webhook; @@ -143,6 +144,44 @@ public function attach(PaymentIntent $intent, string $paymentMethodId, string|nu return $this->request(); } + /** + * Archives the link + */ + public function archive(Link $link){ + $this->method = 'POST'; + $this->apiUrl = $this->apiUrl . $link->id . '/archive'; + + $this->formRequestData(); + $this->setOptions([ + 'headers' => [ + 'Accept' => 'application/json', + ], + 'json' => $this->data, + 'auth' => [config('paymongo.secret_key'), ''], + ]); + + return $this->request(); + } + + /** + * Unarchives the link + */ + public function unarchive(Link $link){ + $this->method = 'POST'; + $this->apiUrl = $this->apiUrl . $link->id . '/unarchive'; + + $this->formRequestData(); + $this->setOptions([ + 'headers' => [ + 'Accept' => 'application/json', + ], + 'json' => $this->data, + 'auth' => [config('paymongo.secret_key'), ''], + ]); + + return $this->request(); + } + /** * Send request to API. * diff --git a/tests/LinkTest.php b/tests/LinkTest.php new file mode 100644 index 0000000..c73fc3a --- /dev/null +++ b/tests/LinkTest.php @@ -0,0 +1,54 @@ +toBeInstanceOf(Link::class); +}); + +it('can not retrieve a link with invalid id', function () { + $this->expectException(NotFoundException::class); + + Paymongo::link() + ->find('test'); +}); + +it('can retrieve a link by id', function () { + $link = createLink(); + + $retrieve = Paymongo::link() + ->find($link->id); + + expect($link->id)->toBe($retrieve->id); +}); + +it('can retrieve a link by reference number', function () { + $link = createLink(); + $retrieve = Paymongo::link() + ->find($link->reference_number); + + expect($link->id)->toBe($retrieve->id); +}); + +it('can archive a link', function () { + $link = createLink(); + $archivedLink = Paymongo::link() + ->archive($link); + + expect($archivedLink->archived)->toBe(true); +}); + +it('can unarchive a link', function () { + $link = createLink(); + $archivedLink = Paymongo::link() + ->archive($link); + + $unarchivedLink = Paymongo::link() + ->unarchive($archivedLink); + + expect($unarchivedLink->archived)->toBe(false); +}); \ No newline at end of file diff --git a/tests/Pest.php b/tests/Pest.php index 227b54a..f15d49f 100644 --- a/tests/Pest.php +++ b/tests/Pest.php @@ -1,13 +1,14 @@ in(__DIR__); @@ -137,6 +138,15 @@ function createCardPayment(): Payment return $cardPayment; } +function createLink(): Link +{ + return Paymongo::link()->create([ + 'amount' => 100.00, + 'description' => 'Link Test', + 'remarks' => 'laravel-paymongo' + ]); +} + function createRequest( $method, $content, From 1a6e9ad46929b64e7599c34feb1a2c561ec489d8 Mon Sep 17 00:00:00 2001 From: Gringiemar Felix Date: Thu, 15 Dec 2022 21:55:33 +0800 Subject: [PATCH 03/17] refactor: link tests --- tests/LinkTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/LinkTest.php b/tests/LinkTest.php index c73fc3a..05003d8 100644 --- a/tests/LinkTest.php +++ b/tests/LinkTest.php @@ -37,7 +37,7 @@ it('can archive a link', function () { $link = createLink(); $archivedLink = Paymongo::link() - ->archive($link); + ->archive(); expect($archivedLink->archived)->toBe(true); }); @@ -48,7 +48,7 @@ ->archive($link); $unarchivedLink = Paymongo::link() - ->unarchive($archivedLink); + ->unarchive(); expect($unarchivedLink->archived)->toBe(false); }); \ No newline at end of file From 0a0ad0c0e038a9239ae9da0fd9932b4da3fa8804 Mon Sep 17 00:00:00 2001 From: Gringiemar Felix Date: Thu, 15 Dec 2022 22:22:22 +0800 Subject: [PATCH 04/17] fix: link tests not using the correct methods --- src/Traits/Request.php | 37 +++++++++++++++++++++++++++---------- tests/LinkTest.php | 13 ++++--------- 2 files changed, 31 insertions(+), 19 deletions(-) diff --git a/src/Traits/Request.php b/src/Traits/Request.php index 8368cc4..a3cd361 100644 --- a/src/Traits/Request.php +++ b/src/Traits/Request.php @@ -4,17 +4,18 @@ use Exception; use GuzzleHttp\Client; -use GuzzleHttp\Exception\ClientException; +use Luigel\Paymongo\Models\Link; use Illuminate\Support\Collection; -use Luigel\Paymongo\Exceptions\AmountTypeNotSupportedException; -use Luigel\Paymongo\Exceptions\BadRequestException; +use Luigel\Paymongo\Models\Webhook; +use Luigel\Paymongo\Models\Customer; +use Luigel\Paymongo\Models\BaseModel; +use GuzzleHttp\Exception\ClientException; +use Luigel\Paymongo\Models\PaymentIntent; use Luigel\Paymongo\Exceptions\NotFoundException; +use Luigel\Paymongo\Exceptions\BadRequestException; use Luigel\Paymongo\Exceptions\PaymentErrorException; use Luigel\Paymongo\Exceptions\UnauthorizedException; -use Luigel\Paymongo\Models\BaseModel; -use Luigel\Paymongo\Models\Link; -use Luigel\Paymongo\Models\PaymentIntent; -use Luigel\Paymongo\Models\Webhook; +use Luigel\Paymongo\Exceptions\AmountTypeNotSupportedException; trait Request { @@ -149,14 +150,12 @@ public function attach(PaymentIntent $intent, string $paymentMethodId, string|nu */ public function archive(Link $link){ $this->method = 'POST'; - $this->apiUrl = $this->apiUrl . $link->id . '/archive'; + $this->apiUrl = $this->apiUrl.$link->id.'/archive'; - $this->formRequestData(); $this->setOptions([ 'headers' => [ 'Accept' => 'application/json', ], - 'json' => $this->data, 'auth' => [config('paymongo.secret_key'), ''], ]); @@ -170,6 +169,24 @@ public function unarchive(Link $link){ $this->method = 'POST'; $this->apiUrl = $this->apiUrl . $link->id . '/unarchive'; + $this->setOptions([ + 'headers' => [ + 'Accept' => 'application/json', + ], + 'auth' => [config('paymongo.secret_key'), ''], + ]); + + return $this->request(); + } + + /** + * Update the customer information + */ + public function updateInfo(Customer $customer, array $payload){ + $this->method = 'PATCH'; + $this->apiUrl = $this->apiUrl . $customer->id; + $this->payload = $payload; + $this->formRequestData(); $this->setOptions([ 'headers' => [ diff --git a/tests/LinkTest.php b/tests/LinkTest.php index 05003d8..a754bcc 100644 --- a/tests/LinkTest.php +++ b/tests/LinkTest.php @@ -35,20 +35,15 @@ }); it('can archive a link', function () { - $link = createLink(); - $archivedLink = Paymongo::link() - ->archive(); + $link = createLink()->archive(); - expect($archivedLink->archived)->toBe(true); + expect($link->archived)->toBe(true); }); it('can unarchive a link', function () { - $link = createLink(); - $archivedLink = Paymongo::link() - ->archive($link); + $archivedLink = createLink()->archive(); - $unarchivedLink = Paymongo::link() - ->unarchive(); + $unarchivedLink = $archivedLink->unarchive(); expect($unarchivedLink->archived)->toBe(false); }); \ No newline at end of file From d6609d10f9e6218655d7f8aa8fe81012386e222d Mon Sep 17 00:00:00 2001 From: Gringiemar Felix Date: Thu, 15 Dec 2022 22:38:50 +0800 Subject: [PATCH 05/17] feat: addded customers api --- src/Models/Customer.php | 24 +++++++++++++++++++ src/Paymongo.php | 10 ++++++++ src/Traits/Request.php | 36 +++++++++++++++++++++++++++- tests/CustomerTest.php | 52 +++++++++++++++++++++++++++++++++++++++++ tests/Pest.php | 13 +++++++++++ 5 files changed, 134 insertions(+), 1 deletion(-) create mode 100644 src/Models/Customer.php create mode 100644 tests/CustomerTest.php diff --git a/src/Models/Customer.php b/src/Models/Customer.php new file mode 100644 index 0000000..26d6725 --- /dev/null +++ b/src/Models/Customer.php @@ -0,0 +1,24 @@ +customer()->updateCustomer($this, $payload); + } + + public function delete(): BaseModel + { + return (new Paymongo)->customer()->deleteCustomer($this); + } + + public function paymentMethods(): BaseModel|Collection + { + return (new Paymongo)->customer()->getPaymentMethods($this); + } +} diff --git a/src/Paymongo.php b/src/Paymongo.php index dd90dcf..c853c9a 100644 --- a/src/Paymongo.php +++ b/src/Paymongo.php @@ -9,6 +9,7 @@ use Luigel\Paymongo\Models\Payment; use Luigel\Paymongo\Models\Webhook; use Luigel\Paymongo\Traits\Request; +use Luigel\Paymongo\Models\Customer; use Luigel\Paymongo\Models\PaymentIntent; use Luigel\Paymongo\Models\PaymentMethod; use Luigel\Paymongo\Traits\HasToggleWebhook; @@ -30,6 +31,7 @@ class Paymongo protected const ENDPOINT_TOKEN = 'tokens/'; protected const ENDPOINT_REFUND = 'refunds/'; protected const ENDPOINT_LINK = 'links/'; + protected const ENDPOINT_CUSTOMER = 'customers/'; public const SOURCE_GCASH = 'gcash'; public const SOURCE_GRAB_PAY = 'grab_pay'; public const AMOUNT_TYPE_FLOAT = 'float'; @@ -118,4 +120,12 @@ public function link(): self return $this; } + + public function customer(): self + { + $this->apiUrl = self::BASE_API.self::ENDPOINT_CUSTOMER; + $this->returnModel = Customer::class; + + return $this; + } } diff --git a/src/Traits/Request.php b/src/Traits/Request.php index a3cd361..81bec2e 100644 --- a/src/Traits/Request.php +++ b/src/Traits/Request.php @@ -182,7 +182,7 @@ public function unarchive(Link $link){ /** * Update the customer information */ - public function updateInfo(Customer $customer, array $payload){ + public function updateCustomer(Customer $customer, array $payload){ $this->method = 'PATCH'; $this->apiUrl = $this->apiUrl . $customer->id; $this->payload = $payload; @@ -199,6 +199,40 @@ public function updateInfo(Customer $customer, array $payload){ return $this->request(); } + /** + * Delete the customer + */ + public function deleteCustomer(Customer $customer){ + $this->method = 'DELETE'; + $this->apiUrl = $this->apiUrl . $customer->id; + + $this->setOptions([ + 'headers' => [ + 'Accept' => 'application/json', + ], + 'auth' => [config('paymongo.secret_key'), ''], + ]); + + return $this->request(); + } + + /** + * Get Customer's Payment Methods + */ + public function getPaymentMethods(Customer $customer){ + $this->method = 'GET'; + $this->apiUrl = $this->apiUrl . $customer->id . '/payment_methods'; + + $this->setOptions([ + 'headers' => [ + 'Accept' => 'application/json', + ], + 'auth' => [config('paymongo.secret_key'), ''], + ]); + + return $this->request(); + } + /** * Send request to API. * diff --git a/tests/CustomerTest.php b/tests/CustomerTest.php new file mode 100644 index 0000000..0bbf338 --- /dev/null +++ b/tests/CustomerTest.php @@ -0,0 +1,52 @@ +toBeInstanceOf(Customer::class); +}); + +it('can not retrieve a customer with invalid id', function () { + $this->expectException(NotFoundException::class); + + Paymongo::customer() + ->find('test'); +}); + +it('can retrieve a customer', function () { + $customer = createCustomer(); + + $retrieve = Paymongo::customer() + ->find($customer->id); + + expect($customer->id)->toBe($retrieve->id); +}); + +it('can update a customer', function () { + $customer = createCustomer(); + + expect($customer->last_name)->toBe('Felix'); + + $updatedCustomer = $customer->update([ + 'last_name' => 'Mongo' + ]); + + expect($updatedCustomer->last_name)->toBe('Mongo'); +}); + +it('can delete a customer', function () { + $customer = createCustomer()->delete(); + + expect($customer->deleted)->toBe(true); +}); + +it('can retrieve a customer\'s payment methods', function () { + $customer = createCustomer()->paymentMethods(); + + expect($customer)->toBeInstanceOf(Collection::class); +}); \ No newline at end of file diff --git a/tests/Pest.php b/tests/Pest.php index f15d49f..96a850b 100644 --- a/tests/Pest.php +++ b/tests/Pest.php @@ -1,10 +1,12 @@ create([ + 'first_name' => 'Gringiemar', + 'last_name' => 'Felix', + 'phone' => '+6391234' . rand(10000, 99999), + 'email' => 'customer' . Str::random(8) . rand(0, 100) . '@email.com', + 'default_device' => 'phone' + ]); +} + function createRequest( $method, $content, From 128e360b44e9fdec7de5b4dd6172b4fa991a17a1 Mon Sep 17 00:00:00 2001 From: Gringiemar Felix Date: Thu, 15 Dec 2022 22:48:25 +0800 Subject: [PATCH 06/17] docs: CHANGELOG.md --- CHANGELOG.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index cd698aa..1a5bb20 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,15 @@ All notable changes to `laravel-paymongo` will be documented in this file +## 2.4.0 (2022-12-15) + +### Added +- Links API +- Customers API + +### Fixed +- Failing tests + ## 1.3.0 (2020-10-31) ### Added From e5841e642006bbb5bf2f29aaea6b0bfe38f62379 Mon Sep 17 00:00:00 2001 From: Gringiemar Felix Date: Thu, 15 Dec 2022 23:09:38 +0800 Subject: [PATCH 07/17] docs: added links api --- docs/docs/Usage/links.md | 65 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 docs/docs/Usage/links.md diff --git a/docs/docs/Usage/links.md b/docs/docs/Usage/links.md new file mode 100644 index 0000000..dbffc53 --- /dev/null +++ b/docs/docs/Usage/links.md @@ -0,0 +1,65 @@ +--- +sidebar_position: 7 +slug: /links +id: links +--- + +# Links + +## Create Link + +Creates a payment link. A payment link that can be used for one-time payments. + +### Payload + +Refer to [Paymongo documentation](https://developers.paymongo.com/reference/links-resource) for payload guidelines. + +### Sample + +```php +use Luigel\Paymongo\Facades\Paymongo; + +$link = Paymongo::link()->create([ + 'amount' => 100.00, + 'description' => 'Link Test', + 'remarks' => 'laravel-paymongo' +]); +``` + +## Get Link + +Retrieve a payment link by passing the id or the reference number to the `find($id)` method. + +### Sample + +```php +use Luigel\Paymongo\Facades\Paymongo; + +$link = Paymongo::link()->find('link_wWaibr22CzEnficNhQNPUdoo'); +$linkbyReference = Paymongo::link()->find('WTmSJbV'); +``` + +## Archive Link + +Archive a payment link by using the `find($id)` method and chaining the `->archive()` method. + +### Sample + +```php +use Luigel\Paymongo\Facades\Paymongo; + +$link = Paymongo::link()->find('link_wWaibr22CzEnficNhQNPUdoo')->archive(); +``` + +## Unarchive Link + +Unarchive a payment link by using the `find($id)` method and chaining the `->unarchive()` method. + +### Sample + +```php +use Luigel\Paymongo\Facades\Paymongo; + +$link = Paymongo::link()->find('link_wWaibr22CzEnficNhQNPUdoo')->unarchive(); +``` + From da9ca2adfb3b47a92656137a7fc8c4e9dbc00a1c Mon Sep 17 00:00:00 2001 From: Gringiemar Felix Date: Thu, 15 Dec 2022 23:20:53 +0800 Subject: [PATCH 08/17] docs: update refunds sidebar position --- docs/docs/Usage/refunds.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/Usage/refunds.md b/docs/docs/Usage/refunds.md index 3b31c77..8163524 100644 --- a/docs/docs/Usage/refunds.md +++ b/docs/docs/Usage/refunds.md @@ -1,5 +1,5 @@ --- -sidebar_position: 8 +sidebar_position: 7 slug: /refunds id: refunds --- From feb1a6a67607453876830c6deed0763ddb6cb65e Mon Sep 17 00:00:00 2001 From: Gringiemar Felix Date: Thu, 15 Dec 2022 23:21:07 +0800 Subject: [PATCH 09/17] docs: added customers api --- docs/docs/Usage/customers.md | 85 ++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 docs/docs/Usage/customers.md diff --git a/docs/docs/Usage/customers.md b/docs/docs/Usage/customers.md new file mode 100644 index 0000000..1035a9e --- /dev/null +++ b/docs/docs/Usage/customers.md @@ -0,0 +1,85 @@ +--- +sidebar_position: 7 +slug: /customers +id: customers +--- + +# Customers + +## Create Customer + +Creates a customer record that holds billing information and is useful for card vaulting purposes. + +### Payload + +Refer to [Paymongo documentation](https://developers.paymongo.com/reference/customer-resource) for payload guidelines. + +### Sample + +```php +use Luigel\Paymongo\Facades\Paymongo; + +$customer = Paymongo::customer()->create([ + 'first_name' => 'Juan', + 'last_name' => 'Doe', + 'phone' => '+639123456789', + 'email' => 'customer@email.com', + 'default_device' => 'phone' +]); +``` + +## Get Customer + +Retrieve a customer by passing the customer id to the `find($id)` method. + +### Sample + +```php +use Luigel\Paymongo\Facades\Paymongo; + +$customer = Paymongo::customer()->find('cus_b9ENKVqcHBfQQmv26uDYDCsD'); +``` + +## Edit Customer + +Edit a customer by using the `find($id)` method and chaining the `->update()` method. Or by chaning `->update()` to your existing instance. + +### Sample + +```php +use Luigel\Paymongo\Facades\Paymongo; + +$customer = Paymongo::customer() + ->find('cus_b9ENKVqcHBfQQmv26uDYDCsD') + ->update([ + 'first_name' => 'Jane' + ]); +``` + +## Delete Customer + +Delete a customer by using the `find($id)` method and chaining the `->delete()` method. Or by chaning `->delete()` to your existing instance. + +### Sample + +```php +use Luigel\Paymongo\Facades\Paymongo; + +$link = Paymongo::customer() + ->find('cus_b9ENKVqcHBfQQmv26uDYDCsD') + ->delete(); +``` + +## Retrieve Customer's Payment Methods + +Retrieve the customer's payment methods by using the `find($id)` method and chaining the `->paymentMethods()` method. Or by chaning `->paymentMethods()` to your existing instance. + +### Sample + +```php +use Luigel\Paymongo\Facades\Paymongo; + +$link = Paymongo::customer() + ->find('cus_b9ENKVqcHBfQQmv26uDYDCsD') + ->paymentMethods(); +``` \ No newline at end of file From 73fac985fe5c0df607285b73019635c3be17d4de Mon Sep 17 00:00:00 2001 From: Gringiemar Felix Date: Sun, 30 Apr 2023 20:23:56 +0800 Subject: [PATCH 10/17] fix: duplicate customer import --- src/Paymongo.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Paymongo.php b/src/Paymongo.php index 6466b55..571d4f7 100644 --- a/src/Paymongo.php +++ b/src/Paymongo.php @@ -2,7 +2,6 @@ namespace Luigel\Paymongo; -use Luigel\Paymongo\Models\Customer; use Luigel\Paymongo\Models\Link; use Luigel\Paymongo\Models\Payment; use Luigel\Paymongo\Models\Webhook; From aca992978f95e0025aee7db589fcd11c0d9e46fd Mon Sep 17 00:00:00 2001 From: Gringiemar Felix Date: Sun, 30 Apr 2023 21:39:50 +0800 Subject: [PATCH 11/17] docs: fix same sidebar_position --- docs/docs/Usage/links.md | 2 +- docs/docs/Usage/refunds.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/docs/Usage/links.md b/docs/docs/Usage/links.md index dbffc53..c32c9e2 100644 --- a/docs/docs/Usage/links.md +++ b/docs/docs/Usage/links.md @@ -1,5 +1,5 @@ --- -sidebar_position: 7 +sidebar_position: 8 slug: /links id: links --- diff --git a/docs/docs/Usage/refunds.md b/docs/docs/Usage/refunds.md index 8163524..1847904 100644 --- a/docs/docs/Usage/refunds.md +++ b/docs/docs/Usage/refunds.md @@ -1,5 +1,5 @@ --- -sidebar_position: 7 +sidebar_position: 9 slug: /refunds id: refunds --- From aabd03f57304a7954ae7c3fa7aad00f982c3d9f9 Mon Sep 17 00:00:00 2001 From: Gringiemar Felix Date: Sun, 30 Apr 2023 21:46:50 +0800 Subject: [PATCH 12/17] feat: added checkout sessions api --- src/Models/Checkout.php | 13 ++++++++++ src/Paymongo.php | 10 ++++++++ src/Traits/Request.php | 24 +++++++++++++++---- tests/CheckoutTest.php | 35 +++++++++++++++++++++++++++ tests/Pest.php | 53 ++++++++++++++++++++++++++++++++++++----- 5 files changed, 124 insertions(+), 11 deletions(-) create mode 100644 src/Models/Checkout.php create mode 100644 tests/CheckoutTest.php diff --git a/src/Models/Checkout.php b/src/Models/Checkout.php new file mode 100644 index 0000000..d3e5c13 --- /dev/null +++ b/src/Models/Checkout.php @@ -0,0 +1,13 @@ +checkout()->expireCheckout($this); + } +} diff --git a/src/Paymongo.php b/src/Paymongo.php index 571d4f7..6d7e5e8 100644 --- a/src/Paymongo.php +++ b/src/Paymongo.php @@ -2,6 +2,7 @@ namespace Luigel\Paymongo; +use Luigel\Paymongo\Models\Checkout; use Luigel\Paymongo\Models\Link; use Luigel\Paymongo\Models\Payment; use Luigel\Paymongo\Models\Webhook; @@ -29,6 +30,7 @@ class Paymongo protected const ENDPOINT_REFUND = 'refunds/'; protected const ENDPOINT_LINK = 'links/'; protected const ENDPOINT_CUSTOMER = 'customers/'; + protected const ENDPOINT_CHECKOUT = 'checkout_sessions/'; public const SOURCE_GCASH = 'gcash'; public const SOURCE_GRAB_PAY = 'grab_pay'; public const AMOUNT_TYPE_FLOAT = 'float'; @@ -125,4 +127,12 @@ public function customer(): self return $this; } + + public function checkout(): self + { + $this->apiUrl = self::BASE_API.self::ENDPOINT_CHECKOUT; + $this->returnModel = Checkout::class; + + return $this; + } } diff --git a/src/Traits/Request.php b/src/Traits/Request.php index b500094..80e120b 100644 --- a/src/Traits/Request.php +++ b/src/Traits/Request.php @@ -7,6 +7,7 @@ use Luigel\Paymongo\Models\Link; use Illuminate\Support\Collection; use Luigel\Paymongo\Models\Webhook; +use Luigel\Paymongo\Models\Checkout; use Luigel\Paymongo\Models\Customer; use Luigel\Paymongo\Models\BaseModel; use GuzzleHttp\Exception\ClientException; @@ -15,11 +16,7 @@ use Luigel\Paymongo\Exceptions\BadRequestException; use Luigel\Paymongo\Exceptions\PaymentErrorException; use Luigel\Paymongo\Exceptions\UnauthorizedException; -use Luigel\Paymongo\Models\BaseModel; -use Luigel\Paymongo\Models\Customer; -use Luigel\Paymongo\Models\Link; -use Luigel\Paymongo\Models\PaymentIntent; -use Luigel\Paymongo\Models\Webhook; +use Luigel\Paymongo\Exceptions\AmountTypeNotSupportedException; trait Request { @@ -242,6 +239,23 @@ public function getPaymentMethods(Customer $customer) return $this->request(); } + /** + * + */ + public function expireCheckout(Checkout $checkout) { + $this->method = 'POST'; + $this->apiUrl = $this->apiUrl.$checkout->id.'/expire'; + + $this->setOptions([ + 'headers' => [ + 'Accept' => 'application/json', + ], + 'auth' => [config('paymongo.secret_key'), ''], + ]); + + return $this->request(); + } + /** * Send request to API. * diff --git a/tests/CheckoutTest.php b/tests/CheckoutTest.php new file mode 100644 index 0000000..51dbb6f --- /dev/null +++ b/tests/CheckoutTest.php @@ -0,0 +1,35 @@ +toBeInstanceOf(Checkout::class); +}); + +it('can not retrieve a checkout session with invalid id', function () { + $this->expectException(NotFoundException::class); + + Paymongo::checkout() + ->find('test'); +}); + +it('can retrieve a checkout session by id', function () { + $checkout = createCheckout(); + + $retrieve = Paymongo::checkout() + ->find($checkout->id); + + expect($checkout->id)->toBe($retrieve->id); +}); + +it('can expire a checkout session', function () { + $checkout = createCheckout(); + + $checkout = $checkout->expire(); + + expect($checkout->status)->toBe('expired'); +}); diff --git a/tests/Pest.php b/tests/Pest.php index adfa3dc..a887100 100644 --- a/tests/Pest.php +++ b/tests/Pest.php @@ -1,16 +1,17 @@ in(__DIR__); @@ -160,6 +161,46 @@ function createCustomer(): Customer ]); } +function createCheckout(): Checkout +{ + return Paymongo::checkout()->create([ + 'cancel_url' => 'https://paymongo.rigelkentcarbonel.com/', + 'billing' => [ + 'name' => 'Gringiemar Felix', + 'email' => 'gringiemar@felix.com', + 'phone' => '+6391234'.rand(10000, 99999), + ], + 'description' => 'My checkout session description', + 'line_items' => [ + [ + 'amount' => 10000, + 'currency' => 'PHP', + 'description' => 'Something of a product.', + 'images' => [ + 'https://images.unsplash.com/photo-1613243555988-441166d4d6fd?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1170&q=80' + ], + 'name' => 'A payment card', + 'quantity' => 1 + ] + ], + 'payment_method_types' => [ + 'atome', + 'billease', + 'card', + 'dob', + 'dob_ubp', + 'gcash', + 'grab_pay', + 'paymaya' + ], + 'success_url' => 'https://paymongo.rigelkentcarbonel.com/', + 'statement_descriptor' => 'Laravel Paymongo Library', + 'metadata' => [ + 'Key' => 'Value' + ] + ]); +} + function createRequest( $method, $content, From 580e44a27999861e6a310d7c62ed6b5877a34b84 Mon Sep 17 00:00:00 2001 From: Gringiemar Felix Date: Sun, 30 Apr 2023 21:46:59 +0800 Subject: [PATCH 13/17] docs: added checkout sessions api --- docs/docs/Usage/checkouts.md | 82 ++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 docs/docs/Usage/checkouts.md diff --git a/docs/docs/Usage/checkouts.md b/docs/docs/Usage/checkouts.md new file mode 100644 index 0000000..40a8299 --- /dev/null +++ b/docs/docs/Usage/checkouts.md @@ -0,0 +1,82 @@ +--- +sidebar_position: 10 +slug: /checkout-sessions +id: checkout-sessions +--- + +# Checkouts + +## Create Checkout + +Creates a checkout session. A checkout session is a customizable checkout page from Paymongo. + +### Payload + +Refer to [Paymongo documentation](https://developers.paymongo.com/reference/checkout-session-resource) for payload guidelines. + +### Sample + +```php +use Luigel\Paymongo\Facades\Paymongo; + +$checkout = Paymongo::checkout()->create([ + 'cancel_url' => 'https://paymongo.rigelkentcarbonel.com/', + 'billing' => [ + 'name' => 'Juan Doe', + 'email' => 'juan@doe.com', + 'phone' => '+639123456789', + ], + 'description' => 'My checkout session description', + 'line_items' => [ + [ + 'amount' => 10000, + 'currency' => 'PHP', + 'description' => 'Something of a product.', + 'images' => [ + 'https://images.unsplash.com/photo-1613243555988-441166d4d6fd?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1170&q=80' + ], + 'name' => 'A payment card', + 'quantity' => 1 + ] + ], + 'payment_method_types' => [ + 'atome', + 'billease', + 'card', + 'dob', + 'dob_ubp', + 'gcash', + 'grab_pay', + 'paymaya' + ], + 'success_url' => 'https://paymongo.rigelkentcarbonel.com/', + 'statement_descriptor' => 'Laravel Paymongo Library', + 'metadata' => [ + 'Key' => 'Value' + ] +]); +``` + +## Get Checkout + +Retrieve a checkout session by passing the id to the `find($id)` method. + +### Sample + +```php +use Luigel\Paymongo\Facades\Paymongo; + +$checkout = Paymongo::checkout()->find('cs_CbFCTDfxvMFNjwjVi26Uzhtj'); +``` + +## Expire Checkout + +Expire a checkout session by using the `find($id)` method and chaining the `->expire()` method. + +### Sample + +```php +use Luigel\Paymongo\Facades\Paymongo; + +$checkout = Paymongo::checkout()->find('cs_CbFCTDfxvMFNjwjVi26Uzhtj')->expire(); +``` \ No newline at end of file From ee3146ea33916dc8a718291ffb67ad1fe7b26903 Mon Sep 17 00:00:00 2001 From: Gringiemar Felix Date: Sun, 30 Apr 2023 21:59:38 +0800 Subject: [PATCH 14/17] docs: add to changelog --- CHANGELOG.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a5bb20..8a07181 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,12 @@ All notable changes to `laravel-paymongo` will be documented in this file -## 2.4.0 (2022-12-15) +## 2.4.0 (2023-04-30) + +### Added +- Checkouts API + +## 2.3.0 (2022-12-15) ### Added - Links API From 2784a24bb7f4136c2cac99541a6390766c2ba600 Mon Sep 17 00:00:00 2001 From: Gringiemar Felix Date: Sun, 30 Apr 2023 22:00:29 +0800 Subject: [PATCH 15/17] fix: missing imports --- src/Traits/Request.php | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/Traits/Request.php b/src/Traits/Request.php index 80e120b..ef387bc 100644 --- a/src/Traits/Request.php +++ b/src/Traits/Request.php @@ -242,19 +242,19 @@ public function getPaymentMethods(Customer $customer) /** * */ - public function expireCheckout(Checkout $checkout) { - $this->method = 'POST'; - $this->apiUrl = $this->apiUrl.$checkout->id.'/expire'; - - $this->setOptions([ - 'headers' => [ - 'Accept' => 'application/json', - ], - 'auth' => [config('paymongo.secret_key'), ''], - ]); + // public function expireCheckout(Checkout $checkout) { + // $this->method = 'POST'; + // $this->apiUrl = $this->apiUrl.$checkout->id.'/expire'; + + // $this->setOptions([ + // 'headers' => [ + // 'Accept' => 'application/json', + // ], + // 'auth' => [config('paymongo.secret_key'), ''], + // ]); - return $this->request(); - } + // return $this->request(); + // } /** * Send request to API. From 72d427089a47a4ac4334b655033351b1912fd3aa Mon Sep 17 00:00:00 2001 From: Gringiemar Felix Date: Sun, 30 Apr 2023 22:02:50 +0800 Subject: [PATCH 16/17] Revert "fix: missing imports" This reverts commit 2784a24bb7f4136c2cac99541a6390766c2ba600. --- src/Traits/Request.php | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/Traits/Request.php b/src/Traits/Request.php index ef387bc..80e120b 100644 --- a/src/Traits/Request.php +++ b/src/Traits/Request.php @@ -242,19 +242,19 @@ public function getPaymentMethods(Customer $customer) /** * */ - // public function expireCheckout(Checkout $checkout) { - // $this->method = 'POST'; - // $this->apiUrl = $this->apiUrl.$checkout->id.'/expire'; - - // $this->setOptions([ - // 'headers' => [ - // 'Accept' => 'application/json', - // ], - // 'auth' => [config('paymongo.secret_key'), ''], - // ]); + public function expireCheckout(Checkout $checkout) { + $this->method = 'POST'; + $this->apiUrl = $this->apiUrl.$checkout->id.'/expire'; + + $this->setOptions([ + 'headers' => [ + 'Accept' => 'application/json', + ], + 'auth' => [config('paymongo.secret_key'), ''], + ]); - // return $this->request(); - // } + return $this->request(); + } /** * Send request to API. From ca845021dc3142dca0534bedf4188137eb99f953 Mon Sep 17 00:00:00 2001 From: Gringiemar Felix Date: Sun, 30 Apr 2023 22:03:16 +0800 Subject: [PATCH 17/17] fix: missing imports from merge --- src/Paymongo.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Paymongo.php b/src/Paymongo.php index 6d7e5e8..f313205 100644 --- a/src/Paymongo.php +++ b/src/Paymongo.php @@ -2,11 +2,13 @@ namespace Luigel\Paymongo; -use Luigel\Paymongo\Models\Checkout; use Luigel\Paymongo\Models\Link; +use Luigel\Paymongo\Models\Refund; +use Luigel\Paymongo\Models\Source; use Luigel\Paymongo\Models\Payment; use Luigel\Paymongo\Models\Webhook; use Luigel\Paymongo\Traits\Request; +use Luigel\Paymongo\Models\Checkout; use Luigel\Paymongo\Models\Customer; use Luigel\Paymongo\Models\PaymentIntent; use Luigel\Paymongo\Models\PaymentMethod;