Invoice: - Enhanced A4-ready layout with proper structure - Store header with invoice number - Billing/shipping address sections - Styled items table with alternating rows - Totals summary with conditional display - Thank you footer Label: - Label button now hidden for virtual-only orders - Uses existing isVirtualOnly detection Print CSS: - Added @page A4 size directive - Print-color-adjust for background colors - 20mm padding for proper margins Documentation: - Updated subscription module plan (comprehensive) - Updated affiliate module plan (comprehensive) - Created shipping label standardization plan
5.7 KiB
5.7 KiB
Subscription Module Plan
Overview
Recurring product subscriptions with flexible billing, integrated as a core plugin module (like Newsletter/Wishlist/Licensing).
Module Architecture
Core Features
- Recurring billing: Weekly, monthly, yearly, custom intervals
- Free trials: X days free before billing starts
- Sign-up fees: One-time fee on first subscription
- Automatic renewals: Process payment on renewal date
- Manual renewal: Allow customers to renew manually
- Proration: Calculate prorated amounts on plan changes
- Pause/Resume: Allow customers to pause subscriptions
Product Integration
- Checkbox under "Additional Options": Enable subscription for this product
- When enabled, show subscription settings:
- Billing period (weekly/monthly/yearly/custom)
- Billing interval (every X periods)
- Free trial days
- Sign-up fee
- Subscription length (0 = unlimited)
- Variable products: Variation-level subscription settings (different durations/prices per variation)
Integration with Licensing
- Licenses can be bound to subscriptions
- When subscription is active → license is valid
- When subscription expires/cancelled → license is revoked
- Auto-renewal keeps license active
Database Schema
Table: woonoow_subscriptions
CREATE TABLE woonoow_subscriptions (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
user_id BIGINT UNSIGNED NOT NULL,
order_id BIGINT UNSIGNED NOT NULL,
product_id BIGINT UNSIGNED NOT NULL,
variation_id BIGINT UNSIGNED DEFAULT NULL,
status ENUM('pending', 'active', 'on-hold', 'cancelled', 'expired', 'pending-cancel') DEFAULT 'pending',
billing_period ENUM('day', 'week', 'month', 'year') NOT NULL,
billing_interval INT UNSIGNED DEFAULT 1,
start_date DATETIME NOT NULL,
trial_end_date DATETIME DEFAULT NULL,
next_payment_date DATETIME DEFAULT NULL,
end_date DATETIME DEFAULT NULL,
last_payment_date DATETIME DEFAULT NULL,
payment_method VARCHAR(100) DEFAULT NULL,
payment_meta LONGTEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_user_id (user_id),
INDEX idx_order_id (order_id),
INDEX idx_status (status),
INDEX idx_next_payment (next_payment_date)
);
Table: woonoow_subscription_orders
Links subscription to renewal orders:
CREATE TABLE woonoow_subscription_orders (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
subscription_id BIGINT UNSIGNED NOT NULL,
order_id BIGINT UNSIGNED NOT NULL,
order_type ENUM('parent', 'renewal', 'switch', 'resubscribe') DEFAULT 'renewal',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
INDEX idx_subscription (subscription_id),
INDEX idx_order (order_id)
);
Backend Structure
includes/Modules/Subscription/
├── SubscriptionModule.php # Bootstrap, hooks, product meta
├── SubscriptionManager.php # Core logic
├── SubscriptionScheduler.php # Cron jobs for renewals
└── SubscriptionSettings.php # Settings schema
includes/Api/SubscriptionsController.php # REST endpoints
SubscriptionManager Methods
- create($order, $product, $user) # Create subscription from order
- renew($subscription_id) # Process renewal
- cancel($subscription_id, $reason) # Cancel subscription
- pause($subscription_id) # Pause subscription
- resume($subscription_id) # Resume paused subscription
- switch($subscription_id, $new_product) # Switch plan
- get_next_payment_date($subscription) # Calculate next date
- process_renewal_payment($subscription) # Charge payment
Cron Jobs
woonoow_process_subscription_renewals: Run daily, process due renewalswoonoow_check_expired_subscriptions: Mark expired subscriptions
REST API Endpoints
Admin Endpoints
GET /subscriptions # List all subscriptions
GET /subscriptions/{id} # Get subscription details
PUT /subscriptions/{id} # Update subscription
POST /subscriptions/{id}/cancel # Cancel subscription
POST /subscriptions/{id}/renew # Force renewal
Customer Endpoints
GET /my-subscriptions # Customer's subscriptions
GET /my-subscriptions/{id} # Subscription detail
POST /my-subscriptions/{id}/cancel # Request cancellation
POST /my-subscriptions/{id}/pause # Pause subscription
POST /my-subscriptions/{id}/resume # Resume subscription
Admin SPA
Subscriptions List (/subscriptions)
- Table: ID, Customer, Product, Status, Next Payment, Actions
- Filters: Status, Product, Date range
- Actions: View, Cancel, Renew
Subscription Detail (/subscriptions/:id)
- Subscription info card
- Related orders list
- Payment history
- Action buttons: Cancel, Pause, Renew
Customer SPA
My Subscriptions (/my-account/subscriptions)
- List of active/past subscriptions
- Status badges
- Next payment info
- Actions: Cancel, Pause, View
Subscription Detail
- Product info
- Billing schedule
- Payment history
- Management actions
Settings Schema
return [
'default_status' => 'active',
'button_text_subscribe' => 'Subscribe Now',
'button_text_renew' => 'Renew Subscription',
'allow_customer_cancel' => true,
'allow_customer_pause' => true,
'max_pause_count' => 3,
'renewal_retry_days' => [1, 3, 5], // Retry failed payments
'expire_after_failed_attempts' => 3,
'send_renewal_reminder' => true,
'reminder_days_before' => 3,
];
Implementation Priority
- Database tables and SubscriptionManager
- Product meta fields for subscription settings
- Order hook to create subscription
- Renewal cron job
- Admin SPA list/detail pages
- Customer SPA pages
- Integration with Licensing module