477 lines
16 KiB
PHP
477 lines
16 KiB
PHP
<?php
|
|
|
|
/**
|
|
* Subscriptions API Controller
|
|
*
|
|
* REST API endpoints for subscription management.
|
|
*
|
|
* @package WooNooW\Api
|
|
*/
|
|
|
|
namespace WooNooW\Api;
|
|
|
|
if (!defined('ABSPATH')) exit;
|
|
|
|
use WP_REST_Request;
|
|
use WP_REST_Response;
|
|
use WP_Error;
|
|
use WooNooW\Core\ModuleRegistry;
|
|
use WooNooW\Modules\Subscription\SubscriptionManager;
|
|
|
|
class SubscriptionsController
|
|
{
|
|
|
|
/**
|
|
* Register REST routes
|
|
*/
|
|
public static function register_routes()
|
|
{
|
|
// Check if module is enabled
|
|
if (!ModuleRegistry::is_enabled('subscription')) {
|
|
return;
|
|
}
|
|
|
|
// Admin routes
|
|
register_rest_route('woonoow/v1', '/subscriptions', [
|
|
'methods' => 'GET',
|
|
'callback' => [__CLASS__, 'get_subscriptions'],
|
|
'permission_callback' => function () {
|
|
return current_user_can('manage_woocommerce');
|
|
},
|
|
]);
|
|
|
|
register_rest_route('woonoow/v1', '/subscriptions/(?P<id>\d+)', [
|
|
'methods' => 'GET',
|
|
'callback' => [__CLASS__, 'get_subscription'],
|
|
'permission_callback' => function () {
|
|
return current_user_can('manage_woocommerce');
|
|
},
|
|
]);
|
|
|
|
register_rest_route('woonoow/v1', '/subscriptions/(?P<id>\d+)', [
|
|
'methods' => 'PUT',
|
|
'callback' => [__CLASS__, 'update_subscription'],
|
|
'permission_callback' => function () {
|
|
return current_user_can('manage_woocommerce');
|
|
},
|
|
]);
|
|
|
|
register_rest_route('woonoow/v1', '/subscriptions/(?P<id>\d+)/cancel', [
|
|
'methods' => 'POST',
|
|
'callback' => [__CLASS__, 'cancel_subscription'],
|
|
'permission_callback' => function () {
|
|
return current_user_can('manage_woocommerce');
|
|
},
|
|
]);
|
|
|
|
register_rest_route('woonoow/v1', '/subscriptions/(?P<id>\d+)/renew', [
|
|
'methods' => 'POST',
|
|
'callback' => [__CLASS__, 'renew_subscription'],
|
|
'permission_callback' => function () {
|
|
return current_user_can('manage_woocommerce');
|
|
},
|
|
]);
|
|
|
|
register_rest_route('woonoow/v1', '/subscriptions/(?P<id>\d+)/pause', [
|
|
'methods' => 'POST',
|
|
'callback' => [__CLASS__, 'pause_subscription'],
|
|
'permission_callback' => function () {
|
|
return current_user_can('manage_woocommerce');
|
|
},
|
|
]);
|
|
|
|
register_rest_route('woonoow/v1', '/subscriptions/(?P<id>\d+)/resume', [
|
|
'methods' => 'POST',
|
|
'callback' => [__CLASS__, 'resume_subscription'],
|
|
'permission_callback' => function () {
|
|
return current_user_can('manage_woocommerce');
|
|
},
|
|
]);
|
|
|
|
// Customer routes
|
|
register_rest_route('woonoow/v1', '/account/subscriptions', [
|
|
'methods' => 'GET',
|
|
'callback' => [__CLASS__, 'get_customer_subscriptions'],
|
|
'permission_callback' => function () {
|
|
return is_user_logged_in();
|
|
},
|
|
]);
|
|
|
|
register_rest_route('woonoow/v1', '/account/subscriptions/(?P<id>\d+)', [
|
|
'methods' => 'GET',
|
|
'callback' => [__CLASS__, 'get_customer_subscription'],
|
|
'permission_callback' => function () {
|
|
return is_user_logged_in();
|
|
},
|
|
]);
|
|
|
|
register_rest_route('woonoow/v1', '/account/subscriptions/(?P<id>\d+)/cancel', [
|
|
'methods' => 'POST',
|
|
'callback' => [__CLASS__, 'customer_cancel'],
|
|
'permission_callback' => function () {
|
|
return is_user_logged_in();
|
|
},
|
|
]);
|
|
|
|
register_rest_route('woonoow/v1', '/account/subscriptions/(?P<id>\d+)/pause', [
|
|
'methods' => 'POST',
|
|
'callback' => [__CLASS__, 'customer_pause'],
|
|
'permission_callback' => function () {
|
|
return is_user_logged_in();
|
|
},
|
|
]);
|
|
|
|
register_rest_route('woonoow/v1', '/account/subscriptions/(?P<id>\d+)/resume', [
|
|
'methods' => 'POST',
|
|
'callback' => [__CLASS__, 'customer_resume'],
|
|
'permission_callback' => function () {
|
|
return is_user_logged_in();
|
|
},
|
|
]);
|
|
|
|
register_rest_route('woonoow/v1', '/account/subscriptions/(?P<id>\d+)/renew', [
|
|
'methods' => 'POST',
|
|
'callback' => [__CLASS__, 'customer_renew'],
|
|
'permission_callback' => function () {
|
|
return is_user_logged_in();
|
|
},
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Get all subscriptions (admin)
|
|
*/
|
|
public static function get_subscriptions(WP_REST_Request $request)
|
|
{
|
|
$args = [
|
|
'status' => $request->get_param('status'),
|
|
'product_id' => $request->get_param('product_id'),
|
|
'user_id' => $request->get_param('user_id'),
|
|
'limit' => $request->get_param('per_page') ?: 20,
|
|
'offset' => (($request->get_param('page') ?: 1) - 1) * ($request->get_param('per_page') ?: 20),
|
|
];
|
|
|
|
$subscriptions = SubscriptionManager::get_all($args);
|
|
$total = SubscriptionManager::count(['status' => $args['status']]);
|
|
|
|
// Enrich with product and user info
|
|
$enriched = [];
|
|
foreach ($subscriptions as $subscription) {
|
|
$enriched[] = self::enrich_subscription($subscription);
|
|
}
|
|
|
|
return new WP_REST_Response([
|
|
'subscriptions' => $enriched,
|
|
'total' => $total,
|
|
'page' => $request->get_param('page') ?: 1,
|
|
'per_page' => $args['limit'],
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Get single subscription (admin)
|
|
*/
|
|
public static function get_subscription(WP_REST_Request $request)
|
|
{
|
|
$subscription = SubscriptionManager::get($request->get_param('id'));
|
|
|
|
if (!$subscription) {
|
|
return new WP_Error('not_found', __('Subscription not found', 'woonoow'), ['status' => 404]);
|
|
}
|
|
|
|
$enriched = self::enrich_subscription($subscription);
|
|
$enriched['orders'] = SubscriptionManager::get_orders($subscription->id);
|
|
|
|
return new WP_REST_Response($enriched);
|
|
}
|
|
|
|
/**
|
|
* Update subscription (admin)
|
|
*/
|
|
public static function update_subscription(WP_REST_Request $request)
|
|
{
|
|
global $wpdb;
|
|
|
|
$subscription = SubscriptionManager::get($request->get_param('id'));
|
|
|
|
if (!$subscription) {
|
|
return new WP_Error('not_found', __('Subscription not found', 'woonoow'), ['status' => 404]);
|
|
}
|
|
|
|
$data = $request->get_json_params();
|
|
$allowed_fields = ['status', 'next_payment_date', 'end_date', 'billing_period', 'billing_interval'];
|
|
|
|
$update_data = [];
|
|
$format = [];
|
|
|
|
foreach ($allowed_fields as $field) {
|
|
if (isset($data[$field])) {
|
|
$update_data[$field] = $data[$field];
|
|
$format[] = is_numeric($data[$field]) ? '%d' : '%s';
|
|
}
|
|
}
|
|
|
|
if (empty($update_data)) {
|
|
return new WP_Error('no_data', __('No valid fields to update', 'woonoow'), ['status' => 400]);
|
|
}
|
|
|
|
$table = $wpdb->prefix . 'woonoow_subscriptions';
|
|
$updated = $wpdb->update($table, $update_data, ['id' => $subscription->id], $format, ['%d']);
|
|
|
|
if ($updated === false) {
|
|
return new WP_Error('update_failed', __('Failed to update subscription', 'woonoow'), ['status' => 500]);
|
|
}
|
|
|
|
return new WP_REST_Response(['success' => true]);
|
|
}
|
|
|
|
/**
|
|
* Cancel subscription (admin)
|
|
*/
|
|
public static function cancel_subscription(WP_REST_Request $request)
|
|
{
|
|
$data = $request->get_json_params();
|
|
$reason = $data['reason'] ?? 'Cancelled by admin';
|
|
|
|
$result = SubscriptionManager::cancel($request->get_param('id'), $reason);
|
|
|
|
if (!$result) {
|
|
return new WP_Error('cancel_failed', __('Failed to cancel subscription', 'woonoow'), ['status' => 500]);
|
|
}
|
|
|
|
return new WP_REST_Response(['success' => true]);
|
|
}
|
|
|
|
/**
|
|
* Renew subscription (admin - force immediate renewal)
|
|
*/
|
|
public static function renew_subscription(WP_REST_Request $request)
|
|
{
|
|
$result = SubscriptionManager::renew($request->get_param('id'));
|
|
|
|
if (!$result) {
|
|
return new WP_Error('renew_failed', __('Failed to process renewal', 'woonoow'), ['status' => 500]);
|
|
}
|
|
|
|
return new WP_REST_Response(['success' => true, 'order_id' => $result['order_id']]);
|
|
}
|
|
|
|
/**
|
|
* Pause subscription (admin)
|
|
*/
|
|
public static function pause_subscription(WP_REST_Request $request)
|
|
{
|
|
$result = SubscriptionManager::pause($request->get_param('id'));
|
|
|
|
if (!$result) {
|
|
return new WP_Error('pause_failed', __('Failed to pause subscription', 'woonoow'), ['status' => 500]);
|
|
}
|
|
|
|
return new WP_REST_Response(['success' => true]);
|
|
}
|
|
|
|
/**
|
|
* Resume subscription (admin)
|
|
*/
|
|
public static function resume_subscription(WP_REST_Request $request)
|
|
{
|
|
$result = SubscriptionManager::resume($request->get_param('id'));
|
|
|
|
if (!$result) {
|
|
return new WP_Error('resume_failed', __('Failed to resume subscription', 'woonoow'), ['status' => 500]);
|
|
}
|
|
|
|
return new WP_REST_Response(['success' => true]);
|
|
}
|
|
|
|
/**
|
|
* Get customer's subscriptions
|
|
*/
|
|
public static function get_customer_subscriptions(WP_REST_Request $request)
|
|
{
|
|
$user_id = get_current_user_id();
|
|
$subscriptions = SubscriptionManager::get_by_user($user_id, [
|
|
'status' => $request->get_param('status'),
|
|
'limit' => $request->get_param('per_page') ?: 20,
|
|
'offset' => (($request->get_param('page') ?: 1) - 1) * ($request->get_param('per_page') ?: 20),
|
|
]);
|
|
|
|
// Enrich each subscription
|
|
$enriched = [];
|
|
foreach ($subscriptions as $subscription) {
|
|
$enriched[] = self::enrich_subscription($subscription);
|
|
}
|
|
|
|
return new WP_REST_Response($enriched);
|
|
}
|
|
|
|
/**
|
|
* Get customer's subscription detail
|
|
*/
|
|
public static function get_customer_subscription(WP_REST_Request $request)
|
|
{
|
|
$user_id = get_current_user_id();
|
|
$subscription = SubscriptionManager::get($request->get_param('id'));
|
|
|
|
if (!$subscription || $subscription->user_id != $user_id) {
|
|
return new WP_Error('not_found', __('Subscription not found', 'woonoow'), ['status' => 404]);
|
|
}
|
|
|
|
$enriched = self::enrich_subscription($subscription);
|
|
$enriched['orders'] = SubscriptionManager::get_orders($subscription->id);
|
|
|
|
return new WP_REST_Response($enriched);
|
|
}
|
|
|
|
/**
|
|
* Customer cancel their own subscription
|
|
*/
|
|
public static function customer_cancel(WP_REST_Request $request)
|
|
{
|
|
// Check if customer cancellation is allowed
|
|
$settings = ModuleRegistry::get_settings('subscription');
|
|
if (empty($settings['allow_customer_cancel'])) {
|
|
return new WP_Error('not_allowed', __('Customer cancellation is not allowed', 'woonoow'), ['status' => 403]);
|
|
}
|
|
|
|
$user_id = get_current_user_id();
|
|
$subscription = SubscriptionManager::get($request->get_param('id'));
|
|
|
|
if (!$subscription || $subscription->user_id != $user_id) {
|
|
return new WP_Error('not_found', __('Subscription not found', 'woonoow'), ['status' => 404]);
|
|
}
|
|
|
|
$data = $request->get_json_params();
|
|
$reason = $data['reason'] ?? 'Cancelled by customer';
|
|
|
|
$result = SubscriptionManager::cancel($subscription->id, $reason);
|
|
|
|
if (!$result) {
|
|
return new WP_Error('cancel_failed', __('Failed to cancel subscription', 'woonoow'), ['status' => 500]);
|
|
}
|
|
|
|
return new WP_REST_Response(['success' => true]);
|
|
}
|
|
|
|
/**
|
|
* Customer pause their own subscription
|
|
*/
|
|
public static function customer_pause(WP_REST_Request $request)
|
|
{
|
|
// Check if customer pause is allowed
|
|
$settings = ModuleRegistry::get_settings('subscription');
|
|
if (empty($settings['allow_customer_pause'])) {
|
|
return new WP_Error('not_allowed', __('Customer pause is not allowed', 'woonoow'), ['status' => 403]);
|
|
}
|
|
|
|
$user_id = get_current_user_id();
|
|
$subscription = SubscriptionManager::get($request->get_param('id'));
|
|
|
|
if (!$subscription || $subscription->user_id != $user_id) {
|
|
return new WP_Error('not_found', __('Subscription not found', 'woonoow'), ['status' => 404]);
|
|
}
|
|
|
|
$result = SubscriptionManager::pause($subscription->id);
|
|
|
|
if (!$result) {
|
|
return new WP_Error('pause_failed', __('Failed to pause subscription. Maximum pauses may have been reached.', 'woonoow'), ['status' => 500]);
|
|
}
|
|
|
|
return new WP_REST_Response(['success' => true]);
|
|
}
|
|
|
|
/**
|
|
* Customer resume their own subscription
|
|
*/
|
|
public static function customer_resume(WP_REST_Request $request)
|
|
{
|
|
$user_id = get_current_user_id();
|
|
$subscription = SubscriptionManager::get($request->get_param('id'));
|
|
|
|
if (!$subscription || $subscription->user_id != $user_id) {
|
|
return new WP_Error('not_found', __('Subscription not found', 'woonoow'), ['status' => 404]);
|
|
}
|
|
|
|
$result = SubscriptionManager::resume($subscription->id);
|
|
|
|
if (!$result) {
|
|
return new WP_Error('resume_failed', __('Failed to resume subscription', 'woonoow'), ['status' => 500]);
|
|
}
|
|
|
|
return new WP_REST_Response(['success' => true]);
|
|
}
|
|
|
|
/**
|
|
* Customer renew their own subscription (Early Renewal)
|
|
*/
|
|
public static function customer_renew(WP_REST_Request $request)
|
|
{
|
|
$user_id = get_current_user_id();
|
|
$subscription = SubscriptionManager::get($request->get_param('id'));
|
|
|
|
if (!$subscription || $subscription->user_id != $user_id) {
|
|
return new WP_Error('not_found', __('Subscription not found', 'woonoow'), ['status' => 404]);
|
|
}
|
|
|
|
// Check if subscription is active (for early renewal) or on-hold with no pending payment
|
|
if ($subscription->status !== 'active' && $subscription->status !== 'on-hold') {
|
|
return new WP_Error('not_allowed', __('Only active subscriptions can be renewed early', 'woonoow'), ['status' => 403]);
|
|
}
|
|
|
|
// Trigger renewal
|
|
$result = SubscriptionManager::renew($subscription->id);
|
|
|
|
// SubscriptionManager::renew returns array (success) or false (failed)
|
|
if (!$result) {
|
|
return new WP_Error('renew_failed', __('Failed to create renewal order', 'woonoow'), ['status' => 500]);
|
|
}
|
|
|
|
return new WP_REST_Response([
|
|
'success' => true,
|
|
'order_id' => $result['order_id'],
|
|
'status' => $result['status']
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Enrich subscription with product and user info
|
|
*/
|
|
private static function enrich_subscription($subscription)
|
|
{
|
|
$enriched = (array) $subscription;
|
|
|
|
// Add product info
|
|
$product_id = $subscription->variation_id ?: $subscription->product_id;
|
|
$product = wc_get_product($product_id);
|
|
$enriched['product_name'] = $product ? $product->get_name() : __('Unknown Product', 'woonoow');
|
|
$enriched['product_image'] = $product ? wp_get_attachment_url($product->get_image_id()) : '';
|
|
|
|
// Add user info
|
|
$user = get_userdata($subscription->user_id);
|
|
$enriched['user_email'] = $user ? $user->user_email : '';
|
|
$enriched['user_name'] = $user ? $user->display_name : __('Unknown User', 'woonoow');
|
|
|
|
// Add computed fields
|
|
$enriched['is_active'] = $subscription->status === 'active';
|
|
$enriched['can_pause'] = $subscription->status === 'active';
|
|
$enriched['can_resume'] = $subscription->status === 'on-hold';
|
|
$enriched['can_cancel'] = in_array($subscription->status, ['active', 'on-hold', 'pending']);
|
|
|
|
// Format billing info
|
|
$period_labels = [
|
|
'day' => __('day', 'woonoow'),
|
|
'week' => __('week', 'woonoow'),
|
|
'month' => __('month', 'woonoow'),
|
|
'year' => __('year', 'woonoow'),
|
|
];
|
|
$interval = $subscription->billing_interval > 1 ? $subscription->billing_interval . ' ' : '';
|
|
$period = $period_labels[$subscription->billing_period] ?? $subscription->billing_period;
|
|
if ($subscription->billing_interval > 1) {
|
|
$period .= 's'; // Pluralize
|
|
}
|
|
$enriched['billing_schedule'] = sprintf(__('Every %s%s', 'woonoow'), $interval, $period);
|
|
|
|
return $enriched;
|
|
}
|
|
}
|