# Changelog of Arabic Receipt Reader (OCR + Saudi ZATCA QR) (`saif-tools/arabic-receipt-reader`) Actor

- **URL**: https://apify.com/saif-tools/arabic-receipt-reader/changelog.md
- **Full Actor documentation**: https://apify.com/saif-tools/arabic-receipt-reader.md

## Changelog

### 0.1 revisions (unreleased, local build only), 23 Oct 2026

boi's answers of 23 Oct 2026 and hitler's review fixes.

- **QR fields are now free inside the receipt price.** The `exact-qr-fields` event is gone from this actor (`pay_per_event.json`, PRICING.md, README). A receipt with a ZATCA QR costs $0.025 (screenshot) or $0.05 (photo). `exactQrFields`, `qr` and `qrCrossCheck` are still in the output, and `includeQrFields` (default `true`) only turns the decoding off.
- **Pricing note:** the README now says that photo vs screenshot is decided by the original pixel count, before the 4 MP downscale.
- **Spending cap:** each image now reserves only its OCR event ($0.025 or $0.05).
- **`chargedEvents` is built from what was actually charged** (`ChargeResult.charged_count`) by `save_row`, which is the same helper as in `arabic-image-ocr`. If the OCR event no longer fits under the cap, the row is saved free and lists nothing.
- **No Tesseract module.** The text-direction helpers (`BIDI`, `word_dir`, `logical_order`, `group_rows`) moved to `textutil.py`, and preprocessing moved to the new shared `imageprep.py`. `ocr.py` is no longer part of this actor, and `pytesseract` is dropped from `requirements.txt`. `test/check_shared.py` now lists the real shared files and fails if an actor-specific module leaks across.
- **Sample fallback in the status message:** when the bundled sample stands in (empty input, or the example URL fails to download), the run's status message and `OUTPUT.note` say so, for example "Input image failed to download; returned built-in sample instead".
- **Cross-links** now point to `https://apify.com/saif-tools/arabic-image-ocr`.
- **Pinned dependencies:** `requirements.txt` pins every direct dependency to the tested version (EasyOCR 1.7.2). The Dockerfile pins torch 2.14.1+cpu and torchvision 0.29.1+cpu, from the CPU index.

### 0.1 (unreleased, local build only), 22 Oct 2026

The first version. It was split out of `arabic-image-ocr` 0.1 (its `full` mode), per boi's decisions of 22 Oct 2026.

**OCR**

- Full OCR with EasyOCR (ar+en, CPU torch). Every number is cross-checked by the Arabic-Indic digit classifier.
- EasyOCR loads lazily: on the first image, not at start-up.
- Every image is downscaled to at most 4 MP before OCR. `imageSize` gives the original and processed sizes; boxes are in original-image pixels.

**Events and pricing**

- `full-ocr-screenshot` ($0.025): images whose original is at most 4 MP.
- `full-ocr-photo` ($0.05): images whose original is over 4 MP.
- \~~`exact-qr-fields` ($0.01) on top of the OCR event~~: removed on 23 Oct, see above.
- `apify-default-dataset-item` stays unpriced.

**Receipt fields and needsReview**

- Receipt fields:
  - total, subtotal and VAT candidates;
  - VAT number and date;
  - line items;
  - `sumCheck`, `vatCheck` and `qrCrossCheck`;
  - a new `reconciliation` block.
- **New `needsReview` rules.** When line items + VAT reconcile with the total (or subtotal + VAT does, or the total matches the QR), low confidence alone does not flag the row. A row is flagged when:

  - the numbers don't reconcile;
  - the printed value disagrees with the QR;
  - no total is found;
  - there is nothing to reconcile against and the total's confidence is below the threshold.

  Low confidence on its own now goes into `notes`.
- New `reviewReasons`:

  - `line_items_do_not_add_up`
  - `subtotal_plus_vat_differs_from_total`
  - `printed_value_differs_from_qr: …`
  - `no_total_found`
  - `total_low_confidence_and_nothing_to_reconcile`

  The old `low_confidence: …` and `sum_not_checked` reasons are gone.

**Fields and inputs**

- `exactQrFields.signatureChecked: false`. We decode the TLV but don't verify the signature or stamp.
- Bundled sample receipt `sample/sample-receipt.png`, used when the input has no images. The Store default run uses it too. Sample rows carry `sample: true` and are free.

**Runtime and build**

- Memory: 4096 MB minimum and default (max 8192). If the run has less than 3000 MB, the actor exits 0 straight away with "Increase memory to 4 GB…" in `OUTPUT` and the status message, and charges nothing.
- Images are processed one at a time.
- The Docker image bakes in the EasyOCR models and has no Tesseract.

### 2026-10-23

- Pinned every dependency to the exact versions tested locally so the first Apify build matches.
- Added constraints.txt (full pip freeze of the tested venv) so transitive dependencies are locked too; the Dockerfile installs with -c constraints.txt.
