Skip to main content

EquipeBaie Invoice Automation

Project description

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 (runs in background — UI stays responsive on network drives), workspace folder for multi-machine setups
  • 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
  • Sub-folder support — the engine recurses into sub-folders when scanning for PDF invoices, so the client can organise invoices by month inside the source folder

ebia_ui/paths.py — centralised path configuration

All filesystem paths are defined in one place, derived from APP_DIR (the workspace):

APP_DIR      = _resolve_app_dir()   # local default or shared drive (see Workspace below)
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 as a template (only if .env does not already exist). Create .env in the same folder and fill in your credentials:

cp ~/.equipe_baie/.env.example ~/.equipe_baie/.env

Edit ~/.equipe_baie/.env:

# 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:

{
  "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:

EquipeBaie.exe --weekly-report

Machine identity in emails

Every monitoring email (both success reports and error alerts) includes a Machine field showing user@hostname — the Windows login name and computer name of the machine that sent the email. This makes it immediately clear which installation triggered the notification when the app runs on more than one machine.

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 (create from .env.example template 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)
Workspace pointer ~/.equipe_baie/workspace.txt (only present when using a shared workspace)

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

Note: When a shared workspace is configured (see below), all paths in the table above point into the shared folder instead of ~/.equipe_baie/. The workspace.txt file itself always stays on the local machine.


Multi-machine workspace (shared drive)

Two machines can share the same configuration, client registry, and processed-file manifest by pointing both installations to a single folder on a shared drive.

Prerequisites: the two machines must never run the app simultaneously, and the shared drive must be reachable before launching the app.

Setup — machine 1 (existing installation)

  1. Open Config → Dossier de travail → click Changer
  2. Pick the shared drive folder (e.g. Z:\EquipeBaie\)
  3. The app copies your existing data (config, clients, manifest, .env, monitoring.json) to the shared folder and writes a local workspace.txt pointer
  4. Confirm the restart prompt — the app reloads from the shared folder

Setup — machine 2 (fresh installation)

  1. Install the app normally
  2. Open Config → Dossier de travail → click Changer
  3. Pick the same shared drive folder (Z:\EquipeBaie\)
  4. The app writes workspace.txt locally; existing files in the shared folder are not overwritten
  5. Confirm the restart prompt

Both machines now read and write the same config.json, clients.json, processed.json, and monitoring files. The workspace pointer (workspace.txt) is machine-local and is the only file that differs between the two machines.


Installation

Windows — client machines

Download EquipeBaie_Setup.exe from the latest GitHub Release.

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

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)

pip install ebia

Development (library + UI + tests)

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

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)

# 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

# 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

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.

# 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.00.2.1
minor New features, backwards-compatible 0.2.00.3.0
major Breaking changes 0.2.01.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.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

ebia-0.5.1-py3-none-any.whl (18.2 kB view details)

Uploaded Python 3

File details

Details for the file ebia-0.5.1-py3-none-any.whl.

File metadata

  • Download URL: ebia-0.5.1-py3-none-any.whl
  • Upload date:
  • Size: 18.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for ebia-0.5.1-py3-none-any.whl
Algorithm Hash digest
SHA256 91a83f81313b1a18fa67050fd0012f8e98786e9ee33f1e67db25154c2fd61632
MD5 80e06b81f3576a11a4065c1e1b806931
BLAKE2b-256 fb9682d5a30fa4d0c65e3ce6b49c17505ffb9f0cc21dcc68870dd41549252e82

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page