Metadata-Version: 2.5
Name: edf-tool
Version: 0.1.0
Summary: Monthly export-of-services invoice + bank EDF form generator for Indian freelancers. Runs fully offline.
Project-URL: Homepage, https://github.com/krushiraj/edf-tool
Project-URL: Issues, https://github.com/krushiraj/edf-tool/issues
Project-URL: Changelog, https://github.com/krushiraj/edf-tool/blob/main/CHANGELOG.md
Author: Krushi Raj Tula
License-Expression: MIT
License-File: LICENSE
Keywords: edf,export of services,fema,freelancer,gst,hdfc,india,invoice,lut,softex
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: End Users/Desktop
Classifier: Operating System :: MacOS
Classifier: Operating System :: Microsoft :: Windows
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Topic :: Office/Business :: Financial :: Accounting
Requires-Python: >=3.9
Description-Content-Type: text/markdown

# edf-tool

**Your monthly export-of-services paperwork in one command, entirely on your own computer.**

If you're an Indian freelancer or sole proprietor paid from abroad (directly or through Deel, Remote, an EOR and so on), your bank wants an **EDF (Export Declaration Form)** for each foreign payment. `edf` generates, every month:

| File | What it is |
|---|---|
| `…_INV-2026-10.pdf` | Your **invoice** to the client: GSTIN, PAN, SAC, IGST line, place of supply, amount in words |
| `…_EDF_INV-2026-10.xlsx` | The **bank's own EDF workbook**, filled in. The bank's formatting, dropdowns and logos are left untouched. |
| `…_EDF_Form_INV-2026-10.pdf` | **Two pages ready to sign and send**: the Request Letter and the Invoice Details |

> [!IMPORTANT]
> **Bank support: HDFC Bank only, for now.** edf-tool fills HDFC Bank's *"Request letter for Export of Services & EDF Filing Cum Disposal Instructions for Credit"* (the September 2026 version of the form). **Other banks may use a different format.** If your bank sends you a different form, edf-tool won't fill it, but [adding a bank](CONTRIBUTING.md#adding-a-bank) is one file. Always check every field before you submit. This is **not tax or legal advice**.

<p align="center">
  <img src="docs/images/sample-invoice.png" width="44%" alt="Sample invoice (fake data)">
  &nbsp;
  <img src="docs/images/sample-edf-request-letter.png" width="44%" alt="Sample HDFC EDF request letter (fake data)">
</p>
<p align="center"><sub>Generated from the fake data in <code>config.example.json</code>.</sub></p>

---

## 🔒 Privacy: nothing leaves your machine

- **No network access, ever.** The code has no networking, sends no telemetry and doesn't check for updates. The test suite fails if any networking module is even imported.
- Your details (PAN, GSTIN, bank account, client) are stored only in `~/.config/edf-tool/config.json`, readable only by you (`0600`).
- Your signature is stored only in `~/.config/edf-tool/signature.png`.
- Generated files go to `~/Documents/EDF/<invoice no>/`, or wherever you choose.
- No Python packages are needed: it's pure standard library, so there's no third-party code to trust.
- PDFs are made locally. The invoice is drawn by edf itself, and the bank form PDF uses your own LibreOffice, run offline.

---

## Install

**Homebrew (macOS / Linux)**
```bash
brew install krushiraj/tap/edf-tool
```

**uv**: run it without installing, or install it as a tool
```bash
uvx edf-tool --help           # one-off run
uv tool install edf-tool      # then just: edf
```

**pipx / pip**
```bash
pipx install edf-tool
# or: python3 -m pip install --user edf-tool
```

**Straight from GitHub** (no PyPI needed)
```bash
uvx --from git+https://github.com/krushiraj/edf-tool edf --help
```

**Optional: LibreOffice**, used *only* to turn the bank workbook into a PDF. The invoice PDF and the Excel file work without it.
```bash
brew install --cask libreoffice          # macOS
sudo apt install libreoffice-calc        # Debian/Ubuntu
```

You need Python 3.9 or newer; macOS already includes it. Check everything with `edf doctor`.

---

## First run (one-time setup)

```bash
edf init
```

Setup asks for everything the bank form and the invoice need. **Every required field must be answered** and is checked as you type: PAN format, GSTIN format *and check digit*, GSTIN-matches-PAN, IFSC, SAC code, phone and email. It covers:

1. **You:** business name, proprietor, address (as on your GST certificate), phone, email, PAN, GSTIN, IEC (or "Not applicable")
2. **Your bank account:** branch, branch address, IFSC, account number
3. **Your client:** legal name, address, country, registration/VAT number (optional)
4. **Who sends the money:** the client directly, or a third party like Deel (name, address, relationship)
5. **The service:** RBI purpose code (e.g. P0802), SAC code (e.g. 998314), description, scope
6. **Monthly defaults:** usual amount, usual transfer fee, invoice number prefix
7. *(optional)* **A picture of your signature**

If you run `edf generate` before setting up, it starts setup for you.

**Prefer a file?** Copy [`config.example.json`](config.example.json), fill it in, then:
```bash
edf init --from my-details.json --signature ~/Desktop/signature.jpg
rm my-details.json        # the details now live in ~/.config/edf-tool/
```

---

## Every month

```bash
edf generate
```

```
Monthly invoice + EDF   (Enter accepts the [suggested] value)

  Invoice date (DD-MM-YYYY) [30-09-2026]:
  Invoice number [INV-2026-10]:
  Work period start [31-08-2026]:
  Work period end [30-09-2026]:
  Due date [30-09-2026]:
  Invoice amount (USD) [2400.00]:
  Fee deducted before it reaches the bank [6.00]:
  Date on the bank request letter [07-10-2026]:

  Invoice   INV-2026-10  dated 30-09-2026, due 30-09-2026
  Client    Example Corp LLC
  Period    August 31, 2026 to September 30, 2026
  Amount    USD 2,400.00   fee USD 6.00   net to bank USD 2,394.00
  Generate these files? (yes/no) [yes]:

✓ Files in ~/Documents/EDF/INV-2026-10
```

Press **Enter** to accept each suggestion:
- **Invoice number:** the next number after the last one you made.
- **Invoice date:** the last day of last month (or of this month, if it's after the 15th).
- **Work period:** from the last day of the previous month to the invoice date.

edf won't let you reuse an invoice number unless you add `--force`.

**About the fee:** if Deel, or a correspondent bank, takes a fee before the money reaches you, enter it here. The bank form then declares the full **export value** (the invoice amount) and the lower **Net Realisable Value**, and explains the difference in the remarks. That's what lets your bank close the EDF cleanly when slightly less money arrives.

### Signing

Pick whichever suits you:

- **macOS Preview** (or any PDF app): open the two PDFs and use Tools → Annotate → Signature.
- **No PDF signing app?** Save your signature once, and edf will stamp it for you:
  ```bash
  edf signature set ~/Desktop/my-signature.jpg   # background removed automatically
  edf generate --sign                            # also writes *_signed.pdf copies
  edf sign INV-2026-10                           # or sign one you've already generated
  ```
  Use a photo or scan of your signature on white paper. PNG works everywhere; on a Mac, JPG and HEIC work too.
- **In the Excel file:** once a signature is saved, it's placed on the signatory line automatically. You can turn this off with `edf config set output.embed_signature_in_excel false`.

Then send the **bank form PDF** and the **invoice PDF** to your branch, along with the `.xlsx` if they ask for it. Many branches also want your **firm's stamp/seal** next to the signature.

---

## Commands

| Command | What it does |
|---|---|
| `edf init` | First-run setup. `--from FILE` reads a JSON file, `--force` redoes setup, `--signature IMG` saves a signature |
| `edf generate` (`gen`) | This month's files. Flags: `--invoice-date`, `--invoice-no`, `--amount`, `--fee`, `--period-start/--period-end`, `--due-date`, `--letter-date`, `--sign`, `--dry-run`, `-y`, `--json` |
| `edf sign INV-…` | Signed PDFs for an invoice already generated |
| `edf signature set IMG \| show \| remove` | Manage your saved signature |
| `edf config show \| path \| edit \| validate` | Look at, open or check the config |
| `edf config set FIELD VALUE` | Change one value, e.g. `edf config set defaults.amount 2500` |
| `edf history` | Invoices generated so far |
| `edf doctor` | Checks the config, bank template, signature, LibreOffice and output folder |
| `edf banks` | Supported bank forms |
| `edf man` | The full manual (also `man edf` when installed with Homebrew) |

Every command accepts `--json` for machine-readable output, and has `--help` with examples.

**Exit codes:**
- `0` OK
- `2` config missing or invalid
- `3` bad input (date, amount, or an invoice number already used)
- `4` bank form doesn't match the known version
- `5` files written, but an optional step was skipped (e.g. no LibreOffice)
- `130` cancelled

---

## Configuration reference

The config lives in `~/.config/edf-tool/config.json`; run `edf config path` to see the exact location. Edit it with `edf config edit` or `edf config set`.

| Field | Example | Notes |
|---|---|---|
| `exporter.firm_name` | `ACME DEV STUDIO` | As on your GST certificate |
| `exporter.proprietor` | `Asha Kumar` | Signs the forms |
| `exporter.constitution` | `Sole Proprietorship` | |
| `exporter.address_lines` | `["12 MG Road", "Bengaluru, KA 560038", "India"]` | Your GST-registered address |
| `exporter.phone`, `exporter.email` | | Printed on the invoice and the bank form |
| `exporter.pan`, `exporter.gstin` | `ABCDE1234F`, `29ABCDE1234F1ZW` | Validated, including the GSTIN check digit |
| `exporter.iec` | `Not applicable` | Most service exporters don't have one |
| `bank.branch_name`, `bank.branch_address`, `bank.ifsc` | | From your bank statement |
| `bank.account_no`, `bank.fee_account_no` | | The account credited, and the account charges are debited from |
| `client.name`, `client.address_lines`, `client.country` | | The service recipient |
| `client.short_address` | `Example Corp LLC, San Francisco, CA, USA` | Used in narrow boxes |
| `client.registration_number`, `client.vat_id` | | Optional |
| `third_party.enabled` | `true` | Set to `true` if Deel, Remote or similar sends the money |
| `third_party.name`, `.address`, `.short_address`, `.country`, `.relationship` | `Deel, Inc.` | The bank must know about third-party payers (FEMA) |
| `service.purpose_code`, `.purpose_description` | `P0802`, `Software consulting / implementation` | RBI purpose code |
| `service.sac` | `998314` | 998314 IT design & development; 998313 IT consulting & support |
| `service.description`, `.short_description`, `.line_item`, `.scope` | | Wording on the invoice and the form |
| `service.currency` | `USD` | Any 3-letter code |
| `defaults.amount`, `defaults.payment_fee` | `2400`, `6` | Used as the suggestions each month |
| `defaults.invoice_prefix` | `INV-` | |
| `output.folder` | `~/Documents/EDF` | |
| `output.file_prefix` | `Acme_Dev` | |
| `output.embed_signature_in_excel` | `true` | |
| `bank_format` | `hdfc_services` | See `edf banks` |
| `bank_template` | *(unset)* | Optional path to a newer copy of the same bank form |

**More than one client?** Keep a separate profile for each one with `EDF_TOOL_HOME`:
```bash
EDF_TOOL_HOME=~/.config/edf-tool-clientB edf init
EDF_TOOL_HOME=~/.config/edf-tool-clientB edf generate
```

---

## Using it with AI agents

edf is built to be driven by coding agents (Claude Code, Codex, Cursor and so on) without anything leaving your machine:

- Everything works without prompts: `-y`, `--from`, and `--json` on every command, with documented exit codes.
- [`AGENTS.md`](AGENTS.md) has step-by-step setup and monthly instructions, plus guardrails.
- [`skills/edf-tool/SKILL.md`](skills/edf-tool/SKILL.md) is a ready-made agent skill. Copy it into your agent's skills folder, e.g. `~/.claude/skills/edf-tool/`.

Tell your agent: *"Set up edf-tool from github.com/krushiraj/edf-tool and generate this month's EDF."*

---

## Good to know

- **GST / LUT:** the invoice shows `IGST (0%)`. Exporting services without charging IGST requires a **Letter of Undertaking (LUT)**, filed for free on the GST portal (form RFD-11). Without an LUT, IGST is payable and then refunded. Check with your CA. You can change the tax line's wording with `edf config set defaults.igst_label "…"`.
- **IEC:** usually not required for exporting services; the form says "Not applicable".
- **The bank form version:** before filling anything, edf checks that the form's labels match the version it knows. If HDFC changes the form, edf stops with exit status 4 rather than writing into the wrong cells. Please [open an issue](https://github.com/krushiraj/edf-tool/issues), and remove your personal data from anything you attach.
- **Fees and realisation:** keep Deel's (or your bank's) statement showing the fee. Banks sometimes ask for it when they close the EDF.

## Troubleshooting

| Problem | Fix |
|---|---|
| `No config found` | Run `edf init` |
| `EDF form PDF skipped` (exit status 5) | Install LibreOffice, or open the `.xlsx` and export the *REQUEST LETTER* and *Invoice Details 1* sheets as PDF |
| LibreOffice installed but not found | `export SOFFICE_PATH=/path/to/soffice` |
| Signature has a grey box around it | `edf signature set img.jpg --threshold 170` (a lower value removes more background) |
| An invoice number was already used | Use the next number, or add `--force` to regenerate it |
| Text cut off in a box on the bank form | Shorten `client.short_address`, `service.short_description` or `third_party.short_address` |

## Contributing

Bug reports and new bank formats are welcome; see [CONTRIBUTING.md](CONTRIBUTING.md). The tests run with only fake data: `python3 -m unittest discover -s tests`.

## License

MIT, © Krushi Raj Tula. The bundled HDFC form belongs to HDFC Bank. It's included unchanged apart from removed document metadata, and isn't covered by the MIT license. This project is not affiliated with or endorsed by HDFC Bank.
