# Recurpay & Licenses

Plugin WordPress de paiements récurrents Stripe, gestion de licences d'activation et facturation électronique conforme (France).

---

## Installation

### Prérequis

- WordPress ≥ 6.4
- PHP ≥ 8.1
- Composer
- Un compte Stripe

### 1. Installation des dépendances

```bash
cd wp-content/plugins/recurpay
composer install --no-dev --optimize-autoloader
```

### 2. Activation

Activez le plugin depuis `Extensions → Extensions installées`.  
Les tables BDD sont créées automatiquement à l'activation.

### 3. Configuration Stripe

1. Allez dans `Recurpay → Réglages → Stripe`
2. Copiez vos clés depuis le [Dashboard Stripe](https://dashboard.stripe.com/apikeys)
3. Créez un webhook Stripe pointant vers :
   ```
   https://votre-site.com/wp-json/rl/v1/stripe
   ```
   Événements à écouter :
   - `customer.subscription.created`
   - `customer.subscription.updated`
   - `customer.subscription.deleted`
   - `invoice.paid`
   - `invoice.payment_failed`
   - `invoice.upcoming`
   - `customer.subscription.trial_will_end`
   - `setup_intent.succeeded`

### 4. Informations vendeur (factures)

Renseignez `Recurpay → Réglages → Vendeur` avec votre SIRET et adresse complète.

---

## Endpoints API REST

| Endpoint | Usage |
|---|---|
| `POST /wp-json/rl/v1/stripe` | Webhooks Stripe |
| `POST /wp-json/rl/v1/license/activate` | Activation licence depuis plugin client |
| `POST /wp-json/rl/v1/license/validate` | Validation périodique (24h) |
| `POST /wp-json/rl/v1/license/deactivate` | Désactivation instance |
| `GET /wp-json/rl/v1/update-check` | Vérification mise à jour plugin |
| `GET /wp-json/rl/v1/portal` | Redirection portail Stripe |
| `GET /wp-json/rl/v1/invoice/{id}/download` | Téléchargement facture PDF |

---

## Intégration côté plugin client

Dans le plugin vendu à vos clients, ajoutez ce code pour la validation de licence :

```php
class MyPlugin_License {

    const API_BASE    = 'https://votre-site.com/wp-json/rl/v1';
    const OPTION_KEY  = 'myplugin_license_data';
    const CHECK_INTERVAL = DAY_IN_SECONDS;
    const GRACE_HOURS    = 72;

    public static function is_valid(): bool {
        $data = get_option( self::OPTION_KEY, [] );
        if ( empty( $data['status'] ) ) {
            return false;
        }
        if ( $data['status'] === 'active' ) {
            // Vérifier si un ping est nécessaire
            if ( time() - ( $data['last_check'] ?? 0 ) > self::CHECK_INTERVAL ) {
                wp_schedule_single_event( time(), 'myplugin_validate_license' );
            }
            return true;
        }
        // Période de grâce offline
        if ( ! empty( $data['grace_until'] ) && time() < $data['grace_until'] ) {
            return true;
        }
        return false;
    }

    public static function activate( string $key ): array {
        $response = wp_remote_post( self::API_BASE . '/license/activate', [
            'body' => [
                'license_key' => $key,
                'domain'      => home_url(),
                'instance_id' => self::get_instance_id(),
            ],
            'timeout' => 15,
        ] );

        if ( is_wp_error( $response ) ) {
            return [ 'success' => false, 'message' => $response->get_error_message() ];
        }

        $body = json_decode( wp_remote_retrieve_body( $response ), true );
        if ( ! empty( $body['success'] ) ) {
            update_option( self::OPTION_KEY, [
                'status'      => 'active',
                'license_key' => $key,
                'token'       => $body['data'],
                'last_check'  => time(),
                'grace_until' => time() + ( self::GRACE_HOURS * HOUR_IN_SECONDS ),
            ] );
        }

        return $body;
    }

    public static function validate(): void {
        $data = get_option( self::OPTION_KEY, [] );
        if ( empty( $data['license_key'] ) ) {
            return;
        }

        $response = wp_remote_post( self::API_BASE . '/license/validate', [
            'body' => [
                'license_key' => $data['license_key'],
                'domain'      => home_url(),
                'instance_id' => self::get_instance_id(),
            ],
            'timeout' => 10,
        ] );

        if ( is_wp_error( $response ) ) {
            // Étendre la période de grâce
            $data['grace_until'] = time() + ( self::GRACE_HOURS * HOUR_IN_SECONDS );
            update_option( self::OPTION_KEY, $data );
            return;
        }

        $body = json_decode( wp_remote_retrieve_body( $response ), true );
        $data['status']      = ( $body['success'] ?? false ) ? 'active' : ( $body['code'] ?? 'invalid' );
        $data['last_check']  = time();
        $data['grace_until'] = time() + ( self::GRACE_HOURS * HOUR_IN_SECONDS );
        update_option( self::OPTION_KEY, $data );
    }

    private static function get_instance_id(): string {
        $id = get_option( 'myplugin_instance_id' );
        if ( empty( $id ) ) {
            $id = wp_generate_uuid4();
            update_option( 'myplugin_instance_id', $id );
        }
        return $id;
    }
}

// Enregistrer le cron de validation
add_action( 'myplugin_validate_license', [ 'MyPlugin_License', 'validate' ] );
```

---

## Surcharge des templates

### Factures PDF
Copiez dans votre thème :
```
votre-theme/recurpay/invoice.php
```

### E-mails
Copiez dans votre thème :
```
votre-theme/recurpay/emails/invoice.php
votre-theme/recurpay/emails/welcome.php
votre-theme/recurpay/emails/suspended.php
votre-theme/recurpay/emails/cancelled.php
votre-theme/recurpay/emails/license.php
votre-theme/recurpay/emails/trial-ending.php
votre-theme/recurpay/emails/payment-failed.php
```

---

## Hooks disponibles

### Actions
| Hook | Description |
|---|---|
| `rl_subscription_activated` | Abonnement activé |
| `rl_subscription_suspended` | Abonnement suspendu |
| `rl_subscription_cancelled` | Abonnement annulé |
| `rl_subscription_reactivated` | Abonnement réactivé |
| `rl_subscription_status_changed` | Changement de statut |
| `rl_payment_completed` | Paiement encaissé |
| `rl_payment_failed` | Paiement échoué |
| `rl_license_created` | Licence créée |
| `rl_license_activated` | Licence activée sur un site |
| `rl_license_deactivated` | Licence désactivée |
| `rl_license_status_changed` | Changement de statut licence |
| `rl_invoice_created` | Facture créée |
| `rl_invoice_pdf_ready` | PDF généré |
| `rl_facturx_exported` | Export Factur-X JSON disponible |
| `rl_trial_ending` | Fin d'essai dans 3 jours |

### Filtres
| Filtre | Description |
|---|---|
| `rl_currency` | Devise active |
| `rl_invoice_number` | Numéro de facture |
| `rl_invoice_lines` | Lignes de détail de la facture |
| `rl_email_subject` | Sujet des e-mails |
| `rl_email_html` | Contenu HTML des e-mails |
| `rl_user_has_feature` | Accès à une fonctionnalité (contenu conditionnel) |

---

## Facturation électronique (Factur-X)

Le plugin génère pour chaque facture un fichier JSON structuré selon la norme EN16931 dans :
```
wp-content/uploads/recurpay/invoices/FAC-2026-0001.json
```

Ce fichier est prêt pour une intégration future dans un flux Factur-X (PDF/A-3 + XML embarqué) lorsque la réforme de la facturation électronique B2B sera applicable.

---

## Licence

GPL v2 ou ultérieure.
