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.
Files changed (87) hide show
  1. zohopy-0.1.0/.dockerignore +25 -0
  2. zohopy-0.1.0/.env.example +25 -0
  3. zohopy-0.1.0/.github/ISSUE_TEMPLATE/bug_report.yml +75 -0
  4. zohopy-0.1.0/.github/ISSUE_TEMPLATE/feature_request.yml +54 -0
  5. zohopy-0.1.0/.github/PULL_REQUEST_TEMPLATE/pull_request.md +16 -0
  6. zohopy-0.1.0/.github/workflows/ci.yml +52 -0
  7. zohopy-0.1.0/.github/workflows/release.yml +72 -0
  8. zohopy-0.1.0/.gitignore +51 -0
  9. zohopy-0.1.0/AGENT.md +173 -0
  10. zohopy-0.1.0/CHANGELOG.md +32 -0
  11. zohopy-0.1.0/Dockerfile +37 -0
  12. zohopy-0.1.0/LICENSE +21 -0
  13. zohopy-0.1.0/PKG-INFO +411 -0
  14. zohopy-0.1.0/README.md +366 -0
  15. zohopy-0.1.0/docker-compose.yml +47 -0
  16. zohopy-0.1.0/pyproject.toml +119 -0
  17. zohopy-0.1.0/scripts/example.py +31 -0
  18. zohopy-0.1.0/src/zohopy/__init__.py +76 -0
  19. zohopy-0.1.0/src/zohopy/__main__.py +6 -0
  20. zohopy-0.1.0/src/zohopy/_auth.py +229 -0
  21. zohopy-0.1.0/src/zohopy/_client.py +414 -0
  22. zohopy-0.1.0/src/zohopy/cli.py +722 -0
  23. zohopy-0.1.0/src/zohopy/config.py +184 -0
  24. zohopy-0.1.0/src/zohopy/exceptions.py +427 -0
  25. zohopy-0.1.0/src/zohopy/logging.py +96 -0
  26. zohopy-0.1.0/src/zohopy/products/__init__.py +1 -0
  27. zohopy-0.1.0/src/zohopy/products/_base.py +153 -0
  28. zohopy-0.1.0/src/zohopy/products/books/__init__.py +258 -0
  29. zohopy-0.1.0/src/zohopy/products/books/accounting.py +77 -0
  30. zohopy-0.1.0/src/zohopy/products/books/bank_rules.py +15 -0
  31. zohopy-0.1.0/src/zohopy/products/books/bank_transactions.py +101 -0
  32. zohopy-0.1.0/src/zohopy/products/books/banking.py +47 -0
  33. zohopy-0.1.0/src/zohopy/products/books/base_currency.py +29 -0
  34. zohopy-0.1.0/src/zohopy/products/books/bills.py +107 -0
  35. zohopy-0.1.0/src/zohopy/products/books/contact_persons.py +63 -0
  36. zohopy-0.1.0/src/zohopy/products/books/contacts.py +138 -0
  37. zohopy-0.1.0/src/zohopy/products/books/credit_notes.py +143 -0
  38. zohopy-0.1.0/src/zohopy/products/books/crm_integration.py +41 -0
  39. zohopy-0.1.0/src/zohopy/products/books/custom_fields.py +134 -0
  40. zohopy-0.1.0/src/zohopy/products/books/custom_modules.py +61 -0
  41. zohopy-0.1.0/src/zohopy/products/books/customer_debit_notes.py +15 -0
  42. zohopy-0.1.0/src/zohopy/products/books/estimates.py +135 -0
  43. zohopy-0.1.0/src/zohopy/products/books/expenses.py +71 -0
  44. zohopy-0.1.0/src/zohopy/products/books/fixed_asset_types.py +15 -0
  45. zohopy-0.1.0/src/zohopy/products/books/fixed_assets.py +77 -0
  46. zohopy-0.1.0/src/zohopy/products/books/invoices.py +250 -0
  47. zohopy-0.1.0/src/zohopy/products/books/items.py +29 -0
  48. zohopy-0.1.0/src/zohopy/products/books/locations.py +41 -0
  49. zohopy-0.1.0/src/zohopy/products/books/payments.py +119 -0
  50. zohopy-0.1.0/src/zohopy/products/books/projects.py +219 -0
  51. zohopy-0.1.0/src/zohopy/products/books/purchase_orders.py +141 -0
  52. zohopy-0.1.0/src/zohopy/products/books/recurring_bills.py +35 -0
  53. zohopy-0.1.0/src/zohopy/products/books/recurring_expenses.py +41 -0
  54. zohopy-0.1.0/src/zohopy/products/books/recurring_invoices.py +41 -0
  55. zohopy-0.1.0/src/zohopy/products/books/reporting_tags.py +97 -0
  56. zohopy-0.1.0/src/zohopy/products/books/retainer_invoices.py +127 -0
  57. zohopy-0.1.0/src/zohopy/products/books/sales_orders.py +147 -0
  58. zohopy-0.1.0/src/zohopy/products/books/sales_receipts.py +23 -0
  59. zohopy-0.1.0/src/zohopy/products/books/settings.py +336 -0
  60. zohopy-0.1.0/src/zohopy/products/books/vendor_credits.py +107 -0
  61. zohopy-0.1.0/src/zohopy/products/inventory/__init__.py +85 -0
  62. zohopy-0.1.0/src/zohopy/products/inventory/adjustments.py +15 -0
  63. zohopy-0.1.0/src/zohopy/products/inventory/bills.py +29 -0
  64. zohopy-0.1.0/src/zohopy/products/inventory/composite_items.py +41 -0
  65. zohopy-0.1.0/src/zohopy/products/inventory/contacts.py +29 -0
  66. zohopy-0.1.0/src/zohopy/products/inventory/invoices.py +35 -0
  67. zohopy-0.1.0/src/zohopy/products/inventory/item_groups.py +29 -0
  68. zohopy-0.1.0/src/zohopy/products/inventory/items.py +35 -0
  69. zohopy-0.1.0/src/zohopy/products/inventory/packages.py +15 -0
  70. zohopy-0.1.0/src/zohopy/products/inventory/purchase_orders.py +29 -0
  71. zohopy-0.1.0/src/zohopy/products/inventory/sales_orders.py +29 -0
  72. zohopy-0.1.0/src/zohopy/products/inventory/settings.py +71 -0
  73. zohopy-0.1.0/src/zohopy/products/inventory/shipments.py +23 -0
  74. zohopy-0.1.0/src/zohopy/products/inventory/transfer_orders.py +23 -0
  75. zohopy-0.1.0/src/zohopy/py.typed +0 -0
  76. zohopy-0.1.0/src/zohopy/setup.py +778 -0
  77. zohopy-0.1.0/tests/__init__.py +0 -0
  78. zohopy-0.1.0/tests/conftest.py +56 -0
  79. zohopy-0.1.0/tests/integration/__init__.py +0 -0
  80. zohopy-0.1.0/tests/integration/test_books_crud.py +677 -0
  81. zohopy-0.1.0/tests/unit/__init__.py +0 -0
  82. zohopy-0.1.0/tests/unit/test_auth.py +57 -0
  83. zohopy-0.1.0/tests/unit/test_books.py +75 -0
  84. zohopy-0.1.0/tests/unit/test_client.py +132 -0
  85. zohopy-0.1.0/tests/unit/test_config.py +114 -0
  86. zohopy-0.1.0/tests/unit/test_exceptions.py +195 -0
  87. 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
@@ -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
@@ -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.