finalizing subscription moduile, ready to test
This commit is contained in:
476
includes/Api/SubscriptionsController.php
Normal file
476
includes/Api/SubscriptionsController.php
Normal file
@@ -0,0 +1,476 @@
|
||||
<?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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user