zohopy 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.
- zohopy-0.1.0/.dockerignore +25 -0
- zohopy-0.1.0/.env.example +25 -0
- zohopy-0.1.0/.github/ISSUE_TEMPLATE/bug_report.yml +75 -0
- zohopy-0.1.0/.github/ISSUE_TEMPLATE/feature_request.yml +54 -0
- zohopy-0.1.0/.github/PULL_REQUEST_TEMPLATE/pull_request.md +16 -0
- zohopy-0.1.0/.github/workflows/ci.yml +52 -0
- zohopy-0.1.0/.github/workflows/release.yml +72 -0
- zohopy-0.1.0/.gitignore +51 -0
- zohopy-0.1.0/AGENT.md +173 -0
- zohopy-0.1.0/CHANGELOG.md +32 -0
- zohopy-0.1.0/Dockerfile +37 -0
- zohopy-0.1.0/LICENSE +21 -0
- zohopy-0.1.0/PKG-INFO +411 -0
- zohopy-0.1.0/README.md +366 -0
- zohopy-0.1.0/docker-compose.yml +47 -0
- zohopy-0.1.0/pyproject.toml +119 -0
- zohopy-0.1.0/scripts/example.py +31 -0
- zohopy-0.1.0/src/zohopy/__init__.py +76 -0
- zohopy-0.1.0/src/zohopy/__main__.py +6 -0
- zohopy-0.1.0/src/zohopy/_auth.py +229 -0
- zohopy-0.1.0/src/zohopy/_client.py +414 -0
- zohopy-0.1.0/src/zohopy/cli.py +722 -0
- zohopy-0.1.0/src/zohopy/config.py +184 -0
- zohopy-0.1.0/src/zohopy/exceptions.py +427 -0
- zohopy-0.1.0/src/zohopy/logging.py +96 -0
- zohopy-0.1.0/src/zohopy/products/__init__.py +1 -0
- zohopy-0.1.0/src/zohopy/products/_base.py +153 -0
- zohopy-0.1.0/src/zohopy/products/books/__init__.py +258 -0
- zohopy-0.1.0/src/zohopy/products/books/accounting.py +77 -0
- zohopy-0.1.0/src/zohopy/products/books/bank_rules.py +15 -0
- zohopy-0.1.0/src/zohopy/products/books/bank_transactions.py +101 -0
- zohopy-0.1.0/src/zohopy/products/books/banking.py +47 -0
- zohopy-0.1.0/src/zohopy/products/books/base_currency.py +29 -0
- zohopy-0.1.0/src/zohopy/products/books/bills.py +107 -0
- zohopy-0.1.0/src/zohopy/products/books/contact_persons.py +63 -0
- zohopy-0.1.0/src/zohopy/products/books/contacts.py +138 -0
- zohopy-0.1.0/src/zohopy/products/books/credit_notes.py +143 -0
- zohopy-0.1.0/src/zohopy/products/books/crm_integration.py +41 -0
- zohopy-0.1.0/src/zohopy/products/books/custom_fields.py +134 -0
- zohopy-0.1.0/src/zohopy/products/books/custom_modules.py +61 -0
- zohopy-0.1.0/src/zohopy/products/books/customer_debit_notes.py +15 -0
- zohopy-0.1.0/src/zohopy/products/books/estimates.py +135 -0
- zohopy-0.1.0/src/zohopy/products/books/expenses.py +71 -0
- zohopy-0.1.0/src/zohopy/products/books/fixed_asset_types.py +15 -0
- zohopy-0.1.0/src/zohopy/products/books/fixed_assets.py +77 -0
- zohopy-0.1.0/src/zohopy/products/books/invoices.py +250 -0
- zohopy-0.1.0/src/zohopy/products/books/items.py +29 -0
- zohopy-0.1.0/src/zohopy/products/books/locations.py +41 -0
- zohopy-0.1.0/src/zohopy/products/books/payments.py +119 -0
- zohopy-0.1.0/src/zohopy/products/books/projects.py +219 -0
- zohopy-0.1.0/src/zohopy/products/books/purchase_orders.py +141 -0
- zohopy-0.1.0/src/zohopy/products/books/recurring_bills.py +35 -0
- zohopy-0.1.0/src/zohopy/products/books/recurring_expenses.py +41 -0
- zohopy-0.1.0/src/zohopy/products/books/recurring_invoices.py +41 -0
- zohopy-0.1.0/src/zohopy/products/books/reporting_tags.py +97 -0
- zohopy-0.1.0/src/zohopy/products/books/retainer_invoices.py +127 -0
- zohopy-0.1.0/src/zohopy/products/books/sales_orders.py +147 -0
- zohopy-0.1.0/src/zohopy/products/books/sales_receipts.py +23 -0
- zohopy-0.1.0/src/zohopy/products/books/settings.py +336 -0
- zohopy-0.1.0/src/zohopy/products/books/vendor_credits.py +107 -0
- zohopy-0.1.0/src/zohopy/products/inventory/__init__.py +85 -0
- zohopy-0.1.0/src/zohopy/products/inventory/adjustments.py +15 -0
- zohopy-0.1.0/src/zohopy/products/inventory/bills.py +29 -0
- zohopy-0.1.0/src/zohopy/products/inventory/composite_items.py +41 -0
- zohopy-0.1.0/src/zohopy/products/inventory/contacts.py +29 -0
- zohopy-0.1.0/src/zohopy/products/inventory/invoices.py +35 -0
- zohopy-0.1.0/src/zohopy/products/inventory/item_groups.py +29 -0
- zohopy-0.1.0/src/zohopy/products/inventory/items.py +35 -0
- zohopy-0.1.0/src/zohopy/products/inventory/packages.py +15 -0
- zohopy-0.1.0/src/zohopy/products/inventory/purchase_orders.py +29 -0
- zohopy-0.1.0/src/zohopy/products/inventory/sales_orders.py +29 -0
- zohopy-0.1.0/src/zohopy/products/inventory/settings.py +71 -0
- zohopy-0.1.0/src/zohopy/products/inventory/shipments.py +23 -0
- zohopy-0.1.0/src/zohopy/products/inventory/transfer_orders.py +23 -0
- zohopy-0.1.0/src/zohopy/py.typed +0 -0
- zohopy-0.1.0/src/zohopy/setup.py +778 -0
- zohopy-0.1.0/tests/__init__.py +0 -0
- zohopy-0.1.0/tests/conftest.py +56 -0
- zohopy-0.1.0/tests/integration/__init__.py +0 -0
- zohopy-0.1.0/tests/integration/test_books_crud.py +677 -0
- zohopy-0.1.0/tests/unit/__init__.py +0 -0
- zohopy-0.1.0/tests/unit/test_auth.py +57 -0
- zohopy-0.1.0/tests/unit/test_books.py +75 -0
- zohopy-0.1.0/tests/unit/test_client.py +132 -0
- zohopy-0.1.0/tests/unit/test_config.py +114 -0
- zohopy-0.1.0/tests/unit/test_exceptions.py +195 -0
- zohopy-0.1.0/tests/unit/test_setup.py +122 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
.venv/
|
|
2
|
+
venv/
|
|
3
|
+
__pycache__/
|
|
4
|
+
*.pyc
|
|
5
|
+
.git/
|
|
6
|
+
.github/
|
|
7
|
+
.gsd/
|
|
8
|
+
.bg-shell/
|
|
9
|
+
.env
|
|
10
|
+
.env.*
|
|
11
|
+
!.env.example
|
|
12
|
+
*.egg-info/
|
|
13
|
+
dist/
|
|
14
|
+
build/
|
|
15
|
+
.pytest_cache/
|
|
16
|
+
.mypy_cache/
|
|
17
|
+
.ruff_cache/
|
|
18
|
+
htmlcov/
|
|
19
|
+
.coverage
|
|
20
|
+
site/
|
|
21
|
+
tests/
|
|
22
|
+
docs/
|
|
23
|
+
AGENT.md
|
|
24
|
+
CHANGELOG.md
|
|
25
|
+
CONTRIBUTING.md
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# ZohoPy Configuration
|
|
2
|
+
# Copy this to .env and fill in your values.
|
|
3
|
+
# NEVER commit .env — it is in .gitignore.
|
|
4
|
+
#
|
|
5
|
+
# Quick setup: python -m zohopy
|
|
6
|
+
# This runs the setup wizard which generates .env for you.
|
|
7
|
+
|
|
8
|
+
# OAuth2 credentials from https://api-console.zoho.com/ (Self Client)
|
|
9
|
+
ZOHO_CLIENT_ID=
|
|
10
|
+
ZOHO_CLIENT_SECRET=
|
|
11
|
+
|
|
12
|
+
# Refresh token — generated by exchanging the Self Client grant code.
|
|
13
|
+
# Run `python -m zohopy` to do this interactively.
|
|
14
|
+
ZOHO_REFRESH_TOKEN=
|
|
15
|
+
|
|
16
|
+
# Your Zoho organization ID (auto-discovered during setup)
|
|
17
|
+
ZOHO_ORGANIZATION_ID=
|
|
18
|
+
|
|
19
|
+
# API domain returned during token exchange (auto-detects data center)
|
|
20
|
+
# e.g. https://www.zohoapis.com, https://www.zohoapis.eu, etc.
|
|
21
|
+
ZOHO_API_DOMAIN=
|
|
22
|
+
|
|
23
|
+
# Data center — auto-detected from API_DOMAIN if set.
|
|
24
|
+
# Manual override: us, eu, in, au, jp, ca, cn, sa
|
|
25
|
+
ZOHO_DATA_CENTER=
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
name: 🐛 Bug Report
|
|
2
|
+
description: Report a bug in ZohoPy
|
|
3
|
+
labels: ["bug", "triage"]
|
|
4
|
+
body:
|
|
5
|
+
- type: markdown
|
|
6
|
+
attributes:
|
|
7
|
+
value: |
|
|
8
|
+
Thank you for reporting a bug! Please fill in the details below.
|
|
9
|
+
|
|
10
|
+
- type: textarea
|
|
11
|
+
id: description
|
|
12
|
+
attributes:
|
|
13
|
+
label: Description
|
|
14
|
+
description: A clear description of the bug.
|
|
15
|
+
placeholder: What happened?
|
|
16
|
+
validations:
|
|
17
|
+
required: true
|
|
18
|
+
|
|
19
|
+
- type: textarea
|
|
20
|
+
id: reproduction
|
|
21
|
+
attributes:
|
|
22
|
+
label: Steps to Reproduce
|
|
23
|
+
description: Minimal code or steps to reproduce the issue.
|
|
24
|
+
placeholder: |
|
|
25
|
+
```python
|
|
26
|
+
from zohopy import ZohoConfig, SyncZohoClient
|
|
27
|
+
config = ZohoConfig()
|
|
28
|
+
# ...
|
|
29
|
+
```
|
|
30
|
+
validations:
|
|
31
|
+
required: true
|
|
32
|
+
|
|
33
|
+
- type: textarea
|
|
34
|
+
id: expected
|
|
35
|
+
attributes:
|
|
36
|
+
label: Expected Behavior
|
|
37
|
+
description: What you expected to happen.
|
|
38
|
+
validations:
|
|
39
|
+
required: true
|
|
40
|
+
|
|
41
|
+
- type: textarea
|
|
42
|
+
id: actual
|
|
43
|
+
attributes:
|
|
44
|
+
label: Actual Behavior
|
|
45
|
+
description: What actually happened (include tracebacks if applicable).
|
|
46
|
+
validations:
|
|
47
|
+
required: true
|
|
48
|
+
|
|
49
|
+
- type: input
|
|
50
|
+
id: version
|
|
51
|
+
attributes:
|
|
52
|
+
label: ZohoPy Version
|
|
53
|
+
placeholder: "0.1.0"
|
|
54
|
+
validations:
|
|
55
|
+
required: true
|
|
56
|
+
|
|
57
|
+
- type: input
|
|
58
|
+
id: python-version
|
|
59
|
+
attributes:
|
|
60
|
+
label: Python Version
|
|
61
|
+
placeholder: "3.12"
|
|
62
|
+
validations:
|
|
63
|
+
required: true
|
|
64
|
+
|
|
65
|
+
- type: dropdown
|
|
66
|
+
id: product
|
|
67
|
+
attributes:
|
|
68
|
+
label: Zoho Product
|
|
69
|
+
options:
|
|
70
|
+
- Books
|
|
71
|
+
- Inventory
|
|
72
|
+
- Both
|
|
73
|
+
- N/A
|
|
74
|
+
validations:
|
|
75
|
+
required: true
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
name: 🚀 Feature Request
|
|
2
|
+
description: Suggest a new feature or enhancement
|
|
3
|
+
labels: ["enhancement"]
|
|
4
|
+
body:
|
|
5
|
+
- type: markdown
|
|
6
|
+
attributes:
|
|
7
|
+
value: |
|
|
8
|
+
Thank you for your feature suggestion!
|
|
9
|
+
|
|
10
|
+
- type: textarea
|
|
11
|
+
id: problem
|
|
12
|
+
attributes:
|
|
13
|
+
label: Problem / Motivation
|
|
14
|
+
description: What problem does this solve? Why is it needed?
|
|
15
|
+
placeholder: I want to be able to...
|
|
16
|
+
validations:
|
|
17
|
+
required: true
|
|
18
|
+
|
|
19
|
+
- type: textarea
|
|
20
|
+
id: solution
|
|
21
|
+
attributes:
|
|
22
|
+
label: Proposed Solution
|
|
23
|
+
description: How should this work? Include API examples if possible.
|
|
24
|
+
placeholder: |
|
|
25
|
+
```python
|
|
26
|
+
# Ideal usage
|
|
27
|
+
books.invoices.bulk_create([...])
|
|
28
|
+
```
|
|
29
|
+
validations:
|
|
30
|
+
required: true
|
|
31
|
+
|
|
32
|
+
- type: dropdown
|
|
33
|
+
id: product
|
|
34
|
+
attributes:
|
|
35
|
+
label: Zoho Product
|
|
36
|
+
options:
|
|
37
|
+
- Books
|
|
38
|
+
- Inventory
|
|
39
|
+
- New Product (specify below)
|
|
40
|
+
- Core Library
|
|
41
|
+
validations:
|
|
42
|
+
required: true
|
|
43
|
+
|
|
44
|
+
- type: textarea
|
|
45
|
+
id: alternatives
|
|
46
|
+
attributes:
|
|
47
|
+
label: Alternatives Considered
|
|
48
|
+
description: Any workarounds or alternative approaches you've considered.
|
|
49
|
+
|
|
50
|
+
- type: textarea
|
|
51
|
+
id: context
|
|
52
|
+
attributes:
|
|
53
|
+
label: Additional Context
|
|
54
|
+
description: Links to Zoho API docs, screenshots, etc.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
## Summary
|
|
2
|
+
|
|
3
|
+
<!-- What does this PR do? Link related issues with "Closes #123". -->
|
|
4
|
+
|
|
5
|
+
## Changes
|
|
6
|
+
|
|
7
|
+
-
|
|
8
|
+
|
|
9
|
+
## Checklist
|
|
10
|
+
|
|
11
|
+
- [ ] Tests added / updated
|
|
12
|
+
- [ ] `ruff check` passes
|
|
13
|
+
- [ ] `mypy` passes
|
|
14
|
+
- [ ] Docs updated (if public API changed)
|
|
15
|
+
- [ ] No credentials, org IDs, or secrets in the diff
|
|
16
|
+
- [ ] CHANGELOG.md updated (for user-facing changes)
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main, dev]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
concurrency:
|
|
10
|
+
group: ci-${{ github.ref }}
|
|
11
|
+
cancel-in-progress: true
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
lint:
|
|
15
|
+
name: Lint & Type-check
|
|
16
|
+
runs-on: ubuntu-latest
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v4
|
|
19
|
+
- uses: actions/setup-python@v5
|
|
20
|
+
with:
|
|
21
|
+
python-version: "3.12"
|
|
22
|
+
- name: Install dependencies
|
|
23
|
+
run: pip install -e ".[dev]"
|
|
24
|
+
- name: Ruff check
|
|
25
|
+
run: ruff check src/ tests/
|
|
26
|
+
- name: Ruff format check
|
|
27
|
+
run: ruff format --check src/ tests/
|
|
28
|
+
- name: Mypy
|
|
29
|
+
run: mypy src/
|
|
30
|
+
|
|
31
|
+
test:
|
|
32
|
+
name: Test (Python ${{ matrix.python-version }})
|
|
33
|
+
runs-on: ubuntu-latest
|
|
34
|
+
strategy:
|
|
35
|
+
fail-fast: false
|
|
36
|
+
matrix:
|
|
37
|
+
python-version: ["3.10", "3.11", "3.12", "3.13"]
|
|
38
|
+
steps:
|
|
39
|
+
- uses: actions/checkout@v4
|
|
40
|
+
- uses: actions/setup-python@v5
|
|
41
|
+
with:
|
|
42
|
+
python-version: ${{ matrix.python-version }}
|
|
43
|
+
- name: Install dependencies
|
|
44
|
+
run: pip install -e ".[dev]"
|
|
45
|
+
- name: Run unit tests
|
|
46
|
+
run: pytest tests/unit/ --cov=zohopy --cov-report=xml -v
|
|
47
|
+
- name: Upload coverage
|
|
48
|
+
if: matrix.python-version == '3.12'
|
|
49
|
+
uses: codecov/codecov-action@v4
|
|
50
|
+
with:
|
|
51
|
+
files: coverage.xml
|
|
52
|
+
fail_ci_if_error: false
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*"
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
build:
|
|
10
|
+
name: Build distribution
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@v4
|
|
14
|
+
with:
|
|
15
|
+
fetch-depth: 0
|
|
16
|
+
- uses: actions/setup-python@v5
|
|
17
|
+
with:
|
|
18
|
+
python-version: "3.12"
|
|
19
|
+
- name: Install build tools
|
|
20
|
+
run: pip install build
|
|
21
|
+
- name: Build
|
|
22
|
+
run: python -m build
|
|
23
|
+
- name: Store distribution packages
|
|
24
|
+
uses: actions/upload-artifact@v4
|
|
25
|
+
with:
|
|
26
|
+
name: python-package-distributions
|
|
27
|
+
path: dist/
|
|
28
|
+
|
|
29
|
+
publish-to-pypi:
|
|
30
|
+
name: Publish to PyPI
|
|
31
|
+
needs: build
|
|
32
|
+
runs-on: ubuntu-latest
|
|
33
|
+
environment:
|
|
34
|
+
name: pypi
|
|
35
|
+
url: https://pypi.org/p/zohopy
|
|
36
|
+
permissions:
|
|
37
|
+
id-token: write
|
|
38
|
+
steps:
|
|
39
|
+
- name: Download distributions
|
|
40
|
+
uses: actions/download-artifact@v4
|
|
41
|
+
with:
|
|
42
|
+
name: python-package-distributions
|
|
43
|
+
path: dist/
|
|
44
|
+
- name: Publish to PyPI
|
|
45
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
46
|
+
|
|
47
|
+
github-release:
|
|
48
|
+
name: GitHub Release
|
|
49
|
+
needs: publish-to-pypi
|
|
50
|
+
runs-on: ubuntu-latest
|
|
51
|
+
permissions:
|
|
52
|
+
contents: write
|
|
53
|
+
id-token: write
|
|
54
|
+
steps:
|
|
55
|
+
- uses: actions/checkout@v4
|
|
56
|
+
- name: Download distributions
|
|
57
|
+
uses: actions/download-artifact@v4
|
|
58
|
+
with:
|
|
59
|
+
name: python-package-distributions
|
|
60
|
+
path: dist/
|
|
61
|
+
- name: Sign with Sigstore
|
|
62
|
+
uses: sigstore/gh-action-sigstore-python@v3.0.0
|
|
63
|
+
with:
|
|
64
|
+
inputs: ./dist/*.tar.gz ./dist/*.whl
|
|
65
|
+
- name: Create GitHub Release
|
|
66
|
+
env:
|
|
67
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
68
|
+
run: gh release create "${{ github.ref_name }}" --generate-notes
|
|
69
|
+
- name: Upload to GitHub Release
|
|
70
|
+
env:
|
|
71
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
72
|
+
run: gh release upload "${{ github.ref_name }}" dist/** --clobber
|
zohopy-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.egg-info/
|
|
6
|
+
dist/
|
|
7
|
+
build/
|
|
8
|
+
*.egg
|
|
9
|
+
.eggs/
|
|
10
|
+
|
|
11
|
+
# Virtual environments
|
|
12
|
+
.venv/
|
|
13
|
+
venv/
|
|
14
|
+
ENV/
|
|
15
|
+
|
|
16
|
+
# IDE
|
|
17
|
+
.idea/
|
|
18
|
+
.vscode/
|
|
19
|
+
*.swp
|
|
20
|
+
*.swo
|
|
21
|
+
|
|
22
|
+
# Testing & Coverage
|
|
23
|
+
.coverage
|
|
24
|
+
htmlcov/
|
|
25
|
+
.pytest_cache/
|
|
26
|
+
|
|
27
|
+
# Type checking
|
|
28
|
+
.mypy_cache/
|
|
29
|
+
|
|
30
|
+
# Linting
|
|
31
|
+
.ruff_cache/
|
|
32
|
+
|
|
33
|
+
# Environment / Secrets — NEVER COMMIT
|
|
34
|
+
.env
|
|
35
|
+
.env.*
|
|
36
|
+
!.env.example
|
|
37
|
+
*.pem
|
|
38
|
+
*.key
|
|
39
|
+
credentials/
|
|
40
|
+
secrets/
|
|
41
|
+
|
|
42
|
+
# OS
|
|
43
|
+
.DS_Store
|
|
44
|
+
Thumbs.db
|
|
45
|
+
|
|
46
|
+
# Docs build
|
|
47
|
+
site/
|
|
48
|
+
|
|
49
|
+
# Local tooling
|
|
50
|
+
.gsd/
|
|
51
|
+
.bg-shell/
|
zohopy-0.1.0/AGENT.md
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
# ZohoPy — Agent Reference
|
|
2
|
+
|
|
3
|
+
Machine-readable reference for AI coding agents.
|
|
4
|
+
All CLI commands support `--json` for structured output.
|
|
5
|
+
|
|
6
|
+
## Quick Reference
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
# Setup
|
|
10
|
+
zohopy setup # Interactive OAuth wizard
|
|
11
|
+
zohopy config --json # Show configuration
|
|
12
|
+
|
|
13
|
+
# Organizations
|
|
14
|
+
zohopy orgs --json # List all organizations
|
|
15
|
+
|
|
16
|
+
# Contacts
|
|
17
|
+
zohopy contacts list --json # List all contacts
|
|
18
|
+
zohopy contacts list --type customer --json # Filter by type
|
|
19
|
+
zohopy contacts get CONTACT_ID --json # Get single contact
|
|
20
|
+
zohopy contacts create '{"contact_name":"X","contact_type":"customer"}' --json
|
|
21
|
+
|
|
22
|
+
# Items
|
|
23
|
+
zohopy items list --json # List all items
|
|
24
|
+
zohopy items get ITEM_ID --json
|
|
25
|
+
zohopy items create '{"name":"Widget","rate":50}' --json
|
|
26
|
+
|
|
27
|
+
# Invoices
|
|
28
|
+
zohopy invoices list --json # List invoices
|
|
29
|
+
zohopy invoices list --status sent --json # Filter by status
|
|
30
|
+
zohopy invoices get INVOICE_ID --json
|
|
31
|
+
zohopy invoices create '{"customer_id":"X","line_items":[{"item_id":"Y","quantity":1}]}' --json
|
|
32
|
+
zohopy invoices mark-sent INVOICE_ID --json
|
|
33
|
+
zohopy invoices void INVOICE_ID --json
|
|
34
|
+
|
|
35
|
+
# Bills
|
|
36
|
+
zohopy bills list --json
|
|
37
|
+
zohopy bills get BILL_ID --json
|
|
38
|
+
zohopy bills create '{"vendor_id":"X","bill_number":"B-001","date":"2026-04-03","line_items":[...]}' --json
|
|
39
|
+
zohopy bills void BILL_ID --json
|
|
40
|
+
|
|
41
|
+
# Estimates
|
|
42
|
+
zohopy estimates list --json
|
|
43
|
+
zohopy estimates get ESTIMATE_ID --json
|
|
44
|
+
zohopy estimates create '{"customer_id":"X","line_items":[...]}' --json
|
|
45
|
+
|
|
46
|
+
# Sales Orders
|
|
47
|
+
zohopy sales-orders list --json
|
|
48
|
+
zohopy sales-orders get SALESORDER_ID --json
|
|
49
|
+
zohopy sales-orders create '{"customer_id":"X","line_items":[...]}' --json
|
|
50
|
+
|
|
51
|
+
# Purchase Orders
|
|
52
|
+
zohopy purchase-orders list --json
|
|
53
|
+
zohopy purchase-orders get PURCHASEORDER_ID --json
|
|
54
|
+
zohopy purchase-orders create '{"vendor_id":"X","line_items":[...]}' --json
|
|
55
|
+
|
|
56
|
+
# Expenses
|
|
57
|
+
zohopy expenses list --json
|
|
58
|
+
zohopy expenses get EXPENSE_ID --json
|
|
59
|
+
zohopy expenses create '{"account_id":"X","amount":50,"date":"2026-04-03"}' --json
|
|
60
|
+
|
|
61
|
+
# Payments
|
|
62
|
+
zohopy payments list-customer --json
|
|
63
|
+
zohopy payments list-vendor --json
|
|
64
|
+
|
|
65
|
+
# Taxes
|
|
66
|
+
zohopy taxes list --json
|
|
67
|
+
zohopy taxes create '{"tax_name":"VAT","tax_percentage":5}' --json
|
|
68
|
+
|
|
69
|
+
# Settings
|
|
70
|
+
zohopy settings preferences --json
|
|
71
|
+
zohopy settings currencies --json
|
|
72
|
+
zohopy settings templates --json
|
|
73
|
+
zohopy settings users --json
|
|
74
|
+
|
|
75
|
+
# Raw API (escape hatch)
|
|
76
|
+
zohopy raw get /books/v3/contacts --json
|
|
77
|
+
zohopy raw post /books/v3/contacts --data '{"contact_name":"Test"}' --json
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Python SDK Quick Reference
|
|
81
|
+
|
|
82
|
+
```python
|
|
83
|
+
from zohopy import ZohoConfig, SyncZohoClient
|
|
84
|
+
from zohopy.products.books import ZohoBooks
|
|
85
|
+
|
|
86
|
+
with SyncZohoClient(ZohoConfig()) as client:
|
|
87
|
+
books = ZohoBooks(client)
|
|
88
|
+
|
|
89
|
+
# 43 resource attributes available:
|
|
90
|
+
# books.contacts, books.invoices, books.items, books.bills,
|
|
91
|
+
# books.estimates, books.sales_orders, books.purchase_orders,
|
|
92
|
+
# books.expenses, books.credit_notes, books.vendor_credits,
|
|
93
|
+
# books.customer_payments, books.vendor_payments,
|
|
94
|
+
# books.recurring_invoices, books.recurring_bills,
|
|
95
|
+
# books.recurring_expenses, books.sales_receipts,
|
|
96
|
+
# books.retainer_invoices, books.customer_debit_notes,
|
|
97
|
+
# books.contact_persons, books.bank_accounts,
|
|
98
|
+
# books.bank_transactions, books.chart_of_accounts,
|
|
99
|
+
# books.journals, books.base_currency_adjustments,
|
|
100
|
+
# books.projects, books.tasks, books.time_entries,
|
|
101
|
+
# books.fixed_assets, books.fixed_asset_types,
|
|
102
|
+
# books.organizations, books.taxes, books.currencies,
|
|
103
|
+
# books.users, books.preferences, books.templates,
|
|
104
|
+
# books.opening_balances, books.custom_fields,
|
|
105
|
+
# books.custom_views, books.custom_modules,
|
|
106
|
+
# books.reporting_tags, books.workflows,
|
|
107
|
+
# books.locations, books.crm_integration
|
|
108
|
+
|
|
109
|
+
# Every resource has: create(), list(), get(id), update(id, data), delete(id)
|
|
110
|
+
# Plus resource-specific actions (mark_sent, void, approve, etc.)
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Error Handling
|
|
114
|
+
|
|
115
|
+
```python
|
|
116
|
+
from zohopy import (
|
|
117
|
+
ZohoNotFoundError, # 404 — resource not found
|
|
118
|
+
ZohoValidationError, # 400 — bad request (base)
|
|
119
|
+
ZohoInvalidFieldError, # 400 code 2 — bad field value
|
|
120
|
+
ZohoDuplicateError, # 400 code 4 — already exists
|
|
121
|
+
ZohoEmptyBodyError, # 400 code 11 — missing body
|
|
122
|
+
ZohoBusinessRuleError, # 400 code 4xxx — rule violation
|
|
123
|
+
ZohoFeatureNotEnabledError, # 400 code 110xxx — enable first
|
|
124
|
+
ZohoResourceDependentError, # 400 code 36/1004 — has deps
|
|
125
|
+
ZohoAuthenticationError, # 401 — bad/expired token
|
|
126
|
+
ZohoForbiddenError, # 403 — insufficient scopes
|
|
127
|
+
ZohoRateLimitError, # 429 — rate limited (.retry_after)
|
|
128
|
+
ZohoServerError, # 5xx — Zoho server error
|
|
129
|
+
)
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## Multi-Currency Transactions
|
|
133
|
+
|
|
134
|
+
All transaction endpoints (invoices, bills, estimates, etc.) support:
|
|
135
|
+
- `currency_id` — ID of the currency
|
|
136
|
+
- `exchange_rate` — exchange rate to base currency
|
|
137
|
+
|
|
138
|
+
```python
|
|
139
|
+
books.invoices.create({
|
|
140
|
+
"customer_id": "...",
|
|
141
|
+
"currency_id": "AED_CURRENCY_ID",
|
|
142
|
+
"exchange_rate": 3.67,
|
|
143
|
+
"line_items": [{"item_id": "...", "quantity": 1}],
|
|
144
|
+
})
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## Landed Cost
|
|
148
|
+
|
|
149
|
+
Set `is_landed_cost: True` on bills:
|
|
150
|
+
|
|
151
|
+
```python
|
|
152
|
+
books.bills.create({
|
|
153
|
+
"vendor_id": "...",
|
|
154
|
+
"is_landed_cost": True,
|
|
155
|
+
"line_items": [
|
|
156
|
+
{"item_id": "...", "quantity": 1, "rate": 120}
|
|
157
|
+
],
|
|
158
|
+
})
|
|
159
|
+
# Response includes: allocated_landed_costs, unallocated_landed_costs
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## Environment Variables
|
|
163
|
+
|
|
164
|
+
| Variable | Required | Description |
|
|
165
|
+
|----------|----------|-------------|
|
|
166
|
+
| `ZOHO_CLIENT_ID` | Yes | OAuth client ID |
|
|
167
|
+
| `ZOHO_CLIENT_SECRET` | Yes | OAuth client secret |
|
|
168
|
+
| `ZOHO_REFRESH_TOKEN` | Yes | Permanent refresh token |
|
|
169
|
+
| `ZOHO_ORGANIZATION_ID` | Yes | Zoho org ID |
|
|
170
|
+
| `ZOHO_API_DOMAIN` | No | Auto-detects data center |
|
|
171
|
+
| `ZOHO_DATA_CENTER` | No | Manual: us/eu/in/au/jp/ca/cn/sa |
|
|
172
|
+
| `ZOHOPY_LOG_LEVEL` | No | DEBUG/INFO/WARNING/ERROR |
|
|
173
|
+
| `ZOHOPY_LOG_FORMAT` | No | console/json |
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [0.1.0] - 2026-04-03
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **Zoho Books API v3** — complete coverage with 43 resource types and 347 methods (sync + async)
|
|
15
|
+
- **Sales cycle:** Contacts, Contact Persons, Estimates, Sales Orders, Invoices, Recurring Invoices, Sales Receipts, Credit Notes, Customer Debit Notes, Customer Payments, Retainer Invoices
|
|
16
|
+
- **Purchase cycle:** Purchase Orders, Bills, Recurring Bills, Vendor Credits, Vendor Payments, Expenses, Recurring Expenses
|
|
17
|
+
- **Banking:** Bank Accounts, Bank Transactions, Chart of Accounts, Journals, Base Currency Adjustments
|
|
18
|
+
- **Projects:** Projects, Tasks, Time Entries
|
|
19
|
+
- **Assets:** Fixed Assets, Fixed Asset Types
|
|
20
|
+
- **Settings:** Organizations, Taxes (+ authorities + exemptions), Currencies (+ exchange rates), Users, Preferences, Templates, Opening Balances, Custom Fields, Custom Views, Custom Modules, Reporting Tags, Workflows, Locations
|
|
21
|
+
- **Integration:** Zoho CRM import (customer, vendor, item)
|
|
22
|
+
- **Multi-currency** support on all transactions with exchange rates
|
|
23
|
+
- **Landed cost** support on bills
|
|
24
|
+
- **CLI** — `zohopy` command with 30+ commands, `--json` on every command
|
|
25
|
+
- **OAuth setup wizard** — Self Client + Browser redirect flows with org picker UI
|
|
26
|
+
- **Structured logging** via structlog (JSON/console)
|
|
27
|
+
- **Typed exceptions** — 10+ exception classes mapped from Zoho error codes
|
|
28
|
+
- **Docker + Docker Compose** support
|
|
29
|
+
- **CI/CD** — GitHub Actions with lint, type-check, test matrix (3.10–3.13), PyPI release
|
|
30
|
+
|
|
31
|
+
[Unreleased]: https://github.com/talas9/zohopy/compare/v0.1.0...HEAD
|
|
32
|
+
[0.1.0]: https://github.com/talas9/zohopy/releases/tag/v0.1.0
|
zohopy-0.1.0/Dockerfile
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# ZohoPy Docker image
|
|
2
|
+
#
|
|
3
|
+
# Build: docker build -t zohopy .
|
|
4
|
+
# Run: docker run --env-file .env zohopy contacts list --json
|
|
5
|
+
#
|
|
6
|
+
# NOTE: Build the wheel first with `python -m build` or let CI do it.
|
|
7
|
+
# If no pre-built wheel, we use SETUPTOOLS_SCM_PRETEND_VERSION.
|
|
8
|
+
|
|
9
|
+
FROM python:3.13-slim
|
|
10
|
+
|
|
11
|
+
LABEL org.opencontainers.image.source="https://github.com/talas9/zohopy"
|
|
12
|
+
LABEL org.opencontainers.image.description="ZohoPy — Python client for Zoho APIs"
|
|
13
|
+
LABEL org.opencontainers.image.licenses="MIT"
|
|
14
|
+
|
|
15
|
+
WORKDIR /app
|
|
16
|
+
|
|
17
|
+
# Copy source and install
|
|
18
|
+
COPY pyproject.toml README.md LICENSE ./
|
|
19
|
+
COPY src/ src/
|
|
20
|
+
|
|
21
|
+
# Install — use pretend version since .git is not available
|
|
22
|
+
ENV SETUPTOOLS_SCM_PRETEND_VERSION=0.1.0
|
|
23
|
+
RUN pip install --no-cache-dir . && rm -rf /app/src /app/pyproject.toml
|
|
24
|
+
|
|
25
|
+
# Non-root user
|
|
26
|
+
RUN useradd --create-home --shell /bin/bash zohopy
|
|
27
|
+
USER zohopy
|
|
28
|
+
|
|
29
|
+
# Runtime config
|
|
30
|
+
ENV ZOHOPY_LOG_LEVEL=INFO \
|
|
31
|
+
ZOHOPY_LOG_FORMAT=json \
|
|
32
|
+
PYTHONUNBUFFERED=1
|
|
33
|
+
|
|
34
|
+
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
|
|
35
|
+
CMD python -c "from zohopy import ZohoConfig; print('ok')" || exit 1
|
|
36
|
+
|
|
37
|
+
ENTRYPOINT ["zohopy"]
|
zohopy-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 talas9
|
|
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.
|