mirror of
https://github.com/woocommerce/woocommerce-paypal-payments.git
synced 2026-07-30 02:17:46 +08:00
285 lines
8.8 KiB
PHP
285 lines
8.8 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace WooCommerce\PayPalCommerce\PayPalSubscriptions;
|
|
|
|
use Psr\Log\LoggerInterface;
|
|
use WC_Product;
|
|
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\BillingPlans;
|
|
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\CatalogProducts;
|
|
use WooCommerce\PayPalCommerce\ApiClient\Entity\BillingCycle;
|
|
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
|
|
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
|
use WooCommerce\PayPalCommerce\ApiClient\Factory\BillingCycleFactory;
|
|
use WooCommerce\PayPalCommerce\ApiClient\Factory\PaymentPreferencesFactory;
|
|
use WooCommerce\PayPalCommerce\ApiClient\Helper\CurrencyGetter;
|
|
use WooCommerce\PayPalCommerce\ApiClient\Helper\ItemTrait;
|
|
|
|
class SubscriptionsApiHandler {
|
|
|
|
use ItemTrait;
|
|
|
|
/**
|
|
* Catalog products.
|
|
*
|
|
* @var CatalogProducts
|
|
*/
|
|
private $products_endpoint;
|
|
|
|
/**
|
|
* Billing plans.
|
|
*
|
|
* @var BillingPlans
|
|
*/
|
|
private $billing_plans_endpoint;
|
|
|
|
/**
|
|
* Billing cycle factory.
|
|
*
|
|
* @var BillingCycleFactory
|
|
*/
|
|
private $billing_cycle_factory;
|
|
|
|
/**
|
|
* Payment preferences factory.
|
|
*
|
|
* @var PaymentPreferencesFactory
|
|
*/
|
|
private $payment_preferences_factory;
|
|
|
|
/**
|
|
* The currency.
|
|
*
|
|
* @var CurrencyGetter
|
|
*/
|
|
private CurrencyGetter $currency;
|
|
|
|
/**
|
|
* The logger.
|
|
*
|
|
* @var LoggerInterface
|
|
*/
|
|
private $logger;
|
|
|
|
/**
|
|
* @param CatalogProducts $products_endpoint Products endpoint.
|
|
* @param BillingPlans $billing_plans_endpoint Billing plans endpoint.
|
|
* @param BillingCycleFactory $billing_cycle_factory Billing cycle factory.
|
|
* @param PaymentPreferencesFactory $payment_preferences_factory Payment preferences factory.
|
|
* @param CurrencyGetter $currency The currency.
|
|
* @param LoggerInterface $logger The logger.
|
|
*/
|
|
public function __construct(
|
|
CatalogProducts $products_endpoint,
|
|
BillingPlans $billing_plans_endpoint,
|
|
BillingCycleFactory $billing_cycle_factory,
|
|
PaymentPreferencesFactory $payment_preferences_factory,
|
|
CurrencyGetter $currency,
|
|
LoggerInterface $logger
|
|
) {
|
|
$this->products_endpoint = $products_endpoint;
|
|
$this->billing_plans_endpoint = $billing_plans_endpoint;
|
|
$this->billing_cycle_factory = $billing_cycle_factory;
|
|
$this->payment_preferences_factory = $payment_preferences_factory;
|
|
$this->currency = $currency;
|
|
$this->logger = $logger;
|
|
}
|
|
|
|
/**
|
|
* Creates a Catalog Product and adds it as WC product meta.
|
|
*
|
|
* @param WC_Product $product The WC product.
|
|
* @return void
|
|
*/
|
|
public function create_product( WC_Product $product ) {
|
|
try {
|
|
$subscription_product = $this->products_endpoint->create( $this->prepare_item_string( $product->get_title() ), $this->prepare_item_string( $product->get_description() ) );
|
|
$product->update_meta_data( 'ppcp_subscription_product', $subscription_product->to_array() );
|
|
$product->save();
|
|
} catch ( RuntimeException $exception ) {
|
|
$error = $exception->getMessage();
|
|
if ( $exception instanceof PayPalApiException ) {
|
|
$error = $exception->get_details( $error );
|
|
}
|
|
|
|
$this->logger->error( 'Could not create catalog product on PayPal. ' . $error );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Creates a subscription plan.
|
|
*
|
|
* @param string $plan_name The plan name.
|
|
* @param WC_Product $product The WC product.
|
|
* @return void
|
|
*/
|
|
public function create_plan( string $plan_name, WC_Product $product ): void {
|
|
try {
|
|
$subscription_plan = $this->billing_plans_endpoint->create(
|
|
$plan_name ?: $product->get_title(),
|
|
$product->get_meta( 'ppcp_subscription_product' )['id'] ?? '',
|
|
$this->billing_cycles( $product ),
|
|
$this->payment_preferences_factory->from_wc_product( $product )->to_array()
|
|
);
|
|
|
|
$product->update_meta_data( 'ppcp_subscription_plan', $subscription_plan->to_array() );
|
|
$product->save();
|
|
} catch ( RuntimeException $exception ) {
|
|
$error = $exception->getMessage();
|
|
if ( $exception instanceof PayPalApiException ) {
|
|
$error = $exception->get_details( $error );
|
|
}
|
|
|
|
$this->logger->error( 'Could not create subscription plan on PayPal. ' . $error );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Updates a product.
|
|
*
|
|
* @param WC_Product $product The WC product.
|
|
* @return void
|
|
*/
|
|
public function update_product( WC_Product $product ): void {
|
|
try {
|
|
$catalog_product_id = $product->get_meta( 'ppcp_subscription_product' )['id'] ?? '';
|
|
if ( $catalog_product_id ) {
|
|
$catalog_product = $this->products_endpoint->product( $catalog_product_id );
|
|
$catalog_product_name = $catalog_product->name() ?: '';
|
|
$catalog_product_description = $catalog_product->description() ?: '';
|
|
|
|
$wc_product_description = $this->prepare_item_string( $product->get_description() ) ?: $this->prepare_item_string( $product->get_title() );
|
|
|
|
if ( $catalog_product_name !== $product->get_title() || $catalog_product_description !== $wc_product_description ) {
|
|
$data = array();
|
|
if ( $catalog_product_name !== $product->get_title() ) {
|
|
$data[] = (object) array(
|
|
'op' => 'replace',
|
|
'path' => '/name',
|
|
'value' => $product->get_title(),
|
|
);
|
|
}
|
|
if ( $catalog_product_description !== $wc_product_description ) {
|
|
$data[] = (object) array(
|
|
'op' => 'replace',
|
|
'path' => '/description',
|
|
'value' => $wc_product_description,
|
|
);
|
|
}
|
|
|
|
$this->products_endpoint->update( $catalog_product_id, $data );
|
|
}
|
|
}
|
|
} catch ( RuntimeException $exception ) {
|
|
$error = $exception->getMessage();
|
|
if ( $exception instanceof PayPalApiException ) {
|
|
$error = $exception->get_details( $error );
|
|
}
|
|
|
|
$this->logger->error( 'Could not update catalog product on PayPal. ' . $error );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Updates a plan.
|
|
*
|
|
* @param WC_Product $product The WC product.
|
|
* @return void
|
|
*/
|
|
public function update_plan( WC_Product $product ): void {
|
|
try {
|
|
$subscription_plan_id = $product->get_meta( 'ppcp_subscription_plan' )['id'] ?? '';
|
|
if ( $subscription_plan_id ) {
|
|
$subscription_plan = $this->billing_plans_endpoint->plan( $subscription_plan_id );
|
|
|
|
$price = $subscription_plan->billing_cycles()[0]->pricing_scheme()['fixed_price']['value'] ?? '';
|
|
if ( $price && round( (float) $price, 2 ) !== round( (float) $product->get_price(), 2 ) ) {
|
|
$this->billing_plans_endpoint->update_pricing(
|
|
$subscription_plan_id,
|
|
$this->billing_cycle_factory->from_wc_product( $product )
|
|
);
|
|
}
|
|
}
|
|
} catch ( RuntimeException $exception ) {
|
|
$error = $exception->getMessage();
|
|
if ( $exception instanceof PayPalApiException ) {
|
|
$error = $exception->get_details( $error );
|
|
}
|
|
|
|
$this->logger->error( 'Could not update subscription plan on PayPal. ' . $error );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns billing cycles based on WC Subscription product.
|
|
*
|
|
* @param WC_Product $product The WC Subscription product.
|
|
* @return array
|
|
*/
|
|
private function billing_cycles( WC_Product $product ): array {
|
|
$billing_cycles = array();
|
|
$sequence = 1;
|
|
|
|
$trial_length = $product->get_meta( '_subscription_trial_length' ) ?? '';
|
|
if ( $trial_length ) {
|
|
$billing_cycles[] = ( new BillingCycle(
|
|
array(
|
|
'interval_unit' => $product->get_meta( '_subscription_trial_period' ),
|
|
'interval_count' => $product->get_meta( '_subscription_trial_length' ),
|
|
),
|
|
$sequence,
|
|
'TRIAL',
|
|
array(
|
|
'fixed_price' => array(
|
|
'value' => '0',
|
|
'currency_code' => $this->currency->get(),
|
|
),
|
|
),
|
|
1
|
|
) )->to_array();
|
|
|
|
++$sequence;
|
|
}
|
|
|
|
$interval = $product->get_meta( '_subscription_period' );
|
|
$period_interval = (int) $product->get_meta( '_subscription_period_interval' );
|
|
$update = false;
|
|
if ( $interval === 'day' && $period_interval > 365 ) {
|
|
$period_interval = 365;
|
|
$update = true;
|
|
} elseif ( $interval === 'week' && $period_interval > 52 ) {
|
|
$period_interval = 52;
|
|
$update = true;
|
|
} elseif ( $interval === 'month' && $period_interval > 12 ) {
|
|
$period_interval = 12;
|
|
$update = true;
|
|
} elseif ( $interval === 'year' && $period_interval > 1 ) {
|
|
$period_interval = 1;
|
|
$update = true;
|
|
}
|
|
if ( $update ) {
|
|
$product->add_meta_data( '_subscription_period_interval', (string) $period_interval, true );
|
|
$product->save();
|
|
$this->logger->warning( sprintf( 'Subscription plan on PayPal is to high for %1$s interval change it to maximum of %2$d', $interval, $period_interval ) );
|
|
}
|
|
|
|
$billing_cycles[] = ( new BillingCycle(
|
|
array(
|
|
'interval_unit' => $interval,
|
|
'interval_count' => $period_interval,
|
|
),
|
|
$sequence,
|
|
'REGULAR',
|
|
array(
|
|
'fixed_price' => array(
|
|
'value' => $product->get_meta( '_subscription_price' ) ?: $product->get_price(),
|
|
'currency_code' => $this->currency->get(),
|
|
),
|
|
),
|
|
(int) $product->get_meta( '_subscription_length' )
|
|
) )->to_array();
|
|
|
|
return $billing_cycles;
|
|
}
|
|
}
|