# Pinnex Tally Bridge — v0.3.3

HTTP API that posts vouchers to Tally Prime via its XML/ODBC server,
running as a Windows service on the client's PC.

## What's new in v0.3.3

Two real-world fixes pulled out of a bookkeeping session on Ravya's box
where one Bridge needed to post to two different companies that were
already open in Tally.

### 1. Per-call `tally_company` override

`tally_post_voucher` and `tally_post_voucher_xml` now accept an optional
`tally_company` parameter. When supplied, the Bridge writes that value
into `SVCURRENTCOMPANY` in the generated import envelope for **that one
call only**. The `.env` `TALLY_COMPANY` is no longer the only company a
single Bridge can target.

**Why this matters.** Before v0.3.3 you had to edit
`C:\Program Files\Pinnex Bridge\.env`, save, and `Restart-Service
PinnexBridge` every time you wanted to post to a different open company.
Multi-client CA firms could not switch between clients in the same
chat. v0.3.3 makes the override per-request.

JSON example — POST `/sync/push`:

```json
{
  "tally_company": "Being Zero Consulting Private Limited (From Apr 25)",
  "vouchers": [ ... ]
}
```

If omitted, the Bridge falls back to `.env` `TALLY_COMPANY` — **fully
backward compatible** with v0.3.0 / 0.3.1 / 0.3.2 callers.

The push response now also includes:

```json
{
  "posted": 1, "failed": 0,
  "tally_company": "Being Zero Consulting Private Limited (From Apr 25)",
  "tally_company_source": "per_call_override"
}
```

so you can confirm which company the entries actually landed in.

### 2. `/sync/xml` is now a raw-XML pass-through

In v0.3.0 / 0.3.1 / 0.3.2, `/sync/xml` was a file-download export endpoint
that took a JSON voucher list and returned a Tally Import-XML file. Its
tool description in the MCP wrongly said it forwarded XML to Tally — it
didn't, and a real bookkeeping run today exposed the gap.

v0.3.3 changes `/sync/xml` to **forward raw Tally Import-XML to Tally
Prime**:

```
POST /sync/xml?tally_company=<optional>
Content-Type: text/xml
Authorization: Bearer <LICENSE_KEY>

<?xml version="1.0" encoding="UTF-8"?>
<ENVELOPE>...full Tally envelope here...</ENVELOPE>
```

The Bridge:

- accepts `text/xml`, `application/xml`, or `application/octet-stream`
  bodies (a legacy `{"xml": "<ENVELOPE>...</ENVELOPE>"}` JSON wrapper is
  also accepted),
- sanity-checks that the body looks like a Tally envelope and 400s with
  `xml_malformed` if not,
- if `?tally_company=<name>` is present, rewrites the
  `<SVCURRENTCOMPANY>` element in the envelope before forwarding,
- POSTs the (possibly rewritten) XML to Tally `http://<host>:9000/` with
  `Content-Type: text/xml`,
- parses Tally's response and returns the same wrapper as `/sync/push`:
  `{ posted, failed, created, altered, ignored, errors, tally_response }`.

If you still need the old "build an envelope from JSON vouchers and save
it" behaviour, hit `POST /sync/push` with `dry_run: true` — the response
contains the generated envelope in the `xml` field.

### `/health` now advertises capabilities

```json
{
  "version": "0.3.3",
  "capabilities": {
    "per_call_tally_company_override": true,
    "raw_xml_forwarding": true
  },
  ...
}
```

so a tooling layer can decide at runtime whether the Bridge in front of
it understands the new features.

## What v0.3.2 brought (unchanged in v0.3.3)

- `company_loaded` detection via the documented Collection / List of
  Companies request (fixes the empty-CompanyObject bug on TallyPrime
  Silver).
- `/health` exposes `loaded_companies` and `matched_company` so
  configuration mismatches diagnose themselves.
- `LOG_LEVEL=debug` dumps every Tally request / response body (truncated
  at 10 KB).
- License verify fails open when `api.pinnex.in` is unreachable; cached
  for 7 days.
- `install.ps1` preserves an existing `.env`.

## What it does (unchanged)

- Listens on `:9888` (configurable) on the client's PC.
- Authenticates each request via a bearer license key.
- Maps a clean JSON voucher payload onto Tally's verbose XML import
  envelope. Posts to `http://<tally-host>:9000/`.
- Returns counters (`created`, `altered`, `ignored`, `errors`).
- Falls back to CSV export for offline batch import (`/sync/csv`).
- v0.3.3: forwards raw XML envelopes verbatim (`/sync/xml`).

## Quick upgrade (existing v0.3.0 / v0.3.1 / v0.3.2 boxes)

```
1. Copy PinnexBridge-0.3.3.zip to Windows, extract anywhere.
2. Right-click install.ps1 → Run with PowerShell (as Administrator).
3. curl http://localhost:9888/health → should show version: "0.3.3"
   and capabilities.per_call_tally_company_override: true.
```

Your existing `.env` at `C:\Program Files\Pinnex Bridge\.env` is left
alone. See `UPGRADE-FROM-v0.3.2.md` for the step-by-step.

## Fresh install

```
1. Make sure Tally Prime is running and ODBC server is enabled on :9000.
2. Copy ZIP, extract.
3. Right-click install.ps1 → Run with PowerShell (as Administrator).
4. Paste your license key, firm code, and the EXACT Tally company name.
```

See `installer/README.txt` in the ZIP for full setup and troubleshooting.

## API surface

```
GET  /health                  bridge + Tally + license + company status + capabilities
POST /sync/push               post vouchers to Tally  (auth)
                              body: { vouchers, dry_run?, tally_company? }
POST /sync/csv                return vouchers as CSV  (auth)
                              body: { vouchers }
POST /sync/xml                forward raw Tally Import-XML to Tally  (auth)
                              body: raw XML (Content-Type: text/xml)
                              query: ?tally_company=<optional override>
```

All POST endpoints require `Authorization: Bearer <LICENSE_KEY>`.
