Files
WooNooW/.agent/plans/subscription-module.md
Dwindi Ramadhana 40aee67c46 feat: Implement A4 invoice layout and hide Label for virtual orders
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
2026-01-05 19:16:13 +07:00

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 renewals
  • woonoow_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

  1. Database tables and SubscriptionManager
  2. Product meta fields for subscription settings
  3. Order hook to create subscription
  4. Renewal cron job
  5. Admin SPA list/detail pages
  6. Customer SPA pages
  7. Integration with Licensing module