zakat 0.7.0

A type-safe, comprehensive, and Fiqh-compliant Zakat calculation library. Supports Gold, Silver, Business, Agriculture, Livestock, Professional Income, and Modern Assets (Crypto/Stocks).
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
<div align="center">
<h1>بِسْمِ اللهِ الرَّحْمٰنِ الرَّحِيْمِ</h1>
<h1>السلام عليكم</h1>
</div>

```text
███████╗ █████╗ ██╗  ██╗ █████╗ ████████╗
╚══███╔╝██╔══██╗██║ ██╔╝██╔══██╗╚══██╔══╝
  ███╔╝ ███████║█████╔╝ ███████║   ██║   
 ███╔╝  ██╔══██║██╔═██╗ ██╔══██║   ██║   
███████╗██║  ██║██║  ██╗██║  ██║   ██║   
╚══════╝╚═╝  ╚═╝╚═╝  ╚═╝╚═╝  ╚═╝   ╚═╝   
```

# Zakat


[![Crates.io](https://img.shields.io/crates/v/zakat.svg)](https://crates.io/crates/zakat)
[![Docs.rs](https://docs.rs/zakat/badge.svg)](https://docs.rs/zakat)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

Rust library for Islamic Zakat calculation. Uses `rust_decimal` for precision.

## Features


- Gold, Silver, Business, Agriculture, Livestock, Mining & Rikaz
- Stocks, Mutual Funds, Crypto (as liquid assets)
- Professional Income (Gross/Net)
- Zakat Fitrah
- Configurable Nisab thresholds
- Portfolio aggregation (Dam' al-Amwal)
- Dynamic Portfolio (Add, Remove, Replace assets with stable UUIDs)
- Asset Labeling (e.g., "Main Store", "Crypto Wallet")
- Input Sanitization & Validation (Rejects negative values, ensures safe configuration)
- Flexible Configuration (Env Vars, JSON, Fluent API)
- Fiqh Compliance (Jewelry exemptions, Madhab-specific rules, Hawl requirements)
- Async Support (Optional integration with `tokio` and `async-trait`)
- Live Pricing Interface (e.g. for API integration)
- Detailed Reporting (Livestock in-kind details, calculation traces, metadata support)
- `explain()` Debugging (Get human-readable trace of calculations)
- Custom Strategies (Pluggable `ZakatStrategy` trait for custom rules)
- Full Serialization (Save/Load Portfolios via `serde` & JSON)

## Install


With Async Support (Default):
```toml
[dependencies]
zakat = "0.7.0"
rust_decimal = "1.39"
tokio = { version = "1", features = ["full"] } # Required if using async features
```

Synchronous Only (Lighter weight):
```toml
[dependencies]
zakat = { version = "0.7.0", default-features = false }
rust_decimal = "1.39"
```

## Usage


### Business Zakat


> **Note:** v0.7 continues to use the **Fluent API** introduced in v0.5. No more Builders!

```rust
use zakat::prelude::*;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let config = ZakatConfig::new()
        .with_gold_price(65)  // $65/g
        .with_silver_price(1); // $1/g

    // Fluent API: Infallible construction, chained setters
    let store = BusinessZakat::new()
        .cash(10_000)
        .inventory(50_000)
        .label("Main Store")
        .hawl(true);

    // Validation & Calculation happens here
    let result = store.calculate_zakat(&config)?;

    if result.is_payable {
        println!("Zakat for {}: ${}", result.label.unwrap_or_default(), result.zakat_due);
    }
    
    // NEW: Get a human-readable trace of the calculation
    println!("{}", result.explain());
    
    Ok(())
}
```

### Advanced Usage (Complex Scenarios)


For complex scenarios involving debts and receivables:

```rust
let assets = BusinessZakat::new()
    .cash(50000)
    .inventory(20000)
    .receivables(5000)
    .liabilities(1000)
    .debt(500) // Deductible immediate debt
    .label("Tech Startup")
    .hawl(true);
```

### Portfolio Management


Handles multiple assets with "Dam' al-Amwal" (Wealth Aggregation) logic.

```rust
use zakat::prelude::*;
use zakat::portfolio::PortfolioStatus;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let config = ZakatConfig::new()
        .with_gold_price(65)
        .with_silver_price(1);

    let portfolio = ZakatPortfolio::new()
        .add(IncomeZakatCalculator::new()
            .income(5000)
            .method(IncomeCalculationMethod::Gross)
            .label("Monthly Salary"))
        .add(PreciousMetals::new()
            .weight(100)
            .metal_type(WealthType::Gold)
            .label("Wife's Gold"))
        .add(InvestmentAssets::new()
            .value(20000)
            .kind(InvestmentType::Crypto)
            .debt(2000)
            .label("Binance Portfolio"));

    let result = portfolio.calculate_total(&config);
    println!("Total Zakat Due: ${}", result.total_zakat_due);
    
    // Robust error handling for partial failures
    match result.status {
        PortfolioStatus::Complete => println!("All assets calculated successfully."),
        PortfolioStatus::Partial => {
            println!("Warning: Some assets failed calculation.");
            for failure in result.failures() {
                 println!("Failed item: {:?}", failure);
            }
        }
        PortfolioStatus::Failed => println!("Critical: All asset calculations failed."),
    }

    // Iterate successful details
    for detail in result.successes() {
        if let Some(label) = &detail.label {
            println!(" - {}: ${}", label, detail.zakat_due);
        }
    }
    Ok(())
}
```

### Dynamic Portfolio Operations


New in v0.6: Manage assets dynamically using stable UUIDs.

```rust
use zakat::prelude::*;

fn main() {
    let mut portfolio = ZakatPortfolio::new();
    
    // Add returns the ID
    let (portfolio, id_1) = portfolio.add_with_id(
        BusinessZakat::new().cash(10_000).label("Branch A")
    );
    
    // Or push to mutable reference
    let mut portfolio = portfolio;
    let id_2 = portfolio.push(
        BusinessZakat::new().cash(5_000).label("Branch B")
    );
    
    // Replace an asset (e.g. updating values)
    portfolio.replace(id_1, BusinessZakat::new().cash(12_000).label("Branch A Updated")).unwrap();
    
    // Remove an asset
    portfolio.remove(id_2);
}
```

### Async & Live Pricing (Optional)


Enable the `async` feature to use these capabilities.

```rust
use zakat::prelude::*;
use zakat::pricing::{PriceProvider, Prices};

struct MockApi;

#[cfg(feature = "async")]

#[async_trait::async_trait]

impl PriceProvider for MockApi {
    async fn get_prices(&self) -> Result<Prices, ZakatError> {
        // Simulate API call
        Ok(Prices::new(90.0, 1.2)?)
    }
}

#[tokio::main]

async fn main() -> Result<(), Box<dyn std::error::Error>> {
    #[cfg(feature = "async")]
    {
        let api = MockApi;
        // Initialize config from provider
        let config = ZakatConfig::from_provider(&api).await?;
        
        let portfolio = AsyncZakatPortfolio::new()
            .add(BusinessZakat::new()
                .cash(10_000));
                
        let result = portfolio.calculate_total_async(&config).await;
        println!("Total Due: {}", result.total_zakat_due);
    }
    Ok(())
}
```

### Configuration


Flexible and safe configuration options.

```rust
use zakat::prelude::*;

// Load from Environment Variables (ZAKAT_GOLD_PRICE, etc.)
let config = ZakatConfig::from_env()?;

// Or load from JSON
let config = ZakatConfig::try_from_json("config.json")?;

// Or using Fluent API
let config = ZakatConfig::new()
    .with_gold_price(100)
    .with_silver_price(1)
    .with_madhab(Madhab::Hanafi);
```

### Custom Zakat Strategy (Advanced)


Create custom calculation rules beyond the standard Madhabs:

```rust
use zakat::prelude::*;
use std::sync::Arc;

#[derive(Debug)]

struct GregorianTaxStrategy;

impl ZakatStrategy for GregorianTaxStrategy {
    fn get_rules(&self) -> ZakatRules {
        ZakatRules {
            nisab_standard: NisabStandard::Gold,
            jewelry_exempt: false,
            trade_goods_rate: rust_decimal_macros::dec!(0.02577), // 2.577%
            ..Default::default()
        }
    }
}

fn main() {
    // Use custom strategy with with_madhab() (accepts any impl ZakatStrategy)
    let config = ZakatConfig::new()
        .with_gold_price(100)
        .with_madhab(GregorianTaxStrategy);
    
    // Or share strategy across configs with Arc
    let shared = Arc::new(GregorianTaxStrategy);
    let config = ZakatConfig::new()
        .with_gold_price(100)
        .with_strategy(shared);
}

### Advanced Assets (Jewelry & Livestock)


```rust
use zakat::prelude::*;

// Personal Jewelry (Exempt in Shafi/Maliki, Payable in Hanafi)
let necklace = PreciousMetals::new()
    .weight(100)
    .metal_type(WealthType::Gold)
    .usage(JewelryUsage::PersonalUse)
    .label("Wife's Wedding Necklace");

// Livestock Reporting
let prices = LivestockPrices::new()
    .sheep_price(200)
    .cow_price(1500)
    .camel_price(3000);
    
let camels = LivestockAssets::new()
    .count(30)
    .animal_type(LivestockType::Camel)
    .prices(prices);

let result = camels.calculate_zakat(&config)?;

if result.is_payable {
    // Access detailed "in-kind" payment info
    if let crate::types::PaymentPayload::Livestock { description, .. } = result.payload {
        println!("Pay Due: {}", description);
        // Output: "Pay Due: 1 Bint Makhad"
    }
}
```

## Modules


| Module | Nisab |
| :--- | :--- |
| `maal::precious_metals` | 85g Gold / 595g Silver |
| `maal::business` | 85g Gold |
| `maal::income` | 85g Gold |
| `maal::investments` | 85g Gold |
| `maal::agriculture` | 653 kg |
| `maal::livestock` | Count-based |
| `maal::mining` | Rikaz: None / Mines: 85g Gold |
| `fitrah` | N/A |

## Migrating from v0.4 (Builder Pattern)


v0.5 removes all `*Builder` structs. Migration is straightforward:

```diff
- let assets = BusinessZakatBuilder::default()
-     .cash_on_hand(10_000)
-     .build()?;
+ let assets = BusinessZakat::new()
+     .cash(10_000);
```

Key changes:
- `::builder()` → `::new()` (now infallible, returns `Self`)
- `.build()?` → removed, object is ready immediately
- Validation errors now occur at `.calculate_zakat()` instead of `.build()`
- Errors include Asset Labels for better debugging

## Contributing

1. Add tests
2. Use `rust_decimal`
3. If adding async features, ensure they are gated behind `#[cfg(feature = "async")]`
4. Run `cargo test` and `cargo check --no-default-features`

## Support

<div align="center">

[![GitHub Sponsors](https://img.shields.io/badge/Sponsor-%E2%9D%A4-ea4aaa?style=for-the-badge&logo=github-sponsors)](https://github.com/sponsors/IRedDragonICY)
[![Ko-fi](https://img.shields.io/badge/Ko--fi-F16061?style=for-the-badge&logo=ko-fi&logoColor=white)](https://ko-fi.com/ireddragonicy)
[![Patreon](https://img.shields.io/badge/Patreon-F96854?style=for-the-badge&logo=patreon&logoColor=white)](https://patreon.com/ireddragonicy)
[![PayPal](https://img.shields.io/badge/PayPal-00457C?style=for-the-badge&logo=paypal&logoColor=white)](https://paypal.com/paypalme/IRedDragonICY)
[![Saweria](https://img.shields.io/badge/Saweria-F4801C?style=for-the-badge&logo=data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSIjZmZmZmZmIj48Y2lyY2xlIGN4PSIxMiIgY3k9IjEyIiByPSI4Ii8+PC9zdmc+)](https://saweria.co/IRedDragonICY)

</div>

> *"Those who spend their wealth in the cause of Allah..."* — **Al-Baqarah 2:262**

## License

MIT

## Fiqh References & Compliance

We built this library with a deep respect for Islamic Jurisprudence (Fiqh), ensuring that every calculation isn't just mathematically correct, but religiously valid. Here is the breakdown of the scholarly sources (Dalil) and methodlologies we rely on.

### 1. Precious Metals (Gold & Silver)
For gold and silver, we adhere to the standard Nisab thresholds established in the Sunnah: **85 grams for Gold** (20 Dinars) and **595 grams for Silver** (200 Dirhams). This is based on the Hadith of Ali (ra) in *[Sunan Abu Dawud 1573](https://sunnah.com/abudawud:1573)* and *[Sahih Muslim 979](https://sunnah.com/muslim:979)*.

**What about Jewelry?**
This is a classic area of valid difference (*Ikhtilaf*). By default, we follow the **Hanafi view** (as found in *Al-Hidayah*) which regards personal jewelry as Zakatable wealth, citing the Hadith of the bracelets of fire (*[Sunan Abu Dawud 1558](https://sunnah.com/abudawud:1558)*). However, we fully support the majority opinion (**Shafi'i, Maliki, Hanbali**) which treats permissible personal jewelry as exempt. You can easily toggle this in your configuration to match your Madhab.

### 2. Business Assets (Urud al-Tijarah)
All trade goods are valued at their **current market price**, not the cost price. This comes from the Prophet's (ﷺ) command to Samurah bin Jundub to pay Zakat on what is "prepared for sale" (*[Sunan Abu Dawud 1562](https://sunnah.com/abudawud:1562)*).

Regarding debts: We deduct **Immediate Liabilities** (*Dayn al-Hal*) before calculation. This prevents you from paying Zakat on money that essentially belongs to your creditors, a principle supported by classical texts like *Al-Mughni* and modern standards like **[AAOIFI No. 35](https://aaoifi.com)**.

### 3. Agriculture (Zuru' wal-Thimar)
We handle the varying rates for crops based on how much effort goes into watering them:
*   **10% (Ushr)** for crops watered naturally by rain (*[Sahih Bukhari 1483](https://sunnah.com/bukhari:1483)*).
*   **5% (Half-Ushr)** for strictly irrigated crops requiring cost and labor (*[Sahih Muslim 981](https://sunnah.com/muslim:981)*).

For the Nisab (5 Awsuq), we use the standard conversion of approximately **653 kg** (derived from *[Sahih Muslim 979](https://sunnah.com/muslim:979)*), following the research of Dr. Yusuf Al-Qaradawi in his monumental work, *Fiqh al-Zakah*.

### 4. Livestock (An'am)
Our camel Zakat calculator is meticulously coded to follow the exact age tiers (like *Bint Makhad*, *Bint Labun*) outlined in the famous **Letter of Abu Bakr (ra)** preserved in *[Sahih Bukhari 1454](https://sunnah.com/bukhari:1454)*.

Crucially, we enforce the **Saimah** condition: Zakat is only due if your livestock grazes freely on open pastures for the majority of the year. Feed-lot animals are generally exempt from this specific category.

### 5. Modern Assets & Portfolio
*   **Stocks & Crypto**: We treat these as Trade Goods (*Urud*), subjecting them to a 2.5% rate on their market value, consistent with **[AAOIFI Standard 35](https://aaoifi.com)**.
*   **Professional Income**: We support Dr. Al-Qaradawi's view on *Zakat al-Mustafad*, allowing you to calculate Zakat either on your Gross income (like a harvest) or Net income (after basic needs).
*   **The "Dam' al-Amwal" Principle**: To ensure the computation is most beneficial for the poor (*Anfa' lil-fuqara*), we follow the **Hanafi** methodology of aggregating all your monetary assets (Gold, Silver, Cash, Stocks) into a single pot to check against the Nisab, rather than isolating them.