pennylane-sdk 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pennylane_sdk-0.1.0/.gitattributes +3 -0
- pennylane_sdk-0.1.0/.github/workflows/ci.yml +68 -0
- pennylane_sdk-0.1.0/.github/workflows/docs.yml +37 -0
- pennylane_sdk-0.1.0/.github/workflows/release.yml +39 -0
- pennylane_sdk-0.1.0/.gitignore +31 -0
- pennylane_sdk-0.1.0/CHANGELOG.md +24 -0
- pennylane_sdk-0.1.0/CONTRIBUTING.md +70 -0
- pennylane_sdk-0.1.0/LICENSE +21 -0
- pennylane_sdk-0.1.0/PKG-INFO +140 -0
- pennylane_sdk-0.1.0/README.fr.md +128 -0
- pennylane_sdk-0.1.0/README.md +107 -0
- pennylane_sdk-0.1.0/SECURITY.md +18 -0
- pennylane_sdk-0.1.0/docs/api/clients.md +13 -0
- pennylane_sdk-0.1.0/docs/api/company/accounting.md +17 -0
- pennylane_sdk-0.1.0/docs/api/company/analytics.md +7 -0
- pennylane_sdk-0.1.0/docs/api/company/banking.md +9 -0
- pennylane_sdk-0.1.0/docs/api/company/e-invoicing.md +7 -0
- pennylane_sdk-0.1.0/docs/api/company/exports.md +11 -0
- pennylane_sdk-0.1.0/docs/api/company/invoicing.md +24 -0
- pennylane_sdk-0.1.0/docs/api/company/mandates.md +9 -0
- pennylane_sdk-0.1.0/docs/api/company/misc.md +11 -0
- pennylane_sdk-0.1.0/docs/api/company/purchases.md +9 -0
- pennylane_sdk-0.1.0/docs/api/errors.md +27 -0
- pennylane_sdk-0.1.0/docs/api/filters.md +5 -0
- pennylane_sdk-0.1.0/docs/api/firm.md +49 -0
- pennylane_sdk-0.1.0/docs/api/oauth.md +5 -0
- pennylane_sdk-0.1.0/docs/api/pagination.md +11 -0
- pennylane_sdk-0.1.0/docs/api/webhooks.md +5 -0
- pennylane_sdk-0.1.0/docs/changelog.md +3 -0
- pennylane_sdk-0.1.0/docs/contributing.md +3 -0
- pennylane_sdk-0.1.0/docs/design/resource-map.md +97 -0
- pennylane_sdk-0.1.0/docs/getting-started.md +104 -0
- pennylane_sdk-0.1.0/docs/guides/accounting.md +112 -0
- pennylane_sdk-0.1.0/docs/guides/authentication.md +57 -0
- pennylane_sdk-0.1.0/docs/guides/e-invoicing.md +58 -0
- pennylane_sdk-0.1.0/docs/guides/errors-and-retries.md +77 -0
- pennylane_sdk-0.1.0/docs/guides/firm-api.md +84 -0
- pennylane_sdk-0.1.0/docs/guides/invoicing.md +129 -0
- pennylane_sdk-0.1.0/docs/guides/oauth.md +51 -0
- pennylane_sdk-0.1.0/docs/guides/pagination.md +88 -0
- pennylane_sdk-0.1.0/docs/guides/webhooks.md +64 -0
- pennylane_sdk-0.1.0/docs/index.md +77 -0
- pennylane_sdk-0.1.0/examples/bulk_read_async.py +35 -0
- pennylane_sdk-0.1.0/examples/einvoice_import.py +20 -0
- pennylane_sdk-0.1.0/examples/firm_portfolio.py +22 -0
- pennylane_sdk-0.1.0/examples/invoicing_lifecycle.py +55 -0
- pennylane_sdk-0.1.0/examples/quickstart.py +23 -0
- pennylane_sdk-0.1.0/examples/webhook_receiver.py +41 -0
- pennylane_sdk-0.1.0/mkdocs.yml +95 -0
- pennylane_sdk-0.1.0/pyproject.toml +101 -0
- pennylane_sdk-0.1.0/scripts/check_coverage.py +170 -0
- pennylane_sdk-0.1.0/scripts/show_endpoint.py +151 -0
- pennylane_sdk-0.1.0/scripts/update_specs.py +47 -0
- pennylane_sdk-0.1.0/specs/company_v2.json +127856 -0
- pennylane_sdk-0.1.0/specs/firm_v1.json +31255 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/__init__.py +70 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/_base_client.py +568 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/_client.py +511 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/_exceptions.py +232 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/_files.py +69 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/_models.py +75 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/_pagination.py +258 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/_resource.py +295 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/_throttle.py +75 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/_version.py +1 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/filters.py +137 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/oauth.py +251 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/py.typed +0 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/resources/__init__.py +0 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/resources/company/__init__.py +139 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/resources/company/accounting.py +128 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/resources/company/bank_accounts.py +194 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/resources/company/billing_subscriptions.py +355 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/resources/company/categories.py +293 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/resources/company/changelogs.py +350 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/resources/company/commercial_documents.py +244 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/resources/company/customer_invoice_templates.py +61 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/resources/company/customer_invoices.py +1154 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/resources/company/customers.py +643 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/resources/company/e_invoices.py +97 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/resources/company/exports.py +243 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/resources/company/file_attachments.py +69 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/resources/company/journals.py +104 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/resources/company/ledger_accounts.py +175 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/resources/company/ledger_entries.py +335 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/resources/company/ledger_entry_lines.py +305 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/resources/company/mandates.py +591 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/resources/company/me.py +35 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/resources/company/products.py +227 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/resources/company/purchase_requests.py +186 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/resources/company/quotes.py +481 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/resources/company/supplier_invoices.py +728 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/resources/company/suppliers.py +310 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/resources/company/transactions.py +299 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/resources/company/webhook_subscriptions.py +226 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/resources/firm/__init__.py +109 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/resources/firm/accounting.py +809 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/resources/firm/banking.py +308 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/resources/firm/categories.py +207 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/resources/firm/changelogs.py +206 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/resources/firm/companies.py +78 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/resources/firm/dms.py +285 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/resources/firm/exports.py +189 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/resources/firm/invoicing.py +308 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/types/__init__.py +0 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/types/company/__init__.py +302 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/types/company/accounting.py +36 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/types/company/bank_accounts.py +64 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/types/company/billing_subscriptions.py +177 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/types/company/categories.py +49 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/types/company/changelogs.py +22 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/types/company/commercial_documents.py +142 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/types/company/customer_invoice_templates.py +21 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/types/company/customer_invoices.py +326 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/types/company/customers.py +112 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/types/company/e_invoices.py +36 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/types/company/exports.py +48 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/types/company/file_attachments.py +22 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/types/company/journals.py +19 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/types/company/ledger_accounts.py +27 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/types/company/ledger_entries.py +111 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/types/company/ledger_entry_lines.py +102 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/types/company/mandates.py +149 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/types/company/me.py +39 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/types/company/products.py +37 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/types/company/purchase_requests.py +78 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/types/company/quotes.py +134 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/types/company/supplier_invoices.py +255 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/types/company/suppliers.py +74 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/types/company/transactions.py +152 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/types/company/webhook_subscriptions.py +38 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/types/firm/__init__.py +134 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/types/firm/accounting.py +182 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/types/firm/banking.py +147 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/types/firm/categories.py +55 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/types/firm/changelogs.py +22 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/types/firm/companies.py +26 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/types/firm/dms.py +64 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/types/firm/exports.py +35 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/types/firm/invoicing.py +300 -0
- pennylane_sdk-0.1.0/src/pennylane_sdk/webhooks.py +127 -0
- pennylane_sdk-0.1.0/tests/__init__.py +0 -0
- pennylane_sdk-0.1.0/tests/company/__init__.py +0 -0
- pennylane_sdk-0.1.0/tests/company/test_accounting.py +96 -0
- pennylane_sdk-0.1.0/tests/company/test_bank_accounts.py +131 -0
- pennylane_sdk-0.1.0/tests/company/test_billing_subscriptions.py +273 -0
- pennylane_sdk-0.1.0/tests/company/test_categories.py +195 -0
- pennylane_sdk-0.1.0/tests/company/test_changelogs.py +63 -0
- pennylane_sdk-0.1.0/tests/company/test_commercial_documents.py +220 -0
- pennylane_sdk-0.1.0/tests/company/test_customer_invoice_templates.py +47 -0
- pennylane_sdk-0.1.0/tests/company/test_customer_invoices.py +729 -0
- pennylane_sdk-0.1.0/tests/company/test_customers.py +360 -0
- pennylane_sdk-0.1.0/tests/company/test_e_invoices.py +87 -0
- pennylane_sdk-0.1.0/tests/company/test_exports.py +195 -0
- pennylane_sdk-0.1.0/tests/company/test_file_attachments.py +65 -0
- pennylane_sdk-0.1.0/tests/company/test_journals.py +78 -0
- pennylane_sdk-0.1.0/tests/company/test_ledger_accounts.py +98 -0
- pennylane_sdk-0.1.0/tests/company/test_ledger_entries.py +201 -0
- pennylane_sdk-0.1.0/tests/company/test_ledger_entry_lines.py +243 -0
- pennylane_sdk-0.1.0/tests/company/test_mandates.py +393 -0
- pennylane_sdk-0.1.0/tests/company/test_me.py +49 -0
- pennylane_sdk-0.1.0/tests/company/test_products.py +118 -0
- pennylane_sdk-0.1.0/tests/company/test_purchase_requests.py +185 -0
- pennylane_sdk-0.1.0/tests/company/test_quotes.py +289 -0
- pennylane_sdk-0.1.0/tests/company/test_supplier_invoices.py +501 -0
- pennylane_sdk-0.1.0/tests/company/test_suppliers.py +184 -0
- pennylane_sdk-0.1.0/tests/company/test_transactions.py +202 -0
- pennylane_sdk-0.1.0/tests/company/test_webhook_subscriptions.py +132 -0
- pennylane_sdk-0.1.0/tests/conftest.py +35 -0
- pennylane_sdk-0.1.0/tests/firm/__init__.py +0 -0
- pennylane_sdk-0.1.0/tests/firm/test_accounting.py +393 -0
- pennylane_sdk-0.1.0/tests/firm/test_banking.py +169 -0
- pennylane_sdk-0.1.0/tests/firm/test_categories.py +148 -0
- pennylane_sdk-0.1.0/tests/firm/test_changelogs.py +100 -0
- pennylane_sdk-0.1.0/tests/firm/test_companies.py +87 -0
- pennylane_sdk-0.1.0/tests/firm/test_dms.py +166 -0
- pennylane_sdk-0.1.0/tests/firm/test_exports.py +148 -0
- pennylane_sdk-0.1.0/tests/firm/test_invoicing.py +251 -0
- pennylane_sdk-0.1.0/tests/test_base_client.py +241 -0
- pennylane_sdk-0.1.0/tests/test_client.py +68 -0
- pennylane_sdk-0.1.0/tests/test_exceptions.py +111 -0
- pennylane_sdk-0.1.0/tests/test_files.py +60 -0
- pennylane_sdk-0.1.0/tests/test_filters.py +72 -0
- pennylane_sdk-0.1.0/tests/test_models.py +69 -0
- pennylane_sdk-0.1.0/tests/test_oauth.py +93 -0
- pennylane_sdk-0.1.0/tests/test_pagination.py +182 -0
- pennylane_sdk-0.1.0/tests/test_review_fixes.py +195 -0
- pennylane_sdk-0.1.0/tests/test_throttle.py +59 -0
- pennylane_sdk-0.1.0/tests/test_webhooks.py +82 -0
- pennylane_sdk-0.1.0/uv.lock +1339 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
concurrency:
|
|
9
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
10
|
+
cancel-in-progress: true
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
lint:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v4
|
|
17
|
+
- uses: astral-sh/setup-uv@v5
|
|
18
|
+
- run: uv sync --frozen
|
|
19
|
+
- name: Ruff
|
|
20
|
+
run: uv run ruff check src tests scripts
|
|
21
|
+
- name: Mypy (strict)
|
|
22
|
+
run: uv run mypy --strict src
|
|
23
|
+
|
|
24
|
+
coverage-audit:
|
|
25
|
+
name: API coverage audit (213 operations)
|
|
26
|
+
runs-on: ubuntu-latest
|
|
27
|
+
steps:
|
|
28
|
+
- uses: actions/checkout@v4
|
|
29
|
+
- uses: astral-sh/setup-uv@v5
|
|
30
|
+
- name: Every spec operation implemented (sync + async)
|
|
31
|
+
run: uv run python scripts/check_coverage.py
|
|
32
|
+
|
|
33
|
+
test:
|
|
34
|
+
runs-on: ${{ matrix.os }}
|
|
35
|
+
strategy:
|
|
36
|
+
fail-fast: false
|
|
37
|
+
matrix:
|
|
38
|
+
os: [ubuntu-latest, windows-latest]
|
|
39
|
+
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
|
|
40
|
+
steps:
|
|
41
|
+
- uses: actions/checkout@v4
|
|
42
|
+
- uses: astral-sh/setup-uv@v5
|
|
43
|
+
with:
|
|
44
|
+
python-version: ${{ matrix.python-version }}
|
|
45
|
+
- run: uv sync --frozen
|
|
46
|
+
- name: Tests
|
|
47
|
+
run: uv run pytest -q
|
|
48
|
+
|
|
49
|
+
docs:
|
|
50
|
+
runs-on: ubuntu-latest
|
|
51
|
+
steps:
|
|
52
|
+
- uses: actions/checkout@v4
|
|
53
|
+
- uses: astral-sh/setup-uv@v5
|
|
54
|
+
- run: uv sync --frozen
|
|
55
|
+
- name: Build docs (strict)
|
|
56
|
+
run: uv run mkdocs build --strict
|
|
57
|
+
|
|
58
|
+
build:
|
|
59
|
+
runs-on: ubuntu-latest
|
|
60
|
+
steps:
|
|
61
|
+
- uses: actions/checkout@v4
|
|
62
|
+
- uses: astral-sh/setup-uv@v5
|
|
63
|
+
- name: Build sdist and wheel
|
|
64
|
+
run: uv build
|
|
65
|
+
- uses: actions/upload-artifact@v4
|
|
66
|
+
with:
|
|
67
|
+
name: dist
|
|
68
|
+
path: dist/
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
name: Deploy docs
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
contents: read
|
|
9
|
+
pages: write
|
|
10
|
+
id-token: write
|
|
11
|
+
|
|
12
|
+
concurrency:
|
|
13
|
+
group: pages
|
|
14
|
+
cancel-in-progress: true
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
build:
|
|
18
|
+
runs-on: ubuntu-latest
|
|
19
|
+
steps:
|
|
20
|
+
- uses: actions/checkout@v4
|
|
21
|
+
- uses: astral-sh/setup-uv@v5
|
|
22
|
+
- run: uv sync --frozen
|
|
23
|
+
- name: Build site
|
|
24
|
+
run: uv run mkdocs build --strict
|
|
25
|
+
- uses: actions/upload-pages-artifact@v3
|
|
26
|
+
with:
|
|
27
|
+
path: site/
|
|
28
|
+
|
|
29
|
+
deploy:
|
|
30
|
+
needs: build
|
|
31
|
+
runs-on: ubuntu-latest
|
|
32
|
+
environment:
|
|
33
|
+
name: github-pages
|
|
34
|
+
url: ${{ steps.deployment.outputs.page_url }}
|
|
35
|
+
steps:
|
|
36
|
+
- id: deployment
|
|
37
|
+
uses: actions/deploy-pages@v4
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
name: Release to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags: ["v*"]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
build:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
steps:
|
|
11
|
+
- uses: actions/checkout@v4
|
|
12
|
+
- uses: astral-sh/setup-uv@v5
|
|
13
|
+
- run: uv sync --frozen
|
|
14
|
+
- name: Run tests
|
|
15
|
+
run: uv run pytest -q
|
|
16
|
+
- name: Coverage audit
|
|
17
|
+
run: uv run python scripts/check_coverage.py
|
|
18
|
+
- name: Build sdist and wheel
|
|
19
|
+
run: uv build
|
|
20
|
+
- uses: actions/upload-artifact@v4
|
|
21
|
+
with:
|
|
22
|
+
name: dist
|
|
23
|
+
path: dist/
|
|
24
|
+
|
|
25
|
+
publish:
|
|
26
|
+
needs: build
|
|
27
|
+
runs-on: ubuntu-latest
|
|
28
|
+
environment:
|
|
29
|
+
name: pypi
|
|
30
|
+
url: https://pypi.org/project/pennylane-sdk/
|
|
31
|
+
permissions:
|
|
32
|
+
id-token: write # OIDC trusted publishing — no API token needed
|
|
33
|
+
steps:
|
|
34
|
+
- uses: actions/download-artifact@v4
|
|
35
|
+
with:
|
|
36
|
+
name: dist
|
|
37
|
+
path: dist/
|
|
38
|
+
- name: Publish to PyPI
|
|
39
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.egg-info/
|
|
5
|
+
dist/
|
|
6
|
+
build/
|
|
7
|
+
.venv/
|
|
8
|
+
venv/
|
|
9
|
+
|
|
10
|
+
# Tooling caches
|
|
11
|
+
.pytest_cache/
|
|
12
|
+
.mypy_cache/
|
|
13
|
+
.ruff_cache/
|
|
14
|
+
.coverage
|
|
15
|
+
coverage.xml
|
|
16
|
+
htmlcov/
|
|
17
|
+
|
|
18
|
+
# Docs build
|
|
19
|
+
site/
|
|
20
|
+
|
|
21
|
+
# IDE / OS
|
|
22
|
+
.idea/
|
|
23
|
+
.vscode/
|
|
24
|
+
.DS_Store
|
|
25
|
+
|
|
26
|
+
# Local secrets (never commit API tokens)
|
|
27
|
+
.env
|
|
28
|
+
.env.*
|
|
29
|
+
|
|
30
|
+
# Local tooling configuration
|
|
31
|
+
.claude/
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented here. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the project adheres to [Semantic Versioning](https://semver.org/).
|
|
4
|
+
|
|
5
|
+
## [Unreleased]
|
|
6
|
+
|
|
7
|
+
## [0.1.0] - 2026-07-08
|
|
8
|
+
|
|
9
|
+
Initial release.
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- Full coverage of the Pennylane **Company API v2**: 165 operations across 24 resource modules (customer and supplier invoicing, quotes, customers, products, billing subscriptions, banking, ledger, lettering, trial balance, analytics, FEC/GL/AGL exports, SEPA/GoCardless/Pro Account mandates, e-invoicing, changelogs, webhook subscriptions).
|
|
14
|
+
- Full coverage of the Pennylane **Firm API v1**: 48 operations (companies portfolio, accounting, DMS, exports, invoicing, banking, categories, changelogs).
|
|
15
|
+
- Sync (`Pennylane`, `PennylaneFirm`) and async (`AsyncPennylane`, `AsyncPennylaneFirm`) clients with identical surfaces.
|
|
16
|
+
- Typed Pydantic response models; monetary values as `Decimal` serialized to API-compliant strings.
|
|
17
|
+
- Auto-paginating cursor and page-number pages, re-sending filters across pages.
|
|
18
|
+
- Client-side throttling to the official rate limits, on by default.
|
|
19
|
+
- Conservative retry policy safe for a non-idempotent accounting API (POST never retried on 5xx).
|
|
20
|
+
- Defensive error parsing with a full exception hierarchy.
|
|
21
|
+
- Typed filter builders (`pennylane_sdk.filters`).
|
|
22
|
+
- OAuth 2.0 helpers with serialized refresh (Refresh Token Rotation safe).
|
|
23
|
+
- Webhook signature verification (constant-time HMAC) and payload parsing.
|
|
24
|
+
- Coverage audit script validating the SDK against the vendored official OpenAPI specs.
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
Thanks for helping make pennylane-sdk better! Contributions of every size are welcome: bug reports, docs fixes, new endpoint coverage, ideas.
|
|
4
|
+
|
|
5
|
+
## Development setup
|
|
6
|
+
|
|
7
|
+
Requirements: Python 3.10+ and [uv](https://docs.astral.sh/uv/).
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
git clone https://github.com/GoatAndCow7/pennylane-sdk
|
|
11
|
+
cd pennylane-sdk
|
|
12
|
+
uv sync
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Run the checks the CI runs:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
uv run pytest # tests (all mocked, no token needed)
|
|
19
|
+
uv run mypy --strict src # type checking
|
|
20
|
+
uv run ruff check src tests scripts # lint
|
|
21
|
+
uv run python scripts/check_coverage.py # every API operation implemented?
|
|
22
|
+
uv run mkdocs serve # docs live preview
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Project layout
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
specs/ vendored official OpenAPI specs (source of truth)
|
|
29
|
+
scripts/update_specs.py refresh the specs from pennylane.readme.io
|
|
30
|
+
scripts/check_coverage.py audits that every spec operation exists in sync + async
|
|
31
|
+
scripts/show_endpoint.py inspect one endpoint's schema from the specs
|
|
32
|
+
src/pennylane_sdk/
|
|
33
|
+
_base_client.py HTTP engine: auth, retries, throttle, errors
|
|
34
|
+
_pagination.py cursor and page-number auto-paginating pages
|
|
35
|
+
resources/company|firm/ one module per URL namespace, sync + Async classes
|
|
36
|
+
types/company|firm/ Pydantic response models
|
|
37
|
+
tests/ mirrors resources/, respx-mocked
|
|
38
|
+
docs/ mkdocs-material site
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Adding or fixing an endpoint
|
|
42
|
+
|
|
43
|
+
1. Find the operation in the spec: `uv run python scripts/show_endpoint.py company "customer_invoices/{id}/finalize" put`
|
|
44
|
+
2. Follow the conventions in `docs/design/resource-map.md` (method naming, models, docstrings). `src/pennylane_sdk/resources/company/products.py` is the reference style.
|
|
45
|
+
3. Write the resource method (sync and async), the models, and tests.
|
|
46
|
+
4. Make the four checks above pass. `check_coverage.py` must report full coverage.
|
|
47
|
+
|
|
48
|
+
## Style rules
|
|
49
|
+
|
|
50
|
+
- English everywhere in code and docs.
|
|
51
|
+
- No em dashes or en dashes in text; use plain punctuation.
|
|
52
|
+
- Docstrings state the required scope and link the official reference page.
|
|
53
|
+
- Response model fields are optional (`| None = None`) except `id`; monetary strings use the `Money` type.
|
|
54
|
+
|
|
55
|
+
## Releasing (maintainers)
|
|
56
|
+
|
|
57
|
+
1. Update `CHANGELOG.md` and bump the version in `pyproject.toml` and `src/pennylane_sdk/_version.py`.
|
|
58
|
+
2. Tag: `git tag v0.x.y && git push --tags`.
|
|
59
|
+
3. The `release.yml` workflow tests, builds and publishes to PyPI via trusted publishing.
|
|
60
|
+
|
|
61
|
+
## When the API changes
|
|
62
|
+
|
|
63
|
+
Refresh the vendored specs and see what the coverage audit says:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
uv run python scripts/update_specs.py
|
|
67
|
+
uv run python scripts/check_coverage.py
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
New operations show up as MISSING; removed ones as UNKNOWN CALL. Please open an issue even if you cannot fix it yourself.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Pennylane SDK Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pennylane-sdk
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Unofficial Python SDK for the Pennylane API — the French accounting and invoicing platform
|
|
5
|
+
Project-URL: Homepage, https://github.com/pennylane-sdk/pennylane-sdk
|
|
6
|
+
Project-URL: Documentation, https://github.com/pennylane-sdk/pennylane-sdk#readme
|
|
7
|
+
Project-URL: Repository, https://github.com/pennylane-sdk/pennylane-sdk
|
|
8
|
+
Project-URL: Changelog, https://github.com/pennylane-sdk/pennylane-sdk/blob/main/CHANGELOG.md
|
|
9
|
+
Author: Pennylane SDK Contributors
|
|
10
|
+
License-Expression: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: accounting,api,comptabilite,e-invoicing,factur-x,facturation,france,invoicing,pennylane,sdk
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Natural Language :: English
|
|
16
|
+
Classifier: Natural Language :: French
|
|
17
|
+
Classifier: Operating System :: OS Independent
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
24
|
+
Classifier: Topic :: Office/Business :: Financial :: Accounting
|
|
25
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
26
|
+
Classifier: Typing :: Typed
|
|
27
|
+
Requires-Python: >=3.10
|
|
28
|
+
Requires-Dist: anyio<5,>=4.0
|
|
29
|
+
Requires-Dist: httpx<1,>=0.27
|
|
30
|
+
Requires-Dist: pydantic<3,>=2.7
|
|
31
|
+
Requires-Dist: typing-extensions>=4.10
|
|
32
|
+
Description-Content-Type: text/markdown
|
|
33
|
+
|
|
34
|
+
# pennylane-sdk
|
|
35
|
+
|
|
36
|
+
> The unofficial Python SDK for the [Pennylane](https://www.pennylane.com) API, the French accounting and invoicing platform.
|
|
37
|
+
|
|
38
|
+
🇫🇷 [Version française](README.fr.md)
|
|
39
|
+
|
|
40
|
+
[](https://github.com/GoatAndCow7/pennylane-sdk/actions/workflows/ci.yml)
|
|
41
|
+
[](https://pypi.org/project/pennylane-sdk/)
|
|
42
|
+
[](https://pypi.org/project/pennylane-sdk/)
|
|
43
|
+
[](LICENSE)
|
|
44
|
+
|
|
45
|
+
**[Documentation](https://goatandcow7.github.io/pennylane-sdk/)** | [API coverage: 213/213 operations](#complete-api-coverage)
|
|
46
|
+
|
|
47
|
+
- **Complete**: every operation of the Company API v2 (165) and the Firm API v1 (48), in sync and async, audited against the official OpenAPI specs in CI.
|
|
48
|
+
- **Typed**: Pydantic models everywhere; monetary amounts are `Decimal`, never floats.
|
|
49
|
+
- **Safe for accounting**: the API has no idempotency, so POST is never retried after a server error. No duplicate invoices from a network hiccup.
|
|
50
|
+
- **Rate-limit proof**: built-in client-side throttling to the official limits, plus `retry-after` aware retries on 429.
|
|
51
|
+
- **Effortless pagination**: iterate a list call, the SDK fetches the pages.
|
|
52
|
+
|
|
53
|
+
> Not affiliated with Pennylane SAS. Unrelated to the PennyLane quantum computing framework (which owns `pennylane` on PyPI; this package is `pennylane-sdk`).
|
|
54
|
+
|
|
55
|
+
## Install
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
pip install pennylane-sdk
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Python 3.10+.
|
|
62
|
+
|
|
63
|
+
## Quickstart
|
|
64
|
+
|
|
65
|
+
Create an API token in Pennylane (**Settings > Connectivity > Developers**), then:
|
|
66
|
+
|
|
67
|
+
```python
|
|
68
|
+
from pennylane_sdk import Pennylane, filters
|
|
69
|
+
|
|
70
|
+
client = Pennylane() # reads PENNYLANE_API_TOKEN
|
|
71
|
+
|
|
72
|
+
# List and filter, with transparent pagination
|
|
73
|
+
for invoice in client.customer_invoices.list(
|
|
74
|
+
filter=[filters.gte("date", "2026-01-01")],
|
|
75
|
+
sort="-date",
|
|
76
|
+
):
|
|
77
|
+
print(invoice.invoice_number, invoice.currency_amount)
|
|
78
|
+
|
|
79
|
+
# Create, finalize, send
|
|
80
|
+
invoice = client.customer_invoices.create(
|
|
81
|
+
customer_id=123,
|
|
82
|
+
date="2026-07-08",
|
|
83
|
+
deadline="2026-08-07",
|
|
84
|
+
invoice_lines=[{"product_id": 45, "quantity": "2"}],
|
|
85
|
+
)
|
|
86
|
+
client.customer_invoices.finalize(invoice.id)
|
|
87
|
+
client.customer_invoices.send_by_email(invoice.id)
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Async, same surface:
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
from pennylane_sdk import AsyncPennylane
|
|
94
|
+
|
|
95
|
+
async with AsyncPennylane() as client:
|
|
96
|
+
page = await client.customer_invoices.list(limit=100)
|
|
97
|
+
async for invoice in page:
|
|
98
|
+
...
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Accounting firms, across the whole portfolio:
|
|
102
|
+
|
|
103
|
+
```python
|
|
104
|
+
from pennylane_sdk import PennylaneFirm
|
|
105
|
+
|
|
106
|
+
firm = PennylaneFirm() # reads PENNYLANE_FIRM_API_TOKEN
|
|
107
|
+
for company in firm.companies.list():
|
|
108
|
+
for row in firm.trial_balance.list(
|
|
109
|
+
company.id, period_start="2026-01-01", period_end="2026-06-30"
|
|
110
|
+
):
|
|
111
|
+
...
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
French e-invoicing (2026 reform), Pennylane being an accredited Plateforme Agréée:
|
|
115
|
+
|
|
116
|
+
```python
|
|
117
|
+
client.customer_invoices.send_to_pa(invoice.id) # emit through the PA
|
|
118
|
+
client.supplier_invoices.import_e_invoice(file="factur-x.pdf") # ingest Factur-X/UBL/CII
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Complete API coverage
|
|
122
|
+
|
|
123
|
+
| API | Operations | Resources |
|
|
124
|
+
|---|---|---|
|
|
125
|
+
| Company v2 | 165/165 | customer and supplier invoices, quotes, customers, products, billing subscriptions, banking and reconciliation, journals, ledger entries, lettering, trial balance, analytics, FEC/GL/AGL exports, SEPA/GoCardless/Pro mandates, e-invoicing, changelogs, webhooks |
|
|
126
|
+
| Firm v1 | 48/48 | client portfolio, accounting, DMS, exports, invoicing (read), banking, analytics, changelogs |
|
|
127
|
+
|
|
128
|
+
Coverage is not a promise: `scripts/check_coverage.py` verifies in CI that every operation in the vendored official OpenAPI specs exists in both the sync and async clients.
|
|
129
|
+
|
|
130
|
+
## Learn more
|
|
131
|
+
|
|
132
|
+
- [Getting started](https://goatandcow7.github.io/pennylane-sdk/getting-started/)
|
|
133
|
+
- [Guides](https://goatandcow7.github.io/pennylane-sdk/guides/authentication/): authentication, pagination and filtering, errors and retries, invoicing lifecycle, e-invoicing 2026, accounting, Firm API, webhooks, OAuth apps
|
|
134
|
+
- [API reference](https://goatandcow7.github.io/pennylane-sdk/api/clients/)
|
|
135
|
+
- [Examples](examples/)
|
|
136
|
+
- [Contributing](CONTRIBUTING.md)
|
|
137
|
+
|
|
138
|
+
## License
|
|
139
|
+
|
|
140
|
+
[MIT](LICENSE). Build whatever you want with it.
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# pennylane-sdk
|
|
2
|
+
|
|
3
|
+
> Le SDK Python non officiel pour l'API de [Pennylane](https://www.pennylane.com), la plateforme française de comptabilité et de facturation.
|
|
4
|
+
|
|
5
|
+
🇬🇧 [English version](README.md)
|
|
6
|
+
|
|
7
|
+
**[Documentation complète](https://goatandcow7.github.io/pennylane-sdk/)** (en anglais)
|
|
8
|
+
|
|
9
|
+
## Pourquoi ce SDK
|
|
10
|
+
|
|
11
|
+
- **Complet** : la totalité des opérations de l'API Entreprise v2 (165) et de l'API Cabinet v1 (48), en synchrone et en asynchrone. La couverture est vérifiée automatiquement en CI contre les spécifications OpenAPI officielles de Pennylane.
|
|
12
|
+
- **Typé** : chaque réponse est un modèle Pydantic. Les montants sont des `Decimal`, jamais des floats, exactement comme l'API le demande (les montants circulent en chaînes pour éviter les erreurs d'arrondi).
|
|
13
|
+
- **Sûr pour la compta** : l'API Pennylane n'a pas d'idempotence côté serveur. Le SDK ne réessaie donc jamais un POST après une erreur serveur : impossible de créer une facture en double à cause d'un souci réseau.
|
|
14
|
+
- **Anti rate-limit** : les requêtes sont cadencées côté client aux limites officielles (25 requêtes / 5 s pour les entreprises, 5/s pour les cabinets), et les 429 sont réessayés en respectant `retry-after`. Vos exports de masse passent sans effort.
|
|
15
|
+
- **Pagination invisible** : itérez sur un `list()` et le SDK va chercher les pages suivantes tout seul, en renvoyant vos filtres comme l'API l'exige.
|
|
16
|
+
|
|
17
|
+
> Projet communautaire, non affilié à Pennylane SAS. Sans rapport avec le framework de calcul quantique PennyLane (qui possède le nom `pennylane` sur PyPI ; ce paquet s'appelle `pennylane-sdk`).
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
pip install pennylane-sdk
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Python 3.10 ou plus récent.
|
|
26
|
+
|
|
27
|
+
## Démarrage rapide
|
|
28
|
+
|
|
29
|
+
Créez un jeton API dans Pennylane (**Paramètres > Connectivité > Développeurs**), copiez-le immédiatement (il n'est affiché qu'une fois), puis :
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
export PENNYLANE_API_TOKEN="votre-jeton"
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
```python
|
|
36
|
+
from pennylane_sdk import Pennylane, filters
|
|
37
|
+
|
|
38
|
+
client = Pennylane()
|
|
39
|
+
|
|
40
|
+
# Lister et filtrer, pagination transparente
|
|
41
|
+
for facture in client.customer_invoices.list(
|
|
42
|
+
filter=[filters.gte("date", "2026-01-01")],
|
|
43
|
+
sort="-date",
|
|
44
|
+
):
|
|
45
|
+
print(facture.invoice_number, facture.currency_amount)
|
|
46
|
+
|
|
47
|
+
# Créer un brouillon, le finaliser, l'envoyer
|
|
48
|
+
facture = client.customer_invoices.create(
|
|
49
|
+
customer_id=123,
|
|
50
|
+
date="2026-07-08",
|
|
51
|
+
deadline="2026-08-07",
|
|
52
|
+
invoice_lines=[{"product_id": 45, "quantity": "2"}],
|
|
53
|
+
)
|
|
54
|
+
client.customer_invoices.finalize(facture.id)
|
|
55
|
+
client.customer_invoices.send_by_email(facture.id)
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
La version asynchrone offre exactement la même surface :
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
from pennylane_sdk import AsyncPennylane
|
|
62
|
+
|
|
63
|
+
async with AsyncPennylane() as client:
|
|
64
|
+
page = await client.customer_invoices.list(limit=100)
|
|
65
|
+
async for facture in page:
|
|
66
|
+
...
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Cabinets d'expertise comptable
|
|
70
|
+
|
|
71
|
+
L'API Cabinet permet de travailler sur tout le portefeuille de dossiers clients :
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
from pennylane_sdk import PennylaneFirm
|
|
75
|
+
|
|
76
|
+
cabinet = PennylaneFirm() # lit PENNYLANE_FIRM_API_TOKEN
|
|
77
|
+
|
|
78
|
+
for dossier in cabinet.companies.list():
|
|
79
|
+
# Balance générale du dossier sur la période
|
|
80
|
+
for ligne in cabinet.trial_balance.list(
|
|
81
|
+
dossier.id, period_start="2026-01-01", period_end="2026-06-30"
|
|
82
|
+
):
|
|
83
|
+
print(ligne.number, ligne.debits, ligne.credits)
|
|
84
|
+
|
|
85
|
+
# Export FEC
|
|
86
|
+
export = cabinet.exports.fecs.create(
|
|
87
|
+
dossier.id, period_start="2026-01-01", period_end="2026-12-31"
|
|
88
|
+
)
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Facturation électronique (réforme 2026)
|
|
92
|
+
|
|
93
|
+
Pennylane est Plateforme Agréée (PA) : l'API couvre l'émission et la réception des factures électroniques, et le SDK aussi.
|
|
94
|
+
|
|
95
|
+
```python
|
|
96
|
+
# Émettre une facture via la plateforme agréée
|
|
97
|
+
client.customer_invoices.send_to_pa(facture.id)
|
|
98
|
+
|
|
99
|
+
# Importer une facture fournisseur Factur-X / UBL / CII
|
|
100
|
+
client.supplier_invoices.import_e_invoice(file="facture.xml")
|
|
101
|
+
|
|
102
|
+
# Suivre vos immatriculations PA
|
|
103
|
+
client.pa_registrations.list()
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Ce que couvre le SDK
|
|
107
|
+
|
|
108
|
+
| Domaine | Ressources |
|
|
109
|
+
|---|---|
|
|
110
|
+
| Ventes | factures clients, avoirs, devis, abonnements récurrents, clients, produits, envoi par email ou par PA |
|
|
111
|
+
| Achats | fournisseurs, factures fournisseurs, bons de commande, statuts de paiement |
|
|
112
|
+
| Banque | comptes, transactions, rapprochement avec les factures |
|
|
113
|
+
| Comptabilité | journaux, plan comptable, écritures, lettrage, balance, exercices |
|
|
114
|
+
| Analytique | catégories et axes analytiques sur factures, transactions, écritures |
|
|
115
|
+
| Exports | FEC, grand livre, grand livre analytique |
|
|
116
|
+
| Mandats | SEPA, GoCardless, compte pro |
|
|
117
|
+
| Synchronisation | changelogs par ressource, webhooks (bêta), OAuth 2.0 pour les apps partenaires |
|
|
118
|
+
| Cabinet | dossiers clients, comptabilité, GED, exports, lecture des factures |
|
|
119
|
+
|
|
120
|
+
Gestion des erreurs : une hiérarchie d'exceptions claire (`AuthenticationError`, `ValidationError` avec les détails métier, `RateLimitError` avec `retry_after`...). Voir le [guide des erreurs](https://goatandcow7.github.io/pennylane-sdk/guides/errors-and-retries/).
|
|
121
|
+
|
|
122
|
+
## Contribuer
|
|
123
|
+
|
|
124
|
+
Les contributions sont bienvenues, en anglais de préférence pour le code et les issues. Voir [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
125
|
+
|
|
126
|
+
## Licence
|
|
127
|
+
|
|
128
|
+
[MIT](LICENSE). Utilisez-le librement, y compris commercialement.
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# pennylane-sdk
|
|
2
|
+
|
|
3
|
+
> The unofficial Python SDK for the [Pennylane](https://www.pennylane.com) API, the French accounting and invoicing platform.
|
|
4
|
+
|
|
5
|
+
🇫🇷 [Version française](README.fr.md)
|
|
6
|
+
|
|
7
|
+
[](https://github.com/GoatAndCow7/pennylane-sdk/actions/workflows/ci.yml)
|
|
8
|
+
[](https://pypi.org/project/pennylane-sdk/)
|
|
9
|
+
[](https://pypi.org/project/pennylane-sdk/)
|
|
10
|
+
[](LICENSE)
|
|
11
|
+
|
|
12
|
+
**[Documentation](https://goatandcow7.github.io/pennylane-sdk/)** | [API coverage: 213/213 operations](#complete-api-coverage)
|
|
13
|
+
|
|
14
|
+
- **Complete**: every operation of the Company API v2 (165) and the Firm API v1 (48), in sync and async, audited against the official OpenAPI specs in CI.
|
|
15
|
+
- **Typed**: Pydantic models everywhere; monetary amounts are `Decimal`, never floats.
|
|
16
|
+
- **Safe for accounting**: the API has no idempotency, so POST is never retried after a server error. No duplicate invoices from a network hiccup.
|
|
17
|
+
- **Rate-limit proof**: built-in client-side throttling to the official limits, plus `retry-after` aware retries on 429.
|
|
18
|
+
- **Effortless pagination**: iterate a list call, the SDK fetches the pages.
|
|
19
|
+
|
|
20
|
+
> Not affiliated with Pennylane SAS. Unrelated to the PennyLane quantum computing framework (which owns `pennylane` on PyPI; this package is `pennylane-sdk`).
|
|
21
|
+
|
|
22
|
+
## Install
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
pip install pennylane-sdk
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Python 3.10+.
|
|
29
|
+
|
|
30
|
+
## Quickstart
|
|
31
|
+
|
|
32
|
+
Create an API token in Pennylane (**Settings > Connectivity > Developers**), then:
|
|
33
|
+
|
|
34
|
+
```python
|
|
35
|
+
from pennylane_sdk import Pennylane, filters
|
|
36
|
+
|
|
37
|
+
client = Pennylane() # reads PENNYLANE_API_TOKEN
|
|
38
|
+
|
|
39
|
+
# List and filter, with transparent pagination
|
|
40
|
+
for invoice in client.customer_invoices.list(
|
|
41
|
+
filter=[filters.gte("date", "2026-01-01")],
|
|
42
|
+
sort="-date",
|
|
43
|
+
):
|
|
44
|
+
print(invoice.invoice_number, invoice.currency_amount)
|
|
45
|
+
|
|
46
|
+
# Create, finalize, send
|
|
47
|
+
invoice = client.customer_invoices.create(
|
|
48
|
+
customer_id=123,
|
|
49
|
+
date="2026-07-08",
|
|
50
|
+
deadline="2026-08-07",
|
|
51
|
+
invoice_lines=[{"product_id": 45, "quantity": "2"}],
|
|
52
|
+
)
|
|
53
|
+
client.customer_invoices.finalize(invoice.id)
|
|
54
|
+
client.customer_invoices.send_by_email(invoice.id)
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Async, same surface:
|
|
58
|
+
|
|
59
|
+
```python
|
|
60
|
+
from pennylane_sdk import AsyncPennylane
|
|
61
|
+
|
|
62
|
+
async with AsyncPennylane() as client:
|
|
63
|
+
page = await client.customer_invoices.list(limit=100)
|
|
64
|
+
async for invoice in page:
|
|
65
|
+
...
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Accounting firms, across the whole portfolio:
|
|
69
|
+
|
|
70
|
+
```python
|
|
71
|
+
from pennylane_sdk import PennylaneFirm
|
|
72
|
+
|
|
73
|
+
firm = PennylaneFirm() # reads PENNYLANE_FIRM_API_TOKEN
|
|
74
|
+
for company in firm.companies.list():
|
|
75
|
+
for row in firm.trial_balance.list(
|
|
76
|
+
company.id, period_start="2026-01-01", period_end="2026-06-30"
|
|
77
|
+
):
|
|
78
|
+
...
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
French e-invoicing (2026 reform), Pennylane being an accredited Plateforme Agréée:
|
|
82
|
+
|
|
83
|
+
```python
|
|
84
|
+
client.customer_invoices.send_to_pa(invoice.id) # emit through the PA
|
|
85
|
+
client.supplier_invoices.import_e_invoice(file="factur-x.pdf") # ingest Factur-X/UBL/CII
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Complete API coverage
|
|
89
|
+
|
|
90
|
+
| API | Operations | Resources |
|
|
91
|
+
|---|---|---|
|
|
92
|
+
| Company v2 | 165/165 | customer and supplier invoices, quotes, customers, products, billing subscriptions, banking and reconciliation, journals, ledger entries, lettering, trial balance, analytics, FEC/GL/AGL exports, SEPA/GoCardless/Pro mandates, e-invoicing, changelogs, webhooks |
|
|
93
|
+
| Firm v1 | 48/48 | client portfolio, accounting, DMS, exports, invoicing (read), banking, analytics, changelogs |
|
|
94
|
+
|
|
95
|
+
Coverage is not a promise: `scripts/check_coverage.py` verifies in CI that every operation in the vendored official OpenAPI specs exists in both the sync and async clients.
|
|
96
|
+
|
|
97
|
+
## Learn more
|
|
98
|
+
|
|
99
|
+
- [Getting started](https://goatandcow7.github.io/pennylane-sdk/getting-started/)
|
|
100
|
+
- [Guides](https://goatandcow7.github.io/pennylane-sdk/guides/authentication/): authentication, pagination and filtering, errors and retries, invoicing lifecycle, e-invoicing 2026, accounting, Firm API, webhooks, OAuth apps
|
|
101
|
+
- [API reference](https://goatandcow7.github.io/pennylane-sdk/api/clients/)
|
|
102
|
+
- [Examples](examples/)
|
|
103
|
+
- [Contributing](CONTRIBUTING.md)
|
|
104
|
+
|
|
105
|
+
## License
|
|
106
|
+
|
|
107
|
+
[MIT](LICENSE). Build whatever you want with it.
|