PHPackages                             hamadou/fundry - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. hamadou/fundry

ActiveLibrary

hamadou/fundry
==============

Fundry — simple wallet &amp; funds management for Laravel

v1.0.2(4mo ago)21[1 issues](https://github.com/TALLHAMADOU/Fundry/issues)MITPHPPHP ^8.1

Since Oct 2Pushed 1mo agoCompare

[ Source](https://github.com/TALLHAMADOU/Fundry)[ Packagist](https://packagist.org/packages/hamadou/fundry)[ RSS](/packages/hamadou-fundry/feed)WikiDiscussions main Synced 1mo ago

READMEChangelogDependencies (8)Versions (4)Used By (0)

Fundry
======

[](#fundry)

[![Latest Version on Packagist](https://camo.githubusercontent.com/c033b5c8b5c1aaee3ae3146e97dfbf4092e93d50056ba267c03924299d76b358/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f68616d61646f752f66756e6472792e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/hamadou/fundry)[![Total Downloads](https://camo.githubusercontent.com/663a0b56f60e2f4c3f13a47fb74477107bb81993c1503f08f7d9d70b57b6f3cc/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f68616d61646f752f66756e6472792e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/hamadou/fundry)[![License](https://camo.githubusercontent.com/f8550b496028f922b0325d8406553f5c19ade487cf502116e2781e1aa7bb06a5/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f68616d61646f752f66756e6472792e7376673f7374796c653d666c61742d737175617265)](LICENSE)

**Fundry** est un package Laravel complet et robuste pour la gestion de portefeuilles virtuels, de transactions financières et de devises multiples. Conçu pour les applications e-commerce, plateformes de paiement, systèmes de gestion financière et applications nécessitant une gestion monétaire fiable.

📋 Table des matières
--------------------

[](#-table-des-matières)

1. [À propos du projet](#%C3%A0-propos-du-projet)
2. [Fonctionnalités](#fonctionnalit%C3%A9s)
3. [Architecture](#architecture)
4. [Prérequis](#pr%C3%A9requis)
5. [Installation](#installation)
6. [Configuration](#configuration)
7. [Concepts clés](#concepts-cl%C3%A9s)
8. [Guide d'utilisation](#guide-dutilisation)
9. [Commandes Artisan](#commandes-artisan)
10. [API Reference](#api-reference)
11. [Sécurité](#s%C3%A9curit%C3%A9)
12. [Performance et Cache](#performance-et-cache)
13. [Gestion des erreurs](#gestion-des-erreurs)
14. [Exemples complets](#exemples-complets)
15. [Tests](#tests)
16. [Dépannage](#d%C3%A9pannage)
17. [Contribution](#contribution)
18. [Licence](#licence)

---

🎯 À propos du projet
--------------------

[](#-à-propos-du-projet)

Fundry résout le problème complexe de la gestion financière dans les applications Laravel en fournissant un système de portefeuille simple, élégant et sécurisé. Que vous construisiez une plateforme e-commerce, une passerelle de paiement, ou une application de suivi financier, Fundry offre les outils nécessaires pour une gestion monétaire robuste.

### Capacités principales

[](#capacités-principales)

- ✅ **Gestion multi-devises** - Support complet des devises fiat et cryptomonnaies
- ✅ **Transactions sécurisées** - Verrous de base de données pour éviter les race conditions
- ✅ **Système de commissions** - Gestion flexible des frais de transaction
- ✅ **Validation ISO 4217** - Codes de devise standardisés et validés
- ✅ **Liaison Pays-Devises** - Association automatique des devises aux pays
- ✅ **Historique complet** - Traçabilité totale des transactions
- ✅ **Export de rapports** - Génération PDF et Excel
- ✅ **Limites configurables** - Contrôles de sécurité personnalisables
- ✅ **Cache intégré** - Optimisation des performances
- ✅ **Commandes CLI** - Outils de gestion puissants

---

✨ Fonctionnalités
-----------------

[](#-fonctionnalités)

### 💰 Gestion de portefeuilles

[](#-gestion-de-portefeuilles)

- Création et gestion de portefeuilles multiples par utilisateur
- Types de portefeuilles : Personnel, Business, Épargne, Investissement, Gouvernemental
- Limites configurables (solde max/min, limite de transaction)
- Portefeuilles par défaut
- Statut actif/inactif
- Règles de sécurité personnalisables

### 💱 Support multi-devises

[](#-support-multi-devises)

- Devises fiat (EUR, USD, XOF, etc.)
- Cryptomonnaies (BTC, ETH, USDT, etc.)
- Devises gouvernementales (device)
- Taux de change configurables
- Conversion automatique entre devises
- Validation ISO 4217 pour les devises fiat
- Liaison avec les pays (ISO 3166-1)

### 📊 Gestion des transactions

[](#-gestion-des-transactions)

- Types de transactions : Dépôt, Retrait, Transfert, Échange, Frais, Remboursement
- Statuts : En attente, Complétée, Échouée
- Références uniques pour chaque transaction
- Métadonnées personnalisables
- Historique complet avec filtres
- Calcul de volumes quotidiens

### 🔐 Sécurité

[](#-sécurité)

- Vérification d'autorisation (wallet appartient à l'utilisateur)
- Verrous de base de données (lockForUpdate) pour la concurrence
- Validation stricte des montants
- Protection contre les montants négatifs
- Validation de précision décimale
- Exceptions explicites et sécurisées

### 📄 Exports et rapports

[](#-exports-et-rapports)

- Génération de rapports PDF
- Export Excel
- Filtres avancés (date, utilisateur, devise, type)
- Rapports sur transactions, portefeuilles, devises, limites

---

🏗️ Architecture
---------------

[](#️-architecture)

### Structure du package

[](#structure-du-package)

```
Fundry/
├── src/
│   ├── Models/              # Modèles Eloquent
│   │   ├── Wallet.php      # Portefeuille
│   │   ├── Transaction.php # Transaction
│   │   ├── Currency.php    # Devise
│   │   └── Country.php     # Pays
│   ├── Services/           # Services métier
│   │   ├── WalletService.php
│   │   ├── TransactionService.php
│   │   └── CurrencyService.php
│   ├── DTOs/               # Data Transfer Objects
│   │   ├── DepositDTO.php
│   │   ├── WithdrawalDTO.php
│   │   └── TransferDTO.php
│   ├── Enums/              # Énumérations
│   │   ├── WalletType.php
│   │   ├── TransactionType.php
│   │   ├── TransactionStatus.php
│   │   └── CurrencyType.php
│   ├── Exceptions/         # Exceptions personnalisées
│   ├── Events/             # Événements Laravel
│   ├── Contracts/          # Interfaces
│   └── Console/Commands/   # Commandes Artisan
├── database/migrations/    # Migrations
├── Seeders/                # Seeders
└── tests/                  # Tests unitaires et fonctionnels

```

### Flux de données

[](#flux-de-données)

```
Utilisateur → Facade Fundry → Service → Modèle → Base de données
                ↓
            DTO (validation)
                ↓
            Verrous DB
                ↓
            Transaction DB
                ↓
            Événements

```

---

📦 Prérequis
-----------

[](#-prérequis)

- **PHP** : 8.1 ou supérieur
- **Laravel** : 10.x, 11.x, ou 12.x
- **Extensions PHP** :
    - `bcmath` (calculs monétaires précis)
    - `json` (métadonnées)
- **Base de données** : MySQL, PostgreSQL, SQLite, SQL Server
- **Table `users`** : Le package utilise la table `users` standard de Laravel. Aucune modification de structure n'est nécessaire. Il suffit d'ajouter le trait `HasWallets` au modèle `User`.

---

🚀 Installation
--------------

[](#-installation)

### Étape 1 : Installation via Composer

[](#étape-1--installation-via-composer)

```
composer require hamadou/fundry
```

### Étape 2 : Publier les migrations et la configuration

[](#étape-2--publier-les-migrations-et-la-configuration)

```
# Publier les migrations
php artisan vendor:publish --tag=fundry-migrations

# Publier la configuration
php artisan vendor:publish --tag=fundry-config
```

### Étape 3 : Configurer le modèle User

[](#étape-3--configurer-le-modèle-user)

Le package utilise la table `users` existante de votre projet Laravel. Aucune modification de la structure de la table n'est nécessaire. Il suffit d'ajouter le trait `HasWallets` à votre modèle `User` :

```
// app/Models/User.php
use Hamadou\Fundry\Traits\HasWallets;

class User extends Authenticatable
{
    use HasWallets;

    // ... vos autres traits et méthodes
}
```

**Note importante :** Le package utilise uniquement la colonne `id` de la table `users`. Aucun champ supplémentaire n'est requis dans la migration `users`. La table `users` standard de Laravel est suffisante.

### Étape 4 : Exécuter les migrations

[](#étape-4--exécuter-les-migrations)

```
php artisan migrate
```

Cela créera les tables suivantes :

- `countries` - Pays et leurs devises
- `currencies` - Devises (fiat, crypto, device)
- `wallets` - Portefeuilles utilisateurs (avec foreign key vers `users.id`)
- `transactions` - Historique des transactions (avec foreign key vers `users.id`)

**Important :** Assurez-vous que votre table `users` existe avant d'exécuter les migrations, car les tables `wallets` et `transactions` ont des contraintes de clé étrangère vers `users.id`.

### Étape 5 : Synchroniser les données de base

[](#étape-5--synchroniser-les-données-de-base)

```
# Synchroniser les pays
php artisan fundry:sync-countries

# Seeder les devises principales
php artisan db:seed --class="Hamadou\Fundry\Seeders\CurrencySeeder"
```

---

⚙️ Configuration
----------------

[](#️-configuration)

### Fichier de configuration

[](#fichier-de-configuration)

Le fichier `config/fundry.php` contient toutes les options de configuration :

```
return [
    // Devise par défaut
    'default_currency' => env('FUNDRY_DEFAULT_CURRENCY', 'USD'),

    // Précision décimale
    'precision' => env('FUNDRY_PRECISION', 8),

    // Utiliser le stockage en cents (non recommandé)
    'use_cents_storage' => env('FUNDRY_USE_CENTS', false),

    // Limites par défaut
    'limits' => [
        'daily_deposit' => env('FUNDRY_DAILY_DEPOSIT_LIMIT', 10000),
        'daily_withdrawal' => env('FUNDRY_DAILY_WITHDRAWAL_LIMIT', 10000),
        'daily_transfer' => env('FUNDRY_DAILY_TRANSFER_LIMIT', 50000),
    ],

    // Provider de taux de change
    'exchange_rate_provider' => env('FUNDRY_EXCHANGE_RATE_PROVIDER', 'manual'),
    'exchange_rate_api_key' => env('FUNDRY_EXCHANGE_RATE_API_KEY', null),

    // Cache
    'cache' => [
        'enabled' => env('FUNDRY_CACHE_ENABLED', true),
        'ttl' => env('FUNDRY_CACHE_TTL', 3600), // 1 heure
        'prefix' => 'fundry',
    ],

    // Exports
    'exports' => [
        'pdf' => [
            'orientation' => 'portrait',
            'paper' => 'a4',
        ],
        'excel' => [
            'format' => 'xlsx',
        ],
    ],
];
```

### Variables d'environnement (.env)

[](#variables-denvironnement-env)

```
# Devise par défaut
FUNDRY_DEFAULT_CURRENCY=USD

# Cache
FUNDRY_CACHE_ENABLED=true
FUNDRY_CACHE_TTL=3600

# Taux de change
FUNDRY_EXCHANGE_RATE_PROVIDER=manual
FUNDRY_EXCHANGE_RATE_API_KEY=your_api_key_here

# Limites
FUNDRY_DAILY_DEPOSIT_LIMIT=10000
FUNDRY_DAILY_WITHDRAWAL_LIMIT=10000
FUNDRY_DAILY_TRANSFER_LIMIT=50000
```

---

🧠 Concepts clés
---------------

[](#-concepts-clés)

### Portefeuille (Wallet)

[](#portefeuille-wallet)

Un portefeuille est un compte virtuel associé à un utilisateur et une devise. Chaque utilisateur peut avoir plusieurs portefeuilles.

**Propriétés principales :**

- `balance` : Solde actuel
- `max_balance` : Solde maximum autorisé
- `min_balance` : Solde minimum à maintenir
- `transaction_limit` : Limite par transaction
- `type` : Type de portefeuille (personnel, business, etc.)
- `is_active` : Statut actif/inactif
- `is_default` : Portefeuille par défaut

### Transaction

[](#transaction)

Une transaction représente une opération financière (dépôt, retrait, transfert).

**Types de transactions :**

- `DEPOSIT` : Dépôt de fonds
- `WITHDRAWAL` : Retrait de fonds
- `TRANSFER` : Transfert entre portefeuilles
- `EXCHANGE` : Échange de devises
- `FEE` : Frais de transaction
- `REFUND` : Remboursement

**Statuts :**

- `PENDING` : En attente
- `COMPLETED` : Complétée
- `FAILED` : Échouée

### Devise (Currency)

[](#devise-currency)

Une devise représente une unité monétaire (fiat, crypto, ou device).

**Types de devises :**

- `FIAT` : Monnaie fiduciaire (USD, EUR, XOF, etc.)
- `CRYPTO` : Cryptomonnaie (BTC, ETH, etc.)
- `DEVICE` : Devise gouvernementale

**Propriétés :**

- `iso_code` : Code ISO 4217 (3 lettres)
- `exchange_rate` : Taux de change par rapport à la devise de base
- `decimals` : Nombre de décimales
- `country_id` : Pays associé (pour fiat)

### Pays (Country)

[](#pays-country)

Un pays contient les informations géographiques et sa devise officielle.

**Propriétés :**

- `iso_code` : Code ISO 3166-1 alpha-2 (2 lettres)
- `currency_code` : Code devise ISO 4217
- `continent` : Continent
- `capital` : Capitale

### DTO (Data Transfer Object)

[](#dto-data-transfer-object)

Les DTOs encapsulent les données des transactions avec validation intégrée.

**Avantages :**

- Validation automatique
- Calcul des commissions
- Type-safe
- Réutilisable

---

📖 Guide d'utilisation
---------------------

[](#-guide-dutilisation)

### Utilisation de la Facade

[](#utilisation-de-la-facade)

```
use Hamadou\Fundry\Facades\Fundry;
```

### Création d'un portefeuille

[](#création-dun-portefeuille)

```
use Hamadou\Fundry\Facades\Fundry;
use Hamadou\Fundry\Enums\WalletType;
use Hamadou\Fundry\Models\Currency;

// Récupérer une devise
$usd = Currency::findByIsoCode('USD');

// Créer un portefeuille
$wallet = Fundry::createWallet($user, [
    'currency_id' => $usd->id,
    'name' => 'Mon Portefeuille Principal',
    'type' => WalletType::PERSONAL,
    'balance' => 0,
    'max_balance' => 100000.00,
    'min_balance' => 0,
    'transaction_limit' => 5000.00,
    'is_default' => true,
]);
```

### Dépôt de fonds

[](#dépôt-de-fonds)

#### Méthode simple

[](#méthode-simple)

```
$transaction = Fundry::deposit($wallet, 1000.00, 'Dépôt initial');
```

#### Méthode avec DTO (recommandée)

[](#méthode-avec-dto-recommandée)

```
use Hamadou\Fundry\DTOs\DepositDTO;

$dto = new DepositDTO(
    userId: $user->id,
    walletId: $wallet->id,
    amount: 1000.00,
    description: 'Dépôt initial',
    commissionPercentage: 2.5 // 2.5% de commission
);

$transaction = Fundry::depositWithDTO($dto);

// Le montant net déposé sera 975.00 (1000 - 2.5%)
// La commission sera 25.00
```

#### Créer un DTO depuis un tableau

[](#créer-un-dto-depuis-un-tableau)

```
$dto = DepositDTO::fromArray([
    'user_id' => $user->id,
    'wallet_id' => $wallet->id,
    'amount' => 1000.00,
    'description' => 'Dépôt',
    'commission_percentage' => 2.5,
    'metadata' => [
        'source' => 'bank_transfer',
        'reference' => 'BANK123456',
    ],
]);
```

### Retrait de fonds

[](#retrait-de-fonds)

#### Méthode simple

[](#méthode-simple-1)

```
$transaction = Fundry::withdraw($wallet, 500.00, 'Retrait');
```

#### Méthode avec DTO

[](#méthode-avec-dto)

```
use Hamadou\Fundry\DTOs\WithdrawalDTO;

$dto = new WithdrawalDTO(
    userId: $user->id,
    walletId: $wallet->id,
    amount: 500.00, // Montant net retiré
    description: 'Retrait',
    commissionPercentage: 1.0 // 1% de commission
);

$transaction = Fundry::withdrawWithDTO($dto);

// Le montant total débité sera 505.00 (500 + 1%)
// La commission sera 5.00
```

### Transfert entre portefeuilles

[](#transfert-entre-portefeuilles)

#### Méthode simple

[](#méthode-simple-2)

```
$transaction = Fundry::transfer($wallet1, $wallet2, 1000.00, 'Transfert');
```

#### Méthode avec DTO

[](#méthode-avec-dto-1)

```
use Hamadou\Fundry\DTOs\TransferDTO;

$dto = new TransferDTO(
    userId: $user->id,
    fromWalletId: $wallet1->id,
    toWalletId: $wallet2->id,
    amount: 1000.00,
    description: 'Transfert entre comptes',
    commissionPercentage: 1.5 // 1.5% de commission
);

$transaction = Fundry::transferWithDTO($dto);

// 1015.00 sera débité du wallet source
// 985.00 sera crédité au wallet destination
// 15.00 sera la commission
```

### Consultation du solde

[](#consultation-du-solde)

```
// Solde d'un portefeuille
$balance = Fundry::getWalletBalance($wallet);

// Historique des transactions
$history = Fundry::getWalletHistory($wallet, 50); // 50 dernières transactions

// Transactions d'un utilisateur
$transactions = Fundry::getUserTransactions($user->id, [
    'type' => 'deposit',
    'status' => 'completed',
    'start_date' => '2024-01-01',
    'end_date' => '2024-12-31',
], 100);
```

### Conversion de devises

[](#conversion-de-devises)

```
// Conversion simple
$amount = Fundry::convertAmount(100, 'USD', 'EUR');

// Conversion sécurisée avec validation
use Hamadou\Fundry\Models\Currency;

$usd = Currency::findByIsoCode('USD');
$eur = Currency::findByIsoCode('EUR');

try {
    $amount = $usd->convertToSafe(100, $eur);
    // Conversion réussie
} catch (\Hamadou\Fundry\Exceptions\InvalidCurrencyException $e) {
    // Gérer l'erreur
}
```

### Utilisation du trait HasWallets

[](#utilisation-du-trait-haswallets)

Le trait `HasWallets` ajoute des méthodes pratiques au modèle User :

```
// Créer un portefeuille
$wallet = $user->createWallet([
    'currency_id' => $currency->id,
    'name' => 'Mon Wallet',
    'type' => WalletType::PERSONAL,
]);

// Récupérer un portefeuille par devise
$usdWallet = $user->getWalletByCurrency('USD');

// Portefeuille par défaut
$defaultWallet = $user->getDefaultWallet();

// Solde dans une devise
$balance = $user->getWalletBalance('USD');

// Solde total en USD
$totalUsd = $user->getTotalBalanceInUsd();

// Vérifier si le solde est suffisant
if ($user->hasSufficientBalance(500, 'USD')) {
    // Le solde est suffisant
}

// Portefeuilles par type
$businessWallets = $user->getWalletsByType(WalletType::BUSINESS);
```

### Gestion des pays et devises

[](#gestion-des-pays-et-devises)

#### Créer un pays

[](#créer-un-pays)

```
use Hamadou\Fundry\Models\Country;

$senegal = Country::create([
    'name' => 'Sénégal',
    'name_en' => 'Senegal',
    'iso_code' => 'SN',
    'iso_code_3' => 'SEN',
    'numeric_code' => '686',
    'phone_code' => '+221',
    'continent' => 'Africa',
    'capital' => 'Dakar',
    'currency_code' => 'XOF',
    'currency_name' => 'West African CFA Franc',
    'currency_symbol' => 'CFA',
]);
```

#### Créer une devise liée à un pays

[](#créer-une-devise-liée-à-un-pays)

```
use Hamadou\Fundry\Models\Currency;
use Hamadou\Fundry\Enums\CurrencyType;

$senegal = Country::findByIsoCode('SN');

$xof = Currency::create([
    'iso_code' => 'XOF',
    'code' => 'XOF',
    'name' => 'Franc CFA',
    'country_id' => $senegal->id,
    'type' => CurrencyType::FIAT,
    'symbol' => 'CFA',
    'exchange_rate' => 0.0017,
    'decimals' => 0,
]);
```

#### Rechercher une devise

[](#rechercher-une-devise)

```
// Par code ISO 4217 (avec cache)
$usd = Currency::findByIsoCode('USD');

// Par pays
$france = Country::findByIsoCode('FR');
$euro = $france->currencies()->first();

// Par code devise du pays
$country = Country::where('currency_code', 'EUR')->first();
```

---

🛠️ Commandes Artisan
--------------------

[](#️-commandes-artisan)

Fundry fournit plusieurs commandes Artisan pour faciliter la gestion du système.

### `fundry:install`

[](#fundryinstall)

Installe et configure Fundry dans votre application.

```
php artisan fundry:install
```

**Actions effectuées :**

- Publie la configuration
- Publie les migrations
- Affiche les instructions de configuration

---

### `fundry:sync-countries`

[](#fundrysync-countries)

Synchronise les pays et leurs devises depuis le seeder.

```
php artisan fundry:sync-countries
```

**Options :**

- `--force` : Force la mise à jour même si les pays existent déjà

**Exemple :**

```
php artisan fundry:sync-countries --force
```

**Ce que fait la commande :**

- Charge les pays depuis `CountrySeeder`
- Crée ou met à jour les pays dans la base de données
- Affiche le nombre total de pays synchronisés

---

### `fundry:validate-currencies`

[](#fundryvalidate-currencies)

Valide toutes les devises et détecte les problèmes potentiels.

```
php artisan fundry:validate-currencies
```

**Options :**

- `--fix` : Corrige automatiquement les erreurs détectées

**Exemple :**

```
# Validation simple
php artisan fundry:validate-currencies

# Validation avec correction automatique
php artisan fundry:validate-currencies --fix
```

**Vérifications effectuées :**

- ✅ Codes ISO 4217 valides pour les devises fiat
- ✅ Taux de change valides (&gt; 0)
- ✅ Relations avec les pays
- ✅ Codes normalisés en majuscules
- ✅ Cohérence des données

**Sortie exemple :**

```
🔍 Validation des devises...

✅ Toutes les devises sont valides!
📊 Total de devises validées: 25

```

---

### `fundry:update-rates`

[](#fundryupdate-rates)

Met à jour les taux de change des devises.

```
php artisan fundry:update-rates
```

**Options :**

- `--provider=manual` : Provider à utiliser (manual, exchangerate-api)
- `--api-key=` : Clé API pour le provider externe
- `--base=USD` : Devise de base pour les taux

**Exemples :**

```
# Mode manuel (aucune mise à jour automatique)
php artisan fundry:update-rates

# Avec ExchangeRate-API
php artisan fundry:update-rates \
    --provider=exchangerate-api \
    --api-key=your_api_key_here \
    --base=USD
```

**Ce que fait la commande :**

- Récupère les taux de change depuis le provider
- Met à jour les devises dans la base de données
- Nettoie le cache automatiquement
- Affiche les taux mis à jour

**Sortie exemple :**

```
🔄 Mise à jour des taux de change (Provider: exchangerate-api, Base: USD)...
🌐 Récupération des taux depuis ExchangeRate-API...
✅ 25 taux de change mis à jour avec succès!

📊 Exemples de taux mis à jour:
  • EUR: 1.1
  • GBP: 1.27
  • XOF: 0.0017
  • MAD: 0.10
  • TND: 0.32

```

---

### `fundry:currencies`

[](#fundrycurrencies)

Gère les devises (à compléter selon besoins).

```
php artisan fundry:currencies {action?}
```

**Actions possibles :**

- `list` : Liste toutes les devises
- `sync` : Synchronise les devises
- `seed` : Seed les devises de base

---

### `fundry:cash`

[](#fundrycash)

Opérations cash (à compléter selon besoins).

```
php artisan fundry:cash {action?}
```

---

### `fundry:crypto`

[](#fundrycrypto)

Opérations crypto (sync rates, import data).

```
php artisan fundry:crypto {action?}
```

---

### `fundry:report`

[](#fundryreport)

Génère des rapports PDF ou Excel pour les données Fundry.

```
php artisan fundry:report {type} [options]
```

**Types de rapports :**

- `transactions` : Rapport des transactions
- `wallets` : Rapport des portefeuilles
- `currencies` : Rapport des devises
- `limits` : Rapport des limites configurées

**Options :**

- `--format=pdf` : Format de sortie (pdf|excel)
- `--start-date=` : Date de début (YYYY-MM-DD)
- `--end-date=` : Date de fin (YYYY-MM-DD)
- `--user-id=` : Filtrer par utilisateur
- `--wallet-type=` : Type de portefeuille
- `--currency=` : Devise spécifique
- `--output=` : Fichier de sortie

**Exemples :**

```
# Rapport des transactions en PDF
php artisan fundry:report transactions --format=pdf

# Rapport des transactions en Excel avec filtres
php artisan fundry:report transactions \
    --format=excel \
    --start-date=2024-01-01 \
    --end-date=2024-12-31 \
    --user-id=1 \
    --currency=USD

# Rapport des portefeuilles
php artisan fundry:report wallets --format=pdf --wallet-type=personal

# Rapport des devises
php artisan fundry:report currencies --format=excel

# Rapport avec fichier de sortie personnalisé
php artisan fundry:report transactions \
    --format=pdf \
    --output=rapport_janvier_2024
```

**Emplacement des rapports :**Les rapports sont sauvegardés dans `storage/app/reports/` par défaut.

---

📚 API Reference
---------------

[](#-api-reference)

### Facade Fundry

[](#facade-fundry)

#### Méthodes de portefeuille

[](#méthodes-de-portefeuille)

```
// Créer un portefeuille
Fundry::createWallet($user, array $data): Wallet

// Obtenir le solde
Fundry::getWalletBalance(Wallet $wallet): float

// Historique des transactions
Fundry::getWalletHistory(Wallet $wallet, int $limit = 50): Collection

// Transfert simple
Fundry::transfer(Wallet $from, Wallet $to, float $amount, ?string $description): Transaction

// Transfert avec DTO
Fundry::transferWithDTO(TransferDTO $dto): Transaction
```

#### Méthodes de transaction

[](#méthodes-de-transaction)

```
// Dépôt simple
Fundry::deposit(Wallet $wallet, float $amount, ?string $description): Transaction

// Dépôt avec DTO
Fundry::depositWithDTO(DepositDTO $dto): Transaction

// Retrait simple
Fundry::withdraw(Wallet $wallet, float $amount, ?string $description): Transaction

// Retrait avec DTO
Fundry::withdrawWithDTO(WithdrawalDTO $dto): Transaction

// Obtenir une transaction par référence
Fundry::getTransactionByReference(string $reference): ?Transaction

// Transactions d'un utilisateur
Fundry::getUserTransactions($userId, array $filters = [], int $limit = 50): Collection

// Volume quotidien
Fundry::calculateDailyVolume($userId, string $currencyCode): float
```

#### Méthodes de devise

[](#méthodes-de-devise)

```
// Créer une devise
Fundry::createCurrency(array $data): Currency

// Mettre à jour le taux de change
Fundry::updateExchangeRate(string $currencyCode, float $rate): bool

// Convertir un montant
Fundry::convertAmount(float $amount, string $fromCurrency, string $toCurrency): ?float

// Obtenir les devises supportées
Fundry::getSupportedCurrencies(): array
```

### Modèles

[](#modèles)

#### Wallet

[](#wallet)

```
// Relations
$wallet->user()              // BelongsTo User
$wallet->currency()         // BelongsTo Currency
$wallet->fromTransactions() // HasMany Transaction
$wallet->toTransactions()   // HasMany Transaction

// Scopes
Wallet::active()            // Portefeuilles actifs
Wallet::default()           // Portefeuille par défaut
Wallet::byType($type)       // Par type
Wallet::hasBalance($amount) // Avec solde suffisant

// Méthodes
$wallet->canWithdraw($amount): bool
$wallet->deposit($amount): void
$wallet->withdraw($amount): void
$wallet->belongsToUser($user): bool
$wallet->getBalanceInUsd(): float
$wallet->getFormattedBalance(): string
```

#### Transaction

[](#transaction-1)

```
// Relations
$transaction->user()        // BelongsTo User
$transaction->fromWallet() // BelongsTo Wallet
$transaction->toWallet()    // BelongsTo Wallet
$transaction->currency()    // BelongsTo Currency

// Scopes
Transaction::completed()    // Transactions complétées
Transaction::pending()      // Transactions en attente
Transaction::failed()       // Transactions échouées
Transaction::byType($type)  // Par type
Transaction::recent($days)  // Récentes

// Méthodes
$transaction->markAsCompleted(): void
$transaction->markAsFailed(?string $reason): void
$transaction->isPositive(): bool
$transaction->getFormattedAmount(): string
```

#### Currency

[](#currency)

```
// Relations
$currency->country()        // BelongsTo Country
$currency->wallets()        // HasMany Wallet
$currency->transactions()   // HasMany Transaction

// Scopes
Currency::fiat()            // Devises fiat
Currency::crypto()          // Cryptomonnaies
Currency::device()          // Devises device
Currency::active()           // Devises actives

// Méthodes statiques
Currency::isValidIso4217Code(string $code): bool
Currency::findByIsoCode(string $isoCode): ?Currency

// Méthodes d'instance
$currency->convertTo($amount, Currency $target): float
$currency->convertToSafe($amount, Currency $target): float
$currency->canConvertTo(Currency $target): bool
$currency->getValueInUsd($amount): float
$currency->getValueInEur($amount): float
$currency->getFormattedAmount($amount): string
```

#### Country

[](#country)

```
// Relations
$country->currencies()      // HasMany Currency

// Scopes
Country::active()           // Pays actifs
Country::byIsoCode($code)   // Par code ISO
Country::byCurrencyCode($code) // Par code devise

// Méthodes statiques
Country::isValidIsoCode(string $code): bool
Country::isValidCurrencyCode(string $code): bool
Country::findByIsoCode(string $isoCode): ?Country
Country::findByCurrencyCode(string $currencyCode): ?Country
```

### DTOs

[](#dtos)

#### DepositDTO

[](#depositdto)

```
// Constructeur
new DepositDTO(
    userId: int|string,
    walletId: int,
    amount: float,
    description?: ?string,
    commissionPercentage?: ?float,
    metadata?: ?array
)

// Méthodes
$dto->getNetAmount(): float           // Montant net après commission
$dto->getCommissionAmount(): float     // Montant de la commission
$dto->toArray(): array                 // Convertir en tableau
DepositDTO::fromArray(array): DepositDTO // Créer depuis un tableau
```

#### WithdrawalDTO

[](#withdrawaldto)

```
// Constructeur
new WithdrawalDTO(
    userId: int|string,
    walletId: int,
    amount: float,
    description?: ?string,
    commissionPercentage?: ?float,
    metadata?: ?array
)

// Méthodes
$dto->getTotalAmount(): float          // Montant total (montant + commission)
$dto->getCommissionAmount(): float     // Montant de la commission
$dto->toArray(): array
WithdrawalDTO::fromArray(array): WithdrawalDTO
```

#### TransferDTO

[](#transferdto)

```
// Constructeur
new TransferDTO(
    userId: int|string,
    fromWalletId: int,
    toWalletId: int,
    amount: float,
    description?: ?string,
    commissionPercentage?: ?float,
    metadata?: ?array
)

// Méthodes
$dto->getTotalAmount(): float          // Montant total débité
$dto->getNetAmount(): float            // Montant net crédité
$dto->getCommissionAmount(): float     // Montant de la commission
$dto->toArray(): array
TransferDTO::fromArray(array): TransferDTO
```

---

🔒 Sécurité
----------

[](#-sécurité-1)

### Vérification d'autorisation

[](#vérification-dautorisation)

Toutes les opérations vérifient automatiquement que le wallet appartient à l'utilisateur :

```
// Cette opération lancera une UnauthorizedWalletException
$dto = new DepositDTO(
    userId: $user1->id,
    walletId: $user2Wallet->id, // ❌ Erreur !
    amount: 100.00,
);
```

### Verrous de concurrence

[](#verrous-de-concurrence)

Les opérations critiques utilisent des verrous de base de données (`lockForUpdate()`) pour éviter les race conditions :

```
// Dans WalletService::deposit()
$wallet = Wallet::lockForUpdate()->findOrFail($walletId);
// ... opération sécurisée
```

### Validation des montants

[](#validation-des-montants)

- ✅ Montants doivent être &gt; 0
- ✅ Précision limitée à 8 décimales
- ✅ Validation des limites (max\_balance, min\_balance, transaction\_limit)

### Gestion des exceptions

[](#gestion-des-exceptions)

```
use Hamadou\Fundry\Exceptions\{
    InsufficientFundsException,      // Fonds insuffisants
    InvalidAmountException,          // Montant invalide
    UnauthorizedWalletException,    // Wallet n'appartient pas à l'utilisateur
    InvalidCurrencyException,        // Problème de devise
    ConcurrencyException             // Erreur de concurrence
};
```

---

⚡ Performance et Cache
----------------------

[](#-performance-et-cache)

### Configuration du cache

[](#configuration-du-cache)

Le cache est activé par défaut pour améliorer les performances :

```
// config/fundry.php
'cache' => [
    'enabled' => true,
    'ttl' => 3600, // 1 heure
    'prefix' => 'fundry',
],
```

### Ce qui est mis en cache

[](#ce-qui-est-mis-en-cache)

- ✅ Devises par type
- ✅ Liste des devises supportées
- ✅ Recherche de devises par code ISO
- ✅ Conversions de devises

### Nettoyer le cache

[](#nettoyer-le-cache)

```
use Hamadou\Fundry\Services\CurrencyService;

$currencyService = app(CurrencyService::class);
$currencyService->clearCache();
```

Le cache est automatiquement nettoyé lors de :

- Mise à jour d'une devise
- Synchronisation des taux de change
- Création/modification de devises

### Désactiver le cache

[](#désactiver-le-cache)

```
FUNDRY_CACHE_ENABLED=false
```

---

🚨 Gestion des erreurs
---------------------

[](#-gestion-des-erreurs)

### Exceptions personnalisées

[](#exceptions-personnalisées)

```
try {
    $transaction = Fundry::withdrawWithDTO($dto);
} catch (InsufficientFundsException $e) {
    // Fonds insuffisants ou limites dépassées
    return response()->json(['error' => $e->getMessage()], 400);
} catch (InvalidAmountException $e) {
    // Montant invalide (négatif, trop de décimales, etc.)
    return response()->json(['error' => $e->getMessage()], 400);
} catch (UnauthorizedWalletException $e) {
    // Wallet n'appartient pas à l'utilisateur
    return response()->json(['error' => $e->getMessage()], 403);
} catch (InvalidCurrencyException $e) {
    // Problème de devise (inactive, taux invalide, etc.)
    return response()->json(['error' => $e->getMessage()], 400);
} catch (ConcurrencyException $e) {
    // Erreur de concurrence
    return response()->json(['error' => $e->getMessage()], 409);
}
```

### Codes d'erreur HTTP

[](#codes-derreur-http)

- `400` : Requête invalide (montant invalide, devise invalide)
- `403` : Non autorisé (wallet n'appartient pas à l'utilisateur)
- `409` : Conflit (erreur de concurrence)

---

💡 Exemples complets
-------------------

[](#-exemples-complets)

### Exemple 1 : Système de paiement e-commerce

[](#exemple-1--système-de-paiement-e-commerce)

```
use Hamadou\Fundry\Facades\Fundry;
use Hamadou\Fundry\DTOs\DepositDTO;
use Hamadou\Fundry\Enums\WalletType;

// 1. Créer un wallet pour le client
$wallet = Fundry::createWallet($customer, [
    'currency_id' => Currency::findByIsoCode('USD')->id,
    'name' => 'Portefeuille E-commerce',
    'type' => WalletType::PERSONAL,
]);

// 2. Traiter un paiement avec commission
$dto = new DepositDTO(
    userId: $customer->id,
    walletId: $wallet->id,
    amount: 150.00, // Montant de la commande
    description: "Paiement commande #{$orderId}",
    commissionPercentage: 2.9, // Commission de la plateforme
    metadata: [
        'order_id' => $orderId,
        'payment_method' => 'credit_card',
        'gateway' => 'stripe',
    ]
);

$transaction = Fundry::depositWithDTO($dto);

// 3. Vérifier le solde
$balance = Fundry::getWalletBalance($wallet);

// 4. Rembourser si nécessaire
if ($needsRefund) {
    $refundDto = new DepositDTO(
        userId: $customer->id,
        walletId: $wallet->id,
        amount: $transaction->amount,
        description: "Remboursement commande #{$orderId}",
        metadata: ['original_transaction_id' => $transaction->id]
    );
    Fundry::depositWithDTO($refundDto);
}
```

### Exemple 2 : Transfert entre utilisateurs

[](#exemple-2--transfert-entre-utilisateurs)

```
use Hamadou\Fundry\DTOs\TransferDTO;

// Vérifier que l'expéditeur a suffisamment de fonds
if (!$sender->hasSufficientBalance(50, 'USD')) {
    return response()->json(['error' => 'Solde insuffisant'], 400);
}

// Effectuer le transfert avec commission
$dto = new TransferDTO(
    userId: $sender->id,
    fromWalletId: $senderWallet->id,
    toWalletId: $receiverWallet->id,
    amount: 50.00,
    description: "Paiement de {$sender->name} à {$receiver->name}",
    commissionPercentage: 1.0, // 1% de commission pour la plateforme
    metadata: [
        'payment_type' => 'peer_to_peer',
        'sender_email' => $sender->email,
        'receiver_email' => $receiver->email,
    ]
);

$transaction = Fundry::transferWithDTO($dto);

// Notifier les utilisateurs
event(new PaymentCompleted($transaction));
```

### Exemple 3 : Conversion multi-devises

[](#exemple-3--conversion-multi-devises)

```
// Récupérer tous les wallets d'un utilisateur
$wallets = $user->wallets()->with('currency')->active()->get();

// Convertir tous les soldes en USD
$totalUsd = 0;
$usd = Currency::findByIsoCode('USD');

foreach ($wallets as $wallet) {
    if ($wallet->currency->iso_code === 'USD') {
        $totalUsd += $wallet->balance;
    } else {
        try {
            $converted = $wallet->currency->convertToSafe($wallet->balance, $usd);
            $totalUsd += $converted;
        } catch (InvalidCurrencyException $e) {
            \Log::warning("Impossible de convertir {$wallet->currency->iso_code}: {$e->getMessage()}");
        }
    }
}

return response()->json([
    'total_balance_usd' => round($totalUsd, 2),
    'wallets_count' => $wallets->count(),
]);
```

### Exemple 4 : Système de commissions dynamiques

[](#exemple-4--système-de-commissions-dynamiques)

```
// Calculer la commission en fonction du montant
function calculateCommission(float $amount): float
{
    if ($amount < 100) {
        return 3.0; // 3% pour les petits montants
    } elseif ($amount < 1000) {
        return 2.5; // 2.5% pour les montants moyens
    } else {
        return 1.5; // 1.5% pour les gros montants
    }
}

$amount = 500.00;
$commission = calculateCommission($amount);

$dto = new DepositDTO(
    userId: $user->id,
    walletId: $wallet->id,
    amount: $amount,
    commissionPercentage: $commission,
    description: 'Dépôt avec commission dynamique'
);

$transaction = Fundry::depositWithDTO($dto);
```

### Exemple 5 : Vérification de limites quotidiennes

[](#exemple-5--vérification-de-limites-quotidiennes)

```
use Hamadou\Fundry\Facades\Fundry;

// Vérifier le volume quotidien
$dailyVolume = Fundry::calculateDailyVolume($user->id, 'USD');
$dailyLimit = config('fundry.limits.daily_deposit', 10000);

if ($dailyVolume + $amount > $dailyLimit) {
    return response()->json([
        'error' => 'Limite quotidienne dépassée',
        'daily_limit' => $dailyLimit,
        'current_volume' => $dailyVolume,
        'remaining' => $dailyLimit - $dailyVolume,
    ], 400);
}

// Procéder au dépôt
$transaction = Fundry::deposit($wallet, $amount);
```

---

🧪 Tests
-------

[](#-tests)

### Exécuter les tests

[](#exécuter-les-tests)

```
# Tous les tests
vendor/bin/phpunit

# Tests unitaires uniquement
vendor/bin/phpunit --testsuite=Unit

# Tests Feature uniquement
vendor/bin/phpunit --testsuite=Feature

# Avec couverture de code
vendor/bin/phpunit --coverage-html coverage
```

### Structure des tests

[](#structure-des-tests)

```
tests/
├── TestCase.php                    # Classe de base
├── Unit/
│   ├── Models/
│   │   ├── CurrencyTest.php
│   │   └── WalletTest.php
│   ├── DTOs/
│   │   ├── DepositDTOTest.php
│   │   ├── WithdrawalDTOTest.php
│   │   └── TransferDTOTest.php
│   └── Services/
│       ├── CurrencyServiceTest.php
│       ├── WalletServiceTest.php
│       └── TransactionServiceTest.php
└── Feature/
    └── WalletOperationsTest.php

```

---

🔧 Dépannage
-----------

[](#-dépannage)

### Problème : "Currency not found"

[](#problème--currency-not-found)

**Solution :**

```
# Vérifier que les devises sont bien seedées
php artisan fundry:validate-currencies

# Re-seeder si nécessaire
php artisan db:seed --class="Hamadou\Fundry\Seeders\CurrencySeeder"
```

### Problème : "Insufficient funds" même avec un solde suffisant

[](#problème--insufficient-funds-même-avec-un-solde-suffisant)

**Causes possibles :**

- Limite `min_balance` configurée
- Limite `transaction_limit` dépassée
- Commission non prise en compte dans le calcul

**Solution :**

```
// Vérifier les limites du wallet
$wallet->min_balance;
$wallet->transaction_limit;
$wallet->max_balance;

// Vérifier si le retrait est possible
if ($wallet->canWithdraw($amount)) {
    // OK
}
```

### Problème : Cache non mis à jour

[](#problème--cache-non-mis-à-jour)

**Solution :**

```
use Hamadou\Fundry\Services\CurrencyService;

$currencyService = app(CurrencyService::class);
$currencyService->clearCache();
```

### Problème : "UnauthorizedWalletException"

[](#problème--unauthorizedwalletexception)

**Cause :** Le wallet n'appartient pas à l'utilisateur spécifié dans le DTO.

**Solution :**

```
// Vérifier l'appartenance avant l'opération
if (!$wallet->belongsToUser($user)) {
    throw new UnauthorizedWalletException();
}
```

---

🤝 Contribution
--------------

[](#-contribution)

Les contributions sont les bienvenues ! Pour contribuer :

1. Fork le projet
2. Créer une branche pour votre fonctionnalité (`git checkout -b feature/AmazingFeature`)
3. Commit vos changements (`git commit -m 'Add some AmazingFeature'`)
4. Push vers la branche (`git push origin feature/AmazingFeature`)
5. Ouvrir une Pull Request

### Standards de code

[](#standards-de-code)

- Suivre les standards PSR-12
- Ajouter des tests pour les nouvelles fonctionnalités
- Documenter le code
- Mettre à jour le README si nécessaire

---

📄 Licence
---------

[](#-licence)

Ce projet est sous licence MIT. Voir le fichier [LICENSE](LICENSE) pour plus de détails.

---

👤 Auteur
--------

[](#-auteur)

**Hamadou Tall**

- Email:
- GitHub: [@hamadou](https://github.com/hamadou)

---

🙏 Remerciements
---------------

[](#-remerciements)

- Laravel Framework
- Orchestra Testbench pour les tests
- Maatwebsite Excel pour les exports
- DomPDF pour la génération PDF

---

📞 Support
---------

[](#-support)

Pour toute question ou problème :

- Ouvrir une [issue](https://github.com/hamadou/fundry/issues)
- Contacter l'auteur :

---

**Fait avec ❤️ pour la communauté Laravel**

###  Health Score

35

—

LowBetter than 80% of packages

Maintenance75

Regular maintenance activity

Popularity4

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity46

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~53 days

Total

3

Last Release

122d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/19e54e2d25ff6e87e5f466a188e9be0e430dd711d55ea6d34c0e6ed34a672055?d=identicon)[Tall Hamadou](/maintainers/Tall%20Hamadou)

---

Top Contributors

[![TALLHAMADOU](https://avatars.githubusercontent.com/u/104475228?v=4)](https://github.com/TALLHAMADOU "TALLHAMADOU (16 commits)")

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/hamadou-fundry/health.svg)

```
[![Health](https://phpackages.com/badges/hamadou-fundry/health.svg)](https://phpackages.com/packages/hamadou-fundry)
```

###  Alternatives

[barryvdh/laravel-ide-helper

Laravel IDE Helper, generates correct PHPDocs for all Facade classes, to improve auto-completion.

14.9k123.0M687](/packages/barryvdh-laravel-ide-helper)[tucker-eric/eloquentfilter

An Eloquent way to filter Eloquent Models

1.8k4.8M26](/packages/tucker-eric-eloquentfilter)[spatie/laravel-health

Monitor the health of a Laravel application

86910.0M83](/packages/spatie-laravel-health)[fumeapp/modeltyper

Generate TypeScript interfaces from Laravel Models

196277.9k](/packages/fumeapp-modeltyper)[orchestra/canvas

Code Generators for Laravel Applications and Packages

20917.2M158](/packages/orchestra-canvas)[clickbar/laravel-magellan

This package provides functionality for working with the postgis extension in Laravel.

423715.4k1](/packages/clickbar-laravel-magellan)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
