Metadata-Version: 2.4
Name: ebia
Version: 0.5.0
Summary: EquipeBaie Invoice Automation
Author: AAH
Requires-Python: >=3.12
Description-Content-Type: text/markdown
Requires-Dist: pdfplumber
Requires-Dist: openpyxl
Provides-Extra: app
Requires-Dist: customtkinter>=5.2.0; extra == "app"
Requires-Dist: Pillow>=10.0.0; extra == "app"
Requires-Dist: watchdog>=4.0; extra == "app"
Requires-Dist: python-dotenv>=1.0; extra == "app"
Provides-Extra: dev
Requires-Dist: pytest>=8.0; extra == "dev"
Requires-Dist: pytest-cov>=5.0; extra == "dev"
Requires-Dist: pytest-mock>=3.12; extra == "dev"
Requires-Dist: ruff>=0.4; extra == "dev"
Requires-Dist: mypy>=1.10; extra == "dev"

# Equipe Baie — Invoice Automation

Automated invoicing pipeline that parses PDF invoices, enriches them with client accounting references, and generates Excel accounting exports — with a desktop UI for day-to-day operation.

---

## Project structure

```
EquipeBaie_Freelance-project/
├── src/
│   ├── ebia/                  # Core library (published to PyPI)
│   │   ├── parser.py          # PDF invoice parser
│   │   ├── xls_generator.py   # Excel (.xlsx) generator
│   │   └── cli.py             # CLI entry point
│   └── ebia_ui/               # Desktop application (not on PyPI)
│       ├── paths.py           # All filesystem paths — single source of truth
│       ├── logging_config.py  # App-wide logging setup
│       ├── main.py            # Application entry point
│       ├── core/
│       │   ├── config_manager.py   # Persistent JSON config
│       │   ├── client_manager.py   # Client reference registry
│       │   ├── engine.py           # Orchestration layer (RunEngine)
│       │   ├── manifest.py         # Processed-file tracking (SHA-256)
│       │   └── _mp_worker.py       # Subprocess entry point (multiprocessing)
│       ├── ui/
│       │   ├── main_window.py
│       │   ├── components/    # Reusable widgets, sidebar
│       │   └── views/         # Run, Config, Client, About pages
│       └── assets/            # logo.png, logo.ico, default_clients.json
├── installer/
│   ├── EquipeBaie.iss         # Inno Setup installer script
│   └── equipebaie.cer         # Self-signed code-signing certificate (public key)
├── tests/
│   ├── unit/                  # Pure-function tests, no I/O
│   ├── integration/           # Real PDF/Excel tests
│   └── e2e/                   # CLI subprocess tests
├── scripts/
│   └── build_exe.py           # PyInstaller Windows build (onedir)
└── pyproject.toml
```

---

## Components

### `ebia` — core library

Stateless, no side effects. Can be used standalone via CLI or imported directly.

- **`parser.py`** — extracts `Client`, `date`, `total_ttc` from a French-format PDF invoice using `pdfplumber`; `parse_many()` parses a list of PDFs in parallel using `ProcessPoolExecutor`, returning `(path, dict | Exception, list[LogRecord])` triples — log records collected in the worker are re-emitted by the caller so they reach the UI and log file on all platforms
- **`xls_generator.py`** — generates one `.xlsx` per month with one sheet per day; 3 accounting rows per invoice (411 / 44571 / 701). Supports retroactive insertion (`patch_month_workbook`) for late invoices arriving after a month has already been processed.

### `ebia_ui` — desktop application

Built with `customtkinter`. Requires Python + display (not headless).

- **Run view** — manual trigger + recurring scheduler (daily / weekly / monthly). The engine runs in a separate process (own GIL) so the UI stays responsive during execution. Includes a shortcut button to open the reports folder directly in File Explorer, and a run history table showing the last 20 executions (manual and scheduled) with status, report count, invoice count, and error details.
- **Config view** — VAT rate, invoice folder path, configurable reports output folder, manual PDF archive trigger
- **Client view** — client reference registry (accounting code ↔ client name) backed by a `ttk.Treeview` for instant rendering regardless of list size. Add and edit via modal popup dialog; pre-populated with a default client list on first launch.
- **About view** — app version (read dynamically from the installed package)
- **Manifest** — SHA-256 deduplication: already-processed PDFs are skipped on subsequent runs; only recorded after successful Excel generation
- **Per-month document counters** — each calendar month tracks its own last-used document number independently, so re-running for a past month never resets or conflicts with other months

### `ebia_ui/paths.py` — centralised path configuration

All filesystem paths are defined in one place. To change a location, edit only this file:

```python
APP_DIR      = Path.home() / ".equipe_baie"                          # config, clients, manifest, logs
REPORTS_DIR  = Path.home() / "Documents" / "Equipe_Baie" / "Rapports"
ARCHIVES_DIR = Path.home() / "Documents" / "Equipe_Baie" / "factures_archives"
```

---

## Monitoring

The app can send email notifications via Gmail when invoice runs complete or errors occur. Monitoring is **opt-in** — the app works normally without it.

### Setup

**Step 1 — Credentials** (required for monitoring to activate)

On first launch the app creates `~/.equipe_baie/.env.example`. Copy it and fill in your credentials:

```bash
cp ~/.equipe_baie/.env.example ~/.equipe_baie/.env
```

Edit `~/.equipe_baie/.env`:

```ini
# Gmail — standard passwords are blocked; use an App Password instead:
#   Google Account → Security → 2-Step Verification → App passwords
MAIL_SENDER=your-sender@gmail.com
MAIL_PASSWORD=xxxx-xxxx-xxxx-xxxx

# Primary recipient for all monitoring emails
MAIL_RECEIVER=notify@example.com

# Additional recipients for error alerts only (comma-separated, optional)
MAIL_RECEIVERS_ERROR=

# Display name used in email subjects (default: EquipeBaie)
APP_NAME=EquipeBaie
```

Restart the app after saving — monitoring activates automatically.

**Step 2 — Behaviour** (optional, defaults are production-ready)

On first launch the app creates `~/.equipe_baie/monitoring.json` with sensible defaults. Edit it directly to tune monitoring behaviour — changes are picked up on the next run, no restart needed:

```json
{
  "digest_frequency": "weekly",
  "digest_weekday": 0,
  "smtp_host": "smtp.gmail.com",
  "smtp_port": 587,
  "alert_cooldown_seconds": 300,
  "log_retention_days": 30,
  "notify_on_scheduler_success": true,
  "notify_on_manual_error": true
}
```

| Key | Default | Description |
|---|---|---|
| `digest_frequency` | `"weekly"` | Digest schedule: `"daily"` \| `"weekly"` \| `"monthly"` \| `"none"` |
| `digest_weekday` | `0` | Day for weekly digest: `0`=Monday … `6`=Sunday |
| `smtp_host` | `"smtp.gmail.com"` | SMTP server host |
| `smtp_port` | `587` | SMTP port (STARTTLS) |
| `alert_cooldown_seconds` | `300` | Minimum seconds between consecutive error alert emails |
| `log_retention_days` | `30` | Run log files older than this are deleted on startup |
| `notify_on_scheduler_success` | `true` | Set to `false` to suppress success emails from scheduled runs |
| `notify_on_manual_error` | `true` | Set to `false` to suppress error alerts from manual UI runs |

> **Tip:** For the first 2 weeks after a new install, set `"digest_frequency": "daily"` for maximum visibility, then switch back to `"weekly"`.

### What gets sent and when

| Trigger | Outcome | Email sent |
|---|---|---|
| **Scheduled run** (Task Scheduler) | Success | ✅ Green summary (if `notify_on_scheduler_success=true`) |
| **Scheduled run** (Task Scheduler) | Error / partial | ✅ Red alert with first error message |
| **Manual run** (UI) | Success | ❌ No email (intentional) |
| **Manual run** (UI) | Error | ✅ Red alert (if `notify_on_manual_error=true`) |
| **Digest** | Per `digest_frequency` | ✅ Summary of runs in the past period |
| **Live ERROR/CRITICAL log** | Any session | ✅ Alert email (subject to `alert_cooldown_seconds`) |

### Digest task

A second scheduled task (`EquipeBaie_WeeklyReport`) is registered automatically alongside the main pipeline task. Its schedule follows the `digest_frequency` and `digest_weekday` settings in `monitoring.json`. Re-registering the scheduler task in the UI picks up the latest values.

Setting `"digest_frequency": "none"` removes the digest task entirely.

You can also trigger the digest manually:

```cmd
EquipeBaie.exe --weekly-report
```

### Per-run log files

Every execution (scheduled or manual) creates a log file at:

```
~/.equipe_baie/logs/runs/RUN-YYYYMMDD-HHMMSS-{SCHEDULER|MANUAL}.log
```

Log files are cleaned up automatically on startup after `log_retention_days` days (default: 30).

---

## Application data locations

| Data | Default location |
|---|---|
| Config (VAT rate, folder paths, etc.) | `~/.equipe_baie/config.json` |
| Client reference registry | `~/.equipe_baie/clients.json` |
| Processed-file manifest | `~/.equipe_baie/processed.json` |
| Run history | `~/.equipe_baie/run_history.json` (last 100 runs, all triggers) |
| Application logs | `~/.equipe_baie/logs/ebia.log` (5 MB × 3 rotating backups) |
| Per-run logs | `~/.equipe_baie/logs/runs/RUN-*.log` (kept `log_retention_days` days, default 30) |
| Monitoring credentials | `~/.equipe_baie/.env` (rename from `.env.example` to enable) |
| Monitoring behaviour | `~/.equipe_baie/monitoring.json` (created automatically on first launch) |
| Generated Excel reports | `~/Documents/Equipe_Baie/Rapports/` (configurable in Config view) |
| Archived PDFs | `~/Documents/Equipe_Baie/factures_archives/` (configurable in Config view) |

On Windows `~` resolves to `C:\Users\<user>`, on Linux/macOS to `/home/<user>`.

---

## Installation

### Windows — client machines

Download `EquipeBaie_Setup.exe` from the [latest GitHub Release](https://github.com/Alamajdoub9/EquipeBaie_Freelance-project/releases/latest).

**Before running the installer**, unblock the downloaded file to prevent Windows SmartScreen from prompting. Open PowerShell and run:

```powershell
Unblock-File -Path "$env:USERPROFILE\Downloads\EquipeBaie_Setup.exe"
```

Then double-click `EquipeBaie_Setup.exe`. The installer will:
1. Install the application to `Program Files\EquipeBaie`
2. Silently import the code-signing certificate into the Windows Trusted Root store
3. Create a Start Menu shortcut (and optionally a Desktop shortcut)
4. Register an uninstaller in Programs & Features

After the first installation, all future updates signed with the same certificate will run without any SmartScreen warning — no `Unblock-File` step needed again.

### Library only (CLI usage)

```bash
pip install ebia
```

### Development (library + UI + tests)

```bash
git clone https://github.com/Alamajdoub9/EquipeBaie_Freelance-project.git
cd EquipeBaie_Freelance-project

python -m venv .venv
source .venv/bin/activate          # Linux / macOS
# .venv\Scripts\Activate.ps1       # Windows PowerShell

pip install -e ".[dev,app]"
```

---

## Running the application

```bash
ebia-ui
# or
python -m ebia_ui.main
```

On first launch:
1. Go to **Configurations** and set the invoice folder path (where your PDFs are stored)
2. Optionally adjust the VAT rate, the reports output folder, and the archive folder
3. Go to **Clients** to review the pre-loaded client list and add or edit entries as needed
4. Go to **Exécution** and click **Lancer maintenant**

Generated Excel files are written to the reports folder configured in the Config view (default: `~/Documents/Equipe_Baie/Rapports/`).

To archive processed PDFs after a run, go to **Configurations → Archivage des Factures** and click **Archiver les factures traitées**. Only PDFs already recorded in the manifest are moved.

---

## CLI usage (library only)

```bash
# Parse a single PDF and print extracted fields
ebia --path facture.pdf

# Generate Excel from a folder of PDFs
ebia --path ./invoices --out ./output/result.xlsx --start-piece 1 --start-document 1
```

---

## Running tests

```bash
# All tests
pytest

# By level
pytest -m unit
pytest -m integration
pytest -m e2e

# With coverage
pytest --cov=src/ebia --cov=src/ebia_ui/core --cov-report=term-missing
```

**Test matrix:**

| Suite | What it covers |
|---|---|
| `unit/test_parser.py` | PDF field extraction logic, `parse_many` contract (3-tuple return, log records) |
| `unit/test_generator.py` | Excel row generation and formatting |
| `unit/test_manifest.py` | SHA-256 manifest: load, save, deduplication |
| `unit/test_ebia_ui_core.py` | ConfigManager, ClientManager, RunEngine error paths |
| `integration/test_engine.py` | Full pipeline: PDFs → parse → enrich → xlsx |
| `integration/test_generator_xlsx.py` | Multi-month/multi-day workbook structure |
| `integration/test_parser_pdf.py` | Real PDF corpus parsing |
| `e2e/test_cli.py` | CLI invoked as subprocess |

---

## Delivery

The project has two deliverables released together by the same workflow.

### 1. `ebia` PyPI package

```bash
pip install ebia
```

Published automatically on every release. The `ebia_ui` package is **excluded** from the wheel (internal app, not a public library).

### 2. Windows installer (`EquipeBaie_Setup.exe`)

Built via PyInstaller (onedir) + Inno Setup on a Windows runner and attached to the GitHub Release alongside the wheel. No Python installation required on the target machine.

```bash
# Build the app folder locally (requires PyInstaller)
python scripts/build_exe.py
# produces: dist/EquipeBaie/EquipeBaie.exe

# Build the installer locally (requires Inno Setup installed)
iscc /DMyAppVersion=x.y.z installer\EquipeBaie.iss
# produces: dist/EquipeBaie_Setup.exe
```

---

## Code signing

The Windows installer and executable are signed with a self-signed certificate (`installer/equipebaie.cer`). The certificate is automatically imported into the client machine's Trusted Root store during installation, so no SmartScreen warnings appear on subsequent runs.

The private key (`.pfx`) is stored as a GitHub Actions secret (`CODESIGN_PFX_B64`) and never committed to the repository. The public certificate (`.cer`) is committed and bundled into the installer.

To regenerate the certificate (e.g. after expiry in 2031):
1. Run `New-SelfSignedCertificate` as described in the signing setup guide
2. Export the new `.pfx` and `.cer`
3. Update the `CODESIGN_PFX_B64` and `CODESIGN_PFX_PASSWORD` GitHub secrets
4. Replace `installer/equipebaie.cer` with the new `.cer`
5. Re-run the one-time `Import-Certificate` step on each client machine

---

## Versioning and release

Both deliverables share a single version number defined in `pyproject.toml`. The about view reads it dynamically via `importlib.metadata` — no manual update needed.

**To publish a new release**, trigger the `Release` workflow from the GitHub Actions UI and pick the bump type:

| Input | Effect | Example |
|---|---|---|
| `patch` (default) | Bug fixes | `0.2.0` → `0.2.1` |
| `minor` | New features, backwards-compatible | `0.2.0` → `0.3.0` |
| `major` | Breaking changes | `0.2.0` → `1.0.0` |

The workflow will:
1. Bump the version in `pyproject.toml` and push a `chore: bump version to X.Y.Z` commit to `main`
2. Run the full test suite (gate)
3. Build and publish the wheel to PyPI
4. Create a GitHub Release with the wheel attached
5. Build `EquipeBaie/` (onedir) with PyInstaller on a Windows runner
6. Sign `EquipeBaie.exe` with the code-signing certificate
7. Build `EquipeBaie_Setup.exe` with Inno Setup
8. Sign the installer
9. Attach `EquipeBaie_Setup.exe` to the GitHub Release

---

## Requirements

- Python >= 3.12
- Library deps: `pdfplumber`, `openpyxl`
- UI extra deps: `customtkinter >= 5.2.0`, `Pillow >= 10.0.0`, `watchdog >= 4.0`, `python-dotenv >= 1.0`
- Dev deps: `pytest`, `pytest-cov`, `pytest-mock`, `ruff`, `mypy`

> `watchdog` and `python-dotenv` are bundled in the Windows installer. They are only active when `~/.equipe_baie/.env` is present and correctly filled. Monitoring behaviour is controlled by `~/.equipe_baie/monitoring.json`, which is created automatically on first launch.
