Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a3004b382b | ||
|
|
60e6be57f9 | ||
|
|
7d244da111 | ||
|
|
e9b01b5266 | ||
|
|
db79fee3d2 | ||
|
|
3118f9e4e0 | ||
|
|
f4fac20f19 | ||
|
|
28197bf65f | ||
|
|
108f18b444 | ||
|
|
5e2ba7e3f5 | ||
|
|
9bbb7e8ebe | ||
|
|
60e7b42de2 | ||
|
|
c115b04157 | ||
|
|
385b7f6882 | ||
|
|
b88cd1cf5c | ||
|
|
8b119a836a |
2
.github/workflows/code_style.yml
vendored
2
.github/workflows/code_style.yml
vendored
@ -8,7 +8,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Run PHP CS Fixer
|
||||
uses: docker://oskarstark/php-cs-fixer-ga
|
||||
|
||||
106
.github/workflows/phpunit.yml
vendored
106
.github/workflows/phpunit.yml
vendored
@ -1,53 +1,53 @@
|
||||
name: PHP Unit Tests
|
||||
env:
|
||||
BTCPAY_HOST: ${{ secrets.BTCPAY_HOST }}
|
||||
BTCPAY_API_KEY: ${{ secrets.BTCPAY_API_KEY }}
|
||||
BTCPAY_STORE_ID: ${{ secrets.BTCPAY_STORE_ID }}
|
||||
BTCPAY_NODE_URI: ${{ secrets.BTCPAY_NODE_URI }}
|
||||
on: [ push, pull_request ]
|
||||
|
||||
jobs:
|
||||
phpunit:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
php-versions: ['8.0', '8.1']
|
||||
phpunit-versions: ['latest']
|
||||
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: '0'
|
||||
|
||||
- name: Setup PHP, with composer and extensions
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php-versions }}
|
||||
tools: composer:v2, phpunit:${{ matrix.phpunit-versions }}
|
||||
extensions: curl, json, mbstring, bcmath
|
||||
coverage: xdebug #optional
|
||||
|
||||
- name: Get composer cache directory
|
||||
id: composer-cache
|
||||
run: echo "::set-output name=dir::$(composer config cache-files-dir)"
|
||||
|
||||
- name: Cache composer dependencies
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ${{ steps.composer-cache.outputs.dir }}
|
||||
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
|
||||
restore-keys: ${{ runner.os }}-composer-
|
||||
|
||||
- name: Install Composer dependencies
|
||||
run: composer install --no-progress --optimize-autoloader
|
||||
|
||||
- name: Test with phpunit
|
||||
run: vendor/bin/phpunit --coverage-text
|
||||
|
||||
- name: Setup problem matchers for PHP
|
||||
run: echo "::add-matcher::${{ runner.tool_cache }}/php.json"
|
||||
|
||||
- name: Setup problem matchers for PHPUnit
|
||||
run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json"
|
||||
#name: PHP Unit Tests
|
||||
#env:
|
||||
# BTCPAY_HOST: ${{ secrets.BTCPAY_HOST }}
|
||||
# BTCPAY_API_KEY: ${{ secrets.BTCPAY_API_KEY }}
|
||||
# BTCPAY_STORE_ID: ${{ secrets.BTCPAY_STORE_ID }}
|
||||
# BTCPAY_NODE_URI: ${{ secrets.BTCPAY_NODE_URI }}
|
||||
#on: [ push, pull_request ]
|
||||
#
|
||||
#jobs:
|
||||
# phpunit:
|
||||
# runs-on: ubuntu-latest
|
||||
# strategy:
|
||||
# matrix:
|
||||
# php-versions: ['8.0', '8.1']
|
||||
# phpunit-versions: ['latest']
|
||||
#
|
||||
#
|
||||
# steps:
|
||||
# - name: Checkout
|
||||
# uses: actions/checkout@v3
|
||||
# with:
|
||||
# fetch-depth: '0'
|
||||
#
|
||||
# - name: Setup PHP, with composer and extensions
|
||||
# uses: shivammathur/setup-php@v2
|
||||
# with:
|
||||
# php-version: ${{ matrix.php-versions }}
|
||||
# tools: composer:v2, phpunit:${{ matrix.phpunit-versions }}
|
||||
# extensions: curl, json, mbstring, bcmath
|
||||
# coverage: xdebug #optional
|
||||
#
|
||||
# - name: Get composer cache directory
|
||||
# id: composer-cache
|
||||
# run: echo "::set-output name=dir::$(composer config cache-files-dir)"
|
||||
#
|
||||
# - name: Cache composer dependencies
|
||||
# uses: actions/cache@v2
|
||||
# with:
|
||||
# path: ${{ steps.composer-cache.outputs.dir }}
|
||||
# key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
|
||||
# restore-keys: ${{ runner.os }}-composer-
|
||||
#
|
||||
# - name: Install Composer dependencies
|
||||
# run: composer install --no-progress --optimize-autoloader
|
||||
#
|
||||
# - name: Test with phpunit
|
||||
# run: vendor/bin/phpunit --coverage-text
|
||||
#
|
||||
# - name: Setup problem matchers for PHP
|
||||
# run: echo "::add-matcher::${{ runner.tool_cache }}/php.json"
|
||||
#
|
||||
# - name: Setup problem matchers for PHPUnit
|
||||
# run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json"
|
||||
|
||||
4
.github/workflows/psalm.yml
vendored
4
.github/workflows/psalm.yml
vendored
@ -12,7 +12,7 @@ jobs:
|
||||
php-versions: ['8.0']
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: '0'
|
||||
|
||||
@ -27,7 +27,7 @@ jobs:
|
||||
run: echo "::set-output name=dir::$(composer config cache-files-dir)"
|
||||
|
||||
- name: Cache composer dependencies
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: ${{ steps.composer-cache.outputs.dir }}
|
||||
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@ -3,4 +3,5 @@
|
||||
.php-cs-fixer.cache
|
||||
*.cache
|
||||
composer.lock
|
||||
/tests/.env
|
||||
/tests/.env
|
||||
/.claude/
|
||||
@ -22,3 +22,22 @@ try {
|
||||
} catch (\Throwable $e) {
|
||||
echo "Error: " . $e->getMessage();
|
||||
}
|
||||
|
||||
// Get 2 invoices, skip 2
|
||||
try {
|
||||
echo 'Get invoices:' . PHP_EOL;
|
||||
$client = new Invoice($host, $apiKey);
|
||||
var_dump($client->getAllInvoices($storeId, 2, 2));
|
||||
} catch (\Throwable $e) {
|
||||
echo "Error: " . $e->getMessage();
|
||||
}
|
||||
|
||||
// Get newer/equal than 2024-10-20
|
||||
try {
|
||||
echo 'Get invoices newer/equal than 2024-10-20:' . PHP_EOL;
|
||||
$date = new DateTime('2024-10-20');
|
||||
$client = new Invoice($host, $apiKey);
|
||||
var_dump($client->getAllInvoicesWithFilter($storeId, null, null, null, $date->getTimestamp()));
|
||||
} catch (\Throwable $e) {
|
||||
echo "Error: " . $e->getMessage();
|
||||
}
|
||||
|
||||
@ -43,7 +43,7 @@ class PullPayments
|
||||
$autoApproveClaims = false;
|
||||
$startsAt = null;
|
||||
$expiresAt = null;
|
||||
$paymentMethods = ['BTC'];
|
||||
$paymentMethods = ['BTC-CHAIN'];
|
||||
|
||||
try {
|
||||
$client = new PullPayment($this->host, $this->apiKey);
|
||||
@ -113,7 +113,7 @@ class PullPayments
|
||||
|
||||
public function approvePayout()
|
||||
{
|
||||
$payoutId ='';
|
||||
$payoutId = '';
|
||||
try {
|
||||
$client = new PullPayment($this->host, $this->apiKey);
|
||||
var_dump($client->approvePayout(
|
||||
@ -163,7 +163,7 @@ class PullPayments
|
||||
$pullPaymentId = '';
|
||||
$destination = '';
|
||||
$amount = PreciseNumber::parseString('0.000001');
|
||||
$paymentMethod = '';
|
||||
$paymentMethod = 'BTC-CHAIN';
|
||||
|
||||
try {
|
||||
$client = new PullPayment($this->host, $this->apiKey);
|
||||
|
||||
@ -32,6 +32,21 @@ class StoreOnChainWallets
|
||||
}
|
||||
}
|
||||
|
||||
public function createStoreOnChainWallet()
|
||||
{
|
||||
$cryptoCode = 'BTC';
|
||||
|
||||
try {
|
||||
$client = new StoreOnChainWallet($this->host, $this->apiKey);
|
||||
var_dump($client->createStoreOnchainWallet(
|
||||
$this->storeId,
|
||||
$cryptoCode
|
||||
));
|
||||
} catch (\Throwable $e) {
|
||||
echo "Error: " . $e->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
public function getStoreOnChainWalletFeeRate()
|
||||
{
|
||||
$cryptoCode = 'BTC';
|
||||
@ -171,3 +186,4 @@ $store = new StoreOnChainWallets();
|
||||
$store->getStoreOnChainWalletTransactions();
|
||||
//$store->getStoreOnChainWalletTransaction();
|
||||
//$store->getStoreOnChainWalletUTXOs();
|
||||
//$store->createStoreOnChainWallet();
|
||||
|
||||
@ -8,9 +8,10 @@ use BTCPayServer\Client\Store;
|
||||
$apiKey = '';
|
||||
$host = ''; // e.g. https://your.btcpay-server.tld
|
||||
$storeId = '';
|
||||
$invoiceId = '';
|
||||
$updateStoreId = '';
|
||||
|
||||
// Get information about store on BTCPay Server.
|
||||
|
||||
try {
|
||||
$client = new Store($host, $apiKey);
|
||||
var_dump($client->getStore($storeId));
|
||||
@ -21,7 +22,17 @@ try {
|
||||
// Create a new store.
|
||||
try {
|
||||
$client = new Store($host, $apiKey);
|
||||
var_dump($client->createStore('my new store'));
|
||||
$newStore = $client->createStore('New store', null, 'EUR');
|
||||
var_dump($newStore);
|
||||
} catch (\Throwable $e) {
|
||||
echo "Error: " . $e->getMessage();
|
||||
}
|
||||
|
||||
// Update a store.
|
||||
// You need to pass all variables to make sure it does not get reset to defaults if you want to preserve them.
|
||||
try {
|
||||
$client = new Store($host, $apiKey);
|
||||
var_dump($client->updateStore($updateStoreId, 'Store name CHANGED'));
|
||||
} catch (\Throwable $e) {
|
||||
echo "Error: " . $e->getMessage();
|
||||
}
|
||||
242
examples/subscriptions.php
Normal file
242
examples/subscriptions.php
Normal file
@ -0,0 +1,242 @@
|
||||
<?php
|
||||
|
||||
// Include autoload file.
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
// Import Subscriptions client class.
|
||||
use BTCPayServer\Client\Subscriptions;
|
||||
|
||||
// Fill in with your BTCPay Server data.
|
||||
$apiKey = '';
|
||||
$host = ''; // e.g. https://your.btcpay-server.tld
|
||||
$storeId = '';
|
||||
|
||||
// Create the subscriptions client.
|
||||
try {
|
||||
$client = new Subscriptions($host, $apiKey);
|
||||
|
||||
echo "=== BTCPay Server Subscriptions API Examples ===\n\n";
|
||||
|
||||
// 1. Create a new offering
|
||||
echo "1. Creating a new offering...\n";
|
||||
$offering = $client->createOffering(
|
||||
$storeId,
|
||||
'Premium SaaS App',
|
||||
'https://example.com/success',
|
||||
[
|
||||
'category' => 'saas',
|
||||
'region' => 'us',
|
||||
'version' => '1.0'
|
||||
],
|
||||
[
|
||||
['id' => 'feature-analytics', 'description' => 'Advanced analytics dashboard'],
|
||||
['id' => 'feature-support', 'description' => '24/7 priority support'],
|
||||
['id' => 'feature-api', 'description' => 'Unlimited API access']
|
||||
]
|
||||
);
|
||||
echo "Offering created with ID: " . $offering->getId() . "\n";
|
||||
echo "App Name: " . $offering->getAppName() . "\n\n";
|
||||
|
||||
$offeringId = $offering->getId();
|
||||
|
||||
// 2. Create plans for the offering
|
||||
echo "2. Creating plans for the offering...\n";
|
||||
|
||||
// Basic plan
|
||||
$basicPlan = $client->createOfferingPlan(
|
||||
$storeId,
|
||||
$offeringId,
|
||||
'Basic monthly subscription with essential features',
|
||||
'USD',
|
||||
7,
|
||||
'Basic Plan',
|
||||
true,
|
||||
'1.99',
|
||||
true,
|
||||
null,
|
||||
['tier' => 'basic'],
|
||||
'Monthly',
|
||||
['feature-analytics']
|
||||
);
|
||||
echo "Basic plan created with ID: " . $basicPlan->getId() . "\n";
|
||||
|
||||
// Premium plan
|
||||
$premiumPlan = $client->createOfferingPlan(
|
||||
$storeId,
|
||||
$offeringId,
|
||||
'Premium monthly subscription with all features',
|
||||
'USD',
|
||||
7,
|
||||
'Premium Plan',
|
||||
true,
|
||||
'29.99',
|
||||
true,
|
||||
14,
|
||||
['tier' => 'premium'],
|
||||
'Monthly',
|
||||
['feature-analytics', 'feature-support', 'feature-api']
|
||||
);
|
||||
echo "Premium plan created with ID: " . $premiumPlan->getId() . "\n\n";
|
||||
|
||||
$basicPlanId = $basicPlan->getId();
|
||||
$premiumPlanId = $premiumPlan->getId();
|
||||
|
||||
// 2b. Update the offering
|
||||
echo "2b. Updating the offering...\n";
|
||||
$updatedOffering = $client->updateOffering(
|
||||
$storeId,
|
||||
$offeringId,
|
||||
'Premium SaaS App v2',
|
||||
'https://example.com/success-v2',
|
||||
['category' => 'saas', 'region' => 'eu', 'version' => '2.0']
|
||||
);
|
||||
echo "Offering updated: " . $updatedOffering->getAppName() . "\n\n";
|
||||
|
||||
// 2c. Update a plan
|
||||
echo "2c. Updating the basic plan...\n";
|
||||
$updatedPlan = $client->updateOfferingPlan(
|
||||
$storeId,
|
||||
$offeringId,
|
||||
$basicPlanId,
|
||||
'Updated basic monthly subscription',
|
||||
'USD',
|
||||
7,
|
||||
'Basic Plan v2',
|
||||
null,
|
||||
'2.99'
|
||||
);
|
||||
echo "Plan updated: " . $updatedPlan->getName() . " - " . $updatedPlan->getPrice() . " " . $updatedPlan->getCurrency() . "\n\n";
|
||||
|
||||
// 3. Get all offerings for the store
|
||||
echo "3. Getting all offerings for the store...\n";
|
||||
$offerings = $client->getOfferings($storeId);
|
||||
foreach ($offerings->all() as $off) {
|
||||
echo "- Offering: " . $off->getAppName() . " (ID: " . $off->getId() . ")\n";
|
||||
foreach ($off->getPlans() as $plan) {
|
||||
echo " - Plan: " . $plan->getName() . " - " . $plan->getPrice() . " " . $plan->getCurrency() . "/" . $plan->getRecurringType() . "\n";
|
||||
}
|
||||
}
|
||||
echo "\n";
|
||||
|
||||
// 4. Get a specific offering
|
||||
echo "4. Getting specific offering details...\n";
|
||||
$specificOffering = $client->getOffering($storeId, $offeringId);
|
||||
echo "Offering: " . $specificOffering->getAppName() . "\n";
|
||||
echo "Success URL: " . $specificOffering->getSuccessRedirectUrl() . "\n";
|
||||
echo "Number of plans: " . count($specificOffering->getPlans()) . "\n\n";
|
||||
|
||||
// 5. Get a specific plan
|
||||
echo "5. Getting specific plan details...\n";
|
||||
$specificPlan = $client->getOfferingPlan($storeId, $offeringId, $basicPlanId);
|
||||
echo "Plan: " . $specificPlan->getName() . "\n";
|
||||
echo "Price: " . $specificPlan->getPrice() . " " . $specificPlan->getCurrency() . "\n";
|
||||
echo "Trial Days: " . $specificPlan->getTrialDays() . "\n";
|
||||
echo "Features: " . implode(', ', $specificPlan->getFeatures()) . "\n\n";
|
||||
|
||||
// 6. Create a plan checkout session
|
||||
echo "6. Creating a plan checkout session...\n";
|
||||
$checkout = $client->createPlanCheckout(
|
||||
$storeId,
|
||||
$offeringId,
|
||||
$basicPlanId,
|
||||
null, // If the customer already exists on BTCPay, fill the email or other id here.
|
||||
60,
|
||||
'SoftMigration',
|
||||
['source' => 'web'],
|
||||
['campaign' => 'summer2026'],
|
||||
['flow' => 'new_signup'],
|
||||
false,
|
||||
null, // You can override the plan price here if you want to force more credit or custom amount.
|
||||
'https://example.com/welcome',
|
||||
'test@example.com' // This is optional and will prefill the checkout page with the email.
|
||||
);
|
||||
echo "Checkout created with ID: " . $checkout->getId() . "\n";
|
||||
echo "Checkout URL: " . $checkout->getUrl() . "\n";
|
||||
echo "Is Trial: " . ($checkout->isTrial() ? 'Yes' : 'No') . "\n";
|
||||
echo "New Subscriber: " . ($checkout->isNewSubscriber() ? 'Yes' : 'No') . "\n\n";
|
||||
|
||||
$checkoutId = $checkout->getId();
|
||||
|
||||
// 7. Get plan checkout details
|
||||
echo "7. Getting plan checkout details...\n";
|
||||
$checkoutDetails = $client->getPlanCheckout($checkoutId);
|
||||
echo "Checkout ID: " . $checkoutDetails->getId() . "\n";
|
||||
echo "Plan: " . $checkoutDetails->getPlan()->getName() . "\n";
|
||||
$subscriber = $checkoutDetails->getSubscriber();
|
||||
if ($subscriber && $subscriber->getCustomer()->getIdentities()) {
|
||||
echo "Subscriber Email: " . ($subscriber->getCustomer()->getIdentities()['Email'] ?? 'N/A') . "\n";
|
||||
}
|
||||
echo "\n";
|
||||
|
||||
// 8. Subscriber management examples
|
||||
/*
|
||||
// Fill these variables with actual values to test subscriber operations
|
||||
$offeringId = ''; // e.g. "offering_GFbMSBpybM6i5uEiqc"
|
||||
$customerSelector = ''; // e.g. "ps_N71XxcPDnKNgNDxKHZ" or customer email
|
||||
$suspensionReason = 'User requested cancellation';
|
||||
|
||||
if (!empty($storeId) && !empty($offeringId) && !empty($customerSelector)) {
|
||||
try {
|
||||
// Get subscriber details
|
||||
echo "8. Getting subscriber details...\n";
|
||||
$subscriber = $client->getSubscriber($storeId, $offeringId, $customerSelector);
|
||||
echo "Customer ID: " . $subscriber->getCustomer()->getId() . "\n";
|
||||
echo "Active: " . ($subscriber->isActive() ? 'Yes' : 'No') . "\n";
|
||||
echo "Phase: " . $subscriber->getPhase() . "\n";
|
||||
echo "Created: " . date('Y-m-d H:i:s', $subscriber->getCreated()) . "\n";
|
||||
echo "\n";
|
||||
|
||||
// Suspend subscriber
|
||||
if (!empty($suspensionReason)) {
|
||||
echo "9. Suspending subscriber...\n";
|
||||
$client->suspendSubscriber($storeId, $offeringId, $customerSelector, $suspensionReason);
|
||||
echo "Subscriber suspended successfully!\n";
|
||||
|
||||
// Check status after suspension
|
||||
$suspendedSubscriber = $client->getSubscriber($storeId, $offeringId, $customerSelector);
|
||||
echo "Status after suspension: " . ($suspendedSubscriber->isActive() ? 'Active' : 'Suspended') . "\n";
|
||||
echo "Suspension reason: " . ($suspendedSubscriber->getSuspensionReason() ?? 'N/A') . "\n\n";
|
||||
|
||||
// Update subscriber dates
|
||||
echo "9b. Updating subscriber dates...\n";
|
||||
$updatedSubscriber = $client->updateSubscriberDates(
|
||||
$storeId,
|
||||
$offeringId,
|
||||
$customerSelector,
|
||||
null,
|
||||
time() + (30 * 24 * 60 * 60) // 30 days from now
|
||||
);
|
||||
echo "Subscriber expiration updated\n";
|
||||
echo "Scheduled plan: " . ($updatedSubscriber->getScheduledPlan() ? $updatedSubscriber->getScheduledPlan()->getName() : 'None') . "\n";
|
||||
echo "Scheduled plan activates at: " . ($updatedSubscriber->getScheduledPlanActivatesAt() ? date('Y-m-d H:i:s', $updatedSubscriber->getScheduledPlanActivatesAt()) : 'N/A') . "\n\n";
|
||||
|
||||
// Unsuspend subscriber
|
||||
echo "10. Unsuspending subscriber...\n";
|
||||
$client->unsuspendSubscriber($storeId, $offeringId, $customerSelector);
|
||||
echo "Subscriber unsuspended successfully!\n";
|
||||
|
||||
// Check status after unsuspending
|
||||
$reactivatedSubscriber = $client->getSubscriber($storeId, $offeringId, $customerSelector);
|
||||
echo "Status after unsuspending: " . ($reactivatedSubscriber->isActive() ? 'Active' : 'Suspended') . "\n";
|
||||
echo "Suspension reason: " . ($reactivatedSubscriber->getSuspensionReason() ?? 'N/A') . "\n\n";
|
||||
}
|
||||
|
||||
// Delete subscriber
|
||||
echo "11. Deleting subscriber...\n";
|
||||
$client->deleteSubscriber($storeId, $offeringId, $customerSelector);
|
||||
echo "Subscriber deleted successfully!\n\n";
|
||||
|
||||
} catch (\Throwable $e) {
|
||||
echo "Error in subscriber management: " . $e->getMessage() . "\n";
|
||||
}
|
||||
} else {
|
||||
echo "8. Subscriber management examples skipped - please fill in storeId, offeringId, and customerSelector variables\n";
|
||||
}
|
||||
*/
|
||||
|
||||
echo "=== Examples completed successfully! ===\n";
|
||||
|
||||
} catch (\Throwable $e) {
|
||||
echo "Error: " . $e->getMessage() . "\n";
|
||||
echo "Stack trace:\n" . $e->getTraceAsString() . "\n";
|
||||
}
|
||||
@ -22,7 +22,7 @@ class AbstractClient
|
||||
/** @var ClientInterface */
|
||||
private $httpClient;
|
||||
|
||||
public function __construct(string $baseUrl, string $apiKey, ClientInterface $client = null)
|
||||
public function __construct(string $baseUrl, string $apiKey, ?ClientInterface $client = null)
|
||||
{
|
||||
$this->baseUrl = rtrim($baseUrl, '/');
|
||||
$this->apiKey = $apiKey;
|
||||
|
||||
@ -7,6 +7,7 @@ namespace BTCPayServer\Client;
|
||||
use BTCPayServer\Result\Invoice as ResultInvoice;
|
||||
use BTCPayServer\Result\InvoiceList;
|
||||
use BTCPayServer\Result\InvoicePaymentMethod;
|
||||
use BTCPayServer\Result\PullPayment as ResultPullPayment;
|
||||
use BTCPayServer\Util\PreciseNumber;
|
||||
|
||||
class Invoice extends AbstractClient
|
||||
@ -115,19 +116,71 @@ class Invoice extends AbstractClient
|
||||
}
|
||||
}
|
||||
|
||||
public function getAllInvoices(string $storeId): InvoiceList
|
||||
{
|
||||
return $this->_getAllInvoicesWithFilter($storeId, null);
|
||||
}
|
||||
|
||||
public function getInvoicesByOrderIds(string $storeId, array $orderIds): InvoiceList
|
||||
{
|
||||
return $this->_getAllInvoicesWithFilter($storeId, $orderIds);
|
||||
}
|
||||
|
||||
private function _getAllInvoicesWithFilter(
|
||||
public function getAllInvoices(
|
||||
string $storeId,
|
||||
array $filterByOrderIds = null
|
||||
?int $take = null,
|
||||
?int $skip = null
|
||||
): InvoiceList {
|
||||
return $this->getAllInvoicesWithFilter($storeId, null, null, null, null, null, $take, $skip);
|
||||
}
|
||||
|
||||
public function getInvoicesByOrderIds(
|
||||
string $storeId,
|
||||
array $orderIds,
|
||||
?int $take = null,
|
||||
?int $skip = null
|
||||
): InvoiceList {
|
||||
return $this->getAllInvoicesWithFilter($storeId, $orderIds, null, null, null, null, $take, $skip);
|
||||
}
|
||||
|
||||
public function getInvoicesByText(
|
||||
string $storeId,
|
||||
string $text,
|
||||
?int $take = null,
|
||||
?int $skip = null
|
||||
): InvoiceList {
|
||||
return $this->getAllInvoicesWithFilter($storeId, null, $text, null, null, null, $take, $skip);
|
||||
}
|
||||
|
||||
public function getInvoicesByStatus(
|
||||
string $storeId,
|
||||
array $status,
|
||||
?int $take = null,
|
||||
?int $skip = null
|
||||
): InvoiceList {
|
||||
return $this->getAllInvoicesWithFilter($storeId, null, null, $status, null, null, $take, $skip);
|
||||
}
|
||||
|
||||
public function getInvoicesByStartDate(
|
||||
string $storeId,
|
||||
int $startDate,
|
||||
?int $take = null,
|
||||
?int $skip = null
|
||||
): InvoiceList {
|
||||
return $this->getAllInvoicesWithFilter($storeId, null, null, null, $startDate, null, $take, $skip);
|
||||
}
|
||||
|
||||
public function getInvoicesByEndDate(
|
||||
string $storeId,
|
||||
int $endDate,
|
||||
?int $take = null,
|
||||
?int $skip = null
|
||||
): InvoiceList {
|
||||
return $this->getAllInvoicesWithFilter($storeId, null, null, null, null, $endDate, $take, $skip);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see https://docs.btcpayserver.org/API/Greenfield/v1/#operation/Invoices_GetInvoices
|
||||
*/
|
||||
public function getAllInvoicesWithFilter(
|
||||
string $storeId,
|
||||
?array $filterByOrderIds = null,
|
||||
?string $filterByText = null,
|
||||
?array $filterByStatus = null,
|
||||
?int $filterByStartDate = null,
|
||||
?int $filterByEndDate = null,
|
||||
?int $take = null,
|
||||
?int $skip = null
|
||||
): InvoiceList {
|
||||
$url = $this->getApiUrl() . 'stores/' . urlencode($storeId) . '/invoices?';
|
||||
if ($filterByOrderIds !== null) {
|
||||
@ -135,6 +188,26 @@ class Invoice extends AbstractClient
|
||||
$url .= 'orderId=' . urlencode($filterByOrderId) . '&';
|
||||
}
|
||||
}
|
||||
if ($filterByText !== null) {
|
||||
$url .= 'textSearch=' . urlencode($filterByText) . '&';
|
||||
}
|
||||
if ($filterByStatus !== null) {
|
||||
foreach ($filterByStatus as $filterByStatusItem) {
|
||||
$url .= 'status=' . urlencode($filterByStatusItem) . '&';
|
||||
}
|
||||
}
|
||||
if ($filterByStartDate !== null) {
|
||||
$url .= 'startDate=' . $filterByStartDate . '&';
|
||||
}
|
||||
if ($filterByEndDate !== null) {
|
||||
$url .= 'endDate=' . $filterByEndDate . '&';
|
||||
}
|
||||
if ($take !== null) {
|
||||
$url .= 'take=' . $take . '&';
|
||||
}
|
||||
if ($skip !== null) {
|
||||
$url .= 'skip=' . $skip . '&';
|
||||
}
|
||||
|
||||
// Clean URL.
|
||||
$url = rtrim($url, '&');
|
||||
@ -159,7 +232,8 @@ class Invoice extends AbstractClient
|
||||
public function getPaymentMethods(string $storeId, string $invoiceId): array
|
||||
{
|
||||
$method = 'GET';
|
||||
$url = $this->getApiUrl() . 'stores/' . urlencode($storeId) . '/invoices/' . urlencode($invoiceId) . '/payment-methods';
|
||||
$url = $this->getApiUrl() . 'stores/' . urlencode($storeId) . '/invoices/'
|
||||
. urlencode($invoiceId) . '/payment-methods';
|
||||
$headers = $this->getRequestHeaders();
|
||||
$response = $this->getHttpClient()->request($method, $url, $headers);
|
||||
|
||||
@ -181,11 +255,15 @@ class Invoice extends AbstractClient
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark an invoice status.
|
||||
*
|
||||
* @see https://docs.btcpayserver.org/API/Greenfield/v1/#operation/Invoices_MarkInvoiceStatus
|
||||
* @throws \JsonException
|
||||
*/
|
||||
public function markInvoiceStatus(string $storeId, string $invoiceId, string $markAs): ResultInvoice
|
||||
{
|
||||
$url = $this->getApiUrl() . 'stores/' . urlencode(
|
||||
$storeId
|
||||
) . '/invoices/' . urlencode($invoiceId) . '/status';
|
||||
$url = $this->getApiUrl() . 'stores/' . urlencode($storeId) . '/invoices/' . urlencode($invoiceId) . '/status';
|
||||
$headers = $this->getRequestHeaders();
|
||||
$method = 'POST';
|
||||
|
||||
@ -206,4 +284,49 @@ class Invoice extends AbstractClient
|
||||
throw $this->getExceptionByStatusCode($method, $url, $response);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Refund an invoice.
|
||||
*
|
||||
* @see https://docs.btcpayserver.org/API/Greenfield/v1/#operation/Invoices_Refund
|
||||
* @throws \JsonException
|
||||
*/
|
||||
public function refundInvoice(
|
||||
string $storeId,
|
||||
string $invoiceId,
|
||||
?string $refundVariant = 'CurrentRate',
|
||||
?string $paymentMethod = 'BTC',
|
||||
?string $name = null,
|
||||
?string $description = null,
|
||||
?float $subtractPercentage = 0.0,
|
||||
?PreciseNumber $customAmount = null,
|
||||
?string $customCurrency = null
|
||||
): ResultPullPayment {
|
||||
$url = $this->getApiUrl() . 'stores/' . urlencode($storeId) . '/invoices/' . urlencode($invoiceId) . '/refund';
|
||||
$headers = $this->getRequestHeaders();
|
||||
$method = 'POST';
|
||||
|
||||
$body = json_encode(
|
||||
[
|
||||
'name' => $name,
|
||||
'description' => $description,
|
||||
'paymentMethod' => $paymentMethod,
|
||||
'refundVariant' => $refundVariant,
|
||||
'subtractPercentage' => $subtractPercentage,
|
||||
'customAmount' => $customAmount?->__toString(),
|
||||
'customCurrency' => $customCurrency
|
||||
],
|
||||
JSON_THROW_ON_ERROR
|
||||
);
|
||||
|
||||
$response = $this->getHttpClient()->request($method, $url, $headers, $body);
|
||||
|
||||
if ($response->getStatus() === 200) {
|
||||
return new ResultPullPayment(
|
||||
json_decode($response->getBody(), true, 512, JSON_THROW_ON_ERROR)
|
||||
);
|
||||
} else {
|
||||
throw $this->getExceptionByStatusCode($method, $url, $response);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -170,7 +170,7 @@ class InvoiceCheckoutOptions
|
||||
|
||||
$lastIndex = strrpos($k, $separator);
|
||||
if ($lastIndex !== false) {
|
||||
$k = substr($k, $lastIndex +1);
|
||||
$k = substr($k, $lastIndex + 1);
|
||||
}
|
||||
$array[$k] = $v;
|
||||
}
|
||||
|
||||
@ -50,7 +50,8 @@ class PullPayment extends AbstractClient
|
||||
?bool $autoApproveClaims = false,
|
||||
?int $startsAt,
|
||||
?int $expiresAt,
|
||||
array $paymentMethods
|
||||
?array $paymentMethods = null,
|
||||
?string $description = null
|
||||
): ResultPullPayment {
|
||||
$url = $this->getApiUrl() . 'stores/' .
|
||||
urlencode($storeId) . '/pull-payments';
|
||||
@ -61,6 +62,7 @@ class PullPayment extends AbstractClient
|
||||
$body = json_encode(
|
||||
[
|
||||
'name' => $name,
|
||||
'description' => $description,
|
||||
'amount' => $amount->__toString(),
|
||||
'currency' => $currency,
|
||||
'period' => $period,
|
||||
@ -68,7 +70,8 @@ class PullPayment extends AbstractClient
|
||||
'autoApproveClaims' => $autoApproveClaims,
|
||||
'startsAt' => $startsAt,
|
||||
'expiresAt' => $expiresAt,
|
||||
'paymentMethods' => $paymentMethods
|
||||
'paymentMethods' => $paymentMethods,
|
||||
'payoutMethods' => $paymentMethods
|
||||
],
|
||||
JSON_THROW_ON_ERROR
|
||||
);
|
||||
@ -241,6 +244,7 @@ class PullPayment extends AbstractClient
|
||||
'destination' => $destination,
|
||||
'amount' => $amount->__toString(),
|
||||
'paymentMethod' => $paymentMethod,
|
||||
'payoutMethodId' => $paymentMethod, // BTCPay 2.0.0 compatibilty
|
||||
],
|
||||
JSON_THROW_ON_ERROR
|
||||
);
|
||||
|
||||
@ -20,7 +20,7 @@ class Store extends AbstractClient
|
||||
int $paymentTolerance = 0,
|
||||
bool $anyoneCanCreateInvoice = false,
|
||||
bool $requiresRefundEmail = false,
|
||||
?string $checkoutType = 'V1',
|
||||
?string $checkoutType = 'V2',
|
||||
?array $receipt = null,
|
||||
bool $lightningAmountInSatoshi = false,
|
||||
bool $lightningPrivateRouteHints = false,
|
||||
@ -35,7 +35,15 @@ class Store extends AbstractClient
|
||||
string $networkFeeMode = 'MultiplePaymentsOnly',
|
||||
bool $payJoinEnabled = false,
|
||||
bool $lazyPaymentMethods = false,
|
||||
string $defaultPaymentMethod = 'BTC'
|
||||
string $defaultPaymentMethod = 'BTC',
|
||||
?string $supportUrl = null,
|
||||
bool $archived = false,
|
||||
bool $autodetectLanguage = false,
|
||||
bool $showPayInWalletButton = true,
|
||||
bool $showStoreHeader = true,
|
||||
bool $celebratePayment = true,
|
||||
bool $playSoundOnPayment = false,
|
||||
?array $paymentMethodCriteria = null
|
||||
): ResultStore {
|
||||
$url = $this->getApiUrl() . 'stores';
|
||||
$headers = $this->getRequestHeaders();
|
||||
@ -45,6 +53,7 @@ class Store extends AbstractClient
|
||||
[
|
||||
"name" => $name,
|
||||
"website" => $website,
|
||||
"supportUrl" => $supportUrl,
|
||||
"defaultCurrency" => $defaultCurrency,
|
||||
"invoiceExpiration" => $invoiceExpiration,
|
||||
"displayExpirationTimer" => $displayExpirationTimer,
|
||||
@ -52,6 +61,7 @@ class Store extends AbstractClient
|
||||
"speedPolicy" => $speedPolicy,
|
||||
"lightningDescriptionTemplate" => $lightningDescriptionTemplate,
|
||||
"paymentTolerance" => $paymentTolerance,
|
||||
"archived" => $archived,
|
||||
"anyoneCanCreateInvoice" => $anyoneCanCreateInvoice,
|
||||
"requiresRefundEmail" => $requiresRefundEmail,
|
||||
"checkoutType" => $checkoutType,
|
||||
@ -68,8 +78,14 @@ class Store extends AbstractClient
|
||||
"htmlTitle" => $htmlTitle,
|
||||
"networkFeeMode" => $networkFeeMode,
|
||||
"payJoinEnabled" => $payJoinEnabled,
|
||||
"autodetectLanguage" => $autodetectLanguage,
|
||||
"showPayInWalletButton" => $showPayInWalletButton,
|
||||
"showStoreHeader" => $showStoreHeader,
|
||||
"celebratePayment" => $celebratePayment,
|
||||
"playSoundOnPayment" => $playSoundOnPayment,
|
||||
"lazyPaymentMethods" => $lazyPaymentMethods,
|
||||
"defaultPaymentMethod" => $defaultPaymentMethod
|
||||
"defaultPaymentMethod" => $defaultPaymentMethod,
|
||||
"paymentMethodCriteria" => $paymentMethodCriteria
|
||||
],
|
||||
JSON_THROW_ON_ERROR
|
||||
);
|
||||
@ -97,6 +113,115 @@ class Store extends AbstractClient
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update store settings. Make sure to pass all the settings, even if you don't want to change them.
|
||||
*/
|
||||
public function updateStore(
|
||||
string $storeId,
|
||||
string $name,
|
||||
?string $website = null,
|
||||
string $defaultCurrency = 'USD',
|
||||
int $invoiceExpiration = 900,
|
||||
int $displayExpirationTimer = 300,
|
||||
int $monitoringExpiration = 3600,
|
||||
string $speedPolicy = 'MediumSpeed',
|
||||
?string $lightningDescriptionTemplate = null,
|
||||
int $paymentTolerance = 0,
|
||||
bool $anyoneCanCreateInvoice = false,
|
||||
bool $requiresRefundEmail = false,
|
||||
?string $checkoutType = 'V2',
|
||||
?array $receipt = null,
|
||||
bool $lightningAmountInSatoshi = false,
|
||||
bool $lightningPrivateRouteHints = false,
|
||||
bool $onChainWithLnInvoiceFallback = false,
|
||||
bool $redirectAutomatically = false,
|
||||
bool $showRecommendedFee = true,
|
||||
int $recommendedFeeBlockTarget = 1,
|
||||
string $defaultLang = 'en',
|
||||
?string $customLogo = null,
|
||||
?string $customCSS = null,
|
||||
?string $htmlTitle = null,
|
||||
string $networkFeeMode = 'MultiplePaymentsOnly',
|
||||
bool $payJoinEnabled = false,
|
||||
bool $lazyPaymentMethods = false,
|
||||
string $defaultPaymentMethod = 'BTC',
|
||||
?string $supportUrl = null,
|
||||
bool $archived = false,
|
||||
bool $autodetectLanguage = false,
|
||||
bool $showPayInWalletButton = true,
|
||||
bool $showStoreHeader = true,
|
||||
bool $celebratePayment = true,
|
||||
bool $playSoundOnPayment = false,
|
||||
?array $paymentMethodCriteria = null
|
||||
): ResultStore {
|
||||
$url = $this->getApiUrl() . 'stores/' . urlencode($storeId);
|
||||
$headers = $this->getRequestHeaders();
|
||||
$method = 'PUT';
|
||||
|
||||
$body = json_encode(
|
||||
[
|
||||
"name" => $name,
|
||||
"website" => $website,
|
||||
"supportUrl" => $supportUrl,
|
||||
"defaultCurrency" => $defaultCurrency,
|
||||
"invoiceExpiration" => $invoiceExpiration,
|
||||
"displayExpirationTimer" => $displayExpirationTimer,
|
||||
"monitoringExpiration" => $monitoringExpiration,
|
||||
"speedPolicy" => $speedPolicy,
|
||||
"lightningDescriptionTemplate" => $lightningDescriptionTemplate,
|
||||
"paymentTolerance" => $paymentTolerance,
|
||||
"archived" => $archived,
|
||||
"anyoneCanCreateInvoice" => $anyoneCanCreateInvoice,
|
||||
"requiresRefundEmail" => $requiresRefundEmail,
|
||||
"checkoutType" => $checkoutType,
|
||||
"receipt" => $receipt,
|
||||
"lightningAmountInSatoshi" => $lightningAmountInSatoshi,
|
||||
"lightningPrivateRouteHints" => $lightningPrivateRouteHints,
|
||||
"onChainWithLnInvoiceFallback" => $onChainWithLnInvoiceFallback,
|
||||
"redirectAutomatically" => $redirectAutomatically,
|
||||
"showRecommendedFee" => $showRecommendedFee,
|
||||
"recommendedFeeBlockTarget" => $recommendedFeeBlockTarget,
|
||||
"defaultLang" => $defaultLang,
|
||||
"customLogo" => $customLogo,
|
||||
"customCSS" => $customCSS,
|
||||
"htmlTitle" => $htmlTitle,
|
||||
"networkFeeMode" => $networkFeeMode,
|
||||
"payJoinEnabled" => $payJoinEnabled,
|
||||
"autodetectLanguage" => $autodetectLanguage,
|
||||
"showPayInWalletButton" => $showPayInWalletButton,
|
||||
"showStoreHeader" => $showStoreHeader,
|
||||
"celebratePayment" => $celebratePayment,
|
||||
"playSoundOnPayment" => $playSoundOnPayment,
|
||||
"lazyPaymentMethods" => $lazyPaymentMethods,
|
||||
"defaultPaymentMethod" => $defaultPaymentMethod,
|
||||
"paymentMethodCriteria" => $paymentMethodCriteria
|
||||
],
|
||||
JSON_THROW_ON_ERROR
|
||||
);
|
||||
|
||||
$response = $this->getHttpClient()->request($method, $url, $headers, $body);
|
||||
|
||||
if ($response->getStatus() === 200) {
|
||||
return new ResultStore(json_decode($response->getBody(), true, 512, JSON_THROW_ON_ERROR));
|
||||
} else {
|
||||
throw $this->getExceptionByStatusCode($method, $url, $response);
|
||||
}
|
||||
}
|
||||
|
||||
public function deleteStore(string $storeId): bool
|
||||
{
|
||||
$url = $this->getApiUrl() . 'stores/' . urlencode($storeId);
|
||||
$headers = $this->getRequestHeaders();
|
||||
$method = 'DELETE';
|
||||
$response = $this->getHttpClient()->request($method, $url, $headers);
|
||||
|
||||
if ($response->getStatus() === 200) {
|
||||
return true;
|
||||
} else {
|
||||
throw $this->getExceptionByStatusCode($method, $url, $response);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \BTCPayServer\Result\Store[]
|
||||
*/
|
||||
|
||||
@ -35,6 +35,50 @@ class StoreOnChainWallet extends AbstractClient
|
||||
}
|
||||
}
|
||||
|
||||
public function createStoreOnChainWallet(
|
||||
string $storeId,
|
||||
string $cryptoCode,
|
||||
?string $existingMnemonic = null,
|
||||
?string $passphrase = null,
|
||||
int $accountNumber = 0,
|
||||
bool $savePrivateKeys = false,
|
||||
bool $importKeysToRPC = false,
|
||||
string $wordList = 'English',
|
||||
int $wordCount = 12,
|
||||
string $scriptPubKeyType = 'Segwit'
|
||||
): ResultStoreOnChainWallet {
|
||||
$url = $this->getApiUrl() . 'stores/' .
|
||||
urlencode($storeId) . '/payment-methods/onchain/' .
|
||||
urlencode($cryptoCode) . '/generate';
|
||||
|
||||
$headers = $this->getRequestHeaders();
|
||||
$method = 'POST';
|
||||
|
||||
$body = json_encode(
|
||||
[
|
||||
'existingMnemonic' => $existingMnemonic,
|
||||
'passphrase' => $passphrase,
|
||||
'accountNumber' => $accountNumber,
|
||||
'savePrivateKeys' => $savePrivateKeys,
|
||||
'importKeysToRPC' => $importKeysToRPC,
|
||||
'wordList' => $wordList,
|
||||
'wordCount' => $wordCount,
|
||||
'scriptPubKeyType' => $scriptPubKeyType
|
||||
],
|
||||
JSON_THROW_ON_ERROR
|
||||
);
|
||||
|
||||
$response = $this->getHttpClient()->request($method, $url, $headers, $body);
|
||||
|
||||
if ($response->getStatus() === 200) {
|
||||
return new ResultStoreOnChainWallet(
|
||||
json_decode($response->getBody(), true, 512, JSON_THROW_ON_ERROR)
|
||||
);
|
||||
} else {
|
||||
throw $this->getExceptionByStatusCode($method, $url, $response);
|
||||
}
|
||||
}
|
||||
|
||||
public function getStoreOnChainWalletFeeRate(
|
||||
string $storeId,
|
||||
string $cryptoCode,
|
||||
|
||||
@ -15,9 +15,12 @@ use BTCPayServer\Result\StorePaymentMethodCollection;
|
||||
*/
|
||||
class StorePaymentMethod extends AbstractClient
|
||||
{
|
||||
public function getPaymentMethods(string $storeId): array
|
||||
public function getPaymentMethods(string $storeId, bool $includeConfig = false): array
|
||||
{
|
||||
$url = $this->getApiUrl() . 'stores/' . urlencode($storeId) . '/payment-methods';
|
||||
if ($includeConfig) {
|
||||
$url .= '?includeConfig=true';
|
||||
}
|
||||
$headers = $this->getRequestHeaders();
|
||||
$method = 'GET';
|
||||
$response = $this->getHttpClient()->request($method, $url, $headers);
|
||||
|
||||
@ -10,6 +10,8 @@ use BTCPayServer\Result\StorePaymentMethodLightningNetwork as ResultStorePayment
|
||||
* Handles a stores LightningNetwork payment methods.
|
||||
*
|
||||
* @see https://docs.btcpayserver.org/API/Greenfield/v1/#tag/Store-Payment-Methods-(Lightning-Network)
|
||||
*
|
||||
* @deprecated with BTCPay 2.0. Use \BTCPayServer\Client\StorePaymentMethod->getPaymentMethods() instead.
|
||||
*/
|
||||
class StorePaymentMethodLightningNetwork extends AbstractStorePaymentMethodClient
|
||||
{
|
||||
|
||||
@ -10,6 +10,8 @@ use BTCPayServer\Result\StorePaymentMethodOnChain as ResultStorePaymentMethodOnC
|
||||
* Handles stores on chain payment methods.
|
||||
*
|
||||
* @see https://docs.btcpayserver.org/API/Greenfield/v1/#tag/Store-Payment-Methods-(On-Chain)
|
||||
*
|
||||
* @deprecated with BTCPay 2.0. Use \BTCPayServer\Client\StorePaymentMethod->getPaymentMethods() instead.
|
||||
*/
|
||||
class StorePaymentMethodOnChain extends AbstractStorePaymentMethodClient
|
||||
{
|
||||
@ -133,7 +135,7 @@ class StorePaymentMethodOnChain extends AbstractStorePaymentMethodClient
|
||||
string $storeId,
|
||||
string $cryptoCode,
|
||||
string $derivationScheme,
|
||||
string $accountKeyPath = null
|
||||
?string $accountKeyPath = null
|
||||
): array {
|
||||
// todo: add offset + amount query parameters + check structure of derivationScheme etc.
|
||||
|
||||
|
||||
@ -97,7 +97,7 @@ class StoreRate extends AbstractClient
|
||||
|
||||
public function getRates(
|
||||
string $storeId,
|
||||
array $currencyPairs = null
|
||||
?array $currencyPairs = null
|
||||
): StoreRateList {
|
||||
$url = $this->getApiUrl() . 'stores/' . urlencode($storeId) . '/rates?';
|
||||
$headers = $this->getRequestHeaders();
|
||||
|
||||
493
src/Client/Subscriptions.php
Normal file
493
src/Client/Subscriptions.php
Normal file
@ -0,0 +1,493 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace BTCPayServer\Client;
|
||||
|
||||
use BTCPayServer\Result\Credit;
|
||||
use BTCPayServer\Result\Offering;
|
||||
use BTCPayServer\Result\OfferingList;
|
||||
use BTCPayServer\Result\OfferingPlan;
|
||||
use BTCPayServer\Result\PlanCheckout;
|
||||
use BTCPayServer\Result\PortalSession;
|
||||
use BTCPayServer\Result\Subscriber;
|
||||
|
||||
/**
|
||||
* Handles subscriptions operations.
|
||||
*
|
||||
* @see https://docs.btcpayserver.org/API/Greenfield/v1/#tag/Subscriptions
|
||||
*/
|
||||
class Subscriptions extends AbstractClient
|
||||
{
|
||||
// Offering endpoints
|
||||
|
||||
public function getOffering(string $storeId, string $offeringId): Offering
|
||||
{
|
||||
$url = $this->getApiUrl() . 'stores/' . urlencode($storeId) . '/offerings/' . urlencode($offeringId);
|
||||
$headers = $this->getRequestHeaders();
|
||||
$method = 'GET';
|
||||
$response = $this->getHttpClient()->request($method, $url, $headers);
|
||||
|
||||
if ($response->getStatus() === 200) {
|
||||
return new Offering(json_decode($response->getBody(), true, 512, JSON_THROW_ON_ERROR));
|
||||
} else {
|
||||
throw $this->getExceptionByStatusCode($method, $url, $response);
|
||||
}
|
||||
}
|
||||
|
||||
public function getOfferings(string $storeId): OfferingList
|
||||
{
|
||||
$url = $this->getApiUrl() . 'stores/' . urlencode($storeId) . '/offerings';
|
||||
$headers = $this->getRequestHeaders();
|
||||
$method = 'GET';
|
||||
$response = $this->getHttpClient()->request($method, $url, $headers);
|
||||
|
||||
if ($response->getStatus() === 200) {
|
||||
return new OfferingList(json_decode($response->getBody(), true, 512, JSON_THROW_ON_ERROR));
|
||||
} else {
|
||||
throw $this->getExceptionByStatusCode($method, $url, $response);
|
||||
}
|
||||
}
|
||||
|
||||
public function createOffering(
|
||||
string $storeId,
|
||||
?string $appName = null,
|
||||
?string $successRedirectUrl = null,
|
||||
?array $metadata = null,
|
||||
?array $features = null
|
||||
): Offering {
|
||||
$url = $this->getApiUrl() . 'stores/' . urlencode($storeId) . '/offerings';
|
||||
$headers = $this->getRequestHeaders();
|
||||
$method = 'POST';
|
||||
|
||||
$body = json_encode(
|
||||
[
|
||||
'appName' => $appName,
|
||||
'successRedirectUrl' => $successRedirectUrl,
|
||||
'metadata' => $metadata,
|
||||
'features' => $features
|
||||
],
|
||||
JSON_THROW_ON_ERROR
|
||||
);
|
||||
|
||||
$response = $this->getHttpClient()->request($method, $url, $headers, $body);
|
||||
|
||||
if ($response->getStatus() === 200 || $response->getStatus() === 201) {
|
||||
return new Offering(json_decode($response->getBody(), true, 512, JSON_THROW_ON_ERROR));
|
||||
} else {
|
||||
throw $this->getExceptionByStatusCode($method, $url, $response);
|
||||
}
|
||||
}
|
||||
|
||||
public function updateOffering(
|
||||
string $storeId,
|
||||
string $offeringId,
|
||||
?string $appName = null,
|
||||
?string $successRedirectUrl = null,
|
||||
?array $metadata = null,
|
||||
?array $features = null
|
||||
): Offering {
|
||||
$url = $this->getApiUrl() . 'stores/' . urlencode($storeId) . '/offerings/' . urlencode($offeringId);
|
||||
$headers = $this->getRequestHeaders();
|
||||
$method = 'PUT';
|
||||
|
||||
$body = json_encode(
|
||||
[
|
||||
'appName' => $appName,
|
||||
'successRedirectUrl' => $successRedirectUrl,
|
||||
'metadata' => $metadata,
|
||||
'features' => $features
|
||||
],
|
||||
JSON_THROW_ON_ERROR
|
||||
);
|
||||
|
||||
$response = $this->getHttpClient()->request($method, $url, $headers, $body);
|
||||
|
||||
if ($response->getStatus() === 200) {
|
||||
return new Offering(json_decode($response->getBody(), true, 512, JSON_THROW_ON_ERROR));
|
||||
} else {
|
||||
throw $this->getExceptionByStatusCode($method, $url, $response);
|
||||
}
|
||||
}
|
||||
|
||||
// Plan endpoints
|
||||
|
||||
public function createOfferingPlan(
|
||||
string $storeId,
|
||||
string $offeringId,
|
||||
?string $description = null,
|
||||
?string $currency = null,
|
||||
?int $gracePeriodDays = null,
|
||||
?string $name = null,
|
||||
?bool $optimisticActivation = null,
|
||||
?string $price = null,
|
||||
?bool $renewable = null,
|
||||
?int $trialDays = null,
|
||||
?array $metadata = null,
|
||||
?string $recurringType = null,
|
||||
?array $features = null
|
||||
): OfferingPlan {
|
||||
$url = $this->getApiUrl() . 'stores/' . urlencode($storeId) . '/offerings/' . urlencode($offeringId) . '/plans';
|
||||
$headers = $this->getRequestHeaders();
|
||||
$method = 'POST';
|
||||
|
||||
$body = json_encode(
|
||||
[
|
||||
'description' => $description,
|
||||
'currency' => $currency,
|
||||
'gracePeriodDays' => $gracePeriodDays,
|
||||
'name' => $name,
|
||||
'optimisticActivation' => $optimisticActivation,
|
||||
'price' => $price,
|
||||
'renewable' => $renewable,
|
||||
'trialDays' => $trialDays,
|
||||
'metadata' => $metadata,
|
||||
'recurringType' => $recurringType,
|
||||
'features' => $features
|
||||
],
|
||||
JSON_THROW_ON_ERROR
|
||||
);
|
||||
|
||||
$response = $this->getHttpClient()->request($method, $url, $headers, $body);
|
||||
|
||||
if ($response->getStatus() === 200 || $response->getStatus() === 201) {
|
||||
return new OfferingPlan(json_decode($response->getBody(), true, 512, JSON_THROW_ON_ERROR));
|
||||
} else {
|
||||
throw $this->getExceptionByStatusCode($method, $url, $response);
|
||||
}
|
||||
}
|
||||
|
||||
public function getOfferingPlan(string $storeId, string $offeringId, string $planId): OfferingPlan
|
||||
{
|
||||
$url = $this->getApiUrl() . 'stores/' . urlencode($storeId) . '/offerings/' . urlencode($offeringId) . '/plans/' . urlencode($planId);
|
||||
$headers = $this->getRequestHeaders();
|
||||
$method = 'GET';
|
||||
$response = $this->getHttpClient()->request($method, $url, $headers);
|
||||
|
||||
if ($response->getStatus() === 200) {
|
||||
return new OfferingPlan(json_decode($response->getBody(), true, 512, JSON_THROW_ON_ERROR));
|
||||
} else {
|
||||
throw $this->getExceptionByStatusCode($method, $url, $response);
|
||||
}
|
||||
}
|
||||
|
||||
public function updateOfferingPlan(
|
||||
string $storeId,
|
||||
string $offeringId,
|
||||
string $planId,
|
||||
?string $description = null,
|
||||
?string $currency = null,
|
||||
?int $gracePeriodDays = null,
|
||||
?string $name = null,
|
||||
?bool $optimisticActivation = null,
|
||||
?string $price = null,
|
||||
?bool $renewable = null,
|
||||
?int $trialDays = null,
|
||||
?array $metadata = null,
|
||||
?string $recurringType = null,
|
||||
?array $features = null
|
||||
): OfferingPlan {
|
||||
$url = $this->getApiUrl() . 'stores/' . urlencode($storeId) . '/offerings/' . urlencode($offeringId) . '/plans/' . urlencode($planId);
|
||||
$headers = $this->getRequestHeaders();
|
||||
$method = 'PUT';
|
||||
|
||||
$body = json_encode(
|
||||
[
|
||||
'description' => $description,
|
||||
'currency' => $currency,
|
||||
'gracePeriodDays' => $gracePeriodDays,
|
||||
'name' => $name,
|
||||
'optimisticActivation' => $optimisticActivation,
|
||||
'price' => $price,
|
||||
'renewable' => $renewable,
|
||||
'trialDays' => $trialDays,
|
||||
'metadata' => $metadata,
|
||||
'recurringType' => $recurringType,
|
||||
'features' => $features
|
||||
],
|
||||
JSON_THROW_ON_ERROR
|
||||
);
|
||||
|
||||
$response = $this->getHttpClient()->request($method, $url, $headers, $body);
|
||||
|
||||
if ($response->getStatus() === 200) {
|
||||
return new OfferingPlan(json_decode($response->getBody(), true, 512, JSON_THROW_ON_ERROR));
|
||||
} else {
|
||||
throw $this->getExceptionByStatusCode($method, $url, $response);
|
||||
}
|
||||
}
|
||||
|
||||
// Subscriber endpoints
|
||||
|
||||
public function getSubscriber(string $storeId, string $offeringId, string $customerSelector): Subscriber
|
||||
{
|
||||
$url = $this->getApiUrl() . 'stores/' . urlencode($storeId) . '/offerings/' . urlencode($offeringId) . '/subscribers/' . urlencode($customerSelector);
|
||||
$headers = $this->getRequestHeaders();
|
||||
$method = 'GET';
|
||||
$response = $this->getHttpClient()->request($method, $url, $headers);
|
||||
|
||||
if ($response->getStatus() === 200) {
|
||||
return new Subscriber(json_decode($response->getBody(), true, 512, JSON_THROW_ON_ERROR));
|
||||
} else {
|
||||
throw $this->getExceptionByStatusCode($method, $url, $response);
|
||||
}
|
||||
}
|
||||
|
||||
public function deleteSubscriber(string $storeId, string $offeringId, string $customerSelector): void
|
||||
{
|
||||
$url = $this->getApiUrl() . 'stores/' . urlencode($storeId) . '/offerings/' . urlencode($offeringId) . '/subscribers/' . urlencode($customerSelector);
|
||||
$headers = $this->getRequestHeaders();
|
||||
$method = 'DELETE';
|
||||
$response = $this->getHttpClient()->request($method, $url, $headers);
|
||||
|
||||
if ($response->getStatus() !== 204) {
|
||||
throw $this->getExceptionByStatusCode($method, $url, $response);
|
||||
}
|
||||
}
|
||||
|
||||
public function updateSubscriberDates(
|
||||
string $storeId,
|
||||
string $offeringId,
|
||||
string $customerSelector,
|
||||
?int $startDate = null,
|
||||
?int $expirationDate = null
|
||||
): Subscriber {
|
||||
$url = $this->getApiUrl() . 'stores/' . urlencode($storeId) . '/offerings/' . urlencode($offeringId) . '/subscribers/' . urlencode($customerSelector) . '/dates';
|
||||
$headers = $this->getRequestHeaders();
|
||||
$method = 'PUT';
|
||||
|
||||
$body = json_encode(
|
||||
[
|
||||
'startDate' => $startDate,
|
||||
'expirationDate' => $expirationDate
|
||||
],
|
||||
JSON_THROW_ON_ERROR
|
||||
);
|
||||
|
||||
$response = $this->getHttpClient()->request($method, $url, $headers, $body);
|
||||
|
||||
if ($response->getStatus() === 200) {
|
||||
return new Subscriber(json_decode($response->getBody(), true, 512, JSON_THROW_ON_ERROR));
|
||||
} else {
|
||||
throw $this->getExceptionByStatusCode($method, $url, $response);
|
||||
}
|
||||
}
|
||||
|
||||
public function suspendSubscriber(string $storeId, string $offeringId, string $customerSelector, string $reason): Subscriber
|
||||
{
|
||||
$url = $this->getApiUrl() . 'stores/' . urlencode($storeId) . '/offerings/' . urlencode($offeringId) . '/subscribers/' . urlencode($customerSelector) . '/suspend';
|
||||
$headers = $this->getRequestHeaders();
|
||||
$method = 'POST';
|
||||
|
||||
$body = json_encode(
|
||||
[
|
||||
'reason' => $reason
|
||||
],
|
||||
JSON_THROW_ON_ERROR
|
||||
);
|
||||
|
||||
$response = $this->getHttpClient()->request($method, $url, $headers, $body);
|
||||
|
||||
if ($response->getStatus() === 200) {
|
||||
return new Subscriber(json_decode($response->getBody(), true, 512, JSON_THROW_ON_ERROR));
|
||||
} else {
|
||||
throw $this->getExceptionByStatusCode($method, $url, $response);
|
||||
}
|
||||
}
|
||||
|
||||
public function unsuspendSubscriber(string $storeId, string $offeringId, string $customerSelector): Subscriber
|
||||
{
|
||||
$url = $this->getApiUrl() . 'stores/' . urlencode($storeId) . '/offerings/' . urlencode($offeringId) . '/subscribers/' . urlencode($customerSelector) . '/unsuspend';
|
||||
$headers = $this->getRequestHeaders();
|
||||
$method = 'POST';
|
||||
|
||||
$response = $this->getHttpClient()->request($method, $url, $headers);
|
||||
|
||||
if ($response->getStatus() === 200) {
|
||||
return new Subscriber(json_decode($response->getBody(), true, 512, JSON_THROW_ON_ERROR));
|
||||
} else {
|
||||
throw $this->getExceptionByStatusCode($method, $url, $response);
|
||||
}
|
||||
}
|
||||
|
||||
// Credit endpoints
|
||||
|
||||
public function getCredit(string $storeId, string $offeringId, string $customerSelector, string $currency): Credit
|
||||
{
|
||||
$url = $this->getApiUrl() . 'stores/' . urlencode($storeId) . '/offerings/' . urlencode($offeringId) . '/subscribers/' . urlencode($customerSelector) . '/credits/' . urlencode($currency);
|
||||
$headers = $this->getRequestHeaders();
|
||||
$method = 'GET';
|
||||
$response = $this->getHttpClient()->request($method, $url, $headers);
|
||||
|
||||
if ($response->getStatus() === 200) {
|
||||
return new Credit(json_decode($response->getBody(), true, 512, JSON_THROW_ON_ERROR));
|
||||
} else {
|
||||
throw $this->getExceptionByStatusCode($method, $url, $response);
|
||||
}
|
||||
}
|
||||
|
||||
public function updateCredit(
|
||||
string $storeId,
|
||||
string $offeringId,
|
||||
string $customerSelector,
|
||||
string $currency,
|
||||
?string $credit = null,
|
||||
?string $charge = null,
|
||||
?string $description = null,
|
||||
?bool $allowOverdraft = null
|
||||
): Credit {
|
||||
$url = $this->getApiUrl() . 'stores/' . urlencode($storeId) . '/offerings/' . urlencode($offeringId) . '/subscribers/' . urlencode($customerSelector) . '/credits/' . urlencode($currency);
|
||||
$headers = $this->getRequestHeaders();
|
||||
$method = 'POST';
|
||||
|
||||
$body = json_encode(
|
||||
[
|
||||
'credit' => $credit,
|
||||
'charge' => $charge,
|
||||
'description' => $description,
|
||||
'allowOverdraft' => $allowOverdraft
|
||||
],
|
||||
JSON_THROW_ON_ERROR
|
||||
);
|
||||
|
||||
$response = $this->getHttpClient()->request($method, $url, $headers, $body);
|
||||
|
||||
if ($response->getStatus() === 200) {
|
||||
return new Credit(json_decode($response->getBody(), true, 512, JSON_THROW_ON_ERROR));
|
||||
} else {
|
||||
throw $this->getExceptionByStatusCode($method, $url, $response);
|
||||
}
|
||||
}
|
||||
|
||||
// Plan checkout endpoints
|
||||
|
||||
public function getPlanCheckout(string $checkoutId): PlanCheckout
|
||||
{
|
||||
$url = $this->getApiUrl() . 'plan-checkout/' . urlencode($checkoutId);
|
||||
$headers = $this->getRequestHeaders();
|
||||
$method = 'GET';
|
||||
$response = $this->getHttpClient()->request($method, $url, $headers);
|
||||
|
||||
if ($response->getStatus() === 200) {
|
||||
return new PlanCheckout(json_decode($response->getBody(), true, 512, JSON_THROW_ON_ERROR));
|
||||
} else {
|
||||
throw $this->getExceptionByStatusCode($method, $url, $response);
|
||||
}
|
||||
}
|
||||
|
||||
public function proceedPlanCheckout(string $checkoutId, ?string $email = null): PlanCheckout
|
||||
{
|
||||
$url = $this->getApiUrl() . 'plan-checkout/' . urlencode($checkoutId);
|
||||
$headers = $this->getRequestHeaders();
|
||||
$method = 'POST';
|
||||
|
||||
$params = [];
|
||||
if ($email !== null) {
|
||||
$params['email'] = $email;
|
||||
}
|
||||
|
||||
if (!empty($params)) {
|
||||
$url .= '?' . http_build_query($params);
|
||||
}
|
||||
|
||||
$response = $this->getHttpClient()->request($method, $url, $headers);
|
||||
|
||||
if ($response->getStatus() === 200) {
|
||||
return new PlanCheckout(json_decode($response->getBody(), true, 512, JSON_THROW_ON_ERROR));
|
||||
} else {
|
||||
throw $this->getExceptionByStatusCode($method, $url, $response);
|
||||
}
|
||||
}
|
||||
|
||||
public function createPlanCheckout(
|
||||
string $storeId,
|
||||
string $offeringId,
|
||||
string $planId,
|
||||
?string $customerSelector = null,
|
||||
?int $durationMinutes = null,
|
||||
?string $onPayBehavior = null,
|
||||
?array $newSubscriberMetadata = null,
|
||||
?array $invoiceMetadata = null,
|
||||
?array $metadata = null,
|
||||
?bool $isTrial = null,
|
||||
?string $creditPurchase = null,
|
||||
?string $successRedirectLink = null,
|
||||
?string $newSubscriberEmail = null
|
||||
): PlanCheckout {
|
||||
$url = $this->getApiUrl() . 'plan-checkout';
|
||||
$headers = $this->getRequestHeaders();
|
||||
$method = 'POST';
|
||||
|
||||
$body = json_encode(
|
||||
[
|
||||
'storeId' => $storeId,
|
||||
'offeringId' => $offeringId,
|
||||
'planId' => $planId,
|
||||
'customerSelector' => $customerSelector,
|
||||
'durationMinutes' => $durationMinutes,
|
||||
'onPayBehavior' => $onPayBehavior,
|
||||
'newSubscriberMetadata' => $newSubscriberMetadata,
|
||||
'invoiceMetadata' => $invoiceMetadata,
|
||||
'metadata' => $metadata,
|
||||
'isTrial' => $isTrial,
|
||||
'creditPurchase' => $creditPurchase,
|
||||
'successRedirectLink' => $successRedirectLink,
|
||||
'newSubscriberEmail' => $newSubscriberEmail
|
||||
],
|
||||
JSON_THROW_ON_ERROR
|
||||
);
|
||||
|
||||
$response = $this->getHttpClient()->request($method, $url, $headers, $body);
|
||||
|
||||
if ($response->getStatus() === 200) {
|
||||
return new PlanCheckout(json_decode($response->getBody(), true, 512, JSON_THROW_ON_ERROR));
|
||||
} else {
|
||||
throw $this->getExceptionByStatusCode($method, $url, $response);
|
||||
}
|
||||
}
|
||||
|
||||
// Portal session endpoints
|
||||
|
||||
public function createPortalSession(
|
||||
string $storeId,
|
||||
string $offeringId,
|
||||
string $customerSelector,
|
||||
?int $durationMinutes = null
|
||||
): PortalSession {
|
||||
$url = $this->getApiUrl() . 'subscriber-portal';
|
||||
$headers = $this->getRequestHeaders();
|
||||
$method = 'POST';
|
||||
|
||||
$body = json_encode(
|
||||
[
|
||||
'storeId' => $storeId,
|
||||
'offeringId' => $offeringId,
|
||||
'customerSelector' => $customerSelector,
|
||||
'durationMinutes' => $durationMinutes
|
||||
],
|
||||
JSON_THROW_ON_ERROR
|
||||
);
|
||||
|
||||
$response = $this->getHttpClient()->request($method, $url, $headers, $body);
|
||||
|
||||
if ($response->getStatus() === 200) {
|
||||
return new PortalSession(json_decode($response->getBody(), true, 512, JSON_THROW_ON_ERROR));
|
||||
} else {
|
||||
throw $this->getExceptionByStatusCode($method, $url, $response);
|
||||
}
|
||||
}
|
||||
|
||||
public function getPortalSession(string $portalSessionId): PortalSession
|
||||
{
|
||||
$url = $this->getApiUrl() . 'subscriber-portal/' . urlencode($portalSessionId);
|
||||
$headers = $this->getRequestHeaders();
|
||||
$method = 'GET';
|
||||
$response = $this->getHttpClient()->request($method, $url, $headers);
|
||||
|
||||
if ($response->getStatus() === 200) {
|
||||
return new PortalSession(json_decode($response->getBody(), true, 512, JSON_THROW_ON_ERROR));
|
||||
} else {
|
||||
throw $this->getExceptionByStatusCode($method, $url, $response);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -59,7 +59,7 @@ class User extends AbstractClient
|
||||
|
||||
$response = $this->getHttpClient()->request($method, $url, $headers, $body);
|
||||
|
||||
if ($response->getStatus() === 200) {
|
||||
if ($response->getStatus() === 201) {
|
||||
return new ResultUser(
|
||||
json_decode($response->getBody(), true, 512, JSON_THROW_ON_ERROR)
|
||||
);
|
||||
|
||||
@ -238,7 +238,7 @@ class Webhook extends AbstractClient
|
||||
if ($requestBody && $btcpaySigHeader) {
|
||||
$expectedHeader = 'sha256=' . hash_hmac('sha256', $requestBody, $secret);
|
||||
|
||||
if ($expectedHeader === $btcpaySigHeader) {
|
||||
if (hash_equals($expectedHeader, $btcpaySigHeader)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,7 +6,7 @@ namespace BTCPayServer\Exception;
|
||||
|
||||
class BTCPayException extends \RuntimeException
|
||||
{
|
||||
public function __construct(string $message, int $code, \Throwable $previous = null)
|
||||
public function __construct(string $message, int $code, ?\Throwable $previous = null)
|
||||
{
|
||||
parent::__construct($message, $code, $previous);
|
||||
}
|
||||
|
||||
@ -6,7 +6,7 @@ namespace BTCPayServer\Result;
|
||||
|
||||
abstract class AbstractStorePaymentMethodResult extends AbstractResult
|
||||
{
|
||||
public function __construct(array $data, string $paymentMethod = null)
|
||||
public function __construct(array $data, ?string $paymentMethod = null)
|
||||
{
|
||||
// Temporary workaround until the api provides paymentMethod.
|
||||
if (!isset($data['paymentMethod'])) {
|
||||
|
||||
@ -6,4 +6,18 @@ namespace BTCPayServer\Result;
|
||||
|
||||
class ApiKey extends AbstractResult
|
||||
{
|
||||
public function getApiKey(): string
|
||||
{
|
||||
return $this->getData()['apiKey'];
|
||||
}
|
||||
|
||||
public function getLabel(): string
|
||||
{
|
||||
return $this->getData()['label'];
|
||||
}
|
||||
|
||||
public function getPermissions(): array
|
||||
{
|
||||
return $this->getData()['permissions'];
|
||||
}
|
||||
}
|
||||
|
||||
18
src/Result/Credit.php
Normal file
18
src/Result/Credit.php
Normal file
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace BTCPayServer\Result;
|
||||
|
||||
class Credit extends AbstractResult
|
||||
{
|
||||
public function getCurrency(): string
|
||||
{
|
||||
return $this->getData()['currency'];
|
||||
}
|
||||
|
||||
public function getValue(): string
|
||||
{
|
||||
return $this->getData()['value'];
|
||||
}
|
||||
}
|
||||
33
src/Result/Customer.php
Normal file
33
src/Result/Customer.php
Normal file
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace BTCPayServer\Result;
|
||||
|
||||
class Customer extends AbstractResult
|
||||
{
|
||||
public function getStoreId(): string
|
||||
{
|
||||
return $this->getData()['storeId'];
|
||||
}
|
||||
|
||||
public function getId(): string
|
||||
{
|
||||
return $this->getData()['id'];
|
||||
}
|
||||
|
||||
public function getExternalId(): ?string
|
||||
{
|
||||
return $this->getData()['externalId'] ?? null;
|
||||
}
|
||||
|
||||
public function getIdentities(): ?array
|
||||
{
|
||||
return $this->getData()['identities'] ?? null;
|
||||
}
|
||||
|
||||
public function getMetadata(): ?array
|
||||
{
|
||||
return $this->getData()['metadata'] ?? null;
|
||||
}
|
||||
}
|
||||
18
src/Result/Feature.php
Normal file
18
src/Result/Feature.php
Normal file
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace BTCPayServer\Result;
|
||||
|
||||
class Feature extends AbstractResult
|
||||
{
|
||||
public function getId(): string
|
||||
{
|
||||
return $this->getData()['id'];
|
||||
}
|
||||
|
||||
public function getDescription(): string
|
||||
{
|
||||
return $this->getData()['description'];
|
||||
}
|
||||
}
|
||||
@ -59,25 +59,37 @@ class InvoicePaymentMethod extends AbstractResult
|
||||
public function getNetworkFee(): string
|
||||
{
|
||||
$data = $this->getData();
|
||||
return $data['networkFee'];
|
||||
// BTCPay 2.0.0 compatibility: networkFee was renamed to paymentMethodFee.
|
||||
return $data['networkFee'] ?? $data['paymentMethodFee'];
|
||||
}
|
||||
|
||||
public function getPaymentMethod(): string
|
||||
{
|
||||
$data = $this->getData();
|
||||
return $data['paymentMethod'];
|
||||
// BTCPay 2.0.0 compatibility: paymentMethod was renamed to paymentMethodId.
|
||||
return $data['paymentMethod'] ?? $data['paymentMethodId'];
|
||||
}
|
||||
|
||||
public function getCryptoCode(): string
|
||||
{
|
||||
$data = $this->getData();
|
||||
|
||||
// For future compatibility check if cryptoCode exists.
|
||||
if (isset($data['cryptoCode'])) {
|
||||
return $data['cryptoCode'];
|
||||
} else {
|
||||
// Extract cryptoCode from paymentMethod string.
|
||||
$parts = explode('-', $data['paymentMethod']);
|
||||
$parts = explode('-', $this->getPaymentMethod());
|
||||
return $parts[0];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* New field as of BTCPay 2.0.0.
|
||||
*/
|
||||
public function getCurrency(): ?string
|
||||
{
|
||||
$data = $this->getData();
|
||||
return $data['currency'] ?? null;
|
||||
}
|
||||
}
|
||||
|
||||
66
src/Result/Offering.php
Normal file
66
src/Result/Offering.php
Normal file
@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace BTCPayServer\Result;
|
||||
|
||||
class Offering extends AbstractResult
|
||||
{
|
||||
public function getId(): string
|
||||
{
|
||||
return $this->getData()['id'];
|
||||
}
|
||||
|
||||
public function getStoreId(): string
|
||||
{
|
||||
return $this->getData()['storeId'];
|
||||
}
|
||||
|
||||
public function getAppId(): ?string
|
||||
{
|
||||
return $this->getData()['appId'] ?? null;
|
||||
}
|
||||
|
||||
public function getAppName(): ?string
|
||||
{
|
||||
return $this->getData()['appName'] ?? null;
|
||||
}
|
||||
|
||||
public function getSuccessRedirectUrl(): ?string
|
||||
{
|
||||
return $this->getData()['successRedirectUrl'] ?? null;
|
||||
}
|
||||
|
||||
public function getMetadata(): ?array
|
||||
{
|
||||
return $this->getData()['metadata'] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return OfferingPlan[]
|
||||
*/
|
||||
public function getPlans(): array
|
||||
{
|
||||
$plans = [];
|
||||
if (isset($this->getData()['plans']) && is_array($this->getData()['plans'])) {
|
||||
foreach ($this->getData()['plans'] as $plan) {
|
||||
$plans[] = new OfferingPlan($plan);
|
||||
}
|
||||
}
|
||||
return $plans;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Feature[]
|
||||
*/
|
||||
public function getFeatures(): array
|
||||
{
|
||||
$features = [];
|
||||
if (isset($this->getData()['features']) && is_array($this->getData()['features'])) {
|
||||
foreach ($this->getData()['features'] as $feature) {
|
||||
$features[] = new Feature($feature);
|
||||
}
|
||||
}
|
||||
return $features;
|
||||
}
|
||||
}
|
||||
20
src/Result/OfferingList.php
Normal file
20
src/Result/OfferingList.php
Normal file
@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace BTCPayServer\Result;
|
||||
|
||||
class OfferingList extends AbstractListResult
|
||||
{
|
||||
/**
|
||||
* @return Offering[]
|
||||
*/
|
||||
public function all(): array
|
||||
{
|
||||
$result = [];
|
||||
foreach ($this->getData() as $item) {
|
||||
$result[] = new Offering($item);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
81
src/Result/OfferingPlan.php
Normal file
81
src/Result/OfferingPlan.php
Normal file
@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace BTCPayServer\Result;
|
||||
|
||||
class OfferingPlan extends AbstractResult
|
||||
{
|
||||
public function getId(): string
|
||||
{
|
||||
return $this->getData()['id'];
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return $this->getData()['name'];
|
||||
}
|
||||
|
||||
public function getStatus(): string
|
||||
{
|
||||
return $this->getData()['status'];
|
||||
}
|
||||
|
||||
public function getPrice(): string
|
||||
{
|
||||
return $this->getData()['price'];
|
||||
}
|
||||
|
||||
public function getCurrency(): string
|
||||
{
|
||||
return $this->getData()['currency'];
|
||||
}
|
||||
|
||||
public function getRecurringType(): string
|
||||
{
|
||||
return $this->getData()['recurringType'];
|
||||
}
|
||||
|
||||
public function getGracePeriodDays(): int
|
||||
{
|
||||
return $this->getData()['gracePeriodDays'];
|
||||
}
|
||||
|
||||
public function getTrialDays(): int
|
||||
{
|
||||
return $this->getData()['trialDays'];
|
||||
}
|
||||
|
||||
public function getDescription(): string
|
||||
{
|
||||
return $this->getData()['description'];
|
||||
}
|
||||
|
||||
public function getMemberCount(): int
|
||||
{
|
||||
return $this->getData()['memberCount'];
|
||||
}
|
||||
|
||||
public function isOptimisticActivation(): bool
|
||||
{
|
||||
return $this->getData()['optimisticActivation'];
|
||||
}
|
||||
|
||||
public function isRenewable(): bool
|
||||
{
|
||||
return $this->getData()['renewable'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getFeatures(): array
|
||||
{
|
||||
return $this->getData()['features'] ?? [];
|
||||
}
|
||||
|
||||
public function getMetadata(): ?array
|
||||
{
|
||||
return $this->getData()['metadata'] ?? null;
|
||||
}
|
||||
}
|
||||
113
src/Result/PlanCheckout.php
Normal file
113
src/Result/PlanCheckout.php
Normal file
@ -0,0 +1,113 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace BTCPayServer\Result;
|
||||
|
||||
class PlanCheckout extends AbstractResult
|
||||
{
|
||||
public function getId(): string
|
||||
{
|
||||
return $this->getData()['id'];
|
||||
}
|
||||
|
||||
public function getSubscriber(): ?Subscriber
|
||||
{
|
||||
return isset($this->getData()['subscriber']) ? new Subscriber($this->getData()['subscriber']) : null;
|
||||
}
|
||||
|
||||
public function getPlan(): OfferingPlan
|
||||
{
|
||||
return new OfferingPlan($this->getData()['plan']);
|
||||
}
|
||||
|
||||
public function getBaseUrl(): string
|
||||
{
|
||||
return $this->getData()['baseUrl'];
|
||||
}
|
||||
|
||||
public function getInvoiceId(): ?string
|
||||
{
|
||||
return $this->getData()['invoiceId'] ?? null;
|
||||
}
|
||||
|
||||
public function getSuccessRedirectUrl(): ?string
|
||||
{
|
||||
return $this->getData()['successRedirectUrl'] ?? null;
|
||||
}
|
||||
|
||||
public function getExpiration(): int
|
||||
{
|
||||
return $this->getData()['expiration'];
|
||||
}
|
||||
|
||||
public function getRedirectUrl(): string
|
||||
{
|
||||
return $this->getData()['redirectUrl'];
|
||||
}
|
||||
|
||||
public function getInvoiceMetadata(): ?array
|
||||
{
|
||||
return $this->getData()['invoiceMetadata'] ?? null;
|
||||
}
|
||||
|
||||
public function getMetadata(): ?array
|
||||
{
|
||||
return $this->getData()['metadata'] ?? null;
|
||||
}
|
||||
|
||||
public function isNewSubscriber(): bool
|
||||
{
|
||||
return $this->getData()['newSubscriber'];
|
||||
}
|
||||
|
||||
public function isTrial(): bool
|
||||
{
|
||||
return $this->getData()['isTrial'];
|
||||
}
|
||||
|
||||
public function getCreated(): int
|
||||
{
|
||||
return $this->getData()['created'];
|
||||
}
|
||||
|
||||
public function isPlanStarted(): bool
|
||||
{
|
||||
return $this->getData()['planStarted'];
|
||||
}
|
||||
|
||||
public function getNewSubscriberMetadata(): ?array
|
||||
{
|
||||
return $this->getData()['newSubscriberMetadata'] ?? null;
|
||||
}
|
||||
|
||||
public function getRefundAmount(): ?string
|
||||
{
|
||||
return $this->getData()['refundAmount'] ?? null;
|
||||
}
|
||||
|
||||
public function getCreditedByInvoice(): ?string
|
||||
{
|
||||
return $this->getData()['creditedByInvoice'] ?? null;
|
||||
}
|
||||
|
||||
public function getOnPayBehavior(): ?string
|
||||
{
|
||||
return $this->getData()['onPayBehavior'] ?? null;
|
||||
}
|
||||
|
||||
public function isExpired(): bool
|
||||
{
|
||||
return $this->getData()['isExpired'];
|
||||
}
|
||||
|
||||
public function getUrl(): string
|
||||
{
|
||||
return $this->getData()['url'];
|
||||
}
|
||||
|
||||
public function getCreditPurchase(): ?string
|
||||
{
|
||||
return $this->getData()['creditPurchase'] ?? null;
|
||||
}
|
||||
}
|
||||
38
src/Result/PortalSession.php
Normal file
38
src/Result/PortalSession.php
Normal file
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace BTCPayServer\Result;
|
||||
|
||||
class PortalSession extends AbstractResult
|
||||
{
|
||||
public function getId(): string
|
||||
{
|
||||
return $this->getData()['id'];
|
||||
}
|
||||
|
||||
public function getBaseUrl(): string
|
||||
{
|
||||
return $this->getData()['baseUrl'];
|
||||
}
|
||||
|
||||
public function getSubscriber(): Subscriber
|
||||
{
|
||||
return new Subscriber($this->getData()['subscriber']);
|
||||
}
|
||||
|
||||
public function getExpiration(): ?int
|
||||
{
|
||||
return $this->getData()['expiration'] ?? null;
|
||||
}
|
||||
|
||||
public function isExpired(): bool
|
||||
{
|
||||
return $this->getData()['isExpired'];
|
||||
}
|
||||
|
||||
public function getUrl(): string
|
||||
{
|
||||
return $this->getData()['url'];
|
||||
}
|
||||
}
|
||||
@ -20,6 +20,12 @@ class PullPayment extends AbstractResult
|
||||
return $data['name'];
|
||||
}
|
||||
|
||||
public function getDescription(): string
|
||||
{
|
||||
$data = $this->getData();
|
||||
return $data['description'];
|
||||
}
|
||||
|
||||
public function getCurrency(): string
|
||||
{
|
||||
$data = $this->getData();
|
||||
|
||||
@ -13,17 +13,40 @@ class StorePaymentMethodCollection extends AbstractListResult
|
||||
{
|
||||
$r = [];
|
||||
foreach ($this->getData() as $paymentMethod => $paymentMethodData) {
|
||||
// BTCPay 2.0 compatibility: List is not a keyed array anymore so fix it here.
|
||||
if (is_numeric($paymentMethod)) {
|
||||
$paymentMethod = $paymentMethodData['paymentMethodId'];
|
||||
// Extract the cryptoCode from the paymentMethodId. e.g. "BTC-CHAIN" -> "BTC"
|
||||
$parts = explode('-', $paymentMethod);
|
||||
$extractedCryptoCode = $parts[0];
|
||||
}
|
||||
|
||||
// Consistency: Flatten the array to be consistent with the specific
|
||||
// payment method endpoints.
|
||||
$paymentMethodData += $paymentMethodData['data'];
|
||||
unset($paymentMethodData['data']);
|
||||
if (isset($paymentMethodData['data'])) {
|
||||
$paymentMethodData += $paymentMethodData['data'];
|
||||
unset($paymentMethodData['data']);
|
||||
}
|
||||
|
||||
if (strpos($paymentMethod, 'LightningNetwork') !== false) {
|
||||
// BTCPay 2.0 compatibility: Handle config data if exists.
|
||||
if (isset($paymentMethodData['config'])) {
|
||||
$paymentMethodData += $paymentMethodData['config'];
|
||||
unset($paymentMethodData['config']);
|
||||
}
|
||||
|
||||
// BTCPay 2.0 compatibility: Check for renamed LN payment method id.
|
||||
if (preg_match('/(LightningNetwork|-LN$)/', $paymentMethod)) {
|
||||
// Consistency: Add back the cryptoCode missing on this endpoint
|
||||
// results until it is there.
|
||||
if (!isset($paymentMethodData['cryptoCode'])) {
|
||||
$paymentMethodData['cryptoCode'] = str_replace('-LightningNetwork', '', $paymentMethod);
|
||||
}
|
||||
|
||||
// BTCPay 2.0 compatibility: put the extracted cryptoCode in the cryptoCode field.
|
||||
if (isset($extractedCryptoCode)) {
|
||||
$paymentMethodData['cryptoCode'] = $extractedCryptoCode;
|
||||
}
|
||||
|
||||
$r[] = new StorePaymentMethodLightningNetwork($paymentMethodData, $paymentMethod);
|
||||
} else {
|
||||
// Consistency: Add back the cryptoCode missing on this endpoint
|
||||
@ -31,6 +54,12 @@ class StorePaymentMethodCollection extends AbstractListResult
|
||||
if (!isset($paymentMethodData['cryptoCode'])) {
|
||||
$paymentMethodData['cryptoCode'] = $paymentMethod;
|
||||
}
|
||||
|
||||
// BTCPay 2.0 compatibility: put the currency code in the cryptoCode field.
|
||||
if (isset($extractedCryptoCode)) {
|
||||
$paymentMethodData['cryptoCode'] = $extractedCryptoCode;
|
||||
}
|
||||
|
||||
$r[] = new StorePaymentMethodOnChain($paymentMethodData, $paymentMethod);
|
||||
}
|
||||
}
|
||||
|
||||
93
src/Result/Subscriber.php
Normal file
93
src/Result/Subscriber.php
Normal file
@ -0,0 +1,93 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace BTCPayServer\Result;
|
||||
|
||||
class Subscriber extends AbstractResult
|
||||
{
|
||||
public function getCreated(): int
|
||||
{
|
||||
return $this->getData()['created'];
|
||||
}
|
||||
|
||||
public function getCustomer(): Customer
|
||||
{
|
||||
return new Customer($this->getData()['customer']);
|
||||
}
|
||||
|
||||
public function getOffering(): Offering
|
||||
{
|
||||
return new Offering($this->getData()['offering']);
|
||||
}
|
||||
|
||||
public function getPlan(): OfferingPlan
|
||||
{
|
||||
return new OfferingPlan($this->getData()['plan']);
|
||||
}
|
||||
|
||||
public function getPeriodEnd(): ?int
|
||||
{
|
||||
return $this->getData()['periodEnd'] ?? null;
|
||||
}
|
||||
|
||||
public function getTrialEnd(): ?int
|
||||
{
|
||||
return $this->getData()['trialEnd'] ?? null;
|
||||
}
|
||||
|
||||
public function getGracePeriodEnd(): ?int
|
||||
{
|
||||
return $this->getData()['gracePeriodEnd'] ?? null;
|
||||
}
|
||||
|
||||
public function isActive(): bool
|
||||
{
|
||||
return $this->getData()['isActive'];
|
||||
}
|
||||
|
||||
public function isSuspended(): bool
|
||||
{
|
||||
return $this->getData()['isSuspended'];
|
||||
}
|
||||
|
||||
public function getSuspensionReason(): ?string
|
||||
{
|
||||
return $this->getData()['suspensionReason'] ?? null;
|
||||
}
|
||||
|
||||
public function isAutoRenew(): bool
|
||||
{
|
||||
return $this->getData()['autoRenew'];
|
||||
}
|
||||
|
||||
public function getMetadata(): ?array
|
||||
{
|
||||
return $this->getData()['metadata'] ?? null;
|
||||
}
|
||||
|
||||
public function getProcessingInvoiceId(): ?string
|
||||
{
|
||||
return $this->getData()['processingInvoiceId'] ?? null;
|
||||
}
|
||||
|
||||
public function getNextPlan(): ?OfferingPlan
|
||||
{
|
||||
return isset($this->getData()['nextPlan']) ? new OfferingPlan($this->getData()['nextPlan']) : null;
|
||||
}
|
||||
|
||||
public function getScheduledPlan(): ?OfferingPlan
|
||||
{
|
||||
return isset($this->getData()['scheduledPlan']) ? new OfferingPlan($this->getData()['scheduledPlan']) : null;
|
||||
}
|
||||
|
||||
public function getScheduledPlanActivatesAt(): ?int
|
||||
{
|
||||
return $this->getData()['scheduledPlanActivatesAt'] ?? null;
|
||||
}
|
||||
|
||||
public function getPhase(): string
|
||||
{
|
||||
return $this->getData()['phase'];
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user