Metadata-Version: 2.4
Name: django-toconline
Version: 1.1.0
Summary: Django integration for the TOConline API
License-Expression: MIT
License-File: LICENSE
Keywords: Django,TOConline,API
Author: Daniel Pinto
Author-email: dmp593@gmail.com
Requires-Python: >=3.10,<4.0
Classifier: Environment :: Web Environment
Classifier: Framework :: Django
Classifier: Framework :: Django :: 5.2
Classifier: Framework :: Django :: 6.0
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Software Development :: Libraries
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
Requires-Dist: Django (>=5.2,<7.0)
Requires-Dist: requests (>=2.32.5,<3.0)
Project-URL: Documentation, https://github.com/dmp593/django-toconline#readme
Project-URL: Repository, https://github.com/dmp593/django-toconline
Description-Content-Type: text/markdown

# Django TOConline

A small Django integration for Portugal's TOConline commercial API.

The package deliberately stays close to the HTTP API: it persists OAuth2
tokens, provides generic resource helpers, and implements the few document
operations whose routes do not follow normal CRUD conventions. API responses
are returned as dictionaries/lists, with the outer JSON:API `data` member
removed when present.

Official sources:

- [TOConline API documentation](https://api-docs.toconline.pt/)
- [TOConline OpenAPI specification](https://app.swaggerhub.com/apis-docs/toconline.pt/toc-online_open_api/1.0.0)
- [Compatibility audit for this package](https://github.com/dmp593/django-toconline/blob/main/docs/api-compatibility.md)

## Compatibility

| Django | Python |
| --- | --- |
| 5.2 | 3.10–3.14 |
| 6.0 | 3.12–3.14 |

Django 6.0 itself requires Python 3.12 or newer. The package retains Django
5.2 support so applications still on Python 3.10 or 3.11 have a supported
upgrade path.

## Installation

```bash
python -m pip install django-toconline
```

Add the application to `INSTALLED_APPS` and run migrations:

```python
INSTALLED_APPS = [
    # ...
    "toconline",
]
```

```bash
python manage.py migrate
```

## Configuration

Keep all credentials in environment-backed settings. TOConline supplies the
API URL and OAuth URL with the integration credentials for each company.

```python
import os

TOCONLINE_BASE_URL = os.environ["TOCONLINE_BASE_URL"]
TOCONLINE_OAUTH_BASE_URL = os.environ.get(
    "TOCONLINE_OAUTH_BASE_URL",
    f"{TOCONLINE_BASE_URL}/oauth",
)
TOCONLINE_OAUTH_CLIENT_ID = os.environ["TOCONLINE_OAUTH_CLIENT_ID"]
TOCONLINE_OAUTH_CLIENT_SECRET = os.environ[
    "TOCONLINE_OAUTH_CLIENT_SECRET"
]
TOCONLINE_ALLOWED_DOWNLOAD_HOSTS = ["toconline.pt"]
TOCONLINE_OAUTH_REDIRECT_URI = os.environ.get(
    "TOCONLINE_OAUTH_REDIRECT_URI",
    "https://oauth.pstmn.io/v1/callback",
)
TOCONLINE_TIMEOUT = 10
```

`TOCONLINE_BASE_URL` is the host URL without `/api`.
`TOCONLINE_OAUTH_BASE_URL` is the OAuth service URL ending in `/oauth`; it
defaults to `<TOCONLINE_BASE_URL>/oauth` for backward compatibility.
`TOCONLINE_ALLOWED_DOWNLOAD_HOSTS` is optional. Official `*.toconline.pt`
API hosts allow that domain's subdomains by default; custom/white-label API
hosts should explicitly list every trusted PDF download host.

## Resource operations

Authentication is automatic. The first request obtains and stores a token in
`TocOnlineToken`; subsequent requests refresh it before expiry.
Token values are deliberately hidden from Django admin, but the application
database and its backups must still be treated as sensitive.

```python
from toconline.resources import TocOnlineResource
from toconline.services import toconline

customers = toconline.list(
    TocOnlineResource.CUSTOMERS,
    limit=10,
)

customer = toconline.first(
    TocOnlineResource.CUSTOMERS,
    email="customer@example.com",
)

created = toconline.create(
    TocOnlineResource.CUSTOMERS,
    business_name="Example, Lda.",
    contact_name="Example",
    tax_registration_number="999999990",
)

toconline.update(
    TocOnlineResource.CUSTOMERS,
    created["id"],
    contact_name="Updated name",
)

toconline.delete(TocOnlineResource.CUSTOMERS, created["id"])
```

Keyword arguments to `list()` become JSON:API filters. Raw query parameters
are also supported for TOConline's expression filters and pagination:

```python
documents = toconline.list(
    TocOnlineResource.COMMERCIAL_SALES_DOCUMENTS,
    params={
        "filter": "documents.pending_total>0",
        "page[size]": 25,
    },
)
```

The current `/v1` sales and purchase creation endpoints use plain JSON rather
than a JSON:API envelope. `create()` handles that distinction automatically.
Current receipt updates also use the ID-scoped `/v1` route.

```python
receipt = toconline.create(
    TocOnlineResource.COMMERCIAL_SALES_RECEIPTS,
    date="2026-07-22",
    payment_mechanism="TR",
    lines=[
        {
            "receivable_type": "Document",
            "receivable_id": "123",
            "received_value": 100,
        }
    ],
)

toconline.update(
    TocOnlineResource.COMMERCIAL_SALES_RECEIPTS,
    str(receipt["id"]),
    observations="Updated before finalization",
)
```

The generic helpers are path-driven. They do not imply that every TOConline
resource supports every CRUD operation; use only the methods listed for that
resource in the official documentation.

## Document operations

### Download a PDF

```python
from toconline.resources import TocOnlineDocumentKind

pdf = toconline.download_document(
    "document-id",
    kind=TocOnlineDocumentKind.DOCUMENT,
    n_copies=2,
)
```

Available print kinds are `Document`, `Receipt`, and the currently documented
`PurchasesDocument`. The historical enum member name `PURCHASE_DOCUMENT`
remains available but now sends the corrected plural API value.

### Void a supported document

```python
toconline.void_document(
    TocOnlineResource.COMMERCIAL_SALES_RECEIPTS,
    "receipt-id",
)
```

The old `cancel_document()` name remains as an alias.

### Send a document by email

```python
result = toconline.send_document_via_email(
    from_email="billing@example.com",
    from_name="Billing",
    subject="Your invoice",
    to_email="customer@example.com",
    pk="document-id",
    kind=TocOnlineDocumentKind.DOCUMENT,
)
```

### Communicate a document to the Tax Authority

```python
from toconline.resources import TocOnlineTaxAuthorityDocumentType

result = toconline.communicate_document_to_tax_authority(
    "document-id",
    document_type=TocOnlineTaxAuthorityDocumentType.SALES_DOCUMENT,
    entity_username="tax-portal-user",
    entity_password="base64-encoded-tax-portal-password",
)
```

The misspelled historical method
`send_document_to_finantial_authority()` remains as an alias. Never log the
Tax Authority username or password.

## Calling newly added endpoints

Use `request()` when TOConline publishes a route before this package adds a
convenience constant. Paths are relative to `/api`; absolute URLs and `..`
path traversal are rejected so bearer credentials cannot be sent to another
host.

```python
result = toconline.request(
    "GET",
    "new-resource",
    params={"page[size]": 10},
)
```

## Development and tests

The test suite is deterministic and does not contact TOConline or use real
credentials.

```bash
make requirements-test
make test
```

To expose deprecation warnings during framework upgrades:

```bash
.venv/bin/python -Wa manage.py test tests
```

CI covers the lower supported Python/Django pair, Django 6 on its minimum
Python version, and the newest supported Python/Django pair.

## Upgrade notes from 1.0.x

- The supported Django range is now `>=5.2,<7.0`, which permits Django 6.
- OAuth and API hosts may be configured separately.
- `/v1` resources send plain JSON and receipt updates include the receipt ID
  in the URL.
- AT communication follows the machine-readable OpenAPI `PATCH` operation.
- Email sending now returns parsed response data instead of raising an
  `AttributeError` after a successful request.
- The purchase print type is `PurchasesDocument`, matching the current docs.
- PDF downloads reject hosts outside the TOConline domain by default; custom
  API installations must set `TOCONLINE_ALLOWED_DOWNLOAD_HOSTS`.
- Test settings no longer contain credential-like values, and tests no longer
  mutate a live TOConline account.

## License

MIT. See [LICENSE](LICENSE).

