🆙 Add cms i using 🆙

This commit is contained in:
Remco
2025-11-25 22:42:56 +01:00
parent 94704e0925
commit d44196149e
35591 changed files with 3601123 additions and 0 deletions
@@ -0,0 +1 @@
service_name: github-ci
@@ -0,0 +1 @@
*.pdf filter=lfs diff=lfs merge=lfs -text
@@ -0,0 +1,35 @@
name: Static Analysis
on: [push, pull_request]
jobs:
paypal:
name: PHP ${{ matrix.php-versions }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
php-versions: ['8.0', '8.1', '8.2', '8.3']
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Setup PHP with Composer and extensions
with:
php-version: ${{ matrix.php-versions }}
uses: shivammathur/setup-php@v2
- name: Get Composer cache directory
id: composercache
run: echo "::set-output name=dir::$(composer config cache-files-dir)"
- name: Cache Composer dependencies
uses: actions/cache@v2
with:
php-version: ${{ matrix.php-versions }}
path: ${{ steps.composercache.outputs.dir }}
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
restore-keys: ${{ runner.os }}-composer-
- name: Install Composer dependencies
env:
PHP_VERSION: ${{ matrix.php-versions }}
run: composer install --no-progress --prefer-dist --optimize-autoloader $(if [ "$PHP_VERSION" == "8.0" || "$PHP_VERSION" == "8.1" ]; then echo "--ignore-platform-reqs"; fi;)
- name: Run type checking analysis
env:
PHP_VERSION: ${{ matrix.php-versions }}
run: vendor/bin/phpstan
@@ -0,0 +1,79 @@
name: Laravel PayPal
on: [push, pull_request]
jobs:
paypal:
name: PHP ${{ matrix.php-versions }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
php-versions: ['8.0', '8.1', '8.2', '8.3']
include:
- php-versions: '8.0'
continue-on-error: true
steps:
- name: Checkout
uses: actions/checkout@v2
# with:
# lfs: true
# - name: Checkout LFS objects
# run: git lfs checkout
- name: Setup PHP with Composer and extensions
with:
php-version: ${{ matrix.php-versions }}
uses: shivammathur/setup-php@v2
- name: Get Composer cache directory
id: composercache
run: echo "::set-output name=dir::$(composer config cache-files-dir)"
- name: Cache Composer dependencies
uses: actions/cache@v2
with:
php-version: ${{ matrix.php-versions }}
path: ${{ steps.composercache.outputs.dir }}
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
restore-keys: ${{ runner.os }}-composer-
- name: Install Composer dependencies
env:
PHP_VERSION: ${{ matrix.php-versions }}
run: composer install --no-progress --prefer-dist --optimize-autoloader $(if [ "$PHP_VERSION" == "8.0" || "$PHP_VERSION" == "8.1" ]; then echo "--ignore-platform-reqs"; fi;)
- name: Run tests for PHP 7.2 to 8.0 with code coverage
if: matrix.php-versions == '7.2' || matrix.php-versions == '7.3' || matrix.php-versions == '7.4' || matrix.php-versions == '8.0'
env:
PHP_VERSION: ${{ matrix.php-versions }}
run: vendor/bin/phpunit $(if [ "$PHP_VERSION" == "7.2" ]; then echo "-c phpunit.xml.dist.php72"; fi;) $(if [ "$PHP_VERSION" == "7.3" ]; then echo "-c phpunit.xml.dist.php8"; fi;) $(if [ "$PHP_VERSION" == "7.4" ]; then echo "-c phpunit.xml.dist.php8"; fi;) $(if [ "$PHP_VERSION" == "8.0" ]; then echo "-c phpunit.xml.dist.php8"; fi;) --coverage-clover build/logs/clover.xml
- name: Install PestPHP
if: matrix.php-versions == '8.1' || matrix.php-versions == '8.2' || matrix.php-versions == '8.3'
env:
PHP_VERSION: ${{ matrix.php-versions }}
run: composer require pestphp/pest --dev --with-all-dependencies
- name: Run tests for PHP 8.1+ with code coverage
if: matrix.php-versions == '8.1' || matrix.php-versions == '8.2' || matrix.php-versions == '8.3'
env:
PHP_VERSION: ${{ matrix.php-versions }}
run: vendor/bin/pest --coverage-clover build/logs/clover.xml
- name: Install PHP Coveralls library
env:
PHP_VERSION: ${{ matrix.php-versions }}
run:
composer global require --dev php-coveralls/php-coveralls
- name: Upload coverage results to Coveralls
env:
PHP_VERSION: ${{ matrix.php-versions }}
COVERALLS_REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }}
COVERALLS_PARALLEL: true
COVERALLS_FLAG_NAME: php-${{ matrix.php-versions }}
run:
php-coveralls -v
- name: Upload coverage results to Codecov
uses: codecov/codecov-action@v3
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
coveralls-finish:
needs: [paypal]
runs-on: ubuntu-latest
steps:
- name: Coveralls Finished
uses: coverallsapp/github-action@master
with:
github-token: ${{ secrets.github_token }}
parallel-finished: true
@@ -0,0 +1,10 @@
/vendor
/.idea
.env
composer.lock
/build
*-container*
*.phpunit*
test.php
/.venv
/docs/build
@@ -0,0 +1,35 @@
filter:
excluded_paths: [tests/*]
checks:
php:
remove_extra_empty_lines: true
remove_php_closing_tag: true
remove_trailing_whitespace: true
fix_use_statements:
remove_unused: true
preserve_multiple: false
preserve_blanklines: true
order_alphabetically: true
fix_php_opening_tag: true
fix_linefeed: true
fix_line_ending: true
fix_identation_4spaces: true
fix_doc_comments: true
build:
nodes:
analysis:
tests:
override:
- php-scrutinizer-run
environment:
php:
version: 8.1.13
tests:
override:
-
command: 'vendor/bin/phpunit --coverage-clover=build/logs/clover.xml'
coverage:
file: 'build/logs/clover.xml'
format: 'clover'
@@ -0,0 +1,39 @@
language: php
sudo: false
php:
- 7.0
- 7.1
- 7.2
- 7.3
- 7.4
env:
global:
- setup=stable
- coverage=no
before_script:
- composer update --prefer-dist --no-interaction
script:
- if [[ $coverage = 'yes' ]]; then ./vendor/bin/phpunit $(if [ "$TRAVIS_PHP_VERSION" == "7.1" ] || [ "$TRAVIS_PHP_VERSION" == "7.2" ]; then echo "-c phpunit.xml.legacy"; fi;) --coverage-clover build/logs/clover.xml; fi
- if [[ $coverage = 'no' ]]; then ./vendor/bin/phpunit $(if [ "$TRAVIS_PHP_VERSION" == "7.1" ] || [ "$TRAVIS_PHP_VERSION" == "7.2" ]; then echo "-c phpunit.xml.legacy"; fi;); fi
after_script:
- if [[ $setup = 'coveralls' ]]; then php vendor/bin/php-coveralls -v; fi
matrix:
include:
- php: 7.0
env: setup=coveralls coverage=yes
- php: 7.1
env: setup=coveralls coverage=yes
- php: 7.2
env: setup=coveralls coverage=yes
- php: 7.3
env: setup=coveralls coverage=yes
- php: 7.4
env: setup=coveralls coverage=yes
fast_finish: true
@@ -0,0 +1,19 @@
FROM srmklive/docker-php-cli:7.4
LABEL maintainer="Raza Mehdi<srmk@outlook.com>"
ENV DEBIAN_FRONTEND=noninteractive
# Set apps home directory.
ENV APP_DIR /server/http
# Define current working directory.
WORKDIR ${APP_DIR}
RUN apt-get -y autoclean \
&& apt-get -y autoremove \
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
COPY supervisor.conf /etc/supervisor/conf.d/supervisord.conf
CMD ["/usr/bin/supervisord"]
@@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2015 <Raza Mehdi>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
@@ -0,0 +1,191 @@
# Laravel PayPal
[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE.md)
[![Latest Version on Packagist](https://img.shields.io/packagist/v/srmklive/paypal.svg?style=flat-square)](https://packagist.org/packages/srmklive/paypal)
[![Total Downloads](https://img.shields.io/packagist/dt/srmklive/paypal.svg?style=flat-square)](https://packagist.org/packages/srmklive/paypal)
[![StyleCI](https://github.styleci.io/repos/43671533/shield?branch=v2.0)](https://github.styleci.io/repos/43671533?branch=v2.0)
![Tests](https://github.com/srmklive/laravel-paypal/workflows/TestsV3/badge.svg)
[![Coverage Status](https://coveralls.io/repos/github/srmklive/laravel-paypal/badge.svg?branch=v3.0)](https://coveralls.io/github/srmklive/laravel-paypal?branch=v3.0)
[![Code Quality](https://scrutinizer-ci.com/g/srmklive/laravel-paypal/badges/quality-score.png?b=v3.0)](https://scrutinizer-ci.com/g/srmklive/laravel-paypal/?branch=v3.0)
- [Documentation](#introduction)
- [Usage](#usage)
- [Support](#support)
> [!IMPORTANT]
> Laravel 11 will be the last version supported for v3.0. v4 is being actively worked on, and will be released by end of October 2024. For v4, following are the changes being introduced:
> * PHP 8.1+ required.
> * Laravel 10 & onwards required.
> * Integration of PayPal JS SDK.
> * Symfony plugin.
<a name="introduction"></a>
## Documentation
The documentation for the package can be viewed by clicking the following link:
[https://laravel-paypal.readthedocs.io/en/latest/](https://laravel-paypal.readthedocs.io/en/latest/)
The old documentation can be found at the following link:
[https://srmklive.github.io/laravel-paypal/docs.html](https://srmklive.github.io/laravel-paypal/docs.html)
<a name="usage"></a>
## Usage
Following are some ways through which you can access the paypal provider:
```php
// Import the class namespaces first, before using it directly
use Srmklive\PayPal\Services\PayPal as PayPalClient;
$provider = new PayPalClient;
// Through facade. No need to import namespaces
$provider = \PayPal::setProvider();
```
<a name="usage-paypal-api-configuration"></a>
## Configuration File
The configuration file **paypal.php** is located in the **config** folder. Following are its contents when published:
```php
return [
'mode' => env('PAYPAL_MODE', 'sandbox'), // Can only be 'sandbox' Or 'live'. If empty or invalid, 'live' will be used.
'sandbox' => [
'client_id' => env('PAYPAL_SANDBOX_CLIENT_ID', ''),
'client_secret' => env('PAYPAL_SANDBOX_CLIENT_SECRET', ''),
'app_id' => 'APP-80W284485P519543T',
],
'live' => [
'client_id' => env('PAYPAL_LIVE_CLIENT_ID', ''),
'client_secret' => env('PAYPAL_LIVE_CLIENT_SECRET', ''),
'app_id' => env('PAYPAL_LIVE_APP_ID', ''),
],
'payment_action' => env('PAYPAL_PAYMENT_ACTION', 'Sale'), // Can only be 'Sale', 'Authorization' or 'Order'
'currency' => env('PAYPAL_CURRENCY', 'USD'),
'notify_url' => env('PAYPAL_NOTIFY_URL', ''), // Change this accordingly for your application.
'locale' => env('PAYPAL_LOCALE', 'en_US'), // force gateway language i.e. it_IT, es_ES, en_US ... (for express checkout only)
'validate_ssl' => env('PAYPAL_VALIDATE_SSL', true), // Validate SSL when creating api client.
];
```
## Override PayPal API Configuration
You can override PayPal API configuration by calling `setApiCredentials` method:
```php
$config = [
'mode' => 'live',
'live' => [
'client_id' => 'PAYPAL_LIVE_CLIENT_ID',
'client_secret' => 'PAYPAL_LIVE_CLIENT_SECRET',
'app_id' => 'PAYPAL_LIVE_APP_ID',
],
'payment_action' => 'Sale',
'currency' => 'USD',
'notify_url' => 'https://your-site.com/paypal/notify',
'locale' => 'en_US',
'validate_ssl' => true,
];
$provider->setApiCredentials($config);
```
<a name="usage-paypal-get-access-token"></a>
## Get Access Token
After setting the PayPal API configuration by calling `setApiCredentials` method. You need to get access token before performing any API calls
```php
$provider->getAccessToken();
```
<a name="usage-currency"></a>
## Set Currency
By default, the currency used is `USD`. If you wish to change it, you may call `setCurrency` method to set a different currency before calling any respective API methods:
```php
$provider->setCurrency('EUR');
```
<a name="usage-helpers"></a>
## Helper Methods
> Please note that in the examples below, the call to `addPlanTrialPricing` is optional and it can be omitted when you are creating subscriptions without trial period.
> `setReturnAndCancelUrl()` is optional. If you set urls you have to use real domains. e.g. localhost, project.test does not work.
### Create Recurring Daily Subscription
```php
$response = $provider->addProduct('Demo Product', 'Demo Product', 'SERVICE', 'SOFTWARE')
->addPlanTrialPricing('DAY', 7)
->addDailyPlan('Demo Plan', 'Demo Plan', 1.50)
->setReturnAndCancelUrl('https://example.com/paypal-success', 'https://example.com/paypal-cancel')
->setupSubscription('John Doe', 'john@example.com', '2021-12-10');
```
### Create Recurring Weekly Subscription
```php
$response = $provider->addProduct('Demo Product', 'Demo Product', 'SERVICE', 'SOFTWARE')
->addPlanTrialPricing('DAY', 7)
->addWeeklyPlan('Demo Plan', 'Demo Plan', 30)
->setReturnAndCancelUrl('https://example.com/paypal-success', 'https://example.com/paypal-cancel')
->setupSubscription('John Doe', 'john@example.com', '2021-12-10');
```
### Create Recurring Monthly Subscription
```php
$response = $provider->addProduct('Demo Product', 'Demo Product', 'SERVICE', 'SOFTWARE')
->addPlanTrialPricing('DAY', 7)
->addMonthlyPlan('Demo Plan', 'Demo Plan', 100)
->setReturnAndCancelUrl('https://example.com/paypal-success', 'https://example.com/paypal-cancel')
->setupSubscription('John Doe', 'john@example.com', '2021-12-10');
```
### Create Recurring Annual Subscription
```php
$response = $provider->addProduct('Demo Product', 'Demo Product', 'SERVICE', 'SOFTWARE')
->addPlanTrialPricing('DAY', 7)
->addAnnualPlan('Demo Plan', 'Demo Plan', 600)
->setReturnAndCancelUrl('https://example.com/paypal-success', 'https://example.com/paypal-cancel')
->setupSubscription('John Doe', 'john@example.com', '2021-12-10');
```
### Create Recurring Subscription with Custom Intervals
```php
$response = $provider->addProduct('Demo Product', 'Demo Product', 'SERVICE', 'SOFTWARE')
->addCustomPlan('Demo Plan', 'Demo Plan', 150, 'MONTH', 3)
->setReturnAndCancelUrl('https://example.com/paypal-success', 'https://example.com/paypal-cancel')
->setupSubscription('John Doe', 'john@example.com', '2021-12-10');
```
### Create Subscription by Existing Product & Billing Plan
```php
$response = $this->client->addProductById('PROD-XYAB12ABSB7868434')
->addBillingPlanById('P-5ML4271244454362WXNWU5NQ')
->setReturnAndCancelUrl('https://example.com/paypal-success', 'https://example.com/paypal-cancel')
->setupSubscription('John Doe', 'john@example.com', $start_date);
```
<a name="support"></a>
## Support
This version supports Laravel 6 or greater.
* In case of any issues, kindly create one on the [Issues](https://github.com/srmklive/laravel-paypal/issues) section.
* If you would like to contribute:
* Fork this repository.
* Implement your features.
* Generate pull request.
@@ -0,0 +1,59 @@
{
"name": "srmklive/paypal",
"type": "library",
"description": "Laravel plugin For Processing Payments Through Paypal Express Checkout. Can Be Used Independently With Other Applications.",
"keywords": [
"http",
"rest",
"web service",
"paypal",
"laravel paypal"
],
"license": "MIT",
"authors": [
{
"name": "Raza Mehdi",
"email": "srmk@outlook.com"
}
],
"autoload": {
"psr-4": {
"Srmklive\\PayPal\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"Srmklive\\PayPal\\Tests\\": "tests/"
}
},
"require": {
"php": ">=7.2|^8.0",
"ext-curl": "*",
"guzzlehttp/guzzle": "~7.0",
"illuminate/support": "~6.0|~7.0|~8.0|~9.0|^10.0|^11.0|^12.0",
"nesbot/carbon": "~2.0|^3.0"
},
"require-dev": {
"phpstan/phpstan": "^1.10",
"phpunit/phpunit": "^8.0|^9.0|^10.0|^11.0",
"symfony/var-dumper": "~5.0|^6.0|^7.0"
},
"config": {
"sort-packages": true,
"allow-plugins": {
"pestphp/pest-plugin": true
}
},
"extra": {
"laravel": {
"providers": [
"Srmklive\\PayPal\\Providers\\PayPalServiceProvider"
],
"aliases": {
"PayPal": "Srmklive\\PayPal\\Facades\\PayPal"
}
}
},
"minimum-stability": "dev",
"prefer-stable": true
}
@@ -0,0 +1,25 @@
<?php
/**
* PayPal Setting & API Credentials
* Created by Raza Mehdi <srmk@outlook.com>.
*/
return [
'mode' => env('PAYPAL_MODE', 'sandbox'), // Can only be 'sandbox' Or 'live'. If empty or invalid, 'live' will be used.
'sandbox' => [
'client_id' => env('PAYPAL_SANDBOX_CLIENT_ID', ''),
'client_secret' => env('PAYPAL_SANDBOX_CLIENT_SECRET', ''),
'app_id' => 'APP-80W284485P519543T',
],
'live' => [
'client_id' => env('PAYPAL_LIVE_CLIENT_ID', ''),
'client_secret' => env('PAYPAL_LIVE_CLIENT_SECRET', ''),
'app_id' => env('PAYPAL_LIVE_APP_ID', ''),
],
'payment_action' => env('PAYPAL_PAYMENT_ACTION', 'Sale'), // Can only be 'Sale', 'Authorization' or 'Order'
'currency' => env('PAYPAL_CURRENCY', 'USD'),
'notify_url' => env('PAYPAL_NOTIFY_URL', ''), // Change this accordingly for your application.
'locale' => env('PAYPAL_LOCALE', 'en_US'), // force gateway language i.e. it_IT, es_ES, en_US ... (for express checkout only)
'validate_ssl' => env('PAYPAL_VALIDATE_SSL', true), // Validate SSL when creating api client.
];
@@ -0,0 +1,10 @@
version: '2'
services:
app:
build:
context: ./
dockerfile: Dockerfile
image: srmklive/laravel-paypal
restart: always
volumes:
- ./:/server/http
@@ -0,0 +1,7 @@
<?php
return [
'paypal_transaction_declined' => 'غير قادر على معالجة الدفعة لأن معاملتك تم رفضها على PayPal',
'paypal_transaction_not_verified' => 'غير قادر على التحقق من المعاملة من PayPal',
'paypal_connection_error' => 'غير قادر على الاتصال بـ PayPal. الرجاء المحاولة مرة أخرى',
];
@@ -0,0 +1,7 @@
<?php
return [
'paypal_transaction_declined' => '由于您的交易在PayPal上被拒绝,无法处理付款',
'paypal_transaction_not_verified' => '无法从PayPal验证交易',
'paypal_connection_error' => '无法连接到PayPal。请重试',
];
@@ -0,0 +1,7 @@
<?php
return [
'paypal_transaction_declined' => 'Zahlung konnte nicht verarbeitet werden, da Ihre Transaktion bei PayPal abgelehnt wurde',
'paypal_transaction_not_verified' => 'Transaktion konnte bei PayPal nicht verifiziert werden',
'paypal_connection_error' => 'Verbindung zu PayPal konnte nicht hergestellt werden. Bitte versuchen Sie es erneut',
];
@@ -0,0 +1,7 @@
<?php
return [
'paypal_transaction_declined' => 'Unable To Process Payment As Your Transaction Was Declined On PayPal',
'paypal_transaction_not_verified' => 'Unable To Verify Transaction From PayPal',
'paypal_connection_error' => 'Unable To Connect To PayPal. Please Try Again',
];
@@ -0,0 +1,7 @@
<?php
return [
'paypal_transaction_declined' => 'Imposible procesar el pago ya que tu transacción fue rechazada en PayPal',
'paypal_transaction_not_verified' => 'Imposible verificar la transacción desde PayPal',
'paypal_connection_error' => 'Imposible conectarse a PayPal. Por favor, inténtalo de nuevo',
];
@@ -0,0 +1,7 @@
<?php
return [
'paypal_transaction_declined' => 'Impossible de traiter le paiement car votre transaction a été refusée sur PayPal',
'paypal_transaction_not_verified' => 'Impossible de vérifier la transaction depuis PayPal',
'paypal_connection_error' => 'Impossible de se connecter à PayPal. Veuillez réessayer',
];
@@ -0,0 +1,7 @@
<?php
return [
'paypal_transaction_declined' => 'Nem lehet feldolgozni a fizetést, mivel a tranzakciódat elutasították a PayPal-on',
'paypal_transaction_not_verified' => 'A tranzakciót nem lehet ellenőrizni a PayPal-ról',
'paypal_connection_error' => 'Nem lehet csatlakozni a PayPal-hoz. Kérjük, próbálja újra',
];
@@ -0,0 +1,7 @@
<?php
return [
'paypal_transaction_declined' => 'Impossibile elaborare il pagamento perché la tua transazione è stata rifiutata su PayPal',
'paypal_transaction_not_verified' => 'Impossibile verificare la transazione su PayPal',
'paypal_connection_error' => 'Impossibile connettersi a PayPal. Si prega di riprovare',
];
@@ -0,0 +1,7 @@
<?php
return [
'paypal_transaction_declined' => 'PayPalでお取引が拒否されたため、支払いを処理できません',
'paypal_transaction_not_verified' => 'PayPalからの取引を確認できません',
'paypal_connection_error' => 'PayPalに接続できません。もう一度お試しください',
];
@@ -0,0 +1,9 @@
parameters:
paths:
- src
level: 0
ignoreErrors:
- "#Parameter#"
- "#Call to static method error\\(\\)\\ on an unknown class Log.#"
excludePaths:
- "src/Providers/PayPalServiceProvider.php"
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" bootstrap="vendor/autoload.php" backupGlobals="false" colors="true" processIsolation="false" stopOnFailure="false" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.1/phpunit.xsd" cacheDirectory=".phpunit.cache" backupStaticProperties="false">
<coverage>
<report>
<clover outputFile="build/logs/clover.xml"/>
<html outputDirectory="build/coverage"/>
<text outputFile="build/coverage.txt"/>
</report>
</coverage>
<testsuites>
<testsuite name="PayPal Test Suite">
<directory>tests</directory>
</testsuite>
</testsuites>
<logging>
<junit outputFile="build/report.junit.xml"/>
</logging>
<source>
<include>
<directory suffix=".php">src/</directory>
</include>
<exclude>
<file>src/PayPalFacadeAccessor.php</file>
<file>src/Traits/PayPalVerifyIPN.php</file>
<file>src/Services/Str.php</file>
<directory suffix=".php">src/Facades/</directory>
<directory suffix=".php">src/Providers/</directory>
</exclude>
</source>
</phpunit>
@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit bootstrap="vendor/autoload.php"
backupGlobals="false"
backupStaticAttributes="false"
colors="true"
verbose="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false">
<testsuites>
<testsuite name="PayPal Test Suite">
<directory>tests</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory suffix=".php">src/</directory>
<exclude>
<file>src/PayPalFacadeAccessor.php</file>
<file>src/Traits/PayPalVerifyIPN.php</file>
<file>src/Services/Str.php</file>
<directory suffix=".php">src/Facades/</directory>
<directory suffix=".php">src/Providers/</directory>
</exclude>
</whitelist>
</filter>
<logging>
<log type="junit" target="build/report.junit.xml"/>
<log type="coverage-html" target="build/coverage"/>
<log type="coverage-text" target="build/coverage.txt"/>
<log type="coverage-clover" target="build/logs/clover.xml"/>
</logging>
</phpunit>
@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" bootstrap="vendor/autoload.php" backupGlobals="false" backupStaticAttributes="false" colors="true" verbose="true" convertErrorsToExceptions="true" convertNoticesToExceptions="true" convertWarningsToExceptions="true" processIsolation="false" stopOnFailure="false" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd">
<coverage>
<include>
<directory suffix=".php">src/</directory>
</include>
<exclude>
<file>src/PayPalFacadeAccessor.php</file>
<file>src/Traits/PayPalVerifyIPN.php</file>
<file>src/Services/Str.php</file>
<directory suffix=".php">src/Facades/</directory>
<directory suffix=".php">src/Providers/</directory>
</exclude>
<report>
<clover outputFile="build/logs/clover.xml"/>
<html outputDirectory="build/coverage"/>
<text outputFile="build/coverage.txt"/>
</report>
</coverage>
<testsuites>
<testsuite name="PayPal Test Suite">
<directory>tests</directory>
</testsuite>
</testsuites>
<logging>
<junit outputFile="build/report.junit.xml"/>
</logging>
</phpunit>
@@ -0,0 +1,24 @@
<?php
namespace Srmklive\PayPal\Facades;
/*
* Class Facade
* @package Srmklive\PayPal\Facades
* @see Srmklive\PayPal\ExpressCheckout
*/
use Illuminate\Support\Facades\Facade;
class PayPal extends Facade
{
/**
* Get the registered name of the component.
*
* @return string
*/
protected static function getFacadeAccessor()
{
return 'Srmklive\PayPal\PayPalFacadeAccessor';
}
}
@@ -0,0 +1,43 @@
<?php
namespace Srmklive\PayPal;
use Exception;
use Srmklive\PayPal\Services\PayPal as PayPalClient;
class PayPalFacadeAccessor
{
/**
* PayPal API provider object.
*
* @var
*/
public static $provider;
/**
* Get specific PayPal API provider object to use.
*
* @throws Exception
*
* @return \Srmklive\PayPal\Services\PayPal
*/
public static function getProvider()
{
return self::$provider;
}
/**
* Set PayPal API Client to use.
*
* @throws \Exception
*
* @return \Srmklive\PayPal\Services\PayPal
*/
public static function setProvider()
{
// Set default provider. Defaults to ExpressCheckout
self::$provider = new PayPalClient();
return self::getProvider();
}
}
@@ -0,0 +1,74 @@
<?php
namespace Srmklive\PayPal\Providers;
/*
* Class PayPalServiceProvider
* @package Srmklive\PayPal
*/
use Illuminate\Support\ServiceProvider;
use Srmklive\PayPal\Services\PayPal as PayPalClient;
class PayPalServiceProvider extends ServiceProvider
{
/**
* Indicates if loading of the provider is deferred.
*
* @var bool
*/
protected $defer = false;
/**
* Bootstrap the application events.
*
* @return void
*/
public function boot()
{
// Publish config files
$this->publishes([
__DIR__.'/../../config/config.php' => config_path('paypal.php'),
]);
// Publish Lang Files
$this->loadTranslationsFrom(__DIR__.'/../../lang', 'paypal');
}
/**
* Register the service provider.
*
* @return void
*/
public function register()
{
$this->registerPayPal();
$this->mergeConfig();
}
/**
* Register the application bindings.
*
* @return void
*/
private function registerPayPal()
{
$this->app->singleton('paypal_client', static function () {
return new PayPalClient();
});
}
/**
* Merges user's and paypal's configs.
*
* @return void
*/
private function mergeConfig()
{
$this->mergeConfigFrom(
__DIR__.'/../../config/config.php',
'paypal'
);
}
}
@@ -0,0 +1,58 @@
<?php
namespace Srmklive\PayPal\Services;
use Exception;
use Srmklive\PayPal\Traits\PayPalRequest as PayPalAPIRequest;
use Srmklive\PayPal\Traits\PayPalVerifyIPN;
class PayPal
{
use PayPalAPIRequest;
use PayPalVerifyIPN;
/**
* PayPal constructor.
*
* @param array $config
*
* @throws Exception
*/
public function __construct(array $config = [])
{
// Setting PayPal API Credentials
$this->setConfig($config);
$this->httpBodyParam = 'form_params';
$this->options = [];
$this->setRequestHeader('Accept', 'application/json');
}
/**
* Set ExpressCheckout API endpoints & options.
*
* @param array $credentials
*/
protected function setOptions(array $credentials): void
{
// Setting API Endpoints
$this->config['api_url'] = 'https://api-m.paypal.com';
$this->config['gateway_url'] = 'https://www.paypal.com';
$this->config['ipn_url'] = 'https://ipnpb.paypal.com/cgi-bin/webscr';
if ($this->mode === 'sandbox') {
$this->config['api_url'] = 'https://api-m.sandbox.paypal.com';
$this->config['gateway_url'] = 'https://www.sandbox.paypal.com';
$this->config['ipn_url'] = 'https://ipnpb.sandbox.paypal.com/cgi-bin/webscr';
}
// Adding params outside sandbox / live array
$this->config['payment_action'] = $credentials['payment_action'];
$this->config['notify_url'] = $credentials['notify_url'];
$this->config['locale'] = $credentials['locale'];
}
}
@@ -0,0 +1,34 @@
<?php
namespace Srmklive\PayPal\Services;
use GuzzleHttp\Utils;
class Str extends \Illuminate\Support\Str
{
/**
* Determine if a given value is valid JSON.
*
* @param mixed $value
*
* @return bool
*/
public static function isJson($value): bool
{
if (!is_string($value)) {
return false;
}
if (function_exists('json_validate')) {
return json_validate($value, 512);
}
try {
Utils::jsonDecode($value, true, 512, 4194304);
} catch (\JsonException $jsonException) {
return false;
}
return true;
}
}
@@ -0,0 +1,78 @@
<?php
namespace Srmklive\PayPal\Services;
use GuzzleHttp\Psr7\MimeType;
class VerifyDocuments
{
/**
* @var array
*/
protected static $dispute_evidence_types = [
'application/pdf',
'image/gif',
'image/jpeg',
'image/png',
];
/**
* @var string
*/
protected static $dispute_evidence_file_size = 10;
/**
* @var string
*/
protected static $dispute_evidences_size = 50;
/**
* Get Mime type from filename.
*
* @param string $file
*
* @return string
*/
public static function getMimeType($file)
{
return MimeType::fromFilename($file);
}
/**
* Check if the evidence file being submitted mime type is valid.
*
* @param array $files
*
* @return bool
*/
public static function isValidEvidenceFile(array $files)
{
$validFile = true;
$validSize = true;
$total_size = 0;
$basic = (1024 * 1024);
$file_size = $basic * self::$dispute_evidence_file_size;
$overall_size = $basic * self::$dispute_evidences_size;
foreach ($files as $file) {
$mime_type = self::getMimeType($file);
if (!in_array($mime_type, self::$dispute_evidence_types)) {
$validFile = false;
break;
}
$size = filesize($file);
if ($size > $file_size) {
$validSize = false;
break;
}
$total_size += $size;
}
return (($validFile === false) || ($validSize === false)) || ($total_size > $overall_size) ? false : true;
}
}
@@ -0,0 +1,133 @@
<?php
namespace Srmklive\PayPal\Traits;
trait PayPalAPI
{
use PayPalAPI\Trackers;
use PayPalAPI\CatalogProducts;
use PayPalAPI\Disputes;
use PayPalAPI\DisputesActions;
use PayPalAPI\Identity;
use PayPalAPI\Invoices;
use PayPalAPI\InvoicesSearch;
use PayPalAPI\InvoicesTemplates;
use PayPalAPI\Orders;
use PayPalAPI\PartnerReferrals;
use PayPalAPI\PaymentExperienceWebProfiles;
use PayPalAPI\PaymentMethodsTokens;
use PayPalAPI\PaymentAuthorizations;
use PayPalAPI\PaymentCaptures;
use PayPalAPI\PaymentRefunds;
use PayPalAPI\Payouts;
use PayPalAPI\ReferencedPayouts;
use PayPalAPI\BillingPlans;
use PayPalAPI\Subscriptions;
use PayPalAPI\Reporting;
use PayPalAPI\WebHooks;
use PayPalAPI\WebHooksVerification;
use PayPalAPI\WebHooksEvents;
/**
* Login through PayPal API to get access token.
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/get-an-access-token-curl/
* @see https://developer.paypal.com/docs/api/get-an-access-token-postman/
*/
public function getAccessToken()
{
$this->apiEndPoint = 'v1/oauth2/token';
$this->options['auth'] = [$this->config['client_id'], $this->config['client_secret']];
$this->options[$this->httpBodyParam] = [
'grant_type' => 'client_credentials',
];
$response = $this->doPayPalRequest();
unset($this->options['auth']);
unset($this->options[$this->httpBodyParam]);
if (isset($response['access_token'])) {
$this->setAccessToken($response);
}
return $response;
}
/**
* Set PayPal Rest API access token.
*
* @param array $response
*
* @return void
*/
public function setAccessToken(array $response)
{
$this->access_token = $response['access_token'];
$this->setPayPalAppId($response);
$this->setRequestHeader('Authorization', "{$response['token_type']} {$this->access_token}");
}
/**
* Set PayPal App ID.
*
* @param array $response
*
* @return void
*/
private function setPayPalAppId(array $response)
{
$app_id = empty($response['app_id']) ? $this->config['app_id'] : $response['app_id'];
$this->config['app_id'] = $app_id;
}
/**
* Set records per page for list resources API calls.
*
* @param int $size
*
* @return \Srmklive\PayPal\Services\PayPal
*/
public function setPageSize(int $size): \Srmklive\PayPal\Services\PayPal
{
$this->page_size = $size;
return $this;
}
/**
* Set the current page for list resources API calls.
*
* @param int $size
*
* @return \Srmklive\PayPal\Services\PayPal
*/
public function setCurrentPage(int $page): \Srmklive\PayPal\Services\PayPal
{
$this->current_page = $page;
return $this;
}
/**
* Toggle whether totals for list resources are returned after every API call.
*
* @param bool $totals
*
* @return \Srmklive\PayPal\Services\PayPal
*/
public function showTotals(bool $totals): \Srmklive\PayPal\Services\PayPal
{
$this->show_totals = $totals ? 'true' : 'false';
return $this;
}
}
@@ -0,0 +1,156 @@
<?php
namespace Srmklive\PayPal\Traits\PayPalAPI;
trait BillingPlans
{
use BillingPlans\PricingSchemes;
/**
* Create a new billing plan.
*
* @param array $data
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/subscriptions/v1/#plans_create
*/
public function createPlan(array $data)
{
$this->apiEndPoint = 'v1/billing/plans';
$this->options['json'] = $data;
$this->verb = 'post';
return $this->doPayPalRequest();
}
/**
* List all billing plans.
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/subscriptions/v1/#plans_list
*/
public function listPlans()
{
$this->apiEndPoint = "v1/billing/plans?page={$this->current_page}&page_size={$this->page_size}&total_required={$this->show_totals}";
$this->verb = 'get';
return $this->doPayPalRequest();
}
/**
* Update an existing billing plan.
*
* @param string $plan_id
* @param array $data
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/invoicing/v2/#invoices_update
*/
public function updatePlan(string $plan_id, array $data)
{
$this->apiEndPoint = "v1/billing/plans/{$plan_id}";
$this->options['json'] = $data;
$this->verb = 'patch';
return $this->doPayPalRequest(false);
}
/**
* Show details for an existing billing plan.
*
* @param string $plan_id
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/subscriptions/v1/#plans_get
*/
public function showPlanDetails(string $plan_id)
{
$this->apiEndPoint = "v1/billing/plans/{$plan_id}";
$this->verb = 'get';
return $this->doPayPalRequest();
}
/**
* Activate an existing billing plan.
*
* @param string $plan_id
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/subscriptions/v1/#plans_activate
*/
public function activatePlan(string $plan_id)
{
$this->apiEndPoint = "v1/billing/plans/{$plan_id}/activate";
$this->verb = 'post';
return $this->doPayPalRequest(false);
}
/**
* Deactivate an existing billing plan.
*
* @param string $plan_id
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/subscriptions/v1/#plans_deactivate
*/
public function deactivatePlan(string $plan_id)
{
$this->apiEndPoint = "v1/billing/plans/{$plan_id}/deactivate";
$this->verb = 'post';
return $this->doPayPalRequest(false);
}
/**
* Update pricing for an existing billing plan.
*
* @param string $plan_id
* @param array $pricing
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/subscriptions/v1/#plans_update-pricing-schemes
*/
public function updatePlanPricing(string $plan_id, array $pricing)
{
$this->apiEndPoint = "v1/billing/plans/{$plan_id}/update-pricing-schemes";
$this->options['json'] = [
'pricing_schemes' => $pricing,
];
$this->verb = 'post';
return $this->doPayPalRequest(false);
}
}
@@ -0,0 +1,41 @@
<?php
namespace Srmklive\PayPal\Traits\PayPalAPI\BillingPlans;
use Throwable;
trait PricingSchemes
{
protected $pricing_schemes = [];
/**
* Add pricing scheme for the billing plan.
*
* @param string $interval_unit
* @param int $interval_count
* @param float $price
* @param bool $trial
*
* @throws Throwable
*
* @return \Srmklive\PayPal\Services\PayPal
*/
public function addPricingScheme(string $interval_unit, int $interval_count, float $price, bool $trial = false): \Srmklive\PayPal\Services\PayPal
{
$this->pricing_schemes[] = $this->addPlanBillingCycle($interval_unit, $interval_count, $price, $trial);
return $this;
}
/**
* Process pricing updates for an existing billing plan.
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*/
public function processBillingPlanPricingUpdates()
{
return $this->updatePlanPricing($this->billing_plan['id'], $this->pricing_schemes);
}
}
@@ -0,0 +1,89 @@
<?php
namespace Srmklive\PayPal\Traits\PayPalAPI;
trait CatalogProducts
{
/**
* Create a product.
*
* @param array $data
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/catalog-products/v1/#products_create
*/
public function createProduct(array $data)
{
$this->apiEndPoint = 'v1/catalogs/products';
$this->options['json'] = $data;
$this->verb = 'post';
return $this->doPayPalRequest();
}
/**
* List products.
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/catalog-products/v1/#products_list
*/
public function listProducts()
{
$this->apiEndPoint = "v1/catalogs/products?page={$this->current_page}&page_size={$this->page_size}&total_required={$this->show_totals}";
$this->verb = 'get';
return $this->doPayPalRequest();
}
/**
* Update a product.
*
* @param string $product_id
* @param array $data
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/catalog-products/v1/#products_patch
*/
public function updateProduct(string $product_id, array $data)
{
$this->apiEndPoint = "v1/catalogs/products/{$product_id}";
$this->options['json'] = $data;
$this->verb = 'patch';
return $this->doPayPalRequest(false);
}
/**
* Get product details.
*
* @param string $product_id
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/catalog-products/v1/#products_get
*/
public function showProductDetails(string $product_id)
{
$this->apiEndPoint = "v1/catalogs/products/{$product_id}";
$this->verb = 'get';
return $this->doPayPalRequest();
}
}
@@ -0,0 +1,67 @@
<?php
namespace Srmklive\PayPal\Traits\PayPalAPI;
trait Disputes
{
/**
* List disputes.
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/customer-disputes/v1/#disputes_list
*/
public function listDisputes()
{
$this->apiEndPoint = "v1/customer/disputes?page_size={$this->page_size}";
$this->verb = 'get';
return $this->doPayPalRequest();
}
/**
* Update a dispute.
*
* @param string $dispute_id
* @param array $data
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/customer-disputes/v1/#disputes_patch
*/
public function updateDispute(string $dispute_id, array $data)
{
$this->apiEndPoint = "v1/customer/disputes/{$dispute_id}";
$this->options['json'] = $data;
$this->verb = 'patch';
return $this->doPayPalRequest(false);
}
/**
* Get dispute details.
*
* @param string $dispute_id
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/customer-disputes/v1/#disputes_get
*/
public function showDisputeDetails(string $dispute_id)
{
$this->apiEndPoint = "v1/customer/disputes/{$dispute_id}";
$this->verb = 'get';
return $this->doPayPalRequest();
}
}
@@ -0,0 +1,256 @@
<?php
namespace Srmklive\PayPal\Traits\PayPalAPI;
use GuzzleHttp\Psr7;
use Srmklive\PayPal\Services\VerifyDocuments;
trait DisputesActions
{
/**
* Acknowledge item has been returned.
*
* @param string $dispute_id
* @param string $dispute_note
* @param string $acknowledgement_type
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/customer-disputes/v1/#disputes-actions_acknowledge-return-item
*/
public function acknowledgeItemReturned(string $dispute_id, string $dispute_note, string $acknowledgement_type)
{
$this->apiEndPoint = "v1/customer/disputes/{$dispute_id}/acknowledge-return-item";
$this->options['json'] = [
'note' => $dispute_note,
'acknowledgement_type' => $acknowledgement_type,
];
$this->verb = 'post';
return $this->doPayPalRequest();
}
/**
* Providence evidence in support of a dispute.
*
* @param string $dispute_id
* @param array $file_path
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* https://developer.paypal.com/docs/api/customer-disputes/v1/#disputes_provide-evidence
*/
public function provideDisputeEvidence(string $dispute_id, array $files)
{
if (VerifyDocuments::isValidEvidenceFile($files) === false) {
$this->throwInvalidEvidenceFileException();
}
$this->apiEndPoint = "/v1/customer/disputes/{$dispute_id}/provide-evidence";
$this->setRequestHeader('Content-Type', 'multipart/form-data');
$this->options['multipart'] = [];
foreach ($files as $file) {
$this->options['multipart'][] = [
'name' => basename($file),
'contents' => Psr7\Utils::tryFopen($file, 'r'),
];
}
$this->verb = 'post';
return $this->doPayPalRequest();
}
/**
* Make offer to resolve dispute claim.
*
* @param string $dispute_id
* @param string $dispute_note
* @param float $amount
* @param string $refund_type
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/customer-disputes/v1/#disputes_make-offer
*/
public function makeOfferToResolveDispute(string $dispute_id, string $dispute_note, float $amount, string $refund_type)
{
$this->apiEndPoint = "v1/customer/disputes/{$dispute_id}/make-offer";
$data['note'] = $dispute_note;
$data['offer_type'] = $refund_type;
$data['offer_amount'] = [
'currency_code' => $this->getCurrency(),
'value' => $amount,
];
$this->options['json'] = $data;
$this->verb = 'post';
return $this->doPayPalRequest();
}
/**
* Escalate dispute to claim.
*
* @param string $dispute_id
* @param string $dispute_note
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/customer-disputes/v1/#disputes_escalate
*/
public function escalateDisputeToClaim(string $dispute_id, string $dispute_note)
{
$this->apiEndPoint = "v1/customer/disputes/{$dispute_id}/escalate";
$data['note'] = $dispute_note;
$this->options['json'] = $data;
$this->verb = 'post';
return $this->doPayPalRequest();
}
/**
* Accept offer to resolve dispute.
*
* @param string $dispute_id
* @param string $dispute_note
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/customer-disputes/v1/#disputes_accept-offer
*/
public function acceptDisputeOfferResolution(string $dispute_id, string $dispute_note)
{
$this->apiEndPoint = "v1/customer/disputes/{$dispute_id}/accept-offer";
$this->options['json'] = [
'note' => $dispute_note,
];
$this->verb = 'post';
return $this->doPayPalRequest();
}
/**
* Accept customer dispute claim.
*
* @param string $dispute_id
* @param string $dispute_note
* @param array $data
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/customer-disputes/v1/#disputes_accept-claim
*/
public function acceptDisputeClaim(string $dispute_id, string $dispute_note, array $data = [])
{
$this->apiEndPoint = "v1/customer/disputes/{$dispute_id}/accept-claim";
$data['note'] = $dispute_note;
$data['accept_claim_type'] = 'REFUND';
$this->options['json'] = $data;
$this->verb = 'post';
return $this->doPayPalRequest();
}
/**
* Update dispute status.
*
* @param string $dispute_id
* @param bool $merchant
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/customer-disputes/v1/#disputes_require-evidence
*/
public function updateDisputeStatus(string $dispute_id, bool $merchant = true)
{
$this->apiEndPoint = "v1/customer/disputes/{$dispute_id}/require-evidence";
$data['action'] = ($merchant === true) ? 'SELLER_EVIDENCE' : 'BUYER_EVIDENCE';
$this->options['json'] = $data;
$this->verb = 'post';
return $this->doPayPalRequest();
}
/**
* Settle dispute.
*
* @param string $dispute_id
* @param bool $merchant
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/customer-disputes/v1/#disputes_adjudicate
*/
public function settleDispute(string $dispute_id, bool $merchant = true)
{
$this->apiEndPoint = "v1/customer/disputes/{$dispute_id}/adjudicate";
$data['adjudication_outcome'] = ($merchant === true) ? 'SELLER_FAVOR' : 'BUYER_FAVOR';
$this->options['json'] = $data;
$this->verb = 'post';
return $this->doPayPalRequest();
}
/**
* Decline offer to resolve dispute.
*
* @param string $dispute_id
* @param string $dispute_note
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/customer-disputes/v1/#disputes_deny-offer
*/
public function declineDisputeOfferResolution(string $dispute_id, string $dispute_note)
{
$this->apiEndPoint = "v1/customer/disputes/{$dispute_id}/deny-offer";
$this->options['json'] = [
'note' => $dispute_note,
];
$this->verb = 'post';
return $this->doPayPalRequest();
}
}
@@ -0,0 +1,196 @@
<?php
namespace Srmklive\PayPal\Traits\PayPalAPI;
trait Identity
{
/**
* Get user profile information.
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/identity/v1/#userinfo_get
*/
public function showProfileInfo()
{
$this->apiEndPoint = 'v1/identity/openidconnect/userinfo?schema=openid';
$this->setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
$this->verb = 'get';
return $this->doPayPalRequest();
}
/**
* List Users.
*
* @param string $field
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/identity/v2/#users_list
*/
public function listUsers(string $field = 'userName')
{
$this->apiEndPoint = "v2/scim/Users?filter={$field}";
$this->setRequestHeader('Content-Type', 'application/scim+json');
$this->verb = 'get';
return $this->doPayPalRequest();
}
/**
* Show details for a user by ID.
*
* @param string $user_id
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/identity/v2/#users_get
*/
public function showUserDetails(string $user_id)
{
$this->apiEndPoint = "v2/scim/Users/{$user_id}";
$this->setRequestHeader('Content-Type', 'application/scim+json');
$this->verb = 'get';
return $this->doPayPalRequest();
}
/**
* Delete a user by ID.
*
* @param string $user_id
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/identity/v2/#users_get
*/
public function deleteUser(string $user_id)
{
$this->apiEndPoint = "v2/scim/Users/{$user_id}";
$this->setRequestHeader('Content-Type', 'application/scim+json');
$this->verb = 'delete';
return $this->doPayPalRequest(false);
}
/**
* Create a merchant application.
*
* @param string $client_name
* @param array $redirect_uris
* @param array $contacts
* @param string $payer_id
* @param string $migrated_app
* @param string $application_type
* @param string $logo_url
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/identity/v1/#applications_post
*/
public function createMerchantApplication(string $client_name, array $redirect_uris, array $contacts, string $payer_id, string $migrated_app, string $application_type = 'web', string $logo_url = '')
{
$this->apiEndPoint = 'v1/identity/applications';
$this->options['json'] = array_filter([
'application_type' => $application_type,
'redirect_uris' => $redirect_uris,
'client_name' => $client_name,
'contacts' => $contacts,
'payer_id' => $payer_id,
'migrated_app' => $migrated_app,
'logo_uri' => $logo_url,
]);
$this->verb = 'post';
return $this->doPayPalRequest();
}
/**
* Create a merchant application.
*
* @param array $features
* @param string $account_property
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/identity/v1/#account-settings_post
*/
public function setAccountProperties(array $features, string $account_property = 'BRAINTREE_MERCHANT')
{
$this->apiEndPoint = 'v1/identity/account-settings';
$this->options['json'] = [
'account_property' => $account_property,
'features' => $features,
];
$this->verb = 'post';
return $this->doPayPalRequest();
}
/**
* Create a merchant application.
*
* @param string $account_property
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/identity/v1/#account-settings_deactivate
*/
public function disableAccountProperties(string $account_property = 'BRAINTREE_MERCHANT')
{
$this->apiEndPoint = 'v1/identity/account-settings/deactivate';
$this->options['json'] = [
'account_property' => $account_property,
];
$this->verb = 'post';
return $this->doPayPalRequest();
}
/**
* Get a client token.
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/multiparty/checkout/advanced/integrate/#link-sampleclienttokenrequest
*/
public function getClientToken()
{
$this->apiEndPoint = 'v1/identity/generate-token';
$this->verb = 'post';
return $this->doPayPalRequest();
}
}
@@ -0,0 +1,245 @@
<?php
namespace Srmklive\PayPal\Traits\PayPalAPI\InvoiceSearch;
use Carbon\Carbon;
trait Filters
{
/**
* @var array
*/
protected $invoice_search_filters = [];
/**
* @var array
*/
protected $invoices_date_types = [
'invoice_date',
'due_date',
'payment_date',
'creation_date',
];
/**
* @var array
*/
protected $invoices_status_types = [
'DRAFT',
'SENT',
'SCHEDULED',
'PAID',
'MARKED_AS_PAID',
'CANCELLED',
'REFUNDED',
'PARTIALLY_PAID',
'PARTIALLY_REFUNDED',
'MARKED_AS_REFUNDED',
'UNPAID',
'PAYMENT_PENDING',
];
/**
* @param string $email
*
* @return \Srmklive\PayPal\Services\PayPal
*/
public function addInvoiceFilterByRecipientEmail(string $email): \Srmklive\PayPal\Services\PayPal
{
$this->invoice_search_filters['recipient_email'] = $email;
return $this;
}
/**
* @param string $name
*
* @return \Srmklive\PayPal\Services\PayPal
*/
public function addInvoiceFilterByRecipientFirstName(string $name): \Srmklive\PayPal\Services\PayPal
{
$this->invoice_search_filters['recipient_first_name'] = $name;
return $this;
}
/**
* @param string $name
*
* @return \Srmklive\PayPal\Services\PayPal
*/
public function addInvoiceFilterByRecipientLastName(string $name): \Srmklive\PayPal\Services\PayPal
{
$this->invoice_search_filters['recipient_last_name'] = $name;
return $this;
}
/**
* @param string $name
*
* @return \Srmklive\PayPal\Services\PayPal
*/
public function addInvoiceFilterByRecipientBusinessName(string $name): \Srmklive\PayPal\Services\PayPal
{
$this->invoice_search_filters['recipient_business_name'] = $name;
return $this;
}
/**
* @param string $invoice_number
*
* @return \Srmklive\PayPal\Services\PayPal
*/
public function addInvoiceFilterByInvoiceNumber(string $invoice_number): \Srmklive\PayPal\Services\PayPal
{
$this->invoice_search_filters['invoice_number'] = $invoice_number;
return $this;
}
/**
* @param array $status
*
* @throws \Exception
*
* @return \Srmklive\PayPal\Services\PayPal
*
* @see https://developer.paypal.com/docs/api/invoicing/v2/#definition-invoice_status
*/
public function addInvoiceFilterByInvoiceStatus(array $status): \Srmklive\PayPal\Services\PayPal
{
$invalid_status = false;
foreach ($status as $item) {
if (!in_array($item, $this->invoices_status_types)) {
$invalid_status = true;
}
}
if ($invalid_status === true) {
throw new \Exception('status should be always one of these: '.implode(',', $this->invoices_date_types));
}
$this->invoice_search_filters['status'] = $status;
return $this;
}
/**
* @param string $reference
* @param bool $memo
*
* @return \Srmklive\PayPal\Services\PayPal
*/
public function addInvoiceFilterByReferenceorMemo(string $reference, bool $memo = false): \Srmklive\PayPal\Services\PayPal
{
$field = ($memo === false) ? 'reference' : 'memo';
$this->invoice_search_filters[$field] = $reference;
return $this;
}
/**
* @param string $currency_code
*
* @return \Srmklive\PayPal\Services\PayPal
*/
public function addInvoiceFilterByCurrencyCode(string $currency_code = ''): \Srmklive\PayPal\Services\PayPal
{
$currency = !isset($currency_code) ? $this->getCurrency() : $currency_code;
$this->invoice_search_filters['currency_code'] = $currency;
return $this;
}
/**
* @param float $start_amount
* @param float $end_amount
* @param string $amount_currency
*
* @throws \Exception
*
* @return \Srmklive\PayPal\Services\PayPal
*/
public function addInvoiceFilterByAmountRange(float $start_amount, float $end_amount, string $amount_currency = ''): \Srmklive\PayPal\Services\PayPal
{
if ($start_amount > $end_amount) {
throw new \Exception('Starting amount should always be less than end amount!');
}
$currency = !isset($amount_currency) ? $this->getCurrency() : $amount_currency;
$this->invoice_search_filters['total_amount_range'] = [
'lower_amount' => [
'currency_code' => $currency,
'value' => $start_amount,
],
'upper_amount' => [
'currency_code' => $currency,
'value' => $end_amount,
],
];
return $this;
}
/**
* @param string $start_date
* @param string $end_date
* @param string $date_type
*
* @throws \Exception
*
* @return \Srmklive\PayPal\Services\PayPal
*/
public function addInvoiceFilterByDateRange(string $start_date, string $end_date, string $date_type): \Srmklive\PayPal\Services\PayPal
{
$start_date_obj = Carbon::parse($start_date);
$end_date_obj = Carbon::parse($end_date);
if ($start_date_obj->gt($end_date_obj)) {
throw new \Exception('Starting date should always be less than the end date!');
}
if (!in_array($date_type, $this->invoices_date_types)) {
throw new \Exception('date type should be always one of these: '.implode(',', $this->invoices_date_types));
}
$this->invoice_search_filters["{$date_type}_range"] = [
'start' => $start_date,
'end' => $end_date,
];
return $this;
}
/**
* @param bool $archived
*
* @return \Srmklive\PayPal\Services\PayPal
*/
public function addInvoiceFilterByArchivedStatus(bool $archived = null): \Srmklive\PayPal\Services\PayPal
{
$this->invoice_search_filters['archived'] = $archived;
return $this;
}
/**
* @param array $fields
*
* @return \Srmklive\PayPal\Services\PayPal
*
* @see https://developer.paypal.com/docs/api/invoicing/v2/#definition-field
*/
public function addInvoiceFilterByFields(array $fields): \Srmklive\PayPal\Services\PayPal
{
$this->invoice_search_filters['status'] = $fields;
return $this;
}
}
@@ -0,0 +1,378 @@
<?php
namespace Srmklive\PayPal\Traits\PayPalAPI;
trait Invoices
{
/**
* Create a new draft invoice.
*
* @param array $data
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/invoicing/v2/#invoices_create
*/
public function createInvoice(array $data)
{
$this->apiEndPoint = 'v2/invoicing/invoices';
$this->options['json'] = $data;
$this->verb = 'post';
return $this->doPayPalRequest();
}
/**
* Get list of invoices.
*
* @param array $fields
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/invoicing/v2/#invoices_list
*/
public function listInvoices(array $fields = [])
{
$fields_list = collect($fields);
$fields = ($fields_list->count() > 0) ? "&fields={$fields_list->implode(',')}" : '';
$this->apiEndPoint = "v2/invoicing/invoices?page={$this->current_page}&page_size={$this->page_size}&total_required={$this->show_totals}{$fields}";
$this->verb = 'get';
return $this->doPayPalRequest();
}
/**
* Send an existing invoice.
*
* @param string $invoice_id
* @param string $subject
* @param string $note
* @param bool $send_recipient
* @param bool $send_merchant
* @param array $recipients
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/invoicing/v2/#invoices_send
*/
public function sendInvoice(string $invoice_id, string $subject = '', string $note = '', bool $send_recipient = true, bool $send_merchant = false, array $recipients = [])
{
$this->apiEndPoint = "v2/invoicing/invoices/{$invoice_id}/send";
$this->options['json'] = $this->getInvoiceMessagePayload($subject, $note, $recipients, $send_recipient, $send_merchant);
$this->verb = 'post';
return $this->doPayPalRequest(false);
}
/**
* Send reminder for an existing invoice.
*
* @param string $invoice_id
* @param string $subject
* @param string $note
* @param bool $send_recipient
* @param bool $send_merchant
* @param array $recipients
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/invoicing/v2/#invoices_remind
*/
public function sendInvoiceReminder(string $invoice_id, string $subject = '', string $note = '', bool $send_recipient = true, bool $send_merchant = false, array $recipients = [])
{
$this->apiEndPoint = "v2/invoicing/invoices/{$invoice_id}/remind";
$this->options['json'] = $this->getInvoiceMessagePayload($subject, $note, $recipients, $send_recipient, $send_merchant);
$this->verb = 'post';
return $this->doPayPalRequest(false);
}
/**
* Cancel an existing invoice which is already sent.
*
* @param string $invoice_id
* @param string $subject
* @param string $note
* @param bool $send_recipient
* @param bool $send_merchant
* @param array $recipients
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/invoicing/v2/#invoices_cancel
*/
public function cancelInvoice(string $invoice_id, string $subject = '', string $note = '', bool $send_recipient = true, bool $send_merchant = false, array $recipients = [])
{
$this->apiEndPoint = "v2/invoicing/invoices/{$invoice_id}/cancel";
$this->options['json'] = $this->getInvoiceMessagePayload($subject, $note, $recipients, $send_recipient, $send_merchant);
$this->verb = 'post';
return $this->doPayPalRequest(false);
}
/**
* Register payment against an existing invoice.
*
* @param string $invoice_id
* @param string $payment_date
* @param string $payment_method
* @param float $amount
* @param string $payment_note
* @param string $payment_id
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/invoicing/v2/#invoices_payments
*/
public function registerPaymentInvoice(string $invoice_id, string $payment_date, string $payment_method, float $amount, string $payment_note = '', string $payment_id = '')
{
$this->apiEndPoint = "v2/invoicing/invoices/{$invoice_id}/payments";
$data = [
'payment_id' => $payment_id,
'payment_date' => $payment_date,
'method' => $payment_method,
'note' => $payment_note,
'amount' => [
'currency_code' => $this->currency,
'value' => $amount,
],
];
$this->options['json'] = $data;
$this->verb = 'post';
return $this->doPayPalRequest();
}
/**
* Delete payment against an existing invoice.
*
* @param string $invoice_id
* @param string $transaction_id
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/invoicing/v2/#invoices_payments-delete
*/
public function deleteExternalPaymentInvoice(string $invoice_id, string $transaction_id)
{
$this->apiEndPoint = "v2/invoicing/invoices/{$invoice_id}/payments/{$transaction_id}";
$this->verb = 'delete';
return $this->doPayPalRequest(false);
}
/**
* Register payment against an existing invoice.
*
* @param string $invoice_id
* @param string $payment_date
* @param string $payment_method
* @param float $amount
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/invoicing/v2/#invoices_refunds
*/
public function refundInvoice(string $invoice_id, string $payment_date, string $payment_method, float $amount)
{
$this->apiEndPoint = "v2/invoicing/invoices/{$invoice_id}/refunds";
$data = [
'refund_date' => $payment_date,
'method' => $payment_method,
'amount' => [
'currency_code' => $this->currency,
'value' => $amount,
],
];
$this->options['json'] = $data;
$this->verb = 'post';
return $this->doPayPalRequest();
}
/**
* Delete refund against an existing invoice.
*
* @param string $invoice_id
* @param string $transaction_id
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/invoicing/v2/#invoices_refunds-delete
*/
public function deleteRefundInvoice(string $invoice_id, string $transaction_id)
{
$this->apiEndPoint = "v2/invoicing/invoices/{$invoice_id}/refunds/{$transaction_id}";
$this->verb = 'delete';
return $this->doPayPalRequest(false);
}
/**
* Generate QR code against an existing invoice.
*
* @param string $invoice_id
* @param int $width
* @param int $height
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/invoicing/v2/#invoices_generate-qr-code
*/
public function generateQRCodeInvoice(string $invoice_id, int $width = 100, int $height = 100)
{
$this->apiEndPoint = "v2/invoicing/invoices/{$invoice_id}/generate-qr-code";
$this->options['json'] = [
'width' => $width,
'height' => $height,
];
$this->verb = 'post';
return $this->doPayPalRequest();
}
/**
* Generate the next invoice number.
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/invoicing/v2/#invoices_generate-next-invoice-number
*/
public function generateInvoiceNumber()
{
$this->apiEndPoint = 'v2/invoicing/generate-next-invoice-number';
$this->verb = 'post';
return $this->doPayPalRequest();
}
/**
* Show details for an existing invoice.
*
* @param string $invoice_id
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/invoicing/v2/#invoices_get
*/
public function showInvoiceDetails(string $invoice_id)
{
$this->apiEndPoint = "v2/invoicing/invoices/{$invoice_id}";
$this->verb = 'get';
return $this->doPayPalRequest();
}
/**
* Update an existing invoice.
*
* @param string $invoice_id
* @param array $data
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/invoicing/v2/#invoices_update
*/
public function updateInvoice(string $invoice_id, array $data)
{
$this->apiEndPoint = "v2/invoicing/invoices/{$invoice_id}";
$this->options['json'] = $data;
$this->verb = 'put';
return $this->doPayPalRequest();
}
/**
* Delete an invoice.
*
* @param string $invoice_id
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/invoicing/v2/#invoices_list
*/
public function deleteInvoice(string $invoice_id)
{
$this->apiEndPoint = "v2/invoicing/invoices/{$invoice_id}";
$this->verb = 'delete';
return $this->doPayPalRequest(false);
}
/**
* Get Invoice Message Payload.
*
* @param string $subject
* @param string $note
* @param array $recipients
* @param bool $send_recipient
* @param bool $send_merchant
*
* @return array
*/
protected function getInvoiceMessagePayload(string $subject, string $note, array $recipients, bool $send_recipient, bool $send_merchant): array
{
$data = [
'subject' => !empty($subject) ? $subject : '',
'note' => !empty($note) ? $note : '',
'additional_recipients' => (collect($recipients)->count() > 0) ? $recipients : '',
'send_to_recipient' => $send_recipient,
'send_to_invoicer' => $send_merchant,
];
return collect($data)->filter()->toArray();
}
}
@@ -0,0 +1,36 @@
<?php
namespace Srmklive\PayPal\Traits\PayPalAPI;
use Srmklive\PayPal\Traits\PayPalAPI\InvoiceSearch\Filters;
trait InvoicesSearch
{
use Filters;
/**
* Search and return existing invoices.
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/invoicing/v2/#invoices_list
*/
public function searchInvoices()
{
if (collect($this->invoice_search_filters)->count() < 1) {
$this->invoice_search_filters = [
'currency_code' => $this->getCurrency(),
];
}
$this->apiEndPoint = "v2/invoicing/search-invoices?page={$this->current_page}&page_size={$this->page_size}&total_required={$this->show_totals}";
$this->options['json'] = $this->invoice_search_filters;
$this->verb = 'post';
return $this->doPayPalRequest();
}
}
@@ -0,0 +1,111 @@
<?php
namespace Srmklive\PayPal\Traits\PayPalAPI;
trait InvoicesTemplates
{
/**
* Get list of invoice templates.
*
* @param string $fields
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/invoicing/v2/#templates_list
*/
public function listInvoiceTemplates(string $fields = 'all')
{
$this->apiEndPoint = "v2/invoicing/templates?page={$this->current_page}&page_size={$this->page_size}&fields={$fields}";
$this->verb = 'get';
return $this->doPayPalRequest();
}
/**
* Create a new invoice template.
*
* @param array $data
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/invoicing/v2/#templates_create
*/
public function createInvoiceTemplate(array $data)
{
$this->apiEndPoint = 'v2/invoicing/templates';
$this->options['json'] = $data;
$this->verb = 'post';
return $this->doPayPalRequest();
}
/**
* Show details for an existing invoice.
*
* @param string $template_id
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/invoicing/v2/#templates_get
*/
public function showInvoiceTemplateDetails(string $template_id)
{
$this->apiEndPoint = "v2/invoicing/templates/{$template_id}";
$this->verb = 'get';
return $this->doPayPalRequest();
}
/**
* Update an existing invoice template.
*
* @param string $template_id
* @param array $data
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/invoicing/v2/#templates_update
*/
public function updateInvoiceTemplate(string $template_id, array $data)
{
$this->apiEndPoint = "v2/invoicing/templates/{$template_id}";
$this->options['json'] = $data;
$this->verb = 'put';
return $this->doPayPalRequest();
}
/**
* Delete an invoice template.
*
* @param string $template_id
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/invoicing/v2/#templates_delete
*/
public function deleteInvoiceTemplate(string $template_id)
{
$this->apiEndPoint = "v2/invoicing/templates/{$template_id}";
$this->verb = 'delete';
return $this->doPayPalRequest(false);
}
}
@@ -0,0 +1,163 @@
<?php
namespace Srmklive\PayPal\Traits\PayPalAPI;
trait Orders
{
use Orders\Helpers;
/**
* Creates an order.
*
* @param array $data
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/orders/v2/#orders_create
*/
public function createOrder(array $data)
{
$this->apiEndPoint = 'v2/checkout/orders';
$this->options['json'] = (object) $data;
$this->verb = 'post';
return $this->doPayPalRequest();
}
/**
* Shows details for an order.
*
* @param string $order_id
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/orders/v2/#orders_get
*/
public function showOrderDetails(string $order_id)
{
$this->apiEndPoint = "v2/checkout/orders/{$order_id}";
$this->verb = 'get';
return $this->doPayPalRequest();
}
/**
* Update order details.
*
* @param string $order_id
* @param array $data
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/orders/v2/#orders_patch
*/
public function updateOrder(string $order_id, array $data)
{
$this->apiEndPoint = "v2/checkout/orders/{$order_id}";
$this->options['json'] = $data;
$this->verb = 'patch';
return $this->doPayPalRequest(false);
}
/**
* Confirm the order.
*
* @param string $order_id
* @param array $data
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*/
public function confirmOrder(string $order_id, array $data)
{
$this->apiEndPoint = "v2/checkout/orders/{$order_id}/confirm-payment-source";
$this->options['json'] = (object) $data;
$this->verb = 'post';
return $this->doPayPalRequest();
}
/**
* Authorizes payment for an order.
*
* @param string $order_id
* @param array $data
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/orders/v2/#orders_authorize
*/
public function authorizePaymentOrder(string $order_id, array $data = [])
{
$this->apiEndPoint = "v2/checkout/orders/{$order_id}/authorize";
$this->options['json'] = (object) $data;
$this->verb = 'post';
return $this->doPayPalRequest();
}
/**
* Captures payment for an order.
*
* @param string $order_id
* @param array $data
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/orders/v2/#orders_capture
*/
public function capturePaymentOrder(string $order_id, array $data = [])
{
$this->apiEndPoint = "v2/checkout/orders/{$order_id}/capture";
$this->options['json'] = (object) $data;
$this->verb = 'post';
return $this->doPayPalRequest();
}
/**
* Add tracking information for an Order.
*
* @param string $order_id
* @param array $data
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/orders/v2/#orders_track_create
*/
public function addTrackingForOrder(string $order_id, array $data)
{
$this->apiEndPoint = "v2/checkout/orders/{$order_id}/track";
$this->options['json'] = $data;
$this->verb = 'post';
return $this->doPayPalRequest();
}
}
@@ -0,0 +1,29 @@
<?php
namespace Srmklive\PayPal\Traits\PayPalAPI\Orders;
use Throwable;
trait Helpers
{
/**
* Confirm payment for an order.
*
* @param string $order_id
* @param string $processing_instruction
*
* @throws Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*/
public function setupOrderConfirmation(string $order_id, string $processing_instruction = '')
{
$body = [
'processing_instruction' => $processing_instruction,
'application_context' => $this->experience_context,
'payment_source' => $this->payment_source,
];
return $this->confirmOrder($order_id, $body);
}
}
@@ -0,0 +1,110 @@
<?php
namespace Srmklive\PayPal\Traits\PayPalAPI;
trait PartnerReferrals
{
/**
* Create a Partner Referral.
*
* @param array $partner_data
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/partner-referrals/v2/#partner-referrals_create
*/
public function createPartnerReferral(array $partner_data)
{
$this->apiEndPoint = 'v2/customer/partner-referrals';
$this->options['json'] = $partner_data;
$this->verb = 'post';
return $this->doPayPalRequest();
}
/**
* Get Partner Referral Details.
*
* @param string $partner_referral_id
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/partner-referrals/v2/#partner-referrals_read
*/
public function showReferralData(string $partner_referral_id)
{
$this->apiEndPoint = "v2/customer/partner-referrals/{$partner_referral_id}";
$this->verb = 'get';
return $this->doPayPalRequest();
}
/**
* List Seller Tracking Information.
*
* @param string $partner_id
* @param string $tracking_id
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/partner-referrals/v1/#merchant-integration_find
*/
public function listSellerTrackingInformation(string $partner_id, string $tracking_id)
{
$this->apiEndPoint = "v1/customer/partners/{$partner_id}/merchant-integrations?tracking_id={$tracking_id}";
$this->verb = 'get';
return $this->doPayPalRequest();
}
/**
* Show Seller Status.
*
* @param string $partner_id
* @param string $merchant_id
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/partner-referrals/v1/#merchant-integration_status
*/
public function showSellerStatus(string $partner_id, string $merchant_id)
{
$this->apiEndPoint = "v1/customer/partners/{$partner_id}/merchant-integrations/{$merchant_id}";
$this->verb = 'get';
return $this->doPayPalRequest();
}
/**
* List Merchant Credentials.
*
* @param string $partner_id
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/partner-referrals/v1/#merchant-integration_credentials
*/
public function listMerchantCredentials(string $partner_id)
{
$this->apiEndPoint = "v1/customer/partners/{$partner_id}/merchant-integrations/credentials";
$this->verb = 'get';
return $this->doPayPalRequest();
}
}
@@ -0,0 +1,107 @@
<?php
namespace Srmklive\PayPal\Traits\PayPalAPI;
trait PaymentAuthorizations
{
/**
* Show details for authorized payment.
*
* @param string $authorization_id
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/payments/v2/#authorizations_get
*/
public function showAuthorizedPaymentDetails(string $authorization_id)
{
$this->apiEndPoint = "v2/payments/authorizations/{$authorization_id}";
$this->verb = 'get';
return $this->doPayPalRequest();
}
/**
* Capture an authorized payment.
*
* @param string $authorization_id
* @param string $invoice_id
* @param float $amount
* @param string $note
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/payments/v2/#authorizations_capture
*/
public function captureAuthorizedPayment(string $authorization_id, string $invoice_id, float $amount, string $note)
{
$this->apiEndPoint = "v2/payments/authorizations/{$authorization_id}/capture";
$this->options['json'] = [
'amount' => [
'value' => $amount,
'currency_code' => $this->currency,
],
'invoice_id' => $invoice_id,
'note_to_payer' => $note,
'final_capture' => true,
];
$this->verb = 'post';
return $this->doPayPalRequest();
}
/**
* Reauthorize an authorized payment.
*
* @param string $authorization_id
* @param float $amount
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/payments/v2/#authorizations_reauthorize
*/
public function reAuthorizeAuthorizedPayment(string $authorization_id, float $amount)
{
$this->apiEndPoint = "v2/payments/authorizations/{$authorization_id}/reauthorize";
$this->options['json'] = [
'amount' => [
'value' => $amount,
'currency_code' => $this->currency,
],
];
$this->verb = 'post';
return $this->doPayPalRequest();
}
/**
* Void an authorized payment.
*
* @param string $authorization_id
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/payments/v2/#authorizations_void
*/
public function voidAuthorizedPayment(string $authorization_id)
{
$this->apiEndPoint = "v2/payments/authorizations/{$authorization_id}/void";
$this->verb = 'post';
return $this->doPayPalRequest(false);
}
}
@@ -0,0 +1,58 @@
<?php
namespace Srmklive\PayPal\Traits\PayPalAPI;
trait PaymentCaptures
{
/**
* Show details for a captured payment.
*
* @param string $capture_id
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/payments/v2/#captures_get
*/
public function showCapturedPaymentDetails(string $capture_id)
{
$this->apiEndPoint = "v2/payments/captures/{$capture_id}";
$this->verb = 'get';
return $this->doPayPalRequest();
}
/**
* Refund a captured payment.
*
* @param string $capture_id
* @param string $invoice_id
* @param float $amount
* @param string $note
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/payments/v2/#captures_refund
*/
public function refundCapturedPayment(string $capture_id, string $invoice_id, float $amount, string $note)
{
$this->apiEndPoint = "v2/payments/captures/{$capture_id}/refund";
$this->options['json'] = [
'amount' => [
'value' => $amount,
'currency_code' => $this->currency,
],
'invoice_id' => $invoice_id,
'note_to_payer' => $note,
];
$this->verb = 'post';
return $this->doPayPalRequest();
}
}
@@ -0,0 +1,132 @@
<?php
namespace Srmklive\PayPal\Traits\PayPalAPI;
trait PaymentExperienceWebProfiles
{
/**
* List Web Experience Profiles.
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/payment-experience/v1/#web-profiles_get-list
*/
public function listWebExperienceProfiles()
{
$this->apiEndPoint = 'v1/payment-experience/web-profiles';
$this->verb = 'get';
return $this->doPayPalRequest();
}
/**
* Create a Web Experience Profile.
*
* @param array $data
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/payment-experience/v1/#web-profile_create
*/
public function createWebExperienceProfile(array $data)
{
$this->apiEndPoint = 'v1/payment-experience/web-profiles';
$this->options['json'] = $data;
$this->verb = 'post';
return $this->doPayPalRequest();
}
/**
* Delete a Web Experience Profile.
*
* @param string $profile_id
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/payment-experience/v1/#web-profile_delete
*/
public function deleteWebExperienceProfile(string $profile_id)
{
$this->apiEndPoint = "v1/payment-experience/web-profiles/{$profile_id}";
$this->verb = 'delete';
return $this->doPayPalRequest();
}
/**
* Partially update a Web Experience Profile.
*
* @param string $profile_id
* @param array $data
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/payment-experience/v1/#web-profile_partial-update
*/
public function patchWebExperienceProfile(string $profile_id, array $data)
{
$this->apiEndPoint = "v1/payment-experience/web-profiles/{$profile_id}";
$this->options['json'] = $data;
$this->verb = 'patch';
return $this->doPayPalRequest();
}
/**
* Partially update a Web Experience Profile.
*
* @param string $profile_id
* @param array $data
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/payment-experience/v1/#web-profile_update
*/
public function updateWebExperienceProfile(string $profile_id, array $data)
{
$this->apiEndPoint = "v1/payment-experience/web-profiles/{$profile_id}";
$this->options['json'] = $data;
$this->verb = 'put';
return $this->doPayPalRequest();
}
/**
* Delete a Web Experience Profile.
*
* @param string $profile_id
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/payment-experience/v1/#web-profile_get
*/
public function showWebExperienceProfileDetails(string $profile_id)
{
$this->apiEndPoint = "v1/payment-experience/web-profiles/{$profile_id}";
$this->verb = 'get';
return $this->doPayPalRequest();
}
}
@@ -0,0 +1,126 @@
<?php
namespace Srmklive\PayPal\Traits\PayPalAPI;
trait PaymentMethodsTokens
{
use PaymentMethodsTokens\Helpers;
/**
* Create a payment method token.
*
* @param array $data
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/payment-tokens/v3/#payment-tokens_create
*/
public function createPaymentSourceToken(array $data)
{
$this->apiEndPoint = 'v3/vault/payment-tokens';
$this->options['json'] = $data;
$this->verb = 'post';
return $this->doPayPalRequest();
}
/**
* List all the payment tokens.
*
* @param int $page
* @param int $page_size
* @param bool $totals
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/payment-tokens/v3/#customer_payment-tokens_get
*/
public function listPaymentSourceTokens(int $page = 1, int $page_size = 10, bool $totals = true)
{
$this->apiEndPoint = "v3/vault/payment-tokens?customer_id={$this->customer_source['id']}&page={$page}&page_size={$page_size}&total_required={$totals}";
$this->verb = 'get';
return $this->doPayPalRequest();
}
/**
* Show details for a payment method token.
*
* @param string $token
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/payment-tokens/v3/#payment-tokens_get
*/
public function showPaymentSourceTokenDetails(string $token)
{
$this->apiEndPoint = "v3/vault/payment-tokens/{$token}";
$this->verb = 'get';
return $this->doPayPalRequest();
}
/**
* Show details for a payment token.
*
* @param string $token
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/payment-tokens/v3/#payment-tokens_delete
*/
public function deletePaymentSourceToken(string $token)
{
$this->apiEndPoint = "v3/vault/payment-tokens/{$token}";
$this->verb = 'delete';
return $this->doPayPalRequest(false);
}
/**
* Create a payment setup token.
*
* @param array $data
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/payment-tokens/v3/#setup-tokens_create
*/
public function createPaymentSetupToken(array $data)
{
$this->apiEndPoint = 'v3/vault/setup-tokens';
$this->options['json'] = $data;
$this->verb = 'post';
return $this->doPayPalRequest();
}
/**
* Show details for a payment setup token.
*
* @param string $token
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/payment-tokens/v3/#setup-tokens_get
*/
public function showPaymentSetupTokenDetails(string $token)
{
$this->apiEndPoint = "v3/vault/setup-tokens/{$token}";
$this->verb = 'get';
return $this->doPayPalRequest();
}
}
@@ -0,0 +1,121 @@
<?php
namespace Srmklive\PayPal\Traits\PayPalAPI\PaymentMethodsTokens;
trait Helpers
{
/**
* @var array
*/
protected $payment_source = [];
/**
* @var array
*/
protected $customer_source = [];
/**
* Set payment method token by token id.
*
* @param string $id
* @param string $type
*
* @return \Srmklive\PayPal\Services\PayPal
*/
public function setTokenSource(string $id, string $type): \Srmklive\PayPal\Services\PayPal
{
$token_source = [
'id' => $id,
'type' => $type,
];
return $this->setPaymentSourceDetails('token', $token_source);
}
/**
* Set payment method token customer id.
*
* @param string $id
*
* @return \Srmklive\PayPal\Services\PayPal
*/
public function setCustomerSource(string $id): \Srmklive\PayPal\Services\PayPal
{
$this->customer_source = [
'id' => $id,
];
return $this;
}
/**
* Set payment source data for credit card.
*
* @param array $data
*
* @return \Srmklive\PayPal\Services\PayPal
*/
public function setPaymentSourceCard(array $data): \Srmklive\PayPal\Services\PayPal
{
return $this->setPaymentSourceDetails('card', $data);
}
/**
* Set payment source data for PayPal.
*
* @param array $data
*
* @return \Srmklive\PayPal\Services\PayPal
*/
public function setPaymentSourcePayPal(array $data): \Srmklive\PayPal\Services\PayPal
{
return $this->setPaymentSourceDetails('paypal', $data);
}
/**
* Set payment source data for Venmo.
*
* @param array $data
*
* @return \Srmklive\PayPal\Services\PayPal
*/
public function setPaymentSourceVenmo(array $data): \Srmklive\PayPal\Services\PayPal
{
return $this->setPaymentSourceDetails('venmo', $data);
}
/**
* Set payment source details.
*
* @param string $source
* @param array $data
*
* @return \Srmklive\PayPal\Services\PayPal
*/
protected function setPaymentSourceDetails(string $source, array $data): \Srmklive\PayPal\Services\PayPal
{
$this->payment_source[$source] = $data;
return $this;
}
/**
* Send request for creating payment method token/source.
*
* @param bool $create_source
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*/
public function sendPaymentMethodRequest(bool $create_source = false)
{
$token_payload = ['payment_source' => $this->payment_source];
if (!empty($this->customer_source)) {
$token_payload['customer'] = $this->customer_source;
}
return ($create_source === true) ? $this->createPaymentSetupToken(array_filter($token_payload)) : $this->createPaymentSourceToken(array_filter($token_payload));
}
}
@@ -0,0 +1,26 @@
<?php
namespace Srmklive\PayPal\Traits\PayPalAPI;
trait PaymentRefunds
{
/**
* Show details for authorized payment.
*
* @param string $refund_id
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/payments/v2/#authorizations_get
*/
public function showRefundDetails(string $refund_id)
{
$this->apiEndPoint = "v2/payments/refunds/{$refund_id}";
$this->verb = 'get';
return $this->doPayPalRequest();
}
}
@@ -0,0 +1,88 @@
<?php
namespace Srmklive\PayPal\Traits\PayPalAPI;
trait Payouts
{
/**
* Create a Batch Payout.
*
* @param array $data
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/payments.payouts-batch/v1/#payouts_post
*/
public function createBatchPayout(array $data)
{
$this->apiEndPoint = 'v1/payments/payouts';
$this->options['json'] = $data;
$this->verb = 'post';
return $this->doPayPalRequest();
}
/**
* Show Batch Payout details by ID.
*
* @param string $payout_id
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/payments.payouts-batch/v1/#payouts_get
*/
public function showBatchPayoutDetails(string $payout_id)
{
$this->apiEndPoint = "v1/payments/payouts/{$payout_id}";
$this->verb = 'get';
return $this->doPayPalRequest();
}
/**
* Show Payout Item details by ID.
*
* @param string $payout_item_id
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/payments.payouts-batch/v1/#payouts-item_get
*/
public function showPayoutItemDetails(string $payout_item_id)
{
$this->apiEndPoint = "v1/payments/payouts-item/{$payout_item_id}";
$this->verb = 'get';
return $this->doPayPalRequest();
}
/**
* Show Payout Item details by ID.
*
* @param string $payout_item_id
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/payments.payouts-batch/v1/#payouts-item_cancel
*/
public function cancelUnclaimedPayoutItem(string $payout_item_id)
{
$this->apiEndPoint = "v1/payments/payouts-item/{$payout_item_id}/cancel";
$this->verb = 'post';
return $this->doPayPalRequest();
}
}
@@ -0,0 +1,90 @@
<?php
namespace Srmklive\PayPal\Traits\PayPalAPI;
trait ReferencedPayouts
{
/**
* Create a referenced Batch Payout.
*
* @param array $data
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/referenced-payouts/v1/#referenced-payouts_create_batch
*/
public function createReferencedBatchPayout(array $data)
{
$this->apiEndPoint = 'v1/payments/referenced-payouts';
$this->options['json'] = $data;
$this->verb = 'post';
return $this->doPayPalRequest();
}
/**
* Show Batch Payout details by ID.
*
* @param string $batch_payout_id
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/referenced-payouts/v1/#referenced-payouts_get_batch_details
*/
public function listItemsReferencedInBatchPayout(string $batch_payout_id)
{
$this->apiEndPoint = "v1/payments/referenced-payouts/{$batch_payout_id}";
$this->verb = 'get';
return $this->doPayPalRequest();
}
/**
* Create a referenced Batch Payout Item.
*
* @param array $data
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/referenced-payouts/v1/#referenced-payouts-items_create
*/
public function createReferencedBatchPayoutItem(array $data)
{
$this->apiEndPoint = 'v1/payments/referenced-payouts-items';
$this->options['json'] = $data;
$this->verb = 'post';
return $this->doPayPalRequest();
}
/**
* Show Payout Item details by ID.
*
* @param string $payout_item_id
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/referenced-payouts/v1/#referenced-payouts-items_get
*/
public function showReferencedPayoutItemDetails(string $payout_item_id)
{
$this->apiEndPoint = "v1/payments/referenced-payouts-items/{$payout_item_id}";
$this->verb = 'get';
return $this->doPayPalRequest();
}
}
@@ -0,0 +1,58 @@
<?php
namespace Srmklive\PayPal\Traits\PayPalAPI;
use Carbon\Carbon;
trait Reporting
{
/**
* List all transactions.
*
* @param array $filters
* @param string $fields
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/transaction-search/v1/#transactions_get
*/
public function listTransactions(array $filters, string $fields = 'all')
{
$filters_list = collect($filters)->isEmpty() ? '' :
collect($filters)->map(function ($value, $key) {
return "{$key}={$value}&";
})->implode('');
$this->apiEndPoint = "v1/reporting/transactions?{$filters_list}fields={$fields}&page={$this->current_page}&page_size={$this->page_size}";
$this->verb = 'get';
return $this->doPayPalRequest();
}
/**
* List available balance.
*
* @param string $date
* @param string $balance_currency
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/transaction-search/v1/#balances_get
*/
public function listBalances(string $date = '', string $balance_currency = '')
{
$date = empty($date) ? Carbon::now()->toIso8601ZuluString() : Carbon::parse($date)->toIso8601ZuluString();
$currency = empty($balance_currency) ? $this->getCurrency() : $balance_currency;
$this->apiEndPoint = "v1/reporting/balances?currency_code={$currency}&as_of_time={$date}";
$this->verb = 'get';
return $this->doPayPalRequest();
}
}
@@ -0,0 +1,231 @@
<?php
namespace Srmklive\PayPal\Traits\PayPalAPI;
use Carbon\Carbon;
trait Subscriptions
{
use Subscriptions\Helpers;
/**
* Create a new subscription.
*
* @param array $data
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/subscriptions/v1/#subscriptions_create
*/
public function createSubscription(array $data)
{
$this->apiEndPoint = 'v1/billing/subscriptions';
$this->options['json'] = $data;
$this->verb = 'post';
return $this->doPayPalRequest();
}
/**
* Update an existing billing plan.
*
* @param string $subscription_id
* @param array $data
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/subscriptions/v1/#subscriptions_patch
*/
public function updateSubscription(string $subscription_id, array $data)
{
$this->apiEndPoint = "v1/billing/subscriptions/{$subscription_id}";
$this->options['json'] = $data;
$this->verb = 'patch';
return $this->doPayPalRequest(false);
}
/**
* Show details for an existing subscription.
*
* @param string $subscription_id
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/subscriptions/v1/#subscriptions_get
*/
public function showSubscriptionDetails(string $subscription_id)
{
$this->apiEndPoint = "v1/billing/subscriptions/{$subscription_id}";
$this->verb = 'get';
return $this->doPayPalRequest();
}
/**
* Activate an existing subscription.
*
* @param string $subscription_id
* @param string $reason
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/subscriptions/v1/#subscriptions_activate
*/
public function activateSubscription(string $subscription_id, string $reason)
{
$this->apiEndPoint = "v1/billing/subscriptions/{$subscription_id}/activate";
$this->options['json'] = ['reason' => $reason];
$this->verb = 'post';
return $this->doPayPalRequest(false);
}
/**
* Cancel an existing subscription.
*
* @param string $subscription_id
* @param string $reason
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/subscriptions/v1/#subscriptions_cancel
*/
public function cancelSubscription(string $subscription_id, string $reason)
{
$this->apiEndPoint = "v1/billing/subscriptions/{$subscription_id}/cancel";
$this->options['json'] = ['reason' => $reason];
$this->verb = 'post';
return $this->doPayPalRequest(false);
}
/**
* Suspend an existing subscription.
*
* @param string $subscription_id
* @param string $reason
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/subscriptions/v1/#subscriptions_suspend
*/
public function suspendSubscription(string $subscription_id, string $reason)
{
$this->apiEndPoint = "v1/billing/subscriptions/{$subscription_id}/suspend";
$this->options['json'] = ['reason' => $reason];
$this->verb = 'post';
return $this->doPayPalRequest(false);
}
/**
* Capture payment for an existing subscription.
*
* @param string $subscription_id
* @param string $note
* @param float $amount
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/subscriptions/v1/#subscriptions_capture
*/
public function captureSubscriptionPayment(string $subscription_id, string $note, float $amount)
{
$this->apiEndPoint = "v1/billing/subscriptions/{$subscription_id}/capture";
$this->options['json'] = [
'note' => $note,
'capture_type' => 'OUTSTANDING_BALANCE',
'amount' => [
'currency_code' => $this->currency,
'value' => "{$amount}",
],
];
$this->verb = 'post';
return $this->doPayPalRequest(false);
}
/**
* Revise quantity, product or service for an existing subscription.
*
* @param string $subscription_id
* @param array $items
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/subscriptions/v1/#subscriptions_revise
*/
public function reviseSubscription(string $subscription_id, array $items)
{
$this->apiEndPoint = "v1/billing/subscriptions/{$subscription_id}/revise";
$this->options['json'] = $items;
$this->verb = 'post';
return $this->doPayPalRequest();
}
/**
* List transactions for an existing subscription.
*
* @param string $subscription_id
* @param \DateTimeInterface|string $start_date
* @param \DateTimeInterface|string $end_date
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/subscriptions/v1/#subscriptions_transactions
*/
public function listSubscriptionTransactions(string $subscription_id, $start_date = '', $end_date = '')
{
if (($start_date instanceof \DateTimeInterface) === false) {
$start_date = Carbon::parse($start_date);
}
if (($end_date instanceof \DateTimeInterface) === false) {
$end_date = Carbon::parse($end_date);
}
$start_date = $start_date->toIso8601ZuluString();
$end_date = $end_date->toIso8601ZuluString();
$this->apiEndPoint = "v1/billing/subscriptions/{$subscription_id}/transactions?start_time={$start_date}&end_time={$end_date}";
$this->verb = 'get';
return $this->doPayPalRequest();
}
}
@@ -0,0 +1,513 @@
<?php
namespace Srmklive\PayPal\Traits\PayPalAPI\Subscriptions;
use Carbon\Carbon;
use Illuminate\Support\Str;
use Throwable;
trait Helpers
{
/**
* @var array
*/
protected $trial_pricing = [];
/**
* @var int
*/
protected $payment_failure_threshold = 3;
/**
* @var array
*/
protected $product;
/**
* @var array
*/
protected $billing_plan;
/**
* @var array
*/
protected $shipping_address;
/**
* @var array
*/
protected $payment_preferences;
/**
* @var bool
*/
protected $has_setup_fee = false;
/**
* @var array
*/
protected $taxes;
/**
* @var string
*/
protected $custom_id;
/**
* Setup a subscription.
*
* @param string $customer_name
* @param string $customer_email
* @param string $start_date
*
* @throws Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*/
public function setupSubscription(string $customer_name, string $customer_email, string $start_date = '')
{
$body = [
'plan_id' => $this->billing_plan['id'],
'quantity' => 1,
'subscriber' => [
'name' => [
'given_name' => $customer_name,
],
'email_address' => $customer_email,
],
];
if (!empty($start_date)) {
$body['start_time'] = Carbon::parse($start_date)->toIso8601String();
}
if ($this->has_setup_fee) {
$body['plan'] = [
'payment_preferences' => $this->payment_preferences,
];
}
if (isset($this->shipping_address)) {
$body['subscriber']['shipping_address'] = $this->shipping_address;
}
if (isset($this->experience_context)) {
$body['application_context'] = $this->experience_context;
}
if (isset($this->taxes)) {
$body['taxes'] = $this->taxes;
}
if (isset($this->custom_id)) {
$body['custom_id'] = $this->custom_id;
}
$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);
unset($this->trial_pricing);
unset($this->return_url);
unset($this->cancel_url);
return $subscription;
}
/**
* Add a subscription trial pricing tier.
*
* @param string $interval_type
* @param int $interval_count
* @param float|int $price
* @param int $total_cycles
*
* @return \Srmklive\PayPal\Services\PayPal
*/
public function addPlanTrialPricing(string $interval_type, int $interval_count, float $price = 0, int $total_cycles = 1): \Srmklive\PayPal\Services\PayPal
{
$this->trial_pricing = $this->addPlanBillingCycle($interval_type, $interval_count, $price, $total_cycles, true);
return $this;
}
/**
* Create a recurring daily billing plan.
*
* @param string $name
* @param string $description
* @param float|int $price
* @param int $total_cycles
*
* @throws Throwable
*
* @return \Srmklive\PayPal\Services\PayPal
*/
public function addDailyPlan(string $name, string $description, float $price, int $total_cycles = 0): \Srmklive\PayPal\Services\PayPal
{
if (isset($this->billing_plan)) {
return $this;
}
$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);
return $this;
}
/**
* Create a recurring weekly billing plan.
*
* @param string $name
* @param string $description
* @param float|int $price
* @param int $total_cycles
*
* @throws Throwable
*
* @return \Srmklive\PayPal\Services\PayPal
*/
public function addWeeklyPlan(string $name, string $description, float $price, int $total_cycles = 0): \Srmklive\PayPal\Services\PayPal
{
if (isset($this->billing_plan)) {
return $this;
}
$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);
return $this;
}
/**
* Create a recurring monthly billing plan.
*
* @param string $name
* @param string $description
* @param float|int $price
* @param int $total_cycles
*
* @throws Throwable
*
* @return \Srmklive\PayPal\Services\PayPal
*/
public function addMonthlyPlan(string $name, string $description, float $price, int $total_cycles = 0): \Srmklive\PayPal\Services\PayPal
{
if (isset($this->billing_plan)) {
return $this;
}
$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);
return $this;
}
/**
* Create a recurring annual billing plan.
*
* @param string $name
* @param string $description
* @param float|int $price
* @param int $total_cycles
*
* @throws Throwable
*
* @return \Srmklive\PayPal\Services\PayPal
*/
public function addAnnualPlan(string $name, string $description, float $price, int $total_cycles = 0): \Srmklive\PayPal\Services\PayPal
{
if (isset($this->billing_plan)) {
return $this;
}
$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);
return $this;
}
/**
* Create a recurring billing plan with custom intervals.
*
* @param string $name
* @param string $description
* @param float|int $price
* @param string $interval_unit
* @param int $interval_count
* @param int $total_cycles
*
* @throws Throwable
*
* @return \Srmklive\PayPal\Services\PayPal
*/
public function addCustomPlan(string $name, string $description, float $price, string $interval_unit, int $interval_count, int $total_cycles = 0): \Srmklive\PayPal\Services\PayPal
{
$billing_intervals = ['DAY', 'WEEK', 'MONTH', 'YEAR'];
if (isset($this->billing_plan)) {
return $this;
}
if (!in_array($interval_unit, $billing_intervals)) {
throw new \RuntimeException('Billing intervals should either be '.implode(', ', $billing_intervals));
}
$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);
return $this;
}
/**
* Add Plan's Billing cycle.
*
* @param string $interval_unit
* @param int $interval_count
* @param float $price
* @param int $total_cycles
* @param bool $trial
*
* @return array
*/
protected function addPlanBillingCycle(string $interval_unit, int $interval_count, float $price, int $total_cycles, bool $trial = false): array
{
$pricing_scheme = [
'fixed_price' => [
'value' => bcdiv($price, 1, 2),
'currency_code' => $this->getCurrency(),
],
];
if (empty($this->trial_pricing)) {
$plan_sequence = 1;
} else {
$plan_sequence = 2;
}
return [
'frequency' => [
'interval_unit' => $interval_unit,
'interval_count' => $interval_count,
],
'tenure_type' => ($trial === true) ? 'TRIAL' : 'REGULAR',
'sequence' => ($trial === true) ? 1 : $plan_sequence,
'total_cycles' => $total_cycles,
'pricing_scheme' => $pricing_scheme,
];
}
/**
* Create a product for a subscription's billing plan.
*
* @param string $name
* @param string $description
* @param string $type
* @param string $category
*
* @throws Throwable
*
* @return \Srmklive\PayPal\Services\PayPal
*/
public function addProduct(string $name, string $description, string $type, string $category): \Srmklive\PayPal\Services\PayPal
{
if (isset($this->product)) {
return $this;
}
$request_id = Str::random();
$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;
}
/**
* Add subscription's billing plan's product by ID.
*
* @param string $product_id
*
* @return \Srmklive\PayPal\Services\PayPal
*/
public function addProductById(string $product_id): \Srmklive\PayPal\Services\PayPal
{
$this->product = [
'id' => $product_id,
];
return $this;
}
/**
* Add subscription's billing plan by ID.
*
* @param string $plan_id
*
* @return \Srmklive\PayPal\Services\PayPal
*/
public function addBillingPlanById(string $plan_id): \Srmklive\PayPal\Services\PayPal
{
$this->billing_plan = [
'id' => $plan_id,
];
return $this;
}
/**
* Create a product for a subscription's billing plan.
*
* @param string $name
* @param string $description
* @param array $billing_cycles
*
* @throws Throwable
*
* @return void
*/
protected function addBillingPlan(string $name, string $description, array $billing_cycles): void
{
$request_id = Str::random();
$plan_params = [
'product_id' => $this->product['id'],
'name' => $name,
'description' => $description,
'status' => 'ACTIVE',
'billing_cycles' => $billing_cycles,
'payment_preferences' => [
'auto_bill_outstanding' => true,
'setup_fee_failure_action' => 'CONTINUE',
'payment_failure_threshold' => $this->payment_failure_threshold,
],
];
$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;
}
/**
* Set custom failure threshold when adding a subscription.
*
* @param int $threshold
*
* @return \Srmklive\PayPal\Services\PayPal
*/
public function addPaymentFailureThreshold(int $threshold): \Srmklive\PayPal\Services\PayPal
{
$this->payment_failure_threshold = $threshold;
return $this;
}
/**
* Add setup fee when adding a subscription.
*
* @param float $price
*
* @return \Srmklive\PayPal\Services\PayPal
*/
public function addSetupFee(float $price): \Srmklive\PayPal\Services\PayPal
{
$this->has_setup_fee = true;
$this->payment_preferences = [
'auto_bill_outstanding' => true,
'setup_fee' => [
'value' => bcdiv($price, 1, 2),
'currency_code' => $this->getCurrency(),
],
'setup_fee_failure_action' => 'CONTINUE',
'payment_failure_threshold' => $this->payment_failure_threshold,
];
return $this;
}
/**
* Add shipping address.
*
* @param string $full_name
* @param string $address_line_1
* @param string $address_line_2
* @param string $admin_area_2
* @param string $admin_area_1
* @param string $postal_code
* @param string $country_code
*
* @return \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' => [
'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,
],
];
return $this;
}
/**
* Add taxes when creating a subscription.
*
* @param float $percentage
*
* @return \Srmklive\PayPal\Services\PayPal
*/
public function addTaxes(float $percentage)
{
$this->taxes = [
'percentage' => $percentage,
'inclusive' => false,
];
return $this;
}
/**
* Add custom id.
*
* @param string $custom_id
*
* @return \Srmklive\PayPal\Services\PayPal
*/
public function addCustomId(string $custom_id)
{
$this->custom_id = $custom_id;
return $this;
}
}
@@ -0,0 +1,114 @@
<?php
namespace Srmklive\PayPal\Traits\PayPalAPI;
trait Trackers
{
/**
* Adds tracking information, with or without tracking numbers, for multiple PayPal transactions.
*
* @param array $data
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/tracking/v1/#trackers-batch_post
*/
public function addBatchTracking(array $data)
{
$this->apiEndPoint = 'v1/shipping/trackers-batch';
$this->options['json'] = $data;
$this->verb = 'post';
return $this->doPayPalRequest();
}
/**
* Adds tracking information for a PayPal transaction.
*
* @param array $data
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/tracking/v1/#trackers_post
*/
public function addTracking(array $data)
{
$this->apiEndPoint = 'v1/shipping/trackers';
$this->options['json'] = $data;
$this->verb = 'post';
return $this->doPayPalRequest();
}
/**
* List tracking information based on Transaction ID or tracking number.
*
* @param string $transaction_id
* @param string $tracking_number
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/tracking/v1/#trackers-batch_get
*/
public function listTrackingDetails(string $transaction_id, string $tracking_number = null)
{
$this->apiEndPoint = "v1/shipping/trackers?transaction_id={$transaction_id}".!empty($tracking_number) ? "&tracking_number={$tracking_number}" : '';
$this->verb = 'get';
return $this->doPayPalRequest();
}
/**
* Update tracking information.
*
* @param string $tracking_id
* @param array $data
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/tracking/v1/#trackers_put
*/
public function updateTrackingDetails(string $tracking_id, array $data)
{
$this->apiEndPoint = "v1/shipping/trackers/{$tracking_id}";
$this->options['json'] = $data;
$this->verb = 'put';
return $this->doPayPalRequest(false);
}
/**
* Show tracking information.
*
* @param string $tracking_id
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/tracking/v1/#trackers_get
*/
public function showTrackingDetails(string $tracking_id)
{
$this->apiEndPoint = "v1/shipping/trackers/{$tracking_id}";
$this->verb = 'get';
return $this->doPayPalRequest();
}
}
@@ -0,0 +1,135 @@
<?php
namespace Srmklive\PayPal\Traits\PayPalAPI;
trait WebHooks
{
/**
* Create a new web hook.
*
* @param string $url
* @param array $events
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/webhooks/v1/#webhooks_post
*/
public function createWebHook(string $url, array $events)
{
$this->apiEndPoint = 'v1/notifications/webhooks';
$data = ['url' => $url];
$data['event_types'] = collect($events)->map(function ($item) {
return ['name' => $item];
})->toArray();
$this->options['json'] = $data;
$this->verb = 'post';
return $this->doPayPalRequest();
}
/**
* List all web hooks.
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/webhooks/v1/#webhooks_list
*/
public function listWebHooks()
{
$this->apiEndPoint = 'v1/notifications/webhooks';
$this->verb = 'get';
return $this->doPayPalRequest();
}
/**
* Delete a web hook.
*
* @param string $web_hook_id
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/webhooks/v1/#webhooks_delete
*/
public function deleteWebHook(string $web_hook_id)
{
$this->apiEndPoint = "v1/notifications/webhooks/{$web_hook_id}";
$this->verb = 'delete';
return $this->doPayPalRequest(false);
}
/**
* Update an existing web hook.
*
* @param string $web_hook_id
* @param array $data
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/webhooks/v1/#webhooks_update
*/
public function updateWebHook(string $web_hook_id, array $data)
{
$this->apiEndPoint = "v1/notifications/webhooks/{$web_hook_id}";
$this->options['json'] = $data;
$this->verb = 'patch';
return $this->doPayPalRequest();
}
/**
* Show details for an existing web hook.
*
* @param string $web_hook_id
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/webhooks/v1/#webhooks_get
*/
public function showWebHookDetails(string $web_hook_id)
{
$this->apiEndPoint = "v1/notifications/webhooks/{$web_hook_id}";
$this->verb = 'get';
return $this->doPayPalRequest();
}
/**
* List events for an existing web hook.
*
* @param string $web_hook_id
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/webhooks/v1/#webhooks_get
*/
public function listWebHookEvents($web_hook_id)
{
$this->apiEndPoint = "v1/notifications/webhooks/{$web_hook_id}/event-types";
$this->verb = 'get';
return $this->doPayPalRequest();
}
}
@@ -0,0 +1,86 @@
<?php
namespace Srmklive\PayPal\Traits\PayPalAPI;
trait WebHooksEvents
{
/**
* List all events types for web hooks.
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/webhooks/v1/#webhooks-event-types_list
*/
public function listEventTypes()
{
$this->apiEndPoint = 'v1/notifications/webhooks-event-types';
$this->verb = 'get';
return $this->doPayPalRequest();
}
/**
* List all events notifications for web hooks.
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/webhooks/v1/#webhooks-events_list
*/
public function listEvents()
{
$this->apiEndPoint = 'v1/notifications/webhooks-events';
$this->verb = 'get';
return $this->doPayPalRequest();
}
/**
* List all events notifications for web hooks.
*
* @param string $event_id
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/webhooks/v1/#webhooks-events_get
*/
public function showEventDetails(string $event_id)
{
$this->apiEndPoint = "v1/notifications/webhooks-events/{$event_id}";
$this->verb = 'get';
return $this->doPayPalRequest();
}
/**
* Resend notification for the event.
*
* @param string $event_id
* @param array $items
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/webhooks/v1/#webhooks-events_resend
*/
public function resendEventNotification(string $event_id, array $items)
{
$this->apiEndPoint = "v1/notifications/webhooks-events/{$event_id}/resend";
$this->options['json'] = [
'webhook_ids' => $items,
];
$this->verb = 'post';
return $this->doPayPalRequest();
}
}
@@ -0,0 +1,28 @@
<?php
namespace Srmklive\PayPal\Traits\PayPalAPI;
trait WebHooksVerification
{
/**
* Verify a web hook from PayPal.
*
* @param array $data
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/webhooks/v1/#verify-webhook-signature_post
*/
public function verifyWebHook(array $data)
{
$this->apiEndPoint = 'v1/notifications/verify-webhook-signature';
$this->options['json'] = $data;
$this->verb = 'post';
return $this->doPayPalRequest();
}
}
@@ -0,0 +1,81 @@
<?php
namespace Srmklive\PayPal\Traits;
trait PayPalExperienceContext
{
/**
* @var array
*/
protected $experience_context = [];
/**
* Set Brand Name when setting experience context for payment.
*
* @param string $brand
*
* @return \Srmklive\PayPal\Services\PayPal
*/
public function setBrandName(string $brand): \Srmklive\PayPal\Services\PayPal
{
$this->experience_context = array_merge($this->experience_context, [
'brand_name' => $brand,
]);
return $this;
}
/**
* Set return & cancel urls.
*
* @param string $return_url
* @param string $cancel_url
*
* @return \Srmklive\PayPal\Services\PayPal
*/
public function setReturnAndCancelUrl(string $return_url, string $cancel_url): \Srmklive\PayPal\Services\PayPal
{
$this->experience_context = array_merge($this->experience_context, [
'return_url' => $return_url,
'cancel_url' => $cancel_url,
]);
return $this;
}
/**
* Set stored payment source.
*
* @param string $initiator
* @param string $type
* @param string $usage
* @param bool $previous_reference
* @param string|null $previous_transaction_id
* @param string|null $previous_transaction_date
* @param string|null $previous_transaction_reference_number
* @param string|null $previous_transaction_network
*
* @return \Srmklive\PayPal\Services\PayPal
*/
public function setStoredPaymentSource(string $initiator, string $type, string $usage, bool $previous_reference = false, string $previous_transaction_id = null, string $previous_transaction_date = null, string $previous_transaction_reference_number = null, string $previous_transaction_network = null): \Srmklive\PayPal\Services\PayPal
{
$this->experience_context = array_merge($this->experience_context, [
'stored_payment_source' => [
'payment_initiator' => $initiator,
'payment_type' => $type,
'usage' => $usage,
],
]);
if ($previous_reference === true) {
$this->experience_context['stored_payment_source']['previous_network_transaction_reference'] = [
'id' => $previous_transaction_id,
'date' => $previous_transaction_date,
'acquirer_reference_number' => $previous_transaction_reference_number,
'network' => $previous_transaction_network,
];
}
return $this;
}
}
@@ -0,0 +1,222 @@
<?php
namespace Srmklive\PayPal\Traits;
use GuzzleHttp\Client as HttpClient;
use GuzzleHttp\Exception\ClientException as HttpClientException;
use GuzzleHttp\Utils;
use Psr\Http\Message\StreamInterface;
use RuntimeException;
use Srmklive\PayPal\Services\Str;
trait PayPalHttpClient
{
/**
* Http Client class object.
*
* @var HttpClient
*/
private $client;
/**
* Http Client configuration.
*
* @var array
*/
private $httpClientConfig;
/**
* PayPal API Endpoint.
*
* @var string
*/
private $apiUrl;
/**
* PayPal API Endpoint.
*
* @var string
*/
private $apiEndPoint;
/**
* IPN notification url for PayPal.
*
* @var string
*/
private $notifyUrl;
/**
* Http Client request body parameter name.
*
* @var string
*/
private $httpBodyParam;
/**
* Default payment action for PayPal.
*
* @var string
*/
private $paymentAction;
/**
* Default locale for PayPal.
*
* @var string
*/
private $locale;
/**
* Validate SSL details when creating HTTP client.
*
* @var bool
*/
private $validateSSL;
/**
* Request type.
*
* @var string
*/
protected $verb = 'post';
/**
* Set curl constants if not defined.
*
* @return void
*/
protected function setCurlConstants()
{
$constants = [
'CURLOPT_SSLVERSION' => 32,
'CURL_SSLVERSION_TLSv1_2' => 6,
'CURLOPT_SSL_VERIFYPEER' => 64,
'CURLOPT_SSLCERT' => 10025,
];
foreach ($constants as $key => $item) {
$this->defineCurlConstant($key, $item);
}
}
/**
* Declare a curl constant.
*
* @param string $key
* @param string $value
*
* @return bool
*/
protected function defineCurlConstant(string $key, string $value)
{
return defined($key) ? true : define($key, $value);
}
/**
* Function to initialize/override Http Client.
*
* @param \GuzzleHttp\Client|null $client
*
* @return void
*/
public function setClient(HttpClient $client = null)
{
if ($client instanceof HttpClient) {
$this->client = $client;
return;
}
$this->client = new HttpClient([
'curl' => $this->httpClientConfig,
]);
}
/**
* Function to set Http Client configuration.
*
* @return void
*/
protected function setHttpClientConfiguration()
{
$this->setCurlConstants();
$this->httpClientConfig = [
CURLOPT_SSLVERSION => CURL_SSLVERSION_TLSv1_2,
CURLOPT_SSL_VERIFYPEER => $this->validateSSL,
];
// Initialize Http Client
$this->setClient();
// Set default values.
$this->setDefaultValues();
// Set PayPal IPN Notification URL
$this->notifyUrl = $this->config['notify_url'];
}
/**
* Set default values for configuration.
*
* @return void
*/
private function setDefaultValues()
{
$paymentAction = empty($this->paymentAction) ? 'Sale' : $this->paymentAction;
$this->paymentAction = $paymentAction;
$locale = empty($this->locale) ? 'en_US' : $this->locale;
$this->locale = $locale;
$validateSSL = empty($this->validateSSL) ? true : $this->validateSSL;
$this->validateSSL = $validateSSL;
$this->showTotals(true);
}
/**
* Perform PayPal API request & return response.
*
* @throws \Throwable
*
* @return StreamInterface
*/
private function makeHttpRequest(): StreamInterface
{
try {
return $this->client->{$this->verb}(
$this->apiUrl,
$this->options
)->getBody();
} catch (HttpClientException $e) {
throw new RuntimeException($e->getResponse()->getBody());
}
}
/**
* Function To Perform PayPal API Request.
*
* @param bool $decode
*
* @throws \Throwable
*
* @return array|StreamInterface|string
*/
private function doPayPalRequest(bool $decode = true)
{
try {
$this->apiUrl = collect([$this->config['api_url'], $this->apiEndPoint])->implode('/');
// Perform PayPal HTTP API request.
$response = $this->makeHttpRequest();
return ($decode === false) ? $response->getContents() : Utils::jsonDecode($response, true);
} catch (RuntimeException $t) {
$error = ($decode === false) || (Str::isJson($t->getMessage()) === false) ? $t->getMessage() : Utils::jsonDecode($t->getMessage(), true);
return ['error' => $error];
}
}
}
@@ -0,0 +1,272 @@
<?php
namespace Srmklive\PayPal\Traits;
use RuntimeException;
trait PayPalRequest
{
use PayPalHttpClient;
use PayPalAPI;
use PayPalExperienceContext;
/**
* PayPal API mode to be used.
*
* @var string
*/
public $mode;
/**
* PayPal access token.
*
* @var string
*/
protected $access_token;
/**
* PayPal API configuration.
*
* @var array
*/
private $config;
/**
* Default currency for PayPal.
*
* @var string
*/
protected $currency;
/**
* Additional options for PayPal API request.
*
* @var array
*/
protected $options;
/**
* Set limit to total records per API call.
*
* @var int
*/
protected $page_size = 20;
/**
* Set the current page for list resources API calls.
*
* @var bool
*/
protected $current_page = 1;
/**
* Toggle whether totals for list resources are returned after every API call.
*
* @var string
*/
protected string $show_totals;
/**
* Set PayPal API Credentials.
*
* @param array $credentials
*
* @throws \RuntimeException|\Exception
*/
public function setApiCredentials(array $credentials): void
{
if (empty($credentials)) {
$this->throwConfigurationException();
}
// Setting Default PayPal Mode If not set
$this->setApiEnvironment($credentials);
// Set API configuration for the PayPal provider
$this->setApiProviderConfiguration($credentials);
// Set default currency.
$this->setCurrency($credentials['currency']);
// Set Http Client configuration.
$this->setHttpClientConfiguration();
}
/**
* Function to set currency.
*
* @param string $currency
*
* @throws \RuntimeException
*
* @return \Srmklive\PayPal\Services\PayPal
*/
public function setCurrency(string $currency = 'USD'): \Srmklive\PayPal\Services\PayPal
{
$allowedCurrencies = ['AUD', 'BRL', 'CAD', 'CZK', 'DKK', 'EUR', 'HKD', 'HUF', 'ILS', 'INR', 'JPY', 'MYR', 'MXN', 'NOK', 'NZD', 'PHP', 'PLN', 'GBP', 'SGD', 'SEK', 'CHF', 'TWD', 'THB', 'USD', 'RUB', 'CNY'];
// Check if provided currency is valid.
if (!in_array($currency, $allowedCurrencies, true)) {
throw new RuntimeException('Currency is not supported by PayPal.');
}
$this->currency = $currency;
return $this;
}
/**
* Return the set currency.
*/
public function getCurrency(): string
{
return $this->currency;
}
/**
* Function to add request header.
*
* @param string $key
* @param string $value
*
* @return \Srmklive\PayPal\Services\PayPal
*/
public function setRequestHeader(string $key, string $value): \Srmklive\PayPal\Services\PayPal
{
$this->options['headers'][$key] = $value;
return $this;
}
/**
* Function to add multiple request headers.
*
* @param array $headers
*
* @return \Srmklive\PayPal\Services\PayPal
*/
public function setRequestHeaders(array $headers): \Srmklive\PayPal\Services\PayPal
{
foreach ($headers as $key=>$value) {
$this->setRequestHeader($key, $value);
}
return $this;
}
/**
* Return request options header.
*
* @param string $key
*
* @throws \RuntimeException
*
* @return string
*/
public function getRequestHeader(string $key): string
{
if (isset($this->options['headers'][$key])) {
return $this->options['headers'][$key];
}
throw new RuntimeException('Options header is not set.');
}
/**
* Function To Set PayPal API Configuration.
*
* @param array $config
*
* @throws \Exception
*/
private function setConfig(array $config): void
{
$api_config = empty($config) && function_exists('config') && !empty(config('paypal')) ?
config('paypal') : $config;
// Set Api Credentials
$this->setApiCredentials($api_config);
}
/**
* Set API environment to be used by PayPal.
*
* @param array $credentials
*/
private function setApiEnvironment(array $credentials): void
{
$this->mode = 'live';
if (!empty($credentials['mode'])) {
$this->setValidApiEnvironment($credentials['mode']);
} else {
$this->throwConfigurationException();
}
}
/**
* Validate & set the environment to be used by PayPal.
*
* @param string $mode
*/
private function setValidApiEnvironment(string $mode): void
{
$this->mode = !in_array($mode, ['sandbox', 'live']) ? 'live' : $mode;
}
/**
* Set configuration details for the provider.
*
* @param array $credentials
*
* @throws \Exception
*/
private function setApiProviderConfiguration(array $credentials): void
{
// Setting PayPal API Credentials
if (empty($credentials[$this->mode])) {
$this->throwConfigurationException();
}
$config_params = ['client_id', 'client_secret'];
foreach ($config_params as $item) {
if (empty($credentials[$this->mode][$item])) {
throw new RuntimeException("{$item} missing from the provided configuration. Please add your application {$item}.");
}
}
collect($credentials[$this->mode])->map(function ($value, $key) {
$this->config[$key] = $value;
});
$this->paymentAction = $credentials['payment_action'];
$this->locale = $credentials['locale'];
$this->setRequestHeader('Accept-Language', $this->locale);
$this->validateSSL = $credentials['validate_ssl'];
$this->setOptions($credentials);
}
/**
* @throws RuntimeException
*/
private function throwConfigurationException()
{
throw new RuntimeException('Invalid configuration provided. Please provide valid configuration for PayPal API. You can also refer to the documentation at https://srmklive.github.io/laravel-paypal/docs.html to setup correct configuration.');
}
/**
* @throws RuntimeException
*/
private function throwInvalidEvidenceFileException()
{
throw new RuntimeException('Invalid evidence file type provided.
1. The party can upload up to 50 MB of files per request.
2. Individual files must be smaller than 10 MB.
3. The supported file formats are JPG, JPEG, GIF, PNG, and PDF.
');
}
}
@@ -0,0 +1,53 @@
<?php
namespace Srmklive\PayPal\Traits;
trait PayPalVerifyIPN
{
protected $webhook_id;
public function setWebHookID(string $webhook_id): \Srmklive\PayPal\Services\PayPal
{
$this->webhook_id = $webhook_id;
return $this;
}
/**
* Verify incoming IPN through a web hook id.
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*/
public function verifyIPN(\Illuminate\Http\Request $request)
{
$headers = array_change_key_case($request->headers->all(), CASE_UPPER);
if (!isset($headers['PAYPAL-AUTH-ALGO'][0]) ||
!isset($headers['PAYPAL-TRANSMISSION-ID'][0]) ||
!isset($headers['PAYPAL-CERT-URL'][0]) ||
!isset($headers['PAYPAL-TRANSMISSION-SIG'][0]) ||
!isset($headers['PAYPAL-TRANSMISSION-TIME'][0]) ||
!isset($this->webhook_id)
) {
\Log::error('Invalid headers or webhook id supplied for paypal webhook');
return ['error' => 'Invalid headers or webhook id provided'];
}
$params = json_decode($request->getContent());
$payload = [
'auth_algo' => $headers['PAYPAL-AUTH-ALGO'][0],
'cert_url' => $headers['PAYPAL-CERT-URL'][0],
'transmission_id' => $headers['PAYPAL-TRANSMISSION-ID'][0],
'transmission_sig' => $headers['PAYPAL-TRANSMISSION-SIG'][0],
'transmission_time' => $headers['PAYPAL-TRANSMISSION-TIME'][0],
'webhook_id' => $this->webhook_id,
'webhook_event' => $params,
];
return $this->verifyWebHook($payload);
}
}
@@ -0,0 +1,2 @@
[supervisord]
nodaemon=true
@@ -0,0 +1,81 @@
<?php
namespace Srmklive\PayPal\Tests\Feature;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase;
use Srmklive\PayPal\Services\PayPal as PayPalClient;
use Srmklive\PayPal\Tests\MockClientClasses;
use Srmklive\PayPal\Tests\MockResponsePayloads;
class AdapterBillingPlansPricingHelpersTest extends TestCase
{
use MockClientClasses;
use MockResponsePayloads;
/** @var string */
protected static string $access_token = '';
/** @var PayPalClient */
protected PayPalClient $client;
protected function setUp(): void
{
$this->client = new PayPalClient($this->getApiCredentials());
$this->client->setClient(
$this->mock_http_client(
$this->mockAccessTokenResponse()
)
);
$response = $this->client->getAccessToken();
self::$access_token = $response['access_token'];
parent::setUp();
}
#[Test]
public function it_can_update_pricing_schemes_for_a_billing_plan(): void
{
$this->client->setAccessToken([
'access_token' => self::$access_token,
'token_type' => 'Bearer',
]);
$this->client = $this->client->addBillingPlanById('P-5ML4271244454362WXNWU5NQ')
->addPricingScheme('DAY', 7, 0, true)
->addPricingScheme('MONTH', 1, 100);
$this->client->setClient(
$this->mock_http_client(false)
);
$response = $this->client->processBillingPlanPricingUpdates();
$this->assertEmpty($response);
}
#[Test]
public function it_can_set_custom_limits_when_listing_billing_plans(): void
{
$this->client->setAccessToken([
'access_token' => self::$access_token,
'token_type' => 'Bearer',
]);
$this->client = $this->client->setPageSize(30)
->showTotals(true);
$this->client->setClient(
$this->mock_http_client(
$this->mockListPlansResponse()
)
);
$response = $this->client->setCurrentPage(1)->listPlans();
$this->assertNotEmpty($response);
$this->assertArrayHasKey('plans', $response);
}
}
@@ -0,0 +1,142 @@
<?php
namespace Srmklive\PayPal\Tests\Feature;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase;
use Srmklive\PayPal\Services\PayPal as PayPalClient;
use Srmklive\PayPal\Tests\MockClientClasses;
class AdapterConfigTest extends TestCase
{
use MockClientClasses;
/** @var PayPalClient */
protected PayPalClient $client;
protected function setUp(): void
{
$this->client = new PayPalClient($this->getApiCredentials());
parent::setUp();
}
#[Test]
public function it_throws_exception_if_invalid_credentials_are_provided(): void
{
$this->expectException(\RuntimeException::class);
$this->expectExceptionMessage('Invalid configuration provided. Please provide valid configuration for PayPal API. You can also refer to the documentation at https://srmklive.github.io/laravel-paypal/docs.html to setup correct configuration.');
$this->client = new PayPalClient([]);
}
#[Test]
public function it_throws_exception_if_invalid_mode_is_provided(): void
{
$this->expectException(\RuntimeException::class);
$this->expectExceptionMessage('Invalid configuration provided. Please provide valid configuration for PayPal API. You can also refer to the documentation at https://srmklive.github.io/laravel-paypal/docs.html to setup correct configuration.');
$credentials = $this->getApiCredentials();
$credentials['mode'] = '';
$this->client = new PayPalClient($credentials);
}
#[Test]
public function it_throws_exception_if_empty_credentials_are_provided(): void
{
$this->expectException(\RuntimeException::class);
$this->expectExceptionMessage('Invalid configuration provided. Please provide valid configuration for PayPal API. You can also refer to the documentation at https://srmklive.github.io/laravel-paypal/docs.html to setup correct configuration.');
$credentials = $this->getApiCredentials();
$credentials['sandbox'] = [];
$this->client = new PayPalClient($credentials);
}
#[Test]
public function it_throws_exception_if_credentials_items_are_not_provided(): void
{
$item = 'client_id';
$this->expectException(\RuntimeException::class);
$this->expectExceptionMessage("{$item} missing from the provided configuration. Please add your application {$item}.");
$credentials = $this->getApiCredentials();
$credentials['sandbox'][$item] = '';
$client = new PayPalClient($credentials);
}
#[Test]
public function it_can_take_valid_credentials_and_return_the_client_instance(): void
{
$this->assertInstanceOf(PayPalClient::class, $this->client);
}
#[Test]
public function it_throws_exception_if_invalid_credentials_are_provided_through_method(): void
{
$this->expectException(\RuntimeException::class);
$this->client->setApiCredentials([]);
}
#[Test]
public function it_returns_the_client_instance_if_valid_credentials_are_provided_through_method(): void
{
$this->client->setApiCredentials($this->getApiCredentials());
$this->assertInstanceOf(PayPalClient::class, $this->client);
}
#[Test]
public function it_throws_exception_if_invalid_currency_is_set(): void
{
$this->expectException(\RuntimeException::class);
$this->client->setCurrency('PKR');
$this->assertNotEquals('PKR', $this->client->getCurrency());
}
#[Test]
public function it_can_set_a_valid_currency(): void
{
$this->client->setCurrency('EUR');
$this->assertNotEmpty($this->client->getCurrency());
$this->assertEquals('EUR', $this->client->getCurrency());
}
#[Test]
public function it_can_set_a_request_header(): void
{
$this->client->setRequestHeader('Prefer', 'return=representation');
$this->assertNotEmpty($this->client->getRequestHeader('Prefer'));
$this->assertEquals($this->client->getRequestHeader('Prefer'), 'return=representation');
}
#[Test]
public function it_can_set_multiple_request_headers(): void
{
$this->client->setRequestHeaders([
'PayPal-Request-Id' => 'some-request-id',
'PayPal-Partner-Attribution-Id' => 'some-attribution-id',
]);
$this->assertNotEmpty($this->client->getRequestHeader('PayPal-Request-Id'));
$this->assertEquals($this->client->getRequestHeader('PayPal-Partner-Attribution-Id'), 'some-attribution-id');
}
#[Test]
public function it_throws_exception_if_options_header_not_set(): void
{
$this->expectException(\RuntimeException::class);
$this->expectExceptionCode('0');
$this->expectExceptionMessage('Options header is not set.');
$this->client->getRequestHeader('Prefer');
}
}
@@ -0,0 +1,660 @@
<?php
namespace Srmklive\PayPal\Tests\Feature;
use Carbon\Carbon;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase;
use Srmklive\PayPal\Services\PayPal as PayPalClient;
use Srmklive\PayPal\Tests\MockClientClasses;
use Srmklive\PayPal\Tests\MockResponsePayloads;
class AdapterCreateSubscriptionHelpersTest extends TestCase
{
use MockClientClasses;
use MockResponsePayloads;
/** @var string */
protected static string $access_token = '';
/** @var PayPalClient */
protected PayPalClient $client;
protected function setUp(): void
{
$this->client = new PayPalClient($this->getApiCredentials());
$this->client->setClient(
$this->mock_http_client(
$this->mockAccessTokenResponse()
)
);
$response = $this->client->getAccessToken();
self::$access_token = $response['access_token'];
parent::setUp();
}
#[Test]
public function it_can_create_a_monthly_subscription(): void
{
$this->client->setAccessToken([
'access_token' => self::$access_token,
'token_type' => 'Bearer',
]);
$this->client->setClient(
$this->mock_http_client(
$this->mockCreateCatalogProductsResponse()
)
);
$start_date = Carbon::now()->addDay()->toDateString();
$this->client = $this->client->addProduct('Demo Product', 'Demo Product', 'SERVICE', 'SOFTWARE');
$this->client->setClient(
$this->mock_http_client(
$this->mockCreatePlansResponse()
)
);
$this->client = $this->client->addPlanTrialPricing('DAY', 7)
->addMonthlyPlan('Demo Plan', 'Demo Plan', 100);
$this->client->setClient(
$this->mock_http_client(
$this->mockCreateSubscriptionResponse()
)
);
$response = $this->client->setReturnAndCancelUrl('https://example.com/paypal-success', 'https://example.com/paypal-cancel')
->setupSubscription('John Doe', 'john@example.com', $start_date);
$this->assertNotEmpty($response);
$this->assertArrayHasKey('id', $response);
$this->assertArrayHasKey('plan_id', $response);
}
#[Test]
public function it_can_create_a_daily_subscription(): void
{
$this->client->setAccessToken([
'access_token' => self::$access_token,
'token_type' => 'Bearer',
]);
$this->client->setClient(
$this->mock_http_client(
$this->mockCreateCatalogProductsResponse()
)
);
$start_date = Carbon::now()->addDay()->toDateString();
$this->client = $this->client->addProduct('Demo Product', 'Demo Product', 'SERVICE', 'SOFTWARE');
$this->client->setClient(
$this->mock_http_client(
$this->mockCreatePlansResponse()
)
);
$this->client = $this->client->addPlanTrialPricing('DAY', 7)
->addDailyPlan('Demo Plan', 'Demo Plan', 1.50);
$this->client->setClient(
$this->mock_http_client(
$this->mockCreateSubscriptionResponse()
)
);
$response = $this->client->setReturnAndCancelUrl('https://example.com/paypal-success', 'https://example.com/paypal-cancel')
->setupSubscription('John Doe', 'john@example.com', $start_date);
$this->assertNotEmpty($response);
$this->assertArrayHasKey('id', $response);
$this->assertArrayHasKey('plan_id', $response);
}
#[Test]
public function it_can_create_a_weekly_subscription(): void
{
$this->client->setAccessToken([
'access_token' => self::$access_token,
'token_type' => 'Bearer',
]);
$this->client->setClient(
$this->mock_http_client(
$this->mockCreateCatalogProductsResponse()
)
);
$start_date = Carbon::now()->addDay()->toDateString();
$this->client = $this->client->addProduct('Demo Product', 'Demo Product', 'SERVICE', 'SOFTWARE');
$this->client->setClient(
$this->mock_http_client(
$this->mockCreatePlansResponse()
)
);
$this->client = $this->client->addPlanTrialPricing('DAY', 7)
->addWeeklyPlan('Demo Plan', 'Demo Plan', 50);
$this->client->setClient(
$this->mock_http_client(
$this->mockCreateSubscriptionResponse()
)
);
$response = $this->client->setReturnAndCancelUrl('https://example.com/paypal-success', 'https://example.com/paypal-cancel')
->setupSubscription('John Doe', 'john@example.com', $start_date);
$this->assertNotEmpty($response);
$this->assertArrayHasKey('id', $response);
$this->assertArrayHasKey('plan_id', $response);
}
#[Test]
public function it_can_create_an_annual_subscription(): void
{
$this->client->setAccessToken([
'access_token' => self::$access_token,
'token_type' => 'Bearer',
]);
$this->client->setClient(
$this->mock_http_client(
$this->mockCreateCatalogProductsResponse()
)
);
$start_date = Carbon::now()->addDay()->toDateString();
$this->client = $this->client->addProduct('Demo Product', 'Demo Product', 'SERVICE', 'SOFTWARE');
$this->client->setClient(
$this->mock_http_client(
$this->mockCreatePlansResponse()
)
);
$this->client = $this->client->addPlanTrialPricing('DAY', 7)
->addAnnualPlan('Demo Plan', 'Demo Plan', 100);
$this->client->setClient(
$this->mock_http_client(
$this->mockCreateSubscriptionResponse()
)
);
$response = $this->client->setReturnAndCancelUrl('https://example.com/paypal-success', 'https://example.com/paypal-cancel')
->setupSubscription('John Doe', 'john@example.com', $start_date);
$this->assertNotEmpty($response);
$this->assertArrayHasKey('id', $response);
$this->assertArrayHasKey('plan_id', $response);
}
#[Test]
public function it_can_create_a_subscription_with_custom_defined_interval(): void
{
$this->client->setAccessToken([
'access_token' => self::$access_token,
'token_type' => 'Bearer',
]);
$this->client->setClient(
$this->mock_http_client(
$this->mockCreateCatalogProductsResponse()
)
);
$start_date = Carbon::now()->addDay()->toDateString();
$this->client = $this->client->addProduct('Demo Product', 'Demo Product', 'SERVICE', 'SOFTWARE');
$this->client->setClient(
$this->mock_http_client(
$this->mockCreatePlansResponse()
)
);
$this->client = $this->client->addPlanTrialPricing('DAY', 7)
->addCustomPlan('Demo Plan', 'Demo Plan', 100, 'MONTH', 3);
$this->client->setClient(
$this->mock_http_client(
$this->mockCreateSubscriptionResponse()
)
);
$response = $this->client->setReturnAndCancelUrl('https://example.com/paypal-success', 'https://example.com/paypal-cancel')
->setupSubscription('John Doe', 'john@example.com', $start_date);
$this->assertNotEmpty($response);
$this->assertArrayHasKey('id', $response);
$this->assertArrayHasKey('plan_id', $response);
}
#[Test]
public function it_throws_exception_when_invalid_interval_is_provided_for_creating_a_subscription(): void
{
$this->client->setAccessToken([
'access_token' => self::$access_token,
'token_type' => 'Bearer',
]);
$this->client = $this->client->addProductById('PROD-XYAB12ABSB7868434');
$this->expectException(\RuntimeException::class);
$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(): void
{
$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(): void
{
$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(): void
{
$this->client->setAccessToken([
'access_token' => self::$access_token,
'token_type' => 'Bearer',
]);
$this->client->setClient(
$this->mock_http_client(
$this->mockCreateCatalogProductsResponse()
)
);
$start_date = Carbon::now()->addDay()->toDateString();
$this->client = $this->client->addProduct('Demo Product', 'Demo Product', 'SERVICE', 'SOFTWARE');
$this->client->setClient(
$this->mock_http_client(
$this->mockCreatePlansResponse()
)
);
$this->client = $this->client->addMonthlyPlan('Demo Plan', 'Demo Plan', 100);
$this->client->setClient(
$this->mock_http_client(
$this->mockCreateSubscriptionResponse()
)
);
$response = $this->client->setupSubscription('John Doe', 'john@example.com', $start_date);
$this->assertNotEmpty($response);
$this->assertArrayHasKey('id', $response);
$this->assertArrayHasKey('plan_id', $response);
}
#[Test]
public function it_can_create_a_subscription_by_existing_product_and_billing_plan(): void
{
$this->client->setAccessToken([
'access_token' => self::$access_token,
'token_type' => 'Bearer',
]);
$start_date = Carbon::now()->addDay()->toDateString();
$this->client->setClient(
$this->mock_http_client(
$this->mockCreateSubscriptionResponse()
)
);
$response = $this->client->addProductById('PROD-XYAB12ABSB7868434')
->addBillingPlanById('P-5ML4271244454362WXNWU5NQ')
->setupSubscription('John Doe', 'john@example.com', $start_date);
$this->assertNotEmpty($response);
$this->assertArrayHasKey('id', $response);
$this->assertArrayHasKey('plan_id', $response);
}
#[Test]
public function it_skips_product_and_billing_plan_creation_if_already_set_when_creating_a_daily_subscription(): void
{
$this->client->setAccessToken([
'access_token' => self::$access_token,
'token_type' => 'Bearer',
]);
$start_date = Carbon::now()->addDay()->toDateString();
$this->client = $this->client->addProductById('PROD-XYAB12ABSB7868434')
->addBillingPlanById('P-5ML4271244454362WXNWU5NQ')
->addProduct('Demo Product', 'Demo Product', 'SERVICE', 'SOFTWARE')
->addDailyPlan('Demo Plan', 'Demo Plan', 1.50);
$this->client->setClient(
$this->mock_http_client(
$this->mockCreateSubscriptionResponse()
)
);
$response = $this->client->setupSubscription('John Doe', 'john@example.com', $start_date);
$this->assertNotEmpty($response);
$this->assertArrayHasKey('id', $response);
$this->assertArrayHasKey('plan_id', $response);
}
#[Test]
public function it_skips_product_and_billing_plan_creation_if_already_set_when_creating_a_weekly_subscription(): void
{
$this->client->setAccessToken([
'access_token' => self::$access_token,
'token_type' => 'Bearer',
]);
$start_date = Carbon::now()->addDay()->toDateString();
$this->client = $this->client->addProductById('PROD-XYAB12ABSB7868434')
->addBillingPlanById('P-5ML4271244454362WXNWU5NQ')
->addProduct('Demo Product', 'Demo Product', 'SERVICE', 'SOFTWARE')
->addWeeklyPlan('Demo Plan', 'Demo Plan', 100);
$this->client->setClient(
$this->mock_http_client(
$this->mockCreateSubscriptionResponse()
)
);
$response = $this->client->setupSubscription('John Doe', 'john@example.com', $start_date);
$this->assertNotEmpty($response);
$this->assertArrayHasKey('id', $response);
$this->assertArrayHasKey('plan_id', $response);
}
#[Test]
public function it_skips_product_and_billing_plan_creation_if_already_set_when_creating_a_monthly_subscription(): void
{
$this->client->setAccessToken([
'access_token' => self::$access_token,
'token_type' => 'Bearer',
]);
$start_date = Carbon::now()->addDay()->toDateString();
$this->client = $this->client->addProductById('PROD-XYAB12ABSB7868434')
->addBillingPlanById('P-5ML4271244454362WXNWU5NQ')
->addProduct('Demo Product', 'Demo Product', 'SERVICE', 'SOFTWARE')
->addMonthlyPlan('Demo Plan', 'Demo Plan', 100);
$this->client->setClient(
$this->mock_http_client(
$this->mockCreateSubscriptionResponse()
)
);
$response = $this->client->setupSubscription('John Doe', 'john@example.com', $start_date);
$this->assertNotEmpty($response);
$this->assertArrayHasKey('id', $response);
$this->assertArrayHasKey('plan_id', $response);
}
#[Test]
public function it_skips_product_and_billing_plan_creation_if_already_set_when_creating_an_annual_subscription(): void
{
$this->client->setAccessToken([
'access_token' => self::$access_token,
'token_type' => 'Bearer',
]);
$start_date = Carbon::now()->addDay()->toDateString();
$this->client = $this->client->addProductById('PROD-XYAB12ABSB7868434')
->addBillingPlanById('P-5ML4271244454362WXNWU5NQ')
->addProduct('Demo Product', 'Demo Product', 'SERVICE', 'SOFTWARE')
->addAnnualPlan('Demo Plan', 'Demo Plan', 100);
$this->client->setClient(
$this->mock_http_client(
$this->mockCreateSubscriptionResponse()
)
);
$response = $this->client->setupSubscription('John Doe', 'john@example.com', $start_date);
$this->assertNotEmpty($response);
$this->assertArrayHasKey('id', $response);
$this->assertArrayHasKey('plan_id', $response);
}
#[Test]
public function it_skips_product_and_billing_plan_creation_if_already_set_when_creating_a_subscription_with_custom_intervals(): void
{
$this->client->setAccessToken([
'access_token' => self::$access_token,
'token_type' => 'Bearer',
]);
$start_date = Carbon::now()->addDay()->toDateString();
$this->client = $this->client->addProductById('PROD-XYAB12ABSB7868434')
->addBillingPlanById('P-5ML4271244454362WXNWU5NQ')
->addProduct('Demo Product', 'Demo Product', 'SERVICE', 'SOFTWARE')
->addCustomPlan('Demo Plan', 'Demo Plan', 100, 'MONTH', 3);
$this->client->setClient(
$this->mock_http_client(
$this->mockCreateSubscriptionResponse()
)
);
$response = $this->client->setupSubscription('John Doe', 'john@example.com', $start_date);
$this->assertNotEmpty($response);
$this->assertArrayHasKey('id', $response);
$this->assertArrayHasKey('plan_id', $response);
}
#[Test]
public function it_can_add_setup_fees_when_creating_subscription(): void
{
$this->client->setAccessToken([
'access_token' => self::$access_token,
'token_type' => 'Bearer',
]);
$start_date = Carbon::now()->addDay()->toDateString();
$setup_fee = 9.99;
$this->client = $this->client->addSetupFee($setup_fee)
->addProductById('PROD-XYAB12ABSB7868434')
->addBillingPlanById('P-5ML4271244454362WXNWU5NQ');
$this->client->setClient(
$this->mock_http_client(
$this->mockCreateSubscriptionResponse()
)
);
$response = $this->client->setupSubscription('John Doe', 'john@example.com', $start_date);
$this->assertNotEmpty($response);
$this->assertArrayHasKey('id', $response);
$this->assertArrayHasKey('plan_id', $response);
}
#[Test]
public function it_can_add_shipping_address_when_creating_subscription(): void
{
$this->client->setAccessToken([
'access_token' => self::$access_token,
'token_type' => 'Bearer',
]);
$start_date = Carbon::now()->addDay()->toDateString();
$this->client = $this->client->addShippingAddress('John Doe', 'House no. 123', 'Street 456', 'Test Area', 'Test Area', 10001, 'US')
->addProductById('PROD-XYAB12ABSB7868434')
->addBillingPlanById('P-5ML4271244454362WXNWU5NQ');
$this->client->setClient(
$this->mock_http_client(
$this->mockCreateSubscriptionResponse()
)
);
$response = $this->client->setupSubscription('John Doe', 'john@example.com', $start_date);
$this->assertNotEmpty($response);
$this->assertArrayHasKey('id', $response);
$this->assertArrayHasKey('plan_id', $response);
}
#[Test]
public function it_can_add_custom_payment_failure_threshold_value_when_creating_subscription(): void
{
$this->client->setAccessToken([
'access_token' => self::$access_token,
'token_type' => 'Bearer',
]);
$start_date = Carbon::now()->addDay()->toDateString();
$threshold = 5;
$this->client = $this->client->addPaymentFailureThreshold($threshold)
->addProductById('PROD-XYAB12ABSB7868434')
->addBillingPlanById('P-5ML4271244454362WXNWU5NQ');
$this->client->setClient(
$this->mock_http_client(
$this->mockCreateSubscriptionResponse()
)
);
$response = $this->client->setupSubscription('John Doe', 'john@example.com', $start_date);
$this->assertNotEmpty($response);
$this->assertArrayHasKey('id', $response);
$this->assertArrayHasKey('plan_id', $response);
}
#[Test]
public function it_can_set_tax_percentage_when_creating_subscription(): void
{
$this->client->setAccessToken([
'access_token' => self::$access_token,
'token_type' => 'Bearer',
]);
$start_date = Carbon::now()->addDay()->toDateString();
$percentage = 10;
$this->client = $this->client->addTaxes($percentage)
->addProductById('PROD-XYAB12ABSB7868434')
->addBillingPlanById('P-5ML4271244454362WXNWU5NQ');
$this->client->setClient(
$this->mock_http_client(
$this->mockCreateSubscriptionResponse()
)
);
$response = $this->client->setupSubscription('John Doe', 'john@example.com', $start_date);
$this->assertNotEmpty($response);
$this->assertArrayHasKey('id', $response);
$this->assertArrayHasKey('plan_id', $response);
}
#[Test]
public function it_can_create_a_subscription_with_fixed_installments(): void
{
$this->client->setAccessToken([
'access_token' => self::$access_token,
'token_type' => 'Bearer',
]);
$this->client->setClient(
$this->mock_http_client(
$this->mockCreateCatalogProductsResponse()
)
);
$start_date = Carbon::now()->addDay()->toDateString();
$this->client = $this->client->addProduct('Demo Product', 'Demo Product', 'SERVICE', 'SOFTWARE');
$this->client->setClient(
$this->mock_http_client(
$this->mockCreatePlansResponse()
)
);
$this->client = $this->client->addPlanTrialPricing('DAY', 7)
->addMonthlyPlan('Demo Plan', 'Demo Plan', 100, 12);
$this->client->setClient(
$this->mock_http_client(
$this->mockCreateSubscriptionResponse()
)
);
$response = $this->client->setReturnAndCancelUrl('https://example.com/paypal-success', 'https://example.com/paypal-cancel')
->setupSubscription('John Doe', 'john@example.com', $start_date);
$this->assertNotEmpty($response);
$this->assertArrayHasKey('id', $response);
$this->assertArrayHasKey('plan_id', $response);
}
}
@@ -0,0 +1,70 @@
<?php
namespace Feature;
namespace Srmklive\PayPal\Tests\Feature;
use Carbon\Carbon;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase;
use Srmklive\PayPal\Services\PayPal as PayPalClient;
use Srmklive\PayPal\Tests\MockClientClasses;
use Srmklive\PayPal\Tests\MockRequestPayloads;
use Srmklive\PayPal\Tests\MockResponsePayloads;
class AdapterExperienceContextTest extends TestCase
{
use MockClientClasses;
use MockRequestPayloads;
use MockResponsePayloads;
/** @var string */
protected static string $access_token = '';
/** @var PayPalClient */
protected PayPalClient $client;
protected function setUp(): void
{
$this->client = new PayPalClient($this->getApiCredentials());
$this->client->setClient(
$this->mock_http_client(
$this->mockAccessTokenResponse()
)
);
$response = $this->client->getAccessToken();
self::$access_token = $response['access_token'];
parent::setUp();
}
#[Test]
public function it_can_set_payment_experience_context_before_performing_api_call(): void
{
$this->client->setAccessToken([
'access_token' => self::$access_token,
'token_type' => 'Bearer',
]);
$start_date = Carbon::now()->addDay()->toDateString();
$this->client = $this->client->setReturnAndCancelUrl('https://example.com/paypal-success', 'https://example.com/paypal-cancel')
->setBrandName('Test Brand')
->addProductById('PROD-XYAB12ABSB7868434')
->addBillingPlanById('P-5ML4271244454362WXNWU5NQ');
$this->client->setClient(
$this->mock_http_client(
$this->mockCreateSubscriptionResponse()
)
);
$response = $this->client->setupSubscription('John Doe', 'john@example.com', $start_date);
$this->assertNotEmpty($response);
$this->assertArrayHasKey('id', $response);
$this->assertArrayHasKey('plan_id', $response);
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,75 @@
<?php
namespace Srmklive\PayPal\Tests\Feature;
use Carbon\Carbon;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase;
use Srmklive\PayPal\Services\PayPal as PayPalClient;
use Srmklive\PayPal\Tests\MockClientClasses;
use Srmklive\PayPal\Tests\MockRequestPayloads;
use Srmklive\PayPal\Tests\MockResponsePayloads;
class AdapterOrdersHelperTest extends TestCase
{
use MockClientClasses;
use MockRequestPayloads;
use MockResponsePayloads;
/** @var string */
protected static string $access_token = '';
/** @var PayPalClient */
protected PayPalClient $client;
protected function setUp(): void
{
$this->client = new PayPalClient($this->getApiCredentials());
$this->client->setClient(
$this->mock_http_client(
$this->mockAccessTokenResponse()
)
);
$response = $this->client->getAccessToken();
self::$access_token = $response['access_token'];
parent::setUp();
}
#[Test]
public function it_can_confirm_payment_for_an_order(): void
{
$this->client->setAccessToken([
'access_token' => self::$access_token,
'token_type' => 'Bearer',
]);
$start_date = Carbon::now()->subDays(10)->toDateString();
$this->client = $this->client->setReturnAndCancelUrl('https://example.com/paypal-success', 'https://example.com/paypal-cancel')
->setBrandName('Test Brand')
->setStoredPaymentSource(
'MERCHANT',
'RECURRING',
'SUBSEQUENT',
true,
'5TY05013RG002845M',
$start_date,
'Invoice-005',
'VISA'
);
$this->client->setClient(
$this->mock_http_client(
$this->mockConfirmOrderResponse()
)
);
$response = $this->client->setupOrderConfirmation('5O190127TN364715T', 'ORDER_COMPLETE_ON_PAYMENT_APPROVAL');
$this->assertNotEmpty($response);
$this->assertArrayHasKey('id', $response);
}
}
@@ -0,0 +1,154 @@
<?php
namespace Srmklive\PayPal\Tests\Feature;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase;
use Srmklive\PayPal\Services\PayPal as PayPalClient;
use Srmklive\PayPal\Tests\MockClientClasses;
use Srmklive\PayPal\Tests\MockRequestPayloads;
use Srmklive\PayPal\Tests\MockResponsePayloads;
class AdapterPaymentMethodTokensHelpersTest extends TestCase
{
use MockClientClasses;
use MockRequestPayloads;
use MockResponsePayloads;
/** @var string */
protected static string $access_token = '';
/** @var PayPalClient */
protected PayPalClient $client;
protected function setUp(): void
{
$this->client = new PayPalClient($this->getApiCredentials());
$this->client->setClient(
$this->mock_http_client(
$this->mockAccessTokenResponse()
)
);
$response = $this->client->getAccessToken();
self::$access_token = $response['access_token'];
parent::setUp();
}
#[Test]
public function it_can_create_payment_token_from_a_vault_token(): void
{
$this->client->setAccessToken([
'access_token' => self::$access_token,
'token_type' => 'Bearer',
]);
$this->client->setClient(
$this->mock_http_client(
$this->mockCreatePaymentMethodsTokenResponse()
)
);
$this->client = $this->client->setTokenSource('5C991763VB2781612', 'SETUP_TOKEN')
->setCustomerSource('customer_4029352050');
$response = $this->client->sendPaymentMethodRequest();
$this->assertArrayHasKey('id', $response);
$this->assertArrayHasKey('customer', $response);
}
#[Test]
public function it_can_create_payment_source_from_a_vault_token(): void
{
$this->client->setAccessToken([
'access_token' => self::$access_token,
'token_type' => 'Bearer',
]);
$this->client->setClient(
$this->mock_http_client(
$this->mockCreatePaymentSetupTokenResponse()
)
);
$this->client = $this->client->setTokenSource('5C991763VB2781612', 'SETUP_TOKEN')
->setCustomerSource('customer_4029352050');
$response = $this->client->sendPaymentMethodRequest(true);
$this->assertArrayHasKey('payment_source', $response);
}
#[Test]
public function it_can_create_payment_source_from_a_credit_card(): void
{
$this->client->setAccessToken([
'access_token' => self::$access_token,
'token_type' => 'Bearer',
]);
$this->client->setClient(
$this->mock_http_client(
$this->mockCreatePaymentSetupTokenResponse()
)
);
$this->client = $this->client->setPaymentSourceCard($this->mockCreatePaymentSetupTokensParams()['payment_source']['card'])
->setCustomerSource('customer_4029352050');
$response = $this->client->sendPaymentMethodRequest(true);
$this->assertArrayHasKey('payment_source', $response);
}
#[Test]
public function it_can_create_payment_source_from_a_paypal_account(): void
{
$this->client->setAccessToken([
'access_token' => self::$access_token,
'token_type' => 'Bearer',
]);
$response_data = $this->mockCreatePaymentSetupTokenResponse();
$response_data['payment_source']['paypal'] = $this->mockCreatePaymentSetupPayPalParams()['payment_source']['paypal'];
unset($response_data['payment_source']['card']);
$this->client->setClient(
$this->mock_http_client($response_data)
);
$this->client = $this->client->setPaymentSourcePayPal($this->mockCreatePaymentSetupPayPalParams()['payment_source']['paypal'])
->setCustomerSource('customer_4029352050');
$response = $this->client->sendPaymentMethodRequest(true);
$this->assertArrayHasKey('payment_source', $response);
}
#[Test]
public function it_can_create_payment_source_from_a_venmo_account(): void
{
$this->client->setAccessToken([
'access_token' => self::$access_token,
'token_type' => 'Bearer',
]);
$response_data = $this->mockCreatePaymentSetupTokenResponse();
$response_data['payment_source']['venmo'] = $this->mockCreatePaymentSetupPayPalParams()['payment_source']['paypal'];
unset($response_data['payment_source']['card']);
$this->client->setClient(
$this->mock_http_client($response_data)
);
$this->client = $this->client->setPaymentSourceVenmo($this->mockCreatePaymentSetupPayPalParams()['payment_source']['paypal'])
->setCustomerSource('customer_4029352050');
$response = $this->client->sendPaymentMethodRequest(true);
$this->assertArrayHasKey('payment_source', $response);
}
}
@@ -0,0 +1,130 @@
<?php
namespace Srmklive\PayPal\Tests;
use GuzzleHttp\Client as HttpClient;
use GuzzleHttp\Handler\MockHandler as HttpMockHandler;
use GuzzleHttp\HandlerStack as HttpHandlerStack;
use GuzzleHttp\Psr7\Response as HttpResponse;
use GuzzleHttp\Psr7\Stream as HttpStream;
use GuzzleHttp\Utils;
use Psr\Http\Message\ResponseInterface;
use Srmklive\PayPal\Services\PayPal as PayPalClient;
trait MockClientClasses
{
private function mock_http_client($response): HttpClient
{
$mock = new HttpMockHandler([
new HttpResponse(
200,
[],
($response === false) ? '' : Utils::jsonEncode($response)
),
]);
$handler = HttpHandlerStack::create($mock);
return new HttpClient(['handler' => $handler]);
}
private function mock_http_request($expectedResponse, $expectedEndpoint, $expectedParams, $expectedMethod = 'post')
{
$set_method_name = ($this->setMethodsFunction() === true) ? 'onlyMethods' : 'setMethods';
$mockResponse = $this->getMockBuilder(ResponseInterface::class)
->getMock();
$mockResponse->expects($this->exactly(1))
->method('getBody')
->willReturn(new HttpStream(fopen('data://text/plain,'.$expectedResponse, 'r')));
$mockHttpClient = $this->getMockBuilder(HttpClient::class)
->{$set_method_name}([$expectedMethod])
->getMock();
$mockHttpClient->expects($this->once())
->method($expectedMethod)
->with($expectedEndpoint, $expectedParams)
->willReturn($mockResponse);
return $mockHttpClient;
}
private function mock_client($expectedResponse, $expectedMethod, $token = false, $additionalMethod = null)
{
$set_method_name = ($this->setMethodsFunction() === true) ? 'onlyMethods' : 'setMethods';
$methods = [$expectedMethod, 'setApiCredentials'];
$methods[] = ($token) ? 'getAccessToken' : '';
$methods[] = isset($additionalMethod) ? $additionalMethod : '';
$mockClient = $this->getMockBuilder(PayPalClient::class)
->{$set_method_name}(array_filter($methods))
->getMock();
if ($token) {
$mockClient->expects($this->exactly(1))
->method('getAccessToken');
}
if (isset($additionalMethod)) {
$mockClient->expects($this->any())
->method($additionalMethod);
}
$mockClient->expects($this->exactly(1))
->method('setApiCredentials');
$mockClient->expects($this->exactly(1))
->method($expectedMethod)
->willReturn($expectedResponse);
return $mockClient;
}
private function getMockCredentials(): array
{
return [
'mode' => 'sandbox',
'sandbox' => [
'client_id' => 'some-client-id',
'client_secret' => 'some-access-token',
'app_id' => 'some-app-id',
],
'payment_action' => 'Sale',
'currency' => 'USD',
'notify_url' => '',
'locale' => 'en_US',
'validate_ssl' => true,
];
}
private function getApiCredentials(): array
{
return [
'mode' => 'sandbox',
'sandbox' => [
'client_id' => 'AbJgVQM6g57qPrXimGkBz1UaBOXn1dKLSdUj7BgiB3JhzJRCapzCnkPq6ycOOmgXHtnDZcjwLMJ2IdAI',
'client_secret' => 'EPd_XBNkfhU3-MlSw6gpa6EJj9x8QBdsC3o77jZZWjcFy_hrjR4kzBP8QN3MPPH4g52U_acG4-ogWUxI',
'app_id' => 'APP-80W284485P519543T',
],
'payment_action' => 'Sale',
'currency' => 'USD',
'notify_url' => '',
'locale' => 'en_US',
'validate_ssl' => true,
];
}
protected function setMethodsFunction(): bool
{
$useOnlyMethods = false;
foreach (['8.1', '8.2', '8.3'] as $php_version) {
if (strpos(phpversion(), $php_version) !== false) {
$useOnlyMethods = true;
}
}
return $useOnlyMethods;
}
}
@@ -0,0 +1,26 @@
<?php
namespace Srmklive\PayPal\Tests;
trait MockRequestPayloads
{
use Mocks\Requests\BillingPlans;
use Mocks\Requests\CatalogProducts;
use Mocks\Requests\Disputes;
use Mocks\Requests\DisputesActions;
use Mocks\Requests\Identity;
use Mocks\Requests\Invoices;
use Mocks\Requests\InvoicesSearch;
use Mocks\Requests\InvoicesTemplates;
use Mocks\Requests\Orders;
use Mocks\Requests\PartnerReferrals;
use Mocks\Requests\PaymentExperienceWebProfiles;
use Mocks\Requests\PaymentMethodsTokens;
use Mocks\Requests\PaymentAuthorizations;
use Mocks\Requests\PaymentCaptures;
use Mocks\Requests\Payouts;
use Mocks\Requests\ReferencedPayouts;
use Mocks\Requests\Subscriptions;
use Mocks\Requests\Trackers;
use Mocks\Requests\WebHooks;
}
@@ -0,0 +1,43 @@
<?php
namespace Srmklive\PayPal\Tests;
trait MockResponsePayloads
{
use Mocks\Responses\BillingPlans;
use Mocks\Responses\CatalogProducts;
use Mocks\Responses\Disputes;
use Mocks\Responses\DisputesActions;
use Mocks\Responses\Identity;
use Mocks\Responses\Invoices;
use Mocks\Responses\InvoicesSearch;
use Mocks\Responses\InvoicesTemplates;
use Mocks\Responses\Orders;
use Mocks\Responses\PartnerReferrals;
use Mocks\Responses\PaymentExperienceWebProfiles;
use Mocks\Responses\PaymentMethodsTokens;
use Mocks\Responses\PaymentAuthorizations;
use Mocks\Responses\PaymentCaptures;
use Mocks\Responses\PaymentRefunds;
use Mocks\Responses\Payouts;
use Mocks\Responses\ReferencedPayouts;
use Mocks\Responses\Reporting;
use Mocks\Responses\Subscriptions;
use Mocks\Responses\Trackers;
use Mocks\Responses\WebHooks;
/**
* @return array
*/
private function mockAccessTokenResponse(): array
{
return [
'scope' => 'some_scope',
'access_token' => 'some_access_token',
'token_type' => 'Bearer',
'app_id' => 'APP-80W284485P519543T',
'expires_in' => 32400,
'nonce' => 'some_nonce',
];
}
}
@@ -0,0 +1,115 @@
<?php
namespace Srmklive\PayPal\Tests\Mocks\Requests;
use GuzzleHttp\Utils;
trait BillingPlans
{
/**
* @return array
*/
private function createPlanParams(): array
{
return Utils::jsonDecode('{
"product_id": "PROD-XXCD1234QWER65782",
"name": "Video Streaming Service Plan",
"description": "Video Streaming Service basic plan",
"status": "ACTIVE",
"billing_cycles": [
{
"frequency": {
"interval_unit": "MONTH",
"interval_count": 1
},
"tenure_type": "TRIAL",
"sequence": 1,
"total_cycles": 2,
"pricing_scheme": {
"fixed_price": {
"value": "3",
"currency_code": "USD"
}
}
},
{
"frequency": {
"interval_unit": "MONTH",
"interval_count": 1
},
"tenure_type": "TRIAL",
"sequence": 2,
"total_cycles": 3,
"pricing_scheme": {
"fixed_price": {
"value": "6",
"currency_code": "USD"
}
}
},
{
"frequency": {
"interval_unit": "MONTH",
"interval_count": 1
},
"tenure_type": "REGULAR",
"sequence": 3,
"total_cycles": 12,
"pricing_scheme": {
"fixed_price": {
"value": "10",
"currency_code": "USD"
}
}
}
],
"payment_preferences": {
"auto_bill_outstanding": true,
"setup_fee": {
"value": "10",
"currency_code": "USD"
},
"setup_fee_failure_action": "CONTINUE",
"payment_failure_threshold": 3
},
"taxes": {
"percentage": "10",
"inclusive": false
}
}', true);
}
/**
* @return array
*/
private function updatePlanParams(): array
{
return Utils::jsonDecode('[
{
"op": "replace",
"path": "/payment_preferences/payment_failure_threshold",
"value": 7
}
]', true);
}
/**
* @return array
*/
private function updatePlanPricingParams(): array
{
return Utils::jsonDecode('{
"pricing_schemes": [
{
"billing_cycle_sequence": 2,
"pricing_scheme": {
"fixed_price": {
"value": "50",
"currency_code": "USD"
}
}
}
]
}', true);
}
}
@@ -0,0 +1,37 @@
<?php
namespace Srmklive\PayPal\Tests\Mocks\Requests;
use GuzzleHttp\Utils;
trait CatalogProducts
{
/**
* @return array
*/
private function createProductParams(): array
{
return Utils::jsonDecode('{
"name": "Video Streaming Service",
"description": "Video streaming service",
"type": "SERVICE",
"category": "SOFTWARE",
"image_url": "https://example.com/streaming.jpg",
"home_url": "https://example.com/home"
}', true);
}
/**
* @return array
*/
private function updateProductParams(): array
{
return Utils::jsonDecode('[
{
"op": "replace",
"path": "/description",
"value": "Premium video streaming service"
}
]', true);
}
}
@@ -0,0 +1,27 @@
<?php
namespace Srmklive\PayPal\Tests\Mocks\Requests;
use GuzzleHttp\Utils;
trait Disputes
{
/**
* @return array
*/
protected function updateDisputeParams(): array
{
return Utils::jsonDecode('[
{
"op": "add",
"path": "/partner_actions/-",
"value": {
"id": "AMX-22345",
"name": "ACCEPT_DISPUTE",
"create_time": "2018-01-12T10:41:35.000Z",
"status": "PENDING"
}
}
]', true);
}
}
@@ -0,0 +1,40 @@
<?php
namespace Srmklive\PayPal\Tests\Mocks\Requests;
use GuzzleHttp\Utils;
trait DisputesActions
{
/**
* @return array
*/
protected function acceptDisputeClaimParams(): array
{
return Utils::jsonDecode('{
"note": "Full refund to the customer.",
"accept_claim_type": "REFUND"
}', true);
}
/**
* @return array
*/
protected function acceptDisputeResolutionParams(): array
{
return Utils::jsonDecode('{
"note": "I am ok with the refund offered."
}', true);
}
/**
* @return array
*/
protected function acknowledgeItemReturnedParams(): array
{
return Utils::jsonDecode('{
"note": "I have received the item back.",
"acknowledgement_type": "ITEM_RECEIVED"
}', true);
}
}
@@ -0,0 +1,51 @@
<?php
namespace Srmklive\PayPal\Tests\Mocks\Requests;
use GuzzleHttp\Utils;
trait Identity
{
private function mockCreateMerchantApplicationParams(): array
{
return Utils::jsonDecode('{
"redirect_uris": [
"https://example.com/callback",
"https://example.com/callback2"
],
"client_name": "AGGREGATOR",
"logo_uri": "https://example.com/logo.png",
"contacts": [
"facilitator@example.com",
"merchant@example.com"
],
"policy_uri": "https://example.com/policyuri",
"tos_uri": "https://example.com/tosuri",
"scope": "profile email address",
"token_endpoint_auth_method": "client_secret_basic",
"jwks_uri": "https://example.com/my_public_keys.jwks"
}', true);
}
private function mockSetAccountPropertiesParams(): array
{
return Utils::jsonDecode('{
"categories": [
{
"name": "PAYMENT",
"groups": [
{
"name": "AUTH_SETTLE",
"preferences": [
{
"name": "ENABLE_ENHANCED_AUTH_SETTLE",
"value": "true"
}
]
}
]
}
]
}', true);
}
}
@@ -0,0 +1,457 @@
<?php
namespace Srmklive\PayPal\Tests\Mocks\Requests;
use GuzzleHttp\Utils;
trait Invoices
{
/**
* @return array
*/
private function createInvoiceParams(): array
{
return Utils::jsonDecode('{
"detail": {
"invoice_number": "#123",
"reference": "deal-ref",
"invoice_date": "2018-11-12",
"currency_code": "USD",
"note": "Thank you for your business.",
"term": "No refunds after 30 days.",
"memo": "This is a long contract",
"payment_term": {
"term_type": "NET_10",
"due_date": "2018-11-22"
}
},
"invoicer": {
"name": {
"given_name": "David",
"surname": "Larusso"
},
"address": {
"address_line_1": "1234 First Street",
"address_line_2": "337673 Hillside Court",
"admin_area_2": "Anytown",
"admin_area_1": "CA",
"postal_code": "98765",
"country_code": "US"
},
"email_address": "merchant@example.com",
"phones": [
{
"country_code": "001",
"national_number": "4085551234",
"phone_type": "MOBILE"
}
],
"website": "www.test.com",
"tax_id": "ABcNkWSfb5ICTt73nD3QON1fnnpgNKBy- Jb5SeuGj185MNNw6g",
"logo_url": "https://example.com/logo.PNG",
"additional_notes": "2-4"
},
"primary_recipients": [
{
"billing_info": {
"name": {
"given_name": "Stephanie",
"surname": "Meyers"
},
"address": {
"address_line_1": "1234 Main Street",
"admin_area_2": "Anytown",
"admin_area_1": "CA",
"postal_code": "98765",
"country_code": "US"
},
"email_address": "bill-me@example.com",
"phones": [
{
"country_code": "001",
"national_number": "4884551234",
"phone_type": "HOME"
}
],
"additional_info_value": "add-info"
},
"shipping_info": {
"name": {
"given_name": "Stephanie",
"surname": "Meyers"
},
"address": {
"address_line_1": "1234 Main Street",
"admin_area_2": "Anytown",
"admin_area_1": "CA",
"postal_code": "98765",
"country_code": "US"
}
}
}
],
"items": [
{
"name": "Yoga Mat",
"description": "Elastic mat to practice yoga.",
"quantity": "1",
"unit_amount": {
"currency_code": "USD",
"value": "50.00"
},
"tax": {
"name": "Sales Tax",
"percent": "7.25"
},
"discount": {
"percent": "5"
},
"unit_of_measure": "QUANTITY"
},
{
"name": "Yoga t-shirt",
"quantity": "1",
"unit_amount": {
"currency_code": "USD",
"value": "10.00"
},
"tax": {
"name": "Sales Tax",
"percent": "7.25"
},
"discount": {
"amount": {
"currency_code": "USD",
"value": "5.00"
}
},
"unit_of_measure": "QUANTITY"
}
],
"configuration": {
"partial_payment": {
"allow_partial_payment": true,
"minimum_amount_due": {
"currency_code": "USD",
"value": "20.00"
}
},
"allow_tip": true,
"tax_calculated_after_discount": true,
"tax_inclusive": false,
"template_id": "TEMP-19V05281TU309413B"
},
"amount": {
"breakdown": {
"custom": {
"label": "Packing Charges",
"amount": {
"currency_code": "USD",
"value": "10.00"
}
},
"shipping": {
"amount": {
"currency_code": "USD",
"value": "10.00"
},
"tax": {
"name": "Sales Tax",
"percent": "7.25"
}
},
"discount": {
"invoice_discount": {
"percent": "5"
}
}
}
}
}', true);
}
/**
* @return array
*/
private function updateInvoiceParams(): array
{
return Utils::jsonDecode('{
"id": "INV2-C82X-JNN9-Y6S5-CNXW",
"status": "DRAFT",
"detail": {
"invoice_number": "#123",
"reference": "deal-refernce-update",
"invoice_date": "2018-11-12",
"currency_code": "USD",
"note": "Thank you for your business.",
"term": "No refunds after 30 days.",
"memo": "This is a long contract",
"payment_term": {
"term_type": "NET_10",
"due_date": "2018-11-22"
}
},
"invoicer": {
"name": {
"given_name": "David",
"surname": "Larusso"
},
"address": {
"address_line_1": "1234 First Street",
"address_line_2": "337673 Hillside Court",
"admin_area_2": "Anytown",
"admin_area_1": "CA",
"postal_code": "98765",
"country_code": "US"
},
"email_address": "merchant@example.com",
"phones": [
{
"country_code": "001",
"national_number": "4085551234",
"phone_type": "MOBILE"
}
],
"website": "www.test.com",
"tax_id": "ABcNkWSfb5ICTt73nD3QON1fnnpgNKBy-Jb5SeuGj185MNNw6g",
"logo_url": "https://example.com/logo.PNG",
"additional_notes": "2-4"
},
"primary_recipients": [
{
"billing_info": {
"name": {
"given_name": "Stephanie",
"surname": "Meyers"
},
"address": {
"address_line_1": "1234 Main Street",
"admin_area_2": "Anytown",
"admin_area_1": "CA",
"postal_code": "98765",
"country_code": "US"
},
"email_address": "bill-me@example.com",
"phones": [
{
"country_code": "001",
"national_number": "4884551234",
"phone_type": "HOME"
}
],
"additional_info_value": "add-info"
},
"shipping_info": {
"name": {
"given_name": "Stephanie",
"surname": "Meyers"
},
"address": {
"address_line_1": "1234 Main Street",
"admin_area_2": "Anytown",
"admin_area_1": "CA",
"postal_code": "98765",
"country_code": "US"
}
}
}
],
"items": [
{
"name": "Yoga Mat",
"description": "Elastic mat to practice yoga.",
"quantity": "1",
"unit_amount": {
"currency_code": "USD",
"value": "50.00"
},
"tax": {
"name": "Sales Tax",
"percent": "7.25",
"amount": {
"currency_code": "USD",
"value": "3.27"
}
},
"discount": {
"percent": "5",
"amount": {
"currency_code": "USD",
"value": "2.5"
}
},
"unit_of_measure": "QUANTITY"
},
{
"name": "Yoga t-shirt",
"quantity": "1",
"unit_amount": {
"currency_code": "USD",
"value": "10.00"
},
"tax": {
"name": "Sales Tax",
"percent": "7.25",
"amount": {
"currency_code": "USD",
"value": "0.34"
}
},
"discount": {
"amount": {
"currency_code": "USD",
"value": "5.00"
}
},
"unit_of_measure": "QUANTITY"
}
],
"configuration": {
"partial_payment": {
"allow_partial_payment": true,
"minimum_amount_due": {
"currency_code": "USD",
"value": "20.00"
}
},
"allow_tip": true,
"tax_calculated_after_discount": true,
"tax_inclusive": false,
"template_id": "TEMP-19V05281TU309413B"
},
"amount": {
"currency_code": "USD",
"value": "74.21",
"breakdown": {
"item_total": {
"currency_code": "USD",
"value": "60.00"
},
"custom": {
"label": "Packing Charges",
"amount": {
"currency_code": "USD",
"value": "10.00"
}
},
"shipping": {
"amount": {
"currency_code": "USD",
"value": "10.00"
},
"tax": {
"name": "Sales Tax",
"percent": "7.25",
"amount": {
"currency_code": "USD",
"value": "0.73"
}
}
},
"discount": {
"item_discount": {
"currency_code": "USD",
"value": "-7.50"
},
"invoice_discount": {
"percent": "5",
"amount": {
"currency_code": "USD",
"value": "-2.63"
}
}
},
"tax_total": {
"currency_code": "USD",
"value": "4.34"
}
}
}
}', true);
}
/**
* @return array
*/
private function cancelInvoiceParams(): array
{
return Utils::jsonDecode('{
"subject": "Invoice Cancelled",
"note": "Cancelling the invoice",
"send_to_invoicer": true,
"send_to_recipient": true,
"additional_recipients": [
"user@example.com"
]
}', true);
}
/**
* @return array
*/
private function generateQRCodeInvoiceParams(): array
{
return Utils::jsonDecode('{
"width": 400,
"height": 400
}', true);
}
/**
* @return array
*/
private function registerInvoicePaymentParams(): array
{
return Utils::jsonDecode('{
"width": 400,
"height": 400
}', true);
}
/**
* @return array
*/
private function refundInvoicePaymentParams(): array
{
return Utils::jsonDecode('{
"method": "BANK_TRANSFER",
"refund_date": "2018-05-21",
"amount": {
"currency_code": "USD",
"value": "5.00"
}
}', true);
}
/**
* @return array
*/
private function sendInvoiceParams(): array
{
return Utils::jsonDecode('{
"subject": "Payment due for the invoice #ABC-123",
"note": "Please pay before the due date to avoid incurring late payment charges which will be adjusted in the next bill generated.",
"send_to_invoicer": true,
"additional_recipients": [
"customer-a@example.com",
"customer@example.com"
]
}', true);
}
/**
* @return array
*/
private function sendInvoiceReminderParams(): array
{
return Utils::jsonDecode('{
"subject": "Reminder: Payment due for the invoice #ABC-123",
"note": "Please pay before the due date to avoid incurring late payment charges which will be adjusted in the next bill generated.",
"send_to_invoicer": true,
"additional_recipients": [
"customer-a@example.com",
"customer@example.com"
]
}', true);
}
}
@@ -0,0 +1,31 @@
<?php
namespace Srmklive\PayPal\Tests\Mocks\Requests;
use GuzzleHttp\Utils;
trait InvoicesSearch
{
/**
* @return array
*/
private function invoiceSearchParams(): array
{
return Utils::jsonDecode('{
"total_amount_range": {
"lower_amount": {
"currency_code": "USD",
"value": "20.00"
},
"upper_amount": {
"currency_code": "USD",
"value": "50.00"
}
},
"invoice_date_range": {
"start": "2018-06-01",
"end": "2018-06-21"
}
}', true);
}
}
@@ -0,0 +1,468 @@
<?php
namespace Srmklive\PayPal\Tests\Mocks\Requests;
use GuzzleHttp\Utils;
trait InvoicesTemplates
{
/**
* @return array
*/
private function mockCreateInvoiceTemplateParams(): array
{
return Utils::jsonDecode('{
"default_template": true,
"template_info": {
"configuration": {
"tax_calculated_after_discount": true,
"tax_inclusive": false,
"allow_tip": true,
"partial_payment": {
"allow_partial_payment": true,
"minimum_amount_due": {
"currency_code": "USD",
"value": "20.00"
}
}
},
"detail": {
"reference": "deal-ref",
"note": "Thank you for your business.",
"currency_code": "USD",
"terms_and_conditions": "No refunds after 30 days.",
"memo": "This is a long contract",
"attachments": [
{
"id": "Screen Shot 2018-11-23 at 16.45.01.png",
"reference_url": "https://api.paypal.com/invoice/payerView/attachments/RkG9ggQbd4Mwm1tYdcF6uuixfFTFq32bBdbE1VbtQLdKSoS2ZOYpfjw9gPp7eTrZmVaFaDWzixHXm-OXWHbmigHigHzURDxJs8IIKqcqP8jawnBEZcraEAPVMULxf5iTyOSpAUc2ugW0PWdwDbM6mg-guFAUyj3Z98H7htWNjQY95jb9heOlcSXUe.sbDUR9smAszzzJoA1NXT6rEEegwQ&version=1&sig=JNODB0xEayW8txMQm6ZsIwDnd4eh3hd6ijiRLi4ipHE"
}
],
"payment_term": {
"term_type": "NET_10"
}
},
"invoicer": {
"name": {
"given_name": "David",
"surname": "Larusso"
},
"address": {
"address_line_1": "1234 First Street",
"address_line_2": "337673 Hillside Court",
"admin_area_2": "Anytown",
"admin_area_1": "CA",
"postal_code": "98765",
"country_code": "US"
},
"email_address": "merchant@example.com",
"phones": [
{
"country_code": "001",
"national_number": "4085551234",
"phone_type": "MOBILE"
}
],
"website": "www.test.com",
"tax_id": "ABcNkWSfb5ICTt73nD3QON1fnnpgNKBy-Jb5SeuGj185MNNw6g",
"logo_url": "https://example.com/logo.PNG",
"additional_notes": "2-4"
},
"primary_recipients": [
{
"billing_info": {
"name": {
"given_name": "Stephanie",
"surname": "Meyers"
},
"address": {
"address_line_1": "1234 Main Street",
"admin_area_2": "Anytown",
"admin_area_1": "CA",
"postal_code": "98765",
"country_code": "US"
},
"email_address": "bill-me@example.com",
"phones": [
{
"country_code": "001",
"national_number": "4884551234",
"phone_type": "MOBILE"
}
],
"additional_info": "add-info"
},
"shipping_info": {
"name": {
"given_name": "Stephanie",
"surname": "Meyers"
},
"address": {
"address_line_1": "1234 Main Street",
"admin_area_2": "Anytown",
"admin_area_1": "CA",
"postal_code": "98765",
"country_code": "US"
}
}
}
],
"additional_recipients": [
"inform-me@example.com"
],
"items": [
{
"name": "Yoga Mat",
"description": "new watch",
"quantity": "1",
"unit_amount": {
"currency_code": "USD",
"value": "50.00"
},
"tax": {
"name": "Sales Tax",
"percent": "7.25"
},
"discount": {
"percent": "5"
},
"unit_of_measure": "QUANTITY"
},
{
"name": "Yoga T Shirt",
"quantity": "1",
"unit_amount": {
"currency_code": "USD",
"value": "10.00"
},
"tax": {
"name": "Sales Tax",
"percent": "7.25"
},
"discount": {
"amount": {
"currency_code": "USD",
"value": "5.00"
}
},
"unit_of_measure": "QUANTITY"
}
],
"amount": {
"currency_code": "USD",
"value": "74.21",
"breakdown": {
"custom": {
"label": "Packing Charges",
"amount": {
"currency_code": "USD",
"value": "10.00"
}
},
"shipping": {
"amount": {
"currency_code": "USD",
"value": "10.00"
},
"tax": {
"name": "Sales Tax",
"percent": "7.25"
}
},
"discount": {
"invoice_discount": {
"percent": "5"
}
}
}
}
},
"settings": {
"template_item_settings": [
{
"field_name": "items.date",
"display_preference": {
"hidden": true
}
},
{
"field_name": "items.discount",
"display_preference": {
"hidden": false
}
},
{
"field_name": "items.tax",
"display_preference": {
"hidden": false
}
},
{
"field_name": "items.description",
"display_preference": {
"hidden": false
}
},
{
"field_name": "items.quantity",
"display_preference": {
"hidden": true
}
}
],
"template_subtotal_settings": [
{
"field_name": "custom",
"display_preference": {
"hidden": false
}
},
{
"field_name": "discount",
"display_preference": {
"hidden": false
}
},
{
"field_name": "shipping",
"display_preference": {
"hidden": false
}
}
]
},
"unit_of_measure": "QUANTITY",
"standard_template": false
}', true);
}
/**
* @return array
*/
private function mockUpdateInvoiceTemplateParams(): array
{
return Utils::jsonDecode('{
"default_template": true,
"template_info": {
"configuration": {
"tax_calculated_after_discount": true,
"tax_inclusive": false,
"allow_tip": true,
"partial_payment": {
"allow_partial_payment": true,
"minimum_amount_due": {
"currency_code": "USD",
"value": "20.00"
}
}
},
"detail": {
"reference": "deal-reference-value",
"note": "Thank you for your business.",
"currency_code": "USD",
"terms_and_conditions": "No refunds after 30 days.",
"memo": "This is a long contract",
"attachments": [
{
"id": "Screen Shot 2018-11-23 at 16.45.01.png",
"reference_url": "https://example.com/invoice/payerView/attachments/RkG9ggQbd4Mwm1tYdcF6uuixfFTFq32bBdbE1VbtQLdKSoS2ZOYpfjw9gPp7eTrZmVaFaDWzixHXm-OXWHbmigHigHzURDxJs8IIKqcqP8jawnBEZcraEAPVMULxf5iTyOSpAUc2ugW0PWdwDbM6mg-guFAUyj3Z98H7htWNjQY95jb9heOlcSXUe.sbDUR9smAszzzJoA1NXT6rEEegwQ&version=1&sig=JNODB0xEayW8txMQm6ZsIwDnd4eh3hd6ijiRLi4ipHE"
}
],
"payment_term": {
"term_type": "NET_10"
}
},
"invoicer": {
"name": {
"given_name": "David",
"surname": "Larusso"
},
"address": {
"address_line_1": "1234 First Street",
"address_line_2": "337673 Hillside Court",
"admin_area_2": "Anytown",
"admin_area_1": "CA",
"postal_code": "98765",
"country_code": "US"
},
"email_address": "merchant@example.com",
"phones": [
{
"country_code": "001",
"national_number": "4085551234",
"phone_type": "MOBILE"
}
],
"website": "www.test.com",
"tax_id": "ABcNkWSfb5ICTt73nD3QON1fnnpgNKBy-Jb5SeuGj185MNNw6g",
"logo_url": "https://example.com/logo.PNG",
"additional_notes": "2-4"
},
"primary_recipients": [
{
"billing_info": {
"name": {
"given_name": "Stephanie",
"surname": "Meyers"
},
"address": {
"address_line_1": "1234 Main Street",
"admin_area_2": "Anytown",
"admin_area_1": "CA",
"postal_code": "98765",
"country_code": "US"
},
"email_address": "bill-me@example.com",
"phones": [
{
"country_code": "001",
"national_number": "4884551234",
"phone_type": "MOBILE"
}
],
"additional_info": "add-info"
},
"shipping_info": {
"name": {
"given_name": "Stephanie",
"surname": "Meyers"
},
"address": {
"address_line_1": "1234 Main Street",
"admin_area_2": "Anytown",
"admin_area_1": "CA",
"postal_code": "98765",
"country_code": "US"
}
}
}
],
"additional_recipients": [
"inform-me@example.com"
],
"items": [
{
"name": "Yoga Mat",
"description": "new watch",
"quantity": "1",
"unit_amount": {
"currency_code": "USD",
"value": "50.00"
},
"tax": {
"name": "Sales Tax",
"percent": "7.25"
},
"discount": {
"percent": "5"
},
"unit_of_measure": "QUANTITY"
},
{
"name": "Yoga T Shirt",
"quantity": "1",
"unit_amount": {
"currency_code": "USD",
"value": "10.00"
},
"tax": {
"name": "Sales Tax",
"percent": "7.25"
},
"discount": {
"amount": {
"currency_code": "USD",
"value": "5.00"
}
},
"unit_of_measure": "QUANTITY"
}
],
"amount": {
"currency_code": "USD",
"value": "74.21",
"breakdown": {
"custom": {
"label": "Packing Charges",
"amount": {
"currency_code": "USD",
"value": "10.00"
}
},
"shipping": {
"amount": {
"currency_code": "USD",
"value": "10.00"
},
"tax": {
"name": "Sales Tax",
"percent": "7.25"
}
},
"discount": {
"invoice_discount": {
"percent": "5"
}
}
}
}
},
"settings": {
"template_item_settings": [
{
"field_name": "items.date",
"display_preference": {
"hidden": true
}
},
{
"field_name": "items.discount",
"display_preference": {
"hidden": false
}
},
{
"field_name": "items.tax",
"display_preference": {
"hidden": false
}
},
{
"field_name": "items.description",
"display_preference": {
"hidden": false
}
},
{
"field_name": "items.quantity",
"display_preference": {
"hidden": true
}
}
],
"template_subtotal_settings": [
{
"field_name": "custom",
"display_preference": {
"hidden": false
}
},
{
"field_name": "discount",
"display_preference": {
"hidden": false
}
},
{
"field_name": "shipping",
"display_preference": {
"hidden": false
}
}
]
},
"unit_of_measure": "QUANTITY",
"standard_template": false
}', true);
}
}
@@ -0,0 +1,47 @@
<?php
namespace Srmklive\PayPal\Tests\Mocks\Requests;
use GuzzleHttp\Utils;
trait Orders
{
/*
* @return array
*/
private function createOrderParams(): array
{
return Utils::jsonDecode('{
"intent": "CAPTURE",
"purchase_units": [
{
"amount": {
"currency_code": "USD",
"value": "100.00"
}
}
]
}', true);
}
/*
* @return array
*/
private function updateOrderParams(): array
{
return Utils::jsonDecode('[
{
"op": "replace",
"path": "/purchase_units/@reference_id==\'PUHF\'/shipping/address",
"value": {
"address_line_1": "123 Townsend St",
"address_line_2": "Floor 6",
"admin_area_2": "San Francisco",
"admin_area_1": "CA",
"postal_code": "94107",
"country_code": "US"
}
}
]', true);
}
}
@@ -0,0 +1,291 @@
<?php
namespace Srmklive\PayPal\Tests\Mocks\Requests;
use GuzzleHttp\Utils;
trait PartnerReferrals
{
private function mockCreatePartnerReferralParams(): array
{
return Utils::jsonDecode('{
"individual_owners": [
{
"names": [
{
"prefix": "Mr.",
"given_name": "John",
"surname": "Doe",
"middle_name": "Middle",
"suffix": "Jr.",
"full_name": "John Middle Doe Jr.",
"type": "LEGAL"
}
],
"citizenship": "US",
"addresses": [
{
"address_line_1": "One Washington Square",
"address_line_2": "Apt 123",
"admin_area_2": "San Jose",
"admin_area_1": "CA",
"postal_code": "95112",
"country_code": "US",
"type": "HOME"
}
],
"phones": [
{
"country_code": "1",
"national_number": "6692468839",
"extension_number": "1234",
"type": "MOBILE"
}
],
"birth_details": {
"date_of_birth": "1955-12-29"
},
"type": "PRIMARY"
}
],
"business_entity": {
"business_type": {
"type": "INDIVIDUAL",
"subtype": "ASSO_TYPE_INCORPORATED"
},
"business_industry": {
"category": "1004",
"mcc_code": "2025",
"subcategory": "8931"
},
"business_incorporation": {
"incorporation_country_code": "US",
"incorporation_date": "1986-12-29"
},
"names": [
{
"business_name": "Test Enterprise",
"type": "LEGAL_NAME"
}
],
"emails": [
{
"type": "CUSTOMER_SERVICE",
"email": "customerservice@example.com"
}
],
"website": "https://mystore.testenterprises.com",
"addresses": [
{
"address_line_1": "One Washington Square",
"address_line_2": "Apt 123",
"admin_area_2": "San Jose",
"admin_area_1": "CA",
"postal_code": "95112",
"country_code": "US",
"type": "WORK"
}
],
"phones": [
{
"country_code": "1",
"national_number": "6692478833",
"extension_number": "1234",
"type": "CUSTOMER_SERVICE"
}
],
"beneficial_owners": {
"individual_beneficial_owners": [
{
"names": [
{
"prefix": "Mr.",
"given_name": "John",
"surname": "Doe",
"middle_name": "Middle",
"suffix": "Jr.",
"full_name": "John Middle Doe Jr.",
"type": "LEGAL"
}
],
"citizenship": "US",
"addresses": [
{
"address_line_1": "One Washington Square",
"address_line_2": "Apt 123",
"admin_area_2": "San Jose",
"admin_area_1": "CA",
"postal_code": "95112",
"country_code": "US",
"type": "HOME"
}
],
"phones": [
{
"country_code": "1",
"national_number": "6692468839",
"extension_number": "1234",
"type": "MOBILE"
}
],
"birth_details": {
"date_of_birth": "1955-12-29"
},
"percentage_of_ownership": "50"
}
],
"business_beneficial_owners": [
{
"business_type": {
"type": "INDIVIDUAL",
"subtype": "ASSO_TYPE_INCORPORATED"
},
"business_industry": {
"category": "1004",
"mcc_code": "2025",
"subcategory": "8931"
},
"business_incorporation": {
"incorporation_country_code": "US",
"incorporation_date": "1986-12-29"
},
"names": [
{
"business_name": "Test Enterprise",
"type": "LEGAL_NAME"
}
],
"emails": [
{
"type": "CUSTOMER_SERVICE",
"email": "customerservice@example.com"
}
],
"website": "https://mystore.testenterprises.com",
"addresses": [
{
"address_line_1": "One Washington Square",
"address_line_2": "Apt 123",
"admin_area_2": "San Jose",
"admin_area_1": "CA",
"postal_code": "95112",
"country_code": "US",
"type": "WORK"
}
],
"phones": [
{
"country_code": "1",
"national_number": "6692478833",
"extension_number": "1234",
"type": "CUSTOMER_SERVICE"
}
],
"percentage_of_ownership": "50"
}
]
},
"office_bearers": [
{
"names": [
{
"prefix": "Mr.",
"given_name": "John",
"surname": "Doe",
"middle_name": "Middle",
"suffix": "Jr.",
"full_name": "John Middle Doe Jr.",
"type": "LEGAL"
}
],
"citizenship": "US",
"addresses": [
{
"address_line_1": "One Washington Square",
"address_line_2": "Apt 123",
"admin_area_2": "San Jose",
"admin_area_1": "CA",
"postal_code": "95112",
"country_code": "US",
"type": "HOME"
}
],
"phones": [
{
"country_code": "1",
"national_number": "6692468839",
"extension_number": "1234",
"type": "MOBILE"
}
],
"birth_details": {
"date_of_birth": "1955-12-29"
},
"role": "DIRECTOR"
}
],
"annual_sales_volume_range": {
"minimum_amount": {
"currency_code": "USD",
"value": "10000"
},
"maximum_amount": {
"currency_code": "USD",
"value": "50000"
}
},
"average_monthly_volume_range": {
"minimum_amount": {
"currency_code": "USD",
"value": "1000"
},
"maximum_amount": {
"currency_code": "USD",
"value": "50000"
}
},
"purpose_code": "P0104"
},
"email": "accountemail@example.com",
"preferred_language_code": "en-US",
"tracking_id": "testenterprices123122",
"partner_config_override": {
"partner_logo_url": "https://www.paypalobjects.com/webstatic/mktg/logo/pp_cc_mark_111x69.jpg",
"return_url": "https://testenterprises.com/merchantonboarded",
"return_url_description": "the url to return the merchant after the paypal onboarding process.",
"action_renewal_url": "https://testenterprises.com/renew-exprired-url",
"show_add_credit_card": true
},
"operations": [
{
"operation": "BANK_ADDITION"
}
],
"financial_instruments": {
"banks": [
{
"nick_name": "Bank of America",
"account_number": "123405668293",
"account_type": "CHECKING",
"currency_code": "USD",
"identifiers": [
{
"type": "ROUTING_NUMBER_1",
"value": "123456789"
}
]
}
]
},
"legal_consents": [
{
"type": "SHARE_DATA_CONSENT",
"granted": true
}
],
"products": [
"EXPRESS_CHECKOUT"
]
}', true);
}
}
@@ -0,0 +1,37 @@
<?php
namespace Srmklive\PayPal\Tests\Mocks\Requests;
use GuzzleHttp\Utils;
trait PaymentAuthorizations
{
/**
* @return array
*/
private function mockCaptureAuthorizedPaymentParams(): array
{
return Utils::jsonDecode('{
"amount": {
"value": "10.99",
"currency_code": "USD"
},
"invoice_id": "INVOICE-123",
"note_to_payer": "Payment is due",
"final_capture": true
}', true);
}
/**
* @return array
*/
private function mockReAuthorizeAuthorizedPaymentParams(): array
{
return Utils::jsonDecode('{
"amount": {
"value": "10.99",
"currency_code": "USD"
}
}', true);
}
}
@@ -0,0 +1,23 @@
<?php
namespace Srmklive\PayPal\Tests\Mocks\Requests;
use GuzzleHttp\Utils;
trait PaymentCaptures
{
/**
* @return array
*/
private function mockRefundCapturedPaymentParams(): array
{
return Utils::jsonDecode('{
"amount": {
"value": "10.99",
"currency_code": "USD"
},
"invoice_id": "INVOICE-123",
"note_to_payer": "Defective product"
}', true);
}
}
@@ -0,0 +1,100 @@
<?php
namespace Srmklive\PayPal\Tests\Mocks\Requests;
use GuzzleHttp\Utils;
trait PaymentExperienceWebProfiles
{
/**
* @return array
*/
private function mockCreateWebProfileParams(): array
{
return Utils::jsonDecode('[
{
"id": "XP-GCUV-X35G-HNEY-5MJY",
"name": "exampleProfile",
"flow_config": {
"landing_page_type": "billing",
"bank_txn_pending_url": "https://example.com/flow_config/"
},
"input_fields": {
"no_shipping": 1,
"address_override": 1
},
"presentation": {
"logo_image": "https://example.com/logo_image/"
}
},
{
"id": "XP-A88A-LYLW-8Y3X-E5ER",
"name": "exampleProfile",
"flow_config": {
"landing_page_type": "billing",
"bank_txn_pending_url": "https://example.com/flow_config/"
},
"input_fields": {
"no_shipping": 1,
"address_override": 1
},
"presentation": {
"logo_image": "https://example.com/logo_image/"
}
},
{
"id": "XP-RFV4-PVD8-AGHJ-8E5J",
"name": "exampleProfile",
"flow_config": {
"bank_txn_pending_url": "https://example.com/flow_config/"
},
"input_fields": {
"no_shipping": 1,
"address_override": 1
},
"presentation": {
"logo_image": "https://example.com/logo_image/"
}
}
]', true);
}
/**
* @return array
*/
private function partiallyUpdateWebProfileParams(): array
{
return Utils::jsonDecode('[
{
"op": "add",
"path": "/presentation/brand_name",
"value": "new_brand_name"
},
{
"op": "remove",
"path": "/flow_config/landing_page_type"
}
]', true);
}
/**
* @return array
*/
private function updateWebProfileParams(): array
{
return Utils::jsonDecode('{
"name": "exampleProfile",
"presentation": {
"logo_image": "https://example.com/logo_image/"
},
"input_fields": {
"no_shipping": 1,
"address_override": 1
},
"flow_config": {
"landing_page_type": "billing",
"bank_txn_pending_url": "https://example.com/flow_config/"
}
}', true);
}
}
@@ -0,0 +1,77 @@
<?php
namespace Srmklive\PayPal\Tests\Mocks\Requests;
use GuzzleHttp\Utils;
trait PaymentMethodsTokens
{
/**
* @return array
*/
private function mockCreatePaymentSetupTokensParams(): array
{
return Utils::jsonDecode('{
"payment_source": {
"card": {
"number": "4111111111111111",
"expiry": "2027-02",
"name": "John Doe",
"billing_address": {
"address_line_1": "2211 N First Street",
"address_line_2": "17.3.160",
"admin_area_1": "CA",
"admin_area_2": "San Jose",
"postal_code": "95131",
"country_code": "US"
},
"experience_context": {
"brand_name": "YourBrandName",
"locale": "en-US",
"return_url": "https://example.com/returnUrl",
"cancel_url": "https://example.com/cancelUrl"
}
}
}
}', true);
}
/**
* @return array
*/
private function mockCreatePaymentSetupPayPalParams(): array
{
return Utils::jsonDecode('{
"payment_source": {
"paypal": {
"description": "Description for PayPal to be shown to PayPal payer",
"shipping": {
"name": {
"full_name": "Firstname Lastname"
},
"address": {
"address_line_1": "2211 N First Street",
"address_line_2": "Building 17",
"admin_area_2": "San Jose",
"admin_area_1": "CA",
"postal_code": "95131",
"country_code": "US"
}
},
"permit_multiple_payment_tokens": false,
"usage_pattern": "IMMEDIATE",
"usage_type": "MERCHANT",
"customer_type": "CONSUMER",
"experience_context": {
"shipping_preference": "SET_PROVIDED_ADDRESS",
"payment_method_preference": "IMMEDIATE_PAYMENT_REQUIRED",
"brand_name": "EXAMPLE INC",
"locale": "en-US",
"return_url": "https://example.com/returnUrl",
"cancel_url": "https://example.com/cancelUrl"
}
}
}
}', true);
}
}
@@ -0,0 +1,61 @@
<?php
namespace Srmklive\PayPal\Tests\Mocks\Requests;
use GuzzleHttp\Utils;
trait Payouts
{
/**
* @return array
*/
private function mockCreateBatchPayoutParams(): array
{
return Utils::jsonDecode('{
"sender_batch_header": {
"sender_batch_id": "Payouts_2018_100007",
"email_subject": "You have a payout!",
"email_message": "You have received a payout! Thanks for using our service!"
},
"items": [
{
"recipient_type": "EMAIL",
"amount": {
"value": "9.87",
"currency": "USD"
},
"note": "Thanks for your patronage!",
"sender_item_id": "201403140001",
"receiver": "receiver@example.com",
"alternate_notification_method": {
"phone": {
"country_code": "91",
"national_number": "9999988888"
}
},
"notification_language": "fr-FR"
},
{
"recipient_type": "PHONE",
"amount": {
"value": "112.34",
"currency": "USD"
},
"note": "Thanks for your support!",
"sender_item_id": "201403140002",
"receiver": "91-734-234-1234"
},
{
"recipient_type": "PAYPAL_ID",
"amount": {
"value": "5.32",
"currency": "USD"
},
"note": "Thanks for your patronage!",
"sender_item_id": "201403140003",
"receiver": "G83JXTJ5EHCQ2"
}
]
}', true);
}
}
@@ -0,0 +1,38 @@
<?php
namespace Srmklive\PayPal\Tests\Mocks\Requests;
use GuzzleHttp\Utils;
trait ReferencedPayouts
{
/**
* @return array
*/
private function mockCreateReferencedBatchPayoutParams(): array
{
return Utils::jsonDecode('{
"referenced_payouts": [
{
"reference_id": "2KP03934U4415543C",
"reference_type": "TRANSACTION_ID"
},
{
"reference_id": "8TA4226978212399L",
"reference_type": "TRANSACTION_ID"
}
]
}', true);
}
/**
* @return array
*/
private function mockCreateReferencedBatchPayoutItemParams(): array
{
return Utils::jsonDecode('{
"reference_id": "CAPTURETXNID",
"reference_type": "TRANSACTION_ID"
}', true);
}
}
@@ -0,0 +1,156 @@
<?php
namespace Srmklive\PayPal\Tests\Mocks\Requests;
use GuzzleHttp\Utils;
trait Subscriptions
{
/**
* @return array
*/
private function mockCreateSubscriptionParams(): array
{
return Utils::jsonDecode('{
"plan_id": "P-5ML4271244454362WXNWU5NQ",
"start_time": "2018-11-01T00:00:00Z",
"quantity": "20",
"shipping_amount": {
"currency_code": "USD",
"value": "10.00"
},
"subscriber": {
"name": {
"given_name": "John",
"surname": "Doe"
},
"email_address": "customer@example.com",
"shipping_address": {
"name": {
"full_name": "John Doe"
},
"address": {
"address_line_1": "2211 N First Street",
"address_line_2": "Building 17",
"admin_area_2": "San Jose",
"admin_area_1": "CA",
"postal_code": "95131",
"country_code": "US"
}
}
},
"application_context": {
"brand_name": "walmart",
"locale": "en-US",
"shipping_preference": "SET_PROVIDED_ADDRESS",
"user_action": "SUBSCRIBE_NOW",
"payment_method": {
"payer_selected": "PAYPAL",
"payee_preferred": "IMMEDIATE_PAYMENT_REQUIRED"
},
"return_url": "https://example.com/returnUrl",
"cancel_url": "https://example.com/cancelUrl"
}
}', true);
}
/**
* @return array
*/
private function mockUpdateSubscriptionParams(): array
{
return Utils::jsonDecode('[
{
"op": "replace",
"path": "/billing_info/outstanding_balance",
"value": {
"currency_code": "USD",
"value": "50.00"
}
}
]', true);
}
/**
* @return array
*/
private function mockActivateSubscriptionParams()
{
return Utils::jsonDecode('{
"reason": "Reactivating the subscription"
}', true);
}
/**
* @return array
*/
private function mockCancelSubscriptionParams()
{
return Utils::jsonDecode('{
"reason": "Not satisfied with the service"
}', true);
}
/**
* @return array
*/
private function mockSuspendSubscriptionParams()
{
return Utils::jsonDecode('{
"reason": "Item out of stock"
}', true);
}
/**
* @return array
*/
private function mockCaptureSubscriptionPaymentParams()
{
return Utils::jsonDecode('{
"note": "Charging as the balance reached the limit",
"capture_type": "OUTSTANDING_BALANCE",
"amount": {
"currency_code": "USD",
"value": "100"
}
}', true);
}
/**
* @return array
*/
private function mockUpdateSubscriptionItemsParams()
{
return Utils::jsonDecode('{
"plan_id": "P-5ML4271244454362WXNWU5NQ",
"shipping_amount": {
"currency_code": "USD",
"value": "10.00"
},
"shipping_address": {
"name": {
"full_name": "John Doe"
},
"address": {
"address_line_1": "2211 N First Street",
"address_line_2": "Building 17",
"admin_area_2": "San Jose",
"admin_area_1": "CA",
"postal_code": "95131",
"country_code": "US"
}
},
"application_context": {
"brand_name": "walmart",
"locale": "en-US",
"shipping_preference": "SET_PROVIDED_ADDRESS",
"payment_method": {
"payer_selected": "PAYPAL",
"payee_preferred": "IMMEDIATE_PAYMENT_REQUIRED"
},
"return_url": "https://example.com/returnUrl",
"cancel_url": "https://example.com/cancelUrl"
}
}', true);
}
}
@@ -0,0 +1,44 @@
<?php
namespace Srmklive\PayPal\Tests\Mocks\Requests;
use GuzzleHttp\Utils;
trait Trackers
{
/**
* @return array
*/
private function mockUpdateTrackingDetailsParams(): array
{
return Utils::jsonDecode('{
"transaction_id": "8MC585209K746392H",
"tracking_number": "443844607820",
"status": "SHIPPED",
"carrier": "FEDEX"
}', true);
}
/**
* @return array
*/
private function mockCreateTrackinginBatchesParams(): array
{
return Utils::jsonDecode('{
"trackers": [
{
"transaction_id": "8MC585209K746392H",
"tracking_number": "443844607820",
"status": "SHIPPED",
"carrier": "FEDEX"
},
{
"transaction_id": "53Y56775AE587553X",
"tracking_number": "443844607821",
"status": "SHIPPED",
"carrier": "FEDEX"
}
]
}', true);
}
}
@@ -0,0 +1,120 @@
<?php
namespace Srmklive\PayPal\Tests\Mocks\Requests;
use GuzzleHttp\Utils;
trait WebHooks
{
/**
* @return array
*/
private function mockCreateWebHookParams(): array
{
return Utils::jsonDecode('{
"url": "https://example.com/example_webhook",
"event_types": [
{
"name": "PAYMENT.AUTHORIZATION.CREATED"
},
{
"name": "PAYMENT.AUTHORIZATION.VOIDED"
}
]
}', true);
}
/**
* @return array
*/
private function mockUpdateWebHookParams(): array
{
return Utils::jsonDecode('[
{
"op": "replace",
"path": "/url",
"value": "https://example.com/example_webhook_2"
},
{
"op": "replace",
"path": "/event_types",
"value": [
{
"name": "PAYMENT.SALE.REFUNDED"
}
]
}
]', true);
}
/**
* @return array
*/
private function mockResendWebHookEventNotificationParams(): array
{
return Utils::jsonDecode('{
"webhook_ids": [
"12334456"
]
}', true);
}
/**
* @return array
*/
private function mockVerifyWebHookSignatureParams(): array
{
return Utils::jsonDecode('{
"transmission_id": "69cd13f0-d67a-11e5-baa3-778b53f4ae55",
"transmission_time": "2016-02-18T20:01:35Z",
"cert_url": "cert_url",
"auth_algo": "SHA256withRSA",
"transmission_sig": "lmI95Jx3Y9nhR5SJWlHVIWpg4AgFk7n9bCHSRxbrd8A9zrhdu2rMyFrmz+Zjh3s3boXB07VXCXUZy/UFzUlnGJn0wDugt7FlSvdKeIJenLRemUxYCPVoEZzg9VFNqOa48gMkvF+XTpxBeUx/kWy6B5cp7GkT2+pOowfRK7OaynuxUoKW3JcMWw272VKjLTtTAShncla7tGF+55rxyt2KNZIIqxNMJ48RDZheGU5w1npu9dZHnPgTXB9iomeVRoD8O/jhRpnKsGrDschyNdkeh81BJJMH4Ctc6lnCCquoP/GzCzz33MMsNdid7vL/NIWaCsekQpW26FpWPi/tfj8nLA==",
"webhook_id": "1JE4291016473214C",
"webhook_event": {
"id": "8PT597110X687430LKGECATA",
"create_time": "2013-06-25T21:41:28Z",
"resource_type": "authorization",
"event_type": "PAYMENT.AUTHORIZATION.CREATED",
"summary": "A payment authorization was created",
"resource": {
"id": "2DC87612EK520411B",
"create_time": "2013-06-25T21:39:15Z",
"update_time": "2013-06-25T21:39:17Z",
"state": "authorized",
"amount": {
"total": "7.47",
"currency": "USD",
"details": {
"subtotal": "7.47"
}
},
"parent_payment": "PAY-36246664YD343335CKHFA4AY",
"valid_until": "2013-07-24T21:39:15Z",
"links": [
{
"href": "https://api.paypal.com/v1/payments/authorization/2DC87612EK520411B",
"rel": "self",
"method": "GET"
},
{
"href": "https://api.paypal.com/v1/payments/authorization/2DC87612EK520411B/capture",
"rel": "capture",
"method": "POST"
},
{
"href": "https://api.paypal.com/v1/payments/authorization/2DC87612EK520411B/void",
"rel": "void",
"method": "POST"
},
{
"href": "https://api.paypal.com/v1/payments/payment/PAY-36246664YD343335CKHFA4AY",
"rel": "parent_payment",
"method": "GET"
}
]
}
}
}', true);
}
}
@@ -0,0 +1,306 @@
<?php
namespace Srmklive\PayPal\Tests\Mocks\Responses;
use GuzzleHttp\Utils;
trait BillingPlans
{
/**
* @return array
*/
private function mockCreatePlansResponse(): array
{
return Utils::jsonDecode('{
"id": "P-5ML4271244454362WXNWU5NQ",
"product_id": "PROD-XXCD1234QWER65782",
"name": "Video Streaming Service Plan",
"description": "Video Streaming Service basic plan",
"status": "ACTIVE",
"billing_cycles": [
{
"frequency": {
"interval_unit": "MONTH",
"interval_count": 1
},
"tenure_type": "TRIAL",
"sequence": 1,
"total_cycles": 2,
"pricing_scheme": {
"fixed_price": {
"value": "3",
"currency_code": "USD"
},
"version": 1,
"create_time": "2020-05-27T12:13:51Z",
"update_time": "2020-05-27T12:13:51Z"
}
},
{
"frequency": {
"interval_unit": "MONTH",
"interval_count": 1
},
"tenure_type": "TRIAL",
"sequence": 2,
"total_cycles": 3,
"pricing_scheme": {
"fixed_price": {
"currency_code": "USD",
"value": "6"
},
"version": 1,
"create_time": "2020-05-27T12:13:51Z",
"update_time": "2020-05-27T12:13:51Z"
}
},
{
"frequency": {
"interval_unit": "MONTH",
"interval_count": 1
},
"tenure_type": "REGULAR",
"sequence": 3,
"total_cycles": 12,
"pricing_scheme": {
"fixed_price": {
"currency_code": "USD",
"value": "10"
},
"version": 1,
"create_time": "2020-05-27T12:13:51Z",
"update_time": "2020-05-27T12:13:51Z"
}
}
],
"payment_preferences": {
"auto_bill_outstanding": true,
"setup_fee": {
"value": "10",
"currency_code": "USD"
},
"setup_fee_failure_action": "CONTINUE",
"payment_failure_threshold": 3
},
"taxes": {
"percentage": "10",
"inclusive": false
},
"create_time": "2020-05-27T12:13:51Z",
"update_time": "2020-05-27T12:13:51Z",
"links": [
{
"href": "https://api.paypal.com/v1/billing/plans/P-5ML4271244454362WXNWU5NQ",
"rel": "self",
"method": "GET"
},
{
"href": "https://api.paypal.com/v1/billing/plans/P-5ML4271244454362WXNWU5NQ",
"rel": "edit",
"method": "PATCH"
},
{
"href": "https://api.paypal.com/v1/billing/plans/P-5ML4271244454362WXNWU5NQ/deactivate",
"rel": "deactivate",
"method": "POST"
},
{
"href": "https://api.paypal.com/v1/billing/plans/P-5ML4271244454362WXNWU5NQ/update-pricing-schemes",
"rel": "edit",
"method": "POST"
}
]
}', true);
}
/**
* @return array
*/
private function mockListPlansResponse(): array
{
return Utils::jsonDecode('{
"total_items": 12,
"total_pages": 6,
"plans": [
{
"id": "P-5ML4271244454362WXNWU5NQ",
"product_id": "PROD-XXCD1234QWER65782",
"status": "ACTIVE",
"name": "Zoho Marketing Campaign Plan",
"description": "Zoho Marketing Campaign Plan",
"create_time": "2018-12-10T21:20:49Z",
"links": [
{
"href": "https://api.paypal.com/v1/billing/plans/P-5ML4271244454362WXNWU5NQ",
"rel": "self",
"method": "GET"
}
]
},
{
"id": "P-6LL4271454454362WXNWU5NQ",
"product_id": "PROD-XXCD1234QWER65782",
"status": "ACTIVE",
"name": "Zoho Marketing Campaign Basic Plan",
"description": "Zoho Marketing Campaign Plan",
"create_time": "2019-01-10T21:20:49Z",
"links": [
{
"href": "https://api.paypal.com/v1/billing/plans/P-6LL4271454454362WXNWU5NQ",
"rel": "self",
"method": "GET"
}
]
}
],
"links": [
{
"href": "https://api.paypal.com/v1/billing/plans?product_id=PROD-XXCD1234QWER65782&page_size=2&page=1",
"rel": "self",
"method": "GET"
},
{
"href": "https://api.paypal.com/v1/billing/plans?product_id=PROD-XXCD1234QWER65782&page_size=2&page=1",
"rel": "first",
"method": "GET"
},
{
"href": "https://api.paypal.com/v1/billing/plans?product_id=PROD-XXCD1234QWER65782&page_size=2&page=2",
"rel": "next",
"method": "GET"
},
{
"href": "https://api.paypal.com/v1/billing/plans?product_id=PROD-XXCD1234QWER65782&page_size=2&page=6",
"rel": "last",
"method": "GET"
}
]
}', true);
}
/**
* @return array
*/
private function mockGetPlansResponse(): array
{
return Utils::jsonDecode('{
"id": "P-5ML4271244454362WXNWU5NQ",
"product_id": "PROD-XXCD1234QWER65782",
"name": "Basic Plan",
"description": "Basic Plan",
"status": "ACTIVE",
"billing_cycles": [
{
"frequency": {
"interval_unit": "MONTH",
"interval_count": 1
},
"tenure_type": "TRIAL",
"sequence": 1,
"total_cycles": 2,
"pricing_scheme": {
"fixed_price": {
"currency_code": "USD",
"value": "3"
},
"version": 1,
"create_time": "2020-05-27T12:13:51Z",
"update_time": "2020-05-27T12:13:51Z"
}
},
{
"frequency": {
"interval_unit": "MONTH",
"interval_count": 1
},
"tenure_type": "TRIAL",
"sequence": 2,
"total_cycles": 3,
"pricing_scheme": {
"fixed_price": {
"currency_code": "USD",
"value": "6"
},
"version": 1,
"create_time": "2020-05-27T12:13:51Z",
"update_time": "2020-05-27T12:13:51Z"
}
},
{
"frequency": {
"interval_unit": "MONTH",
"interval_count": 1
},
"tenure_type": "REGULAR",
"sequence": 3,
"total_cycles": 12,
"pricing_scheme": {
"fixed_price": {
"value": "10",
"currency_code": "USD"
},
"status": "ACTIVE",
"version": 1,
"create_time": "2020-05-27T12:13:51Z",
"update_time": "2020-05-27T12:13:51Z"
}
}
],
"taxes": {
"percentage": "10",
"inclusive": false
},
"create_time": "2020-05-27T12:13:51Z",
"update_time": "2020-05-27T12:13:51Z",
"links": [
{
"href": "https://api.paypal.com/v1/billing/plans/P-5ML4271244454362WXNWU5NQ",
"rel": "self",
"method": "GET"
},
{
"href": "https://api.paypal.com/v1/billing/plans/P-5ML4271244454362WXNWU5NQ",
"rel": "edit",
"method": "PATCH"
},
{
"href": "https://api.paypal.com/v1/billing/plans/P-5ML4271244454362WXNWU5NQ/deactivate",
"rel": "deactivate",
"method": "POST"
},
{
"href": "https://api.paypal.com/v1/billing/plans/P-5ML4271244454362WXNWU5NQ/update-pricing-schemes",
"rel": "edit",
"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);
}
}
@@ -0,0 +1,153 @@
<?php
namespace Srmklive\PayPal\Tests\Mocks\Responses;
use GuzzleHttp\Utils;
trait CatalogProducts
{
/**
* @return array
*/
private function mockCreateCatalogProductsResponse(): array
{
return Utils::jsonDecode('{
"id": "PROD-XYAB12ABSB7868434",
"name": "Video Streaming Service",
"description": "Video streaming service",
"type": "SERVICE",
"category": "SOFTWARE",
"image_url": "https://example.com/streaming.jpg",
"home_url": "https://example.com/home",
"create_time": "2020-01-10T21:20:49Z",
"update_time": "2020-01-10T21:20:49Z",
"links": [
{
"href": "https://api.paypal.com/v1/catalogs/products/72255d4849af8ed6e0df1173",
"rel": "self",
"method": "GET"
},
{
"href": "https://api.paypal.com/v1/catalogs/products/72255d4849af8ed6e0df1173",
"rel": "edit",
"method": "PATCH"
}
]
}', true);
}
/**
* @return array
*/
private function mockListCatalogProductsResponse(): array
{
return Utils::jsonDecode('{
"total_items": 20,
"total_pages": 1,
"products": [
{
"id": "72255d4849af8ed6e0df1173",
"name": "Video Streaming Service",
"description": "Video streaming service",
"create_time": "2018-12-10T21:20:49Z",
"links": [
{
"href": "https://api.paypal.com/v1/catalogs/products/72255d4849af8ed6e0df1173",
"rel": "self",
"method": "GET"
}
]
},
{
"id": "PROD-XYAB12ABSB7868434",
"name": "Video Streaming Service",
"description": "Audio streaming service",
"create_time": "2018-12-10T21:20:49Z",
"links": [
{
"href": "https://api.paypal.com/v1/catalogs/products/125d4849af8ed6e0df18",
"rel": "self",
"method": "GET"
}
]
}
],
"links": [
{
"href": "https://api.paypal.com/v1/catalogs/products?page_size=2&page=1",
"rel": "self",
"method": "GET"
},
{
"href": "https://api.paypal.com/v1/catalogs/products?page_size=2&page=2",
"rel": "next",
"method": "GET"
},
{
"href": "https://api.paypal.com/v1/catalogs/products?page_size=2&page=10",
"rel": "last",
"method": "GET"
}
]
}', true);
}
/**
* @return array
*/
private function mockGetCatalogProductsResponse(): array
{
return Utils::jsonDecode('{
"id": "72255d4849af8ed6e0df1173",
"name": "Video Streaming Service",
"description": "Video streaming service",
"type": "SERVICE",
"category": "SOFTWARE",
"image_url": "https://example.com/streaming.jpg",
"home_url": "https://example.com/home",
"create_time": "2018-12-10T21:20:49Z",
"update_time": "2018-12-10T21:20:49Z",
"links": [
{
"href": "https://api.paypal.com/v1/catalogs/products/72255d4849af8ed6e0df1173",
"rel": "self",
"method": "GET"
},
{
"href": "https://api.paypal.com/v1/catalogs/products/72255d4849af8ed6e0df1173",
"rel": "edit",
"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);
}
}
@@ -0,0 +1,145 @@
<?php
namespace Srmklive\PayPal\Tests\Mocks\Responses;
use GuzzleHttp\Utils;
trait Disputes
{
/**
* @return array
*/
private function mockListDisputesResponse(): array
{
return Utils::jsonDecode('{
"items": [
{
"dispute_id": "PP-000-003-648-191",
"create_time": "2017-01-24T10:41:35.000Z",
"update_time": "2017-01-24T11:40:32.000Z",
"status": "WAITING_FOR_SELLER_RESPONSE",
"reason": "MERCHANDISE_OR_SERVICE_NOT_RECEIVED",
"dispute_state": "REQUIRED_OTHER_PARTY_ACTION",
"dispute_amount": {
"currency_code": "USD",
"value": "50.00"
},
"links": [
{
"href": "https://api-m.sandbox.paypal.com/v1/customer/disputes/PP-000-003-648-191",
"rel": "self",
"method": "GET"
}
]
},
{
"dispute_id": "PP-000-003-648-175",
"create_time": "2017-01-24T10:37:23.000Z",
"update_time": "2017-01-24T11:32:32.000Z",
"status": "UNDER_REVIEW",
"reason": "UNAUTHORISED",
"dispute_amount": {
"currency_code": "USD",
"value": "20.00"
},
"links": [
{
"href": "https://api-m.sandbox.paypal.com/v1/customer/disputes/PP-000-003-648-175",
"rel": "self",
"method": "GET"
}
]
}
],
"links": [
{
"href": "https://api-m.sandbox.paypal.com/v1/customer/disputes",
"rel": "self",
"method": "GET"
},
{
"href": "https://api-m.sandbox.paypal.com/v1/customer/disputes",
"rel": "first",
"method": "GET"
}
]
}', true);
}
/**
* @return array
*/
private function mockGetDisputesResponse(): array
{
return Utils::jsonDecode('{
"dispute_id": "PP-D-4012",
"create_time": "2019-04-11T04:18:00.000Z",
"update_time": "2019-04-21T04:19:08.000Z",
"disputed_transactions": [
{
"seller_transaction_id": "3BC38643YC807283D",
"create_time": "2019-04-11T04:16:58.000Z",
"transaction_status": "REVERSED",
"gross_amount": {
"currency_code": "USD",
"value": "192.00"
},
"buyer": {
"name": "Lupe Justin"
},
"seller": {
"email": "merchant@example.com",
"merchant_id": "5U29WL78XSAEL",
"name": "Lesley Paul"
}
}
],
"reason": "MERCHANDISE_OR_SERVICE_NOT_AS_DESCRIBED",
"status": "RESOLVED",
"dispute_amount": {
"currency_code": "USD",
"value": "96.00"
},
"dispute_outcome": {
"outcome_code": "RESOLVED_BUYER_FAVOUR",
"amount_refunded": {
"currency_code": "USD",
"value": "96.00"
}
},
"dispute_life_cycle_stage": "CHARGEBACK",
"dispute_channel": "INTERNAL",
"messages": [
{
"posted_by": "BUYER",
"time_posted": "2019-04-11T04:18:04.000Z",
"content": "SNAD case created through automation"
}
],
"extensions": {
"merchandize_dispute_properties": {
"issue_type": "SERVICE",
"service_details": {
"sub_reasons": [
"INCOMPLETE"
],
"purchase_url": "https://ebay.in"
}
}
},
"offer": {
"buyer_requested_amount": {
"currency_code": "USD",
"value": "96.00"
}
},
"links": [
{
"href": "https://api-m.sandbox.paypal.com/v1/customer/disputes/PP-D-4012",
"rel": "self",
"method": "GET"
}
]
}', true);
}
}
@@ -0,0 +1,56 @@
<?php
namespace Srmklive\PayPal\Tests\Mocks\Responses;
use GuzzleHttp\Utils;
trait DisputesActions
{
/**
* @return array
*/
private function mockAcceptDisputesClaimResponse(): array
{
return Utils::jsonDecode('{
"links": [
{
"rel": "self",
"method": "GET",
"href": "https://api-m.sandbox.paypal.com/v1/customer/disputes/PP-D-27803"
}
]
}', true);
}
/**
* @return array
*/
private function mockAcceptDisputesOfferResolutionResponse(): array
{
return Utils::jsonDecode('{
"links": [
{
"rel": "self",
"method": "GET",
"href": "https://api-m.sandbox.paypal.com/v1/customer/disputes/PP-000-000-651-454"
}
]
}', true);
}
/**
* @return array
*/
private function mockAcknowledgeItemReturnedResponse(): array
{
return Utils::jsonDecode('{
"links": [
{
"rel": "self",
"method": "GET",
"href": "https://api-m.sandbox.paypal.com/v1/customer/disputes/PP-000-000-651-454"
}
]
}', true);
}
}
@@ -0,0 +1,182 @@
<?php
namespace Srmklive\PayPal\Tests\Mocks\Responses;
use GuzzleHttp\Utils;
trait Identity
{
private function mockShowProfileInfoResponse(): array
{
return Utils::jsonDecode('{
"address": {
"street_address": "7917394 Annursnac Hill Road Unit 0C",
"locality": "Ventura",
"region": "CA",
"postal_code": "93003",
"country": "US"
}
}', true);
}
private function mocklistUsersResponse(): array
{
return Utils::jsonDecode('{
"schemas": [
"http://example.com"
],
"startIndex": 1,
"itemsPerPage": 1,
"totalResults": 5000,
"Resources": [
{
"schemas": [
"http://example.com"
],
"externalId": "string",
"userName": "string",
"name": {
"familyName": "string",
"givenName": "string",
"middleName": "string",
"honorificPrefix": "string",
"honorificSuffix": "string"
},
"active": true,
"emails": [
{
"type": "work",
"primary": true,
"value": "string"
}
],
"phoneNumbers": [
{
"value": "string",
"type": "work",
"primary": true
}
],
"addresses": [
{
"streetAddress": "string",
"locality": "string",
"region": "string",
"postalCode": "string",
"type": "work",
"country": "string"
}
],
"entitlements": [
{
"value": "string"
}
],
"id": "string",
"meta": {
"resourceType": "User",
"location": "http://example.com",
"created": "string",
"lastModified": "string"
},
"preferredLanguage": "string",
"timezone": "string"
}
]
}', true);
}
private function mocklistUserResponse(): array
{
return Utils::jsonDecode('{
"schemas": [
"http://example.com"
],
"externalId": "string",
"userName": "string",
"name": {
"familyName": "string",
"givenName": "string",
"middleName": "string",
"honorificPrefix": "string",
"honorificSuffix": "string"
},
"active": true,
"emails": [
{
"type": "work",
"primary": true,
"value": "string"
}
],
"phoneNumbers": [
{
"value": "string",
"type": "work",
"primary": true
}
],
"addresses": [
{
"streetAddress": "string",
"locality": "string",
"region": "string",
"postalCode": "string",
"type": "work",
"country": "string"
}
],
"entitlements": [
{
"value": "string"
}
],
"id": "string",
"meta": {
"resourceType": "User",
"location": "http://example.com",
"created": "string",
"lastModified": "string"
},
"preferredLanguage": "string",
"timezone": "string"
}', true);
}
private function mockCreateMerchantApplicationResponse(): array
{
return Utils::jsonDecode('{
"client_id": "AeTeCqaPp7JZBfUUb2d21cQ2KqyQGVhonfiUOJu99kgLhFFSrE59ruvhLOT4K3NzQoErgsUH6MY9uRqD",
"client_secret": "cf136dc3c1fc93f31185e5885805d",
"client_id_issued_at": 2893256800,
"client_secret_expires_at": 2893276800,
"redirect_uris": [
"https://example.com/callback",
"https://example.com/callback2"
],
"grant_types": [
"authorization_code",
"refresh_token"
],
"client_name": "AGGREGATOR",
"logo_uri": "https://example.com/logo.png",
"contacts": [
"facilitator@example.com",
"merchant@example.com"
],
"policy_uri": "https://example.com/policyuri",
"tos_uri": "https://example.com/tosuri",
"scope": "profile email address",
"token_endpoint_auth_method": "client_secret_basic",
"jwks_uri": "https://example.com/my_public_keys.jwks"
}', true);
}
private function mockGetClientTokenResponse(): array
{
return Utils::jsonDecode('{
"client_token": "eyJicmFpbnRyZWUiOnsiYXV0aG9yaXphdGlvbkZpbmdlcnByaW50IjoiYjA0MWE2M2JlMTM4M2NlZGUxZTI3OWFlNDlhMWIyNzZlY2FjOTYzOWU2NjlhMGIzODQyYTdkMTY3NzcwYmY0OHxtZXJjaGFudF9pZD1yd3dua3FnMnhnNTZobTJuJnB1YmxpY19rZXk9czlic3BuaGtxMmYzaDk0NCZjcmVhdGVkX2F0PTIwMTgtMTEtMTRUMTE6MTg6MDAuMTU3WiIsInZlcnNpb24iOiIzLXBheXBhbCJ9LCJwYXlwYWwiOnsiYWNjZXNzVG9rZW4iOiJBMjFBQUhNVExyMmctVDlhSTJacUZHUmlFZ0ZFZGRHTGwxTzRlX0lvdk9ESVg2Q3pSdW5BVy02TzI2MjdiWUJ2cDNjQ0FNWi1lTFBNc2NDWnN0bDUyNHJyUGhUQklJNlBBIn19",
"expires_in": 3600
}', true);
}
}

Some files were not shown because too many files have changed in this diff Show More