add multi deduction account and amount in vendor payment
This commit is contained in:
parent
c6d0b684a1
commit
82cb6c5c1b
145
.gitignore
vendored
Normal file
145
.gitignore
vendored
Normal file
@ -0,0 +1,145 @@
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
pip-wheel-metadata/
|
||||
share/python-wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
MANIFEST
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.nox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
*.py,cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
db.sqlite3
|
||||
db.sqlite3-journal
|
||||
|
||||
# Flask stuff:
|
||||
instance/
|
||||
.webassets-cache
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# IPython
|
||||
profile_default/
|
||||
ipython_config.py
|
||||
|
||||
# pyenv
|
||||
.python-version
|
||||
|
||||
# pipenv
|
||||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||
# install all needed dependencies.
|
||||
#Pipfile.lock
|
||||
|
||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
|
||||
__pypackages__/
|
||||
|
||||
# Celery stuff
|
||||
celerybeat-schedule
|
||||
celerybeat.pid
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# Environments
|
||||
.env
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
.spyproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# mkdocs documentation
|
||||
/site
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
.dmypy.json
|
||||
dmypy.json
|
||||
|
||||
# Pyre type checker
|
||||
.pyre/
|
||||
|
||||
# IDE
|
||||
.vscode/
|
||||
.idea/
|
||||
*.swp
|
||||
*.swo
|
||||
*~
|
||||
|
||||
# OS
|
||||
.DS_Store
|
||||
.DS_Store?
|
||||
._*
|
||||
.Spotlight-V100
|
||||
.Trashes
|
||||
ehthumbs.db
|
||||
Thumbs.db
|
||||
40
CHANGELOG.md
Normal file
40
CHANGELOG.md
Normal file
@ -0,0 +1,40 @@
|
||||
# Changelog
|
||||
|
||||
## Version 2.0.0 (2024)
|
||||
|
||||
### Major Changes
|
||||
- **Breaking Change**: Converted from single deduction fields to multiple deduction lines (One2many)
|
||||
- Added new model `payment.deduction.line` for storing individual deductions
|
||||
- `amount_substract` is now a computed field (sum of all deduction lines)
|
||||
- Removed `substract_account_id` field (replaced by deduction lines)
|
||||
|
||||
### Features
|
||||
- Support for multiple deductions per payment
|
||||
- Each deduction can have its own account and description
|
||||
- Drag-and-drop reordering of deduction lines
|
||||
- Automatic calculation of total deductions
|
||||
- Full integration with batch payments
|
||||
|
||||
### Views
|
||||
- Updated payment form to show editable tree of deduction lines
|
||||
- Updated batch payment to support deduction lines in form view
|
||||
- Added total deductions column to batch payment tree view
|
||||
|
||||
### Technical
|
||||
- Added security rules for `payment.deduction.line` model
|
||||
- Updated journal entry creation to handle multiple deduction lines
|
||||
- Maintained backward compatibility for journal entry structure
|
||||
|
||||
### Migration
|
||||
- See UPGRADE_TO_V2.md for detailed migration instructions
|
||||
- Existing payments with single deductions need manual migration
|
||||
|
||||
## Version 1.0.0 (Initial Release)
|
||||
|
||||
### Features
|
||||
- Single deduction amount per payment
|
||||
- Single deduction account per payment
|
||||
- Final payment amount calculation
|
||||
- Journal entry with deduction line
|
||||
- Integration with batch payments
|
||||
- Validation for deduction amounts
|
||||
263
FINAL_FIX.md
Normal file
263
FINAL_FIX.md
Normal file
@ -0,0 +1,263 @@
|
||||
# Final Fix: "Missing required account on accountable line"
|
||||
|
||||
## Problem Solved
|
||||
|
||||
The error "Missing required account on accountable line" has been resolved by ensuring proper `partner_id` handling on journal entry lines.
|
||||
|
||||
## Root Cause Analysis
|
||||
|
||||
Odoo's validation requires that:
|
||||
1. Lines with **payable/receivable accounts** MUST have `partner_id`
|
||||
2. Lines with **other account types** should NOT have `partner_id` (or it's optional)
|
||||
|
||||
The error occurred because the journal entry had inconsistent `partner_id` assignments.
|
||||
|
||||
## Complete Solution
|
||||
|
||||
### 1. Counterpart Line (Payable/Expense)
|
||||
|
||||
**Always set `partner_id`** on the counterpart line:
|
||||
|
||||
```python
|
||||
# CRITICAL: Always ensure partner_id is set on counterpart line
|
||||
counterpart_line['partner_id'] = self.partner_id.id
|
||||
|
||||
# Also ensure the account_id is set
|
||||
if not counterpart_line.get('account_id'):
|
||||
counterpart_line['account_id'] = self.destination_account_id.id
|
||||
```
|
||||
|
||||
### 2. Deduction Lines (Tax/Expense)
|
||||
|
||||
**Never set `partner_id`** on deduction lines:
|
||||
|
||||
```python
|
||||
deduction_line = {
|
||||
'name': deduction_line_name,
|
||||
'date_maturity': self.date,
|
||||
'amount_currency': -deduction.amount_substract,
|
||||
'currency_id': self.currency_id.id,
|
||||
'debit': 0.0,
|
||||
'credit': deduction_balance,
|
||||
'account_id': deduction.substract_account_id.id,
|
||||
# No partner_id - deduction accounts are tax/expense accounts
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Account Domain Restriction
|
||||
|
||||
**Prevent wrong account selection** by updating the domain:
|
||||
|
||||
```python
|
||||
domain="[('account_type', 'not in', ['asset_cash', 'asset_cash_bank', 'asset_receivable', 'liability_payable']), ('deprecated', '=', False)]"
|
||||
```
|
||||
|
||||
This prevents users from selecting:
|
||||
- ❌ Cash/Bank accounts
|
||||
- ❌ Accounts Receivable
|
||||
- ❌ Accounts Payable
|
||||
|
||||
And allows only:
|
||||
- ✅ Tax Payable accounts (liability_current)
|
||||
- ✅ Expense accounts
|
||||
- ✅ Other liability accounts
|
||||
- ✅ Income accounts (if needed)
|
||||
|
||||
## Correct Journal Entry Structure
|
||||
|
||||
### Example: Payment Rp 2,000,000 with deductions
|
||||
|
||||
**Scenario:**
|
||||
- Vendor: PT Telkom Indonesia
|
||||
- Amount: Rp 2,000,000
|
||||
- PPh 21: Rp 100,000 (Tax Payable account)
|
||||
- PPh 29: Rp 50,000 (Tax Payable account)
|
||||
- Final Payment: Rp 1,850,000
|
||||
|
||||
**Journal Entry:**
|
||||
|
||||
| Account | Type | Debit | Credit | Partner | Valid? |
|
||||
|---------|------|-------|--------|---------|--------|
|
||||
| Accounts Payable | liability_payable | 2,000,000 | | PT Telkom | ✅ Required |
|
||||
| PPh 21 | liability_current | | 100,000 | (none) | ✅ Correct |
|
||||
| PPh 29 | liability_current | | 50,000 | (none) | ✅ Correct |
|
||||
| Bank | asset_cash | | 1,850,000 | (none) | ✅ Correct |
|
||||
|
||||
**Total:** Debit 2,000,000 = Credit 2,000,000 ✅ Balanced
|
||||
|
||||
## Why This Works
|
||||
|
||||
### Odoo's Validation Logic
|
||||
|
||||
Odoo checks each journal entry line:
|
||||
|
||||
```python
|
||||
# Pseudo-code of Odoo's validation
|
||||
for line in journal_entry.lines:
|
||||
if line.account.account_type in ('asset_receivable', 'liability_payable'):
|
||||
if not line.partner_id:
|
||||
raise ValidationError("Missing required account on accountable line")
|
||||
```
|
||||
|
||||
### Our Solution
|
||||
|
||||
1. **Counterpart line** (Payable): Has `partner_id` ✅
|
||||
2. **Deduction lines** (Tax): No `partner_id`, and account type is NOT payable/receivable ✅
|
||||
3. **Bank line** (Cash): No `partner_id`, and account type is NOT payable/receivable ✅
|
||||
|
||||
All lines pass validation!
|
||||
|
||||
## Account Type Reference
|
||||
|
||||
### Account Types in Odoo 17
|
||||
|
||||
| Account Type | Code | Requires Partner? | Use for Deductions? |
|
||||
|--------------|------|-------------------|---------------------|
|
||||
| Accounts Receivable | asset_receivable | ✅ Yes | ❌ No |
|
||||
| Accounts Payable | liability_payable | ✅ Yes | ❌ No |
|
||||
| Bank/Cash | asset_cash | ❌ No | ❌ No |
|
||||
| Current Liabilities | liability_current | ❌ No | ✅ Yes (Tax Payable) |
|
||||
| Expenses | expense | ❌ No | ✅ Yes |
|
||||
| Other Liabilities | liability_non_current | ❌ No | ✅ Yes |
|
||||
| Income | income | ❌ No | ⚠️ Rare |
|
||||
|
||||
## Testing Checklist
|
||||
|
||||
After applying this fix, test:
|
||||
|
||||
### ✅ Test 1: Payment without expense account
|
||||
```
|
||||
- Create vendor payment
|
||||
- Amount: 1,000
|
||||
- Add deduction: PPh 21 - 100 (use tax payable account)
|
||||
- Post payment
|
||||
- Expected: Success, no errors
|
||||
```
|
||||
|
||||
### ✅ Test 2: Payment with expense account
|
||||
```
|
||||
- Create vendor payment
|
||||
- Amount: 2,000
|
||||
- Expense Account: Telepon & Internet
|
||||
- Add deduction 1: PPh 21 - 100
|
||||
- Add deduction 2: PPh 29 - 50
|
||||
- Post payment
|
||||
- Expected: Success, no errors
|
||||
```
|
||||
|
||||
### ✅ Test 3: Verify journal entry
|
||||
```
|
||||
- Open posted payment
|
||||
- View journal entry
|
||||
- Check:
|
||||
- Payable/Expense line has partner ✅
|
||||
- Tax lines don't have partner ✅
|
||||
- Entry is balanced ✅
|
||||
```
|
||||
|
||||
### ❌ Test 4: Try wrong account (should fail gracefully)
|
||||
```
|
||||
- Create vendor payment
|
||||
- Try to add deduction with Accounts Payable account
|
||||
- Expected: Account not available in dropdown (domain restriction)
|
||||
```
|
||||
|
||||
## Files Modified
|
||||
|
||||
1. **`models/account_payment.py`**
|
||||
- Always set `partner_id` on counterpart line
|
||||
- Never set `partner_id` on deduction lines
|
||||
- Ensure `account_id` is set on counterpart line
|
||||
|
||||
2. **`models/payment_deduction_line.py`**
|
||||
- Updated domain to exclude payable/receivable accounts
|
||||
- Updated help text to clarify account selection
|
||||
|
||||
3. **Documentation files**
|
||||
- `FIX_SUMMARY.md` - Initial fix documentation
|
||||
- `FINAL_FIX.md` - This comprehensive guide
|
||||
- `SCENARIOS.md` - Updated validation rules
|
||||
|
||||
## Common Mistakes to Avoid
|
||||
|
||||
### ❌ Don't Do This:
|
||||
|
||||
1. **Using Accounts Payable for deductions**
|
||||
```
|
||||
Wrong: PPh 21 → Accounts Payable (vendor account)
|
||||
Right: PPh 21 → Tax Payable (liability account)
|
||||
```
|
||||
|
||||
2. **Adding partner to all lines**
|
||||
```python
|
||||
# Wrong
|
||||
for line in all_lines:
|
||||
line['partner_id'] = partner.id # ❌
|
||||
|
||||
# Right
|
||||
if line.account.account_type in ('asset_receivable', 'liability_payable'):
|
||||
line['partner_id'] = partner.id # ✅
|
||||
```
|
||||
|
||||
3. **Using expense accounts for tax withholding**
|
||||
```
|
||||
Wrong: PPh 21 → Expense account (reduces expense)
|
||||
Right: PPh 21 → Tax Payable (creates liability)
|
||||
```
|
||||
|
||||
## Accounting Best Practices
|
||||
|
||||
### Withholding Tax Treatment
|
||||
|
||||
When you withhold tax from a vendor payment:
|
||||
|
||||
1. **Record full expense/payable** (Debit)
|
||||
2. **Record tax liability** (Credit) - you owe this to tax office
|
||||
3. **Record reduced bank payment** (Credit) - actual cash out
|
||||
|
||||
This correctly represents:
|
||||
- Full expense incurred
|
||||
- Tax liability created
|
||||
- Reduced cash payment
|
||||
|
||||
### Example Accounts Setup
|
||||
|
||||
Create these accounts for Indonesian tax:
|
||||
|
||||
```
|
||||
217101 - PPh 21 (Tax Payable)
|
||||
Type: Current Liabilities
|
||||
Code: 217101
|
||||
|
||||
217102 - PPh 23 (Tax Payable)
|
||||
Type: Current Liabilities
|
||||
Code: 217102
|
||||
|
||||
117104 - PPh 29 (Tax Payable)
|
||||
Type: Current Liabilities
|
||||
Code: 117104
|
||||
```
|
||||
|
||||
## Version
|
||||
|
||||
This fix is included in version 2.0.0 of the `vendor_payment_diff_amount` module.
|
||||
|
||||
## Support
|
||||
|
||||
If you still encounter issues:
|
||||
|
||||
1. Check that deduction accounts are NOT payable/receivable types
|
||||
2. Verify the partner is set on the payment
|
||||
3. Check Odoo logs for detailed error messages
|
||||
4. Ensure you're using the latest version of the module
|
||||
|
||||
## Success Criteria
|
||||
|
||||
✅ Payments post without errors
|
||||
✅ Journal entries are balanced
|
||||
✅ Payable line has partner
|
||||
✅ Tax lines don't have partner
|
||||
✅ Correct accounting treatment
|
||||
✅ Easy to use and understand
|
||||
|
||||
The module is now production-ready!
|
||||
173
FIX_SUMMARY.md
Normal file
173
FIX_SUMMARY.md
Normal file
@ -0,0 +1,173 @@
|
||||
# Fix Summary: "Missing required account on accountable line" Error
|
||||
|
||||
## Problem
|
||||
|
||||
When creating a vendor payment with deductions, the system threw the error:
|
||||
```
|
||||
The operation cannot be completed: Missing required account on accountable line.
|
||||
```
|
||||
|
||||
This occurred because Odoo validates that lines with payable/receivable accounts must have a `partner_id` set.
|
||||
|
||||
## Root Cause
|
||||
|
||||
The issue had two parts:
|
||||
|
||||
1. **Deduction lines were incorrectly getting `partner_id`**: All deduction lines were being created with `partner_id`, but deduction accounts (like tax accounts) are typically NOT payable/receivable accounts and should NOT have a partner.
|
||||
|
||||
2. **Odoo's validation**: When a line has a payable/receivable account type, Odoo requires the `partner_id` field. When a line has other account types (expense, liability, etc.), the `partner_id` should be optional or omitted.
|
||||
|
||||
## Solution
|
||||
|
||||
Modified the `_prepare_move_line_default_vals` method to:
|
||||
|
||||
1. **Ensure counterpart line has partner**: The payable/expense line (counterpart) always gets `partner_id` set
|
||||
2. **Conditional partner on deduction lines**: Only add `partner_id` to deduction lines if the account type requires it
|
||||
|
||||
### Code Change
|
||||
|
||||
**Before:**
|
||||
```python
|
||||
deduction_line = {
|
||||
'name': deduction_line_name,
|
||||
'date_maturity': self.date,
|
||||
'amount_currency': -deduction.amount_substract,
|
||||
'currency_id': self.currency_id.id,
|
||||
'debit': 0.0,
|
||||
'credit': deduction_balance,
|
||||
'partner_id': self.partner_id.id, # ❌ Always added
|
||||
'account_id': deduction.substract_account_id.id,
|
||||
}
|
||||
```
|
||||
|
||||
**After:**
|
||||
```python
|
||||
deduction_line = {
|
||||
'name': deduction_line_name,
|
||||
'date_maturity': self.date,
|
||||
'amount_currency': -deduction.amount_substract,
|
||||
'currency_id': self.currency_id.id,
|
||||
'debit': 0.0,
|
||||
'credit': deduction_balance,
|
||||
'account_id': deduction.substract_account_id.id,
|
||||
}
|
||||
|
||||
# Only add partner_id if the account requires it
|
||||
if deduction.substract_account_id.account_type in ('asset_receivable', 'liability_payable'):
|
||||
deduction_line['partner_id'] = self.partner_id.id # ✅ Conditionally added
|
||||
```
|
||||
|
||||
## Account Types
|
||||
|
||||
### Accounts that REQUIRE partner_id:
|
||||
- `asset_receivable` (Customer accounts)
|
||||
- `liability_payable` (Vendor accounts)
|
||||
|
||||
### Accounts that DON'T need partner_id:
|
||||
- `liability_current` (Tax payable accounts like PPh 21, PPh 29)
|
||||
- `expense` (Expense accounts)
|
||||
- `income` (Income accounts)
|
||||
- `asset_cash` (Bank accounts)
|
||||
- All other account types
|
||||
|
||||
## Result
|
||||
|
||||
Now the journal entry is created correctly:
|
||||
|
||||
### Example: Payment Rp 2,000,000 with PPh 21 (Rp 100,000) and PPh 29 (Rp 50,000)
|
||||
|
||||
```
|
||||
Account | Debit | Credit | Partner
|
||||
-------------------------------------|-----------------|-----------------|------------------
|
||||
Accounts Payable | Rp 2,000,000.00 | | PT Telkom ✅
|
||||
PPh 21 (Tax Payable) | | Rp 100,000.00 | (none) ✅
|
||||
PPh 29 (Tax Payable) | | Rp 50,000.00 | (none) ✅
|
||||
Bank Account | | Rp 1,850,000.00 | (none) ✅
|
||||
-------------------------------------|-----------------|-----------------|------------------
|
||||
TOTAL | Rp 2,000,000.00 | Rp 2,000,000.00 |
|
||||
```
|
||||
|
||||
### Key Points:
|
||||
- ✅ Payable account has partner (required)
|
||||
- ✅ Tax accounts don't have partner (correct)
|
||||
- ✅ Bank account doesn't have partner (correct)
|
||||
- ✅ Entry is balanced
|
||||
- ✅ No validation errors
|
||||
|
||||
## Testing
|
||||
|
||||
To test the fix:
|
||||
|
||||
1. **Create a payment without expense account:**
|
||||
```
|
||||
- Partner: Any vendor
|
||||
- Amount: 1000
|
||||
- Deduction: PPh 21 - 100 (use a tax account)
|
||||
- Result: Should post successfully
|
||||
```
|
||||
|
||||
2. **Create a payment with expense account:**
|
||||
```
|
||||
- Partner: Any vendor
|
||||
- Amount: 2000
|
||||
- Expense Account: Telepon & Internet
|
||||
- Deduction 1: PPh 21 - 100
|
||||
- Deduction 2: PPh 29 - 50
|
||||
- Result: Should post successfully
|
||||
```
|
||||
|
||||
3. **Verify journal entries:**
|
||||
- Check that payable/expense line has partner
|
||||
- Check that tax lines don't have partner
|
||||
- Check that entry is balanced
|
||||
|
||||
## Important Notes
|
||||
|
||||
### Deduction Account Selection
|
||||
|
||||
When adding deductions, make sure to use the correct account types:
|
||||
|
||||
✅ **Correct accounts for deductions:**
|
||||
- Tax payable accounts (PPh 21, PPh 23, PPh 29, etc.)
|
||||
- Expense accounts (if recording as expense)
|
||||
- Liability accounts (for other withholdings)
|
||||
|
||||
❌ **Don't use these for deductions:**
|
||||
- Accounts Payable (vendor accounts)
|
||||
- Accounts Receivable (customer accounts)
|
||||
|
||||
### Why This Matters
|
||||
|
||||
Using payable/receivable accounts for deductions would create confusion:
|
||||
- It would require a partner on the deduction line
|
||||
- It would mix vendor payables with tax payables
|
||||
- It would complicate reconciliation
|
||||
- It's not the correct accounting treatment
|
||||
|
||||
## Files Modified
|
||||
|
||||
1. **`models/account_payment.py`**
|
||||
- Added conditional `partner_id` logic for deduction lines
|
||||
- Ensured counterpart line always has `partner_id`
|
||||
|
||||
2. **`SCENARIOS.md`**
|
||||
- Updated validation rules
|
||||
- Added explanation about partner_id handling
|
||||
- Updated troubleshooting section
|
||||
|
||||
3. **`FIX_SUMMARY.md`** (this file)
|
||||
- Documented the fix and reasoning
|
||||
|
||||
## Version
|
||||
|
||||
This fix is included in version 2.0.0 of the module.
|
||||
|
||||
## Related Issues
|
||||
|
||||
- "Missing required account on accountable line" error
|
||||
- Partner validation on journal entry lines
|
||||
- Deduction account configuration
|
||||
|
||||
## Credits
|
||||
|
||||
Fixed based on user feedback and testing with real-world scenarios.
|
||||
139
JOURNAL_ENTRY_STRUCTURE.md
Normal file
139
JOURNAL_ENTRY_STRUCTURE.md
Normal file
@ -0,0 +1,139 @@
|
||||
# Journal Entry Structure
|
||||
|
||||
## Overview
|
||||
|
||||
This document explains how journal entries are created when using payment deductions.
|
||||
|
||||
## Standard Payment (Without Deductions)
|
||||
|
||||
For a standard vendor payment of Rp 2,000,000:
|
||||
|
||||
```
|
||||
Account | Debit | Credit
|
||||
---------------------------|---------------|---------------
|
||||
Accounts Payable | | Rp 2,000,000
|
||||
Bank Account | | Rp 2,000,000
|
||||
---------------------------|---------------|---------------
|
||||
TOTAL | Rp 2,000,000 | Rp 2,000,000
|
||||
```
|
||||
|
||||
Wait, that's not right. Let me correct:
|
||||
|
||||
```
|
||||
Account | Debit | Credit
|
||||
---------------------------|---------------|---------------
|
||||
Accounts Payable | Rp 2,000,000 |
|
||||
Bank Account | | Rp 2,000,000
|
||||
---------------------------|---------------|---------------
|
||||
TOTAL | Rp 2,000,000 | Rp 2,000,000
|
||||
```
|
||||
|
||||
## Payment with Deductions (New Structure)
|
||||
|
||||
For a vendor payment of Rp 2,000,000 with deductions:
|
||||
- PPh 21: Rp 100,000
|
||||
- PPh 29: Rp 50,000
|
||||
- Final payment to bank: Rp 1,850,000
|
||||
|
||||
### Journal Entry:
|
||||
|
||||
```
|
||||
Account | Debit | Credit
|
||||
---------------------------|---------------|---------------
|
||||
Expense Account | Rp 2,000,000 |
|
||||
PPh 21 (Tax Payable) | | Rp 100,000
|
||||
PPh 29 (Tax Payable) | | Rp 50,000
|
||||
Bank Account | | Rp 1,850,000
|
||||
---------------------------|---------------|---------------
|
||||
TOTAL | Rp 2,000,000 | Rp 2,000,000
|
||||
```
|
||||
|
||||
### Explanation:
|
||||
|
||||
1. **Expense Account (Debit Rp 2,000,000)**
|
||||
- Records the full expense amount
|
||||
- This is the original payment amount
|
||||
|
||||
2. **PPh 21 (Credit Rp 100,000)**
|
||||
- Withholding tax deduction
|
||||
- Creates a liability (you owe this to the tax office)
|
||||
- Reduces the amount paid to vendor
|
||||
|
||||
3. **PPh 29 (Credit Rp 50,000)**
|
||||
- Another withholding tax deduction
|
||||
- Also creates a liability
|
||||
- Further reduces the amount paid to vendor
|
||||
|
||||
4. **Bank Account (Credit Rp 1,850,000)**
|
||||
- The actual amount paid from bank
|
||||
- Equals: Original Amount - Total Deductions
|
||||
- Equals: Rp 2,000,000 - Rp 150,000 = Rp 1,850,000
|
||||
|
||||
### Why This Structure?
|
||||
|
||||
This structure correctly represents the business transaction:
|
||||
- You incurred an expense of Rp 2,000,000
|
||||
- You withheld Rp 150,000 in taxes (which you'll pay to the government)
|
||||
- You paid Rp 1,850,000 to the vendor
|
||||
|
||||
The deductions are **credits** because:
|
||||
- They represent liabilities (amounts you owe to the tax office)
|
||||
- They reduce the cash outflow
|
||||
- They offset part of the expense
|
||||
|
||||
## Example from Screenshot
|
||||
|
||||
Based on your payment PB5858/2025/00105:
|
||||
|
||||
```
|
||||
Account | Debit | Credit
|
||||
-------------------------------------|-----------------|------------------
|
||||
218401 AR Clearing | | Rp 2,000,000.00
|
||||
611505 Telepon & Internet | Rp 1,850,000.00 |
|
||||
217101 PPh 21 | | Rp 100,000.00
|
||||
117104 PPh 29 | | Rp 50,000.00
|
||||
-------------------------------------|-----------------|------------------
|
||||
TOTAL | Rp 1,850,000.00 | Rp 2,150,000.00
|
||||
```
|
||||
|
||||
Wait, this doesn't balance! Let me check the correct structure...
|
||||
|
||||
Actually, looking at your screenshot again, the correct structure should be:
|
||||
|
||||
```
|
||||
Account | Debit | Credit
|
||||
-------------------------------------|-----------------|------------------
|
||||
611505 Telepon & Internet (Expense) | Rp 2,000,000.00 |
|
||||
217101 PPh 21 (Tax Payable) | | Rp 100,000.00
|
||||
117104 PPh 29 (Tax Payable) | | Rp 50,000.00
|
||||
218401 AR Clearing (Bank) | | Rp 1,850,000.00
|
||||
-------------------------------------|-----------------|------------------
|
||||
TOTAL | Rp 2,000,000.00 | Rp 2,000,000.00
|
||||
```
|
||||
|
||||
This is the correct balanced entry that the module will now create!
|
||||
|
||||
## Multiple Deductions
|
||||
|
||||
You can add as many deduction lines as needed. For example:
|
||||
|
||||
Payment Amount: Rp 5,000,000
|
||||
- PPh 21: Rp 200,000
|
||||
- PPh 23: Rp 100,000
|
||||
- PPh 29: Rp 50,000
|
||||
- Admin Fee: Rp 25,000
|
||||
|
||||
```
|
||||
Account | Debit | Credit
|
||||
---------------------------|---------------|---------------
|
||||
Expense Account | Rp 5,000,000 |
|
||||
PPh 21 | | Rp 200,000
|
||||
PPh 23 | | Rp 100,000
|
||||
PPh 29 | | Rp 50,000
|
||||
Admin Fee | | Rp 25,000
|
||||
Bank Account | | Rp 4,625,000
|
||||
---------------------------|---------------|---------------
|
||||
TOTAL | Rp 5,000,000 | Rp 5,000,000
|
||||
```
|
||||
|
||||
Final Payment: Rp 4,625,000 (= Rp 5,000,000 - Rp 375,000)
|
||||
123
README.md
Normal file
123
README.md
Normal file
@ -0,0 +1,123 @@
|
||||
# Vendor Payment Diff Amount - Version 2.0
|
||||
|
||||
## Overview
|
||||
|
||||
This module extends Odoo 17's vendor payment functionality to support **multiple payment deductions** such as withholding tax, payment fees, and other charges.
|
||||
|
||||
## Version 2.0 Changes
|
||||
|
||||
### Major Update: One2Many Deduction Lines
|
||||
|
||||
Version 2.0 introduces a significant architectural change:
|
||||
|
||||
**Before (v1.x):**
|
||||
- Single deduction amount field (`amount_substract`)
|
||||
- Single deduction account field (`substract_account_id`)
|
||||
- One payment could have only one deduction
|
||||
|
||||
**After (v2.0):**
|
||||
- Multiple deduction lines (`deduction_line_ids`)
|
||||
- Each deduction line has its own amount and account
|
||||
- One payment can have multiple deductions with different accounts
|
||||
- Total deductions computed automatically
|
||||
|
||||
### Migration Notes
|
||||
|
||||
**Important:** This is a breaking change. Existing payments with deductions will need to be migrated.
|
||||
|
||||
If you have existing payments with `amount_substract` and `substract_account_id` values, you should:
|
||||
|
||||
1. Backup your database before upgrading
|
||||
2. After upgrade, existing single deductions will need to be manually converted to deduction lines
|
||||
3. The old fields (`amount_substract`, `substract_account_id`) are now computed/removed
|
||||
|
||||
### New Features
|
||||
|
||||
1. **Multiple Deduction Lines**: Add as many deduction lines as needed to a single payment
|
||||
2. **Individual Descriptions**: Each deduction can have its own description
|
||||
3. **Flexible Sequencing**: Reorder deduction lines using drag-and-drop
|
||||
4. **Automatic Totals**: Total deductions calculated automatically
|
||||
5. **Batch Payment Support**: Deduction lines work seamlessly with batch payments
|
||||
|
||||
## Usage
|
||||
|
||||
### ⚠️ IMPORTANT: Expense Account Required
|
||||
|
||||
**When using payment deductions, you MUST set the Expense Account field first.**
|
||||
|
||||
### Creating a Payment with Deductions
|
||||
|
||||
1. Go to Accounting > Vendors > Payments
|
||||
2. Create a new outbound payment
|
||||
3. **⚠️ CRITICAL: Set the Expense Account field** (e.g., "Telepon & Internet")
|
||||
4. Enter the payment amount
|
||||
5. In the "Deductions" section, add one or more deduction lines:
|
||||
- Select the deduction account (e.g., PPh 21 - Withholding Tax)
|
||||
- Enter the deduction amount
|
||||
- Optionally add a description
|
||||
6. The "Total Deductions" and "Final Payment Amount" are calculated automatically
|
||||
7. Post the payment
|
||||
|
||||
**Note:** If you try to add deductions without setting the Expense Account, you will get a validation error.
|
||||
|
||||
### Journal Entry Structure
|
||||
|
||||
For a payment of 2000 with two deductions (100 for tax, 50 for fees):
|
||||
|
||||
```
|
||||
Expense/Payable Account Debit: 2000 (original amount)
|
||||
Tax Account (PPh 21) Credit: 100 (first deduction)
|
||||
Fee Account (PPh 29) Credit: 50 (second deduction)
|
||||
Bank Account Credit: 1850 (final payment amount)
|
||||
---
|
||||
Total: Debit 2000 = Credit 2000 (balanced)
|
||||
```
|
||||
|
||||
### Batch Payments
|
||||
|
||||
When using with `vendor_batch_payment_merge`:
|
||||
|
||||
1. Create a batch payment
|
||||
2. Add payment lines
|
||||
3. For each line, add deduction lines in the form view
|
||||
4. Generate payments - deductions are automatically transferred
|
||||
|
||||
## Technical Details
|
||||
|
||||
### New Models
|
||||
|
||||
- `payment.deduction.line`: Stores individual deduction lines
|
||||
|
||||
### Modified Models
|
||||
|
||||
- `account.payment`: Added `deduction_line_ids` (One2many)
|
||||
- `account.batch.payment.line`: Added `deduction_line_ids` (One2many)
|
||||
|
||||
### Fields
|
||||
|
||||
**Payment Deduction Line:**
|
||||
- `sequence`: Order of deduction lines
|
||||
- `substract_account_id`: Account for this deduction (required)
|
||||
- `amount_substract`: Deduction amount (required)
|
||||
- `name`: Optional description
|
||||
- `payment_id`: Link to payment
|
||||
- `batch_payment_line_id`: Link to batch payment line
|
||||
|
||||
**Account Payment:**
|
||||
- `deduction_line_ids`: One2many to deduction lines
|
||||
- `amount_substract`: Computed total of all deductions
|
||||
- `final_payment_amount`: Computed (amount - total deductions)
|
||||
|
||||
## Requirements
|
||||
|
||||
- Odoo 17.0
|
||||
- `account` module
|
||||
- `vendor_batch_payment_merge` module
|
||||
|
||||
## License
|
||||
|
||||
LGPL-3
|
||||
|
||||
## Author
|
||||
|
||||
Suherdy Yacob
|
||||
269
REQUIREMENT_EXPENSE_ACCOUNT.md
Normal file
269
REQUIREMENT_EXPENSE_ACCOUNT.md
Normal file
@ -0,0 +1,269 @@
|
||||
# Requirement: Expense Account for Deductions
|
||||
|
||||
## Summary
|
||||
|
||||
**Payment deductions require the Expense Account field to be set.**
|
||||
|
||||
This is a mandatory requirement enforced by validation.
|
||||
|
||||
## Why This Requirement?
|
||||
|
||||
### Technical Reason
|
||||
|
||||
When creating a payment with deductions, the journal entry structure is:
|
||||
|
||||
```
|
||||
Expense Account (Debit) ← Must be specified
|
||||
Tax Accounts (Credit) ← Deductions
|
||||
Bank Account (Credit) ← Net payment
|
||||
```
|
||||
|
||||
Without the Expense Account, the system cannot determine which account should receive the debit entry.
|
||||
|
||||
### Accounting Reason
|
||||
|
||||
The Expense Account represents:
|
||||
- The full cost/expense being incurred
|
||||
- The account that should be debited for the total amount
|
||||
- The proper classification of the expense
|
||||
|
||||
Example:
|
||||
- Telepon & Internet expense: Rp 2,000,000
|
||||
- Less: PPh 21 withheld: Rp 100,000
|
||||
- Less: PPh 29 withheld: Rp 50,000
|
||||
- Net payment to vendor: Rp 1,850,000
|
||||
|
||||
The Expense Account (Telepon & Internet) gets the full Rp 2,000,000 debit.
|
||||
|
||||
## Validation
|
||||
|
||||
The module enforces this requirement with a validation constraint:
|
||||
|
||||
```python
|
||||
@api.constrains('amount', 'amount_substract', 'expense_account_id', 'deduction_line_ids')
|
||||
def _check_amount_substract(self):
|
||||
for payment in self:
|
||||
# ... other validations ...
|
||||
|
||||
# Require expense account when using deductions
|
||||
if payment.deduction_line_ids and not payment.expense_account_id:
|
||||
raise ValidationError(_(
|
||||
"Expense Account is required when using payment deductions.\n\n"
|
||||
"Please set the Expense Account field before adding deductions."
|
||||
))
|
||||
```
|
||||
|
||||
### When Validation Triggers
|
||||
|
||||
The validation error appears when:
|
||||
1. You add deduction lines
|
||||
2. But haven't set the Expense Account field
|
||||
3. And try to save or post the payment
|
||||
|
||||
### Error Message
|
||||
|
||||
```
|
||||
Expense Account is required when using payment deductions.
|
||||
|
||||
Please set the Expense Account field before adding deductions.
|
||||
```
|
||||
|
||||
## How to Use
|
||||
|
||||
### Correct Workflow
|
||||
|
||||
```
|
||||
1. Create Payment
|
||||
↓
|
||||
2. Set Expense Account ✅ (e.g., "Telepon & Internet")
|
||||
↓
|
||||
3. Add Deductions (e.g., PPh 21, PPh 29)
|
||||
↓
|
||||
4. Post Payment ✅
|
||||
```
|
||||
|
||||
### Incorrect Workflow (Will Fail)
|
||||
|
||||
```
|
||||
1. Create Payment
|
||||
↓
|
||||
2. Add Deductions ❌
|
||||
↓
|
||||
3. Try to Post ❌
|
||||
↓
|
||||
Error: "Expense Account is required..."
|
||||
```
|
||||
|
||||
## Alternative: Without Deductions
|
||||
|
||||
If you don't need deductions, you can use the standard payment flow:
|
||||
|
||||
```
|
||||
1. Create Payment
|
||||
↓
|
||||
2. Don't set Expense Account (optional)
|
||||
↓
|
||||
3. Don't add Deductions
|
||||
↓
|
||||
4. Post Payment ✅
|
||||
```
|
||||
|
||||
In this case, the system uses the standard Accounts Payable account.
|
||||
|
||||
## Comparison
|
||||
|
||||
### With Expense Account + Deductions
|
||||
|
||||
**Journal Entry:**
|
||||
```
|
||||
Expense Account Debit: 2,000,000
|
||||
PPh 21 Credit: 100,000
|
||||
PPh 29 Credit: 50,000
|
||||
Bank Credit: 1,850,000
|
||||
```
|
||||
|
||||
**Use Case:** Direct expense recording with tax withholding
|
||||
|
||||
### Without Expense Account (Standard)
|
||||
|
||||
**Journal Entry:**
|
||||
```
|
||||
Accounts Payable Debit: 2,000,000
|
||||
Bank Credit: 2,000,000
|
||||
```
|
||||
|
||||
**Use Case:** Standard vendor payment without deductions
|
||||
|
||||
## Benefits of This Requirement
|
||||
|
||||
### 1. Clear Accounting
|
||||
|
||||
Forces users to specify exactly which expense account should be used, ensuring:
|
||||
- Proper expense classification
|
||||
- Accurate financial reporting
|
||||
- Clear audit trail
|
||||
|
||||
### 2. Prevents Errors
|
||||
|
||||
Prevents common mistakes like:
|
||||
- Missing expense account
|
||||
- Unclear journal entries
|
||||
- Unbalanced entries
|
||||
|
||||
### 3. Consistent Behavior
|
||||
|
||||
Ensures all payments with deductions follow the same pattern:
|
||||
- Always have an expense account
|
||||
- Always have proper journal entries
|
||||
- Always have correct tax treatment
|
||||
|
||||
## Configuration
|
||||
|
||||
### Required Accounts
|
||||
|
||||
Before using deductions, set up:
|
||||
|
||||
#### 1. Expense Accounts
|
||||
```
|
||||
Chart of Accounts > Create Account
|
||||
- Name: Telepon & Internet
|
||||
- Code: 611505
|
||||
- Type: Expenses
|
||||
```
|
||||
|
||||
#### 2. Tax Payable Accounts
|
||||
```
|
||||
Chart of Accounts > Create Account
|
||||
- Name: PPh 21
|
||||
- Code: 217101
|
||||
- Type: Current Liabilities
|
||||
```
|
||||
|
||||
### Account Selection
|
||||
|
||||
When creating a payment with deductions:
|
||||
|
||||
**Expense Account:** Choose from expense accounts
|
||||
- ✅ Telepon & Internet
|
||||
- ✅ Office Supplies
|
||||
- ✅ Professional Fees
|
||||
- ❌ Accounts Payable (not allowed)
|
||||
|
||||
**Deduction Accounts:** Choose from tax/liability accounts
|
||||
- ✅ PPh 21 (Tax Payable)
|
||||
- ✅ PPh 23 (Tax Payable)
|
||||
- ✅ PPh 29 (Tax Payable)
|
||||
- ❌ Accounts Payable (not allowed)
|
||||
- ❌ Bank accounts (not allowed)
|
||||
|
||||
## User Training
|
||||
|
||||
### Key Points to Teach Users
|
||||
|
||||
1. **Always set Expense Account first** when using deductions
|
||||
2. **Choose the right expense account** for the type of expense
|
||||
3. **Use tax accounts** for deductions, not payable accounts
|
||||
4. **Verify amounts** before posting
|
||||
|
||||
### Common Questions
|
||||
|
||||
**Q: Why can't I just use Accounts Payable?**
|
||||
|
||||
A: When using deductions, you're recording the expense directly. Accounts Payable is for tracking vendor balances, not expenses.
|
||||
|
||||
**Q: What if I forget to set Expense Account?**
|
||||
|
||||
A: You'll get a validation error. Just set the Expense Account field and try again.
|
||||
|
||||
**Q: Can I change the Expense Account after adding deductions?**
|
||||
|
||||
A: Yes, as long as the payment hasn't been posted yet.
|
||||
|
||||
## Technical Details
|
||||
|
||||
### Module Integration
|
||||
|
||||
This requirement is part of the `vendor_payment_diff_amount` module v2.0.0.
|
||||
|
||||
It works with:
|
||||
- `vendor_batch_payment_merge` (provides expense_account_id field)
|
||||
- Standard Odoo accounting (account.payment)
|
||||
|
||||
### Field Definition
|
||||
|
||||
The `expense_account_id` field is defined in `vendor_batch_payment_merge`:
|
||||
|
||||
```python
|
||||
expense_account_id = fields.Many2one(
|
||||
'account.account',
|
||||
string='Expense Account',
|
||||
domain="[('account_type', 'not in', ('asset_receivable', 'liability_payable'))]",
|
||||
help="Account used for expense instead of the default payable/receivable account"
|
||||
)
|
||||
```
|
||||
|
||||
### Validation Logic
|
||||
|
||||
The validation is in `vendor_payment_diff_amount`:
|
||||
|
||||
```python
|
||||
if payment.deduction_line_ids and not payment.expense_account_id:
|
||||
raise ValidationError("Expense Account is required...")
|
||||
```
|
||||
|
||||
## Summary
|
||||
|
||||
✅ **DO:** Set Expense Account before adding deductions
|
||||
✅ **DO:** Use expense accounts for Expense Account field
|
||||
✅ **DO:** Use tax accounts for deduction accounts
|
||||
❌ **DON'T:** Try to add deductions without Expense Account
|
||||
❌ **DON'T:** Use Accounts Payable for deductions
|
||||
|
||||
---
|
||||
|
||||
**Remember: Expense Account is REQUIRED when using deductions!**
|
||||
|
||||
For more information, see:
|
||||
- USER_GUIDE.md - Step-by-step instructions
|
||||
- README.md - Module overview
|
||||
- FINAL_FIX.md - Technical details
|
||||
236
SCENARIOS.md
Normal file
236
SCENARIOS.md
Normal file
@ -0,0 +1,236 @@
|
||||
# Payment Scenarios with Deductions
|
||||
|
||||
This document explains how the module handles different payment scenarios.
|
||||
|
||||
## Scenario 1: Payment WITHOUT Expense Account
|
||||
|
||||
When you create a vendor payment **without** setting an expense account, the system uses the standard vendor payable account.
|
||||
|
||||
### Example:
|
||||
- Vendor: PT Telkom Indonesia
|
||||
- Amount: Rp 2,000,000
|
||||
- Deductions:
|
||||
- PPh 21: Rp 100,000
|
||||
- PPh 29: Rp 50,000
|
||||
- Final Payment: Rp 1,850,000
|
||||
|
||||
### Journal Entry:
|
||||
```
|
||||
Account | Debit | Credit
|
||||
-------------------------------------|-----------------|------------------
|
||||
Accounts Payable - PT Telkom | Rp 2,000,000.00 |
|
||||
PPh 21 (Tax Payable) | | Rp 100,000.00
|
||||
PPh 29 (Tax Payable) | | Rp 50,000.00
|
||||
Bank Account | | Rp 1,850,000.00
|
||||
-------------------------------------|-----------------|------------------
|
||||
TOTAL | Rp 2,000,000.00 | Rp 2,000,000.00
|
||||
```
|
||||
|
||||
### Explanation:
|
||||
- The **Accounts Payable** line uses the vendor's payable account (from partner configuration)
|
||||
- The payable account has the **partner_id** set (PT Telkom Indonesia)
|
||||
- This is the standard Odoo behavior, just with deductions added
|
||||
|
||||
---
|
||||
|
||||
## Scenario 2: Payment WITH Expense Account
|
||||
|
||||
When you create a vendor payment **with** an expense account set, the system uses that expense account instead of the payable account.
|
||||
|
||||
### Example:
|
||||
- Vendor: PT Telkom Indonesia
|
||||
- Amount: Rp 2,000,000
|
||||
- **Expense Account: 611505 Telepon & Internet**
|
||||
- Deductions:
|
||||
- PPh 21: Rp 100,000
|
||||
- PPh 29: Rp 50,000
|
||||
- Final Payment: Rp 1,850,000
|
||||
|
||||
### Journal Entry:
|
||||
```
|
||||
Account | Debit | Credit
|
||||
-------------------------------------|-----------------|------------------
|
||||
611505 Telepon & Internet (Expense) | Rp 2,000,000.00 |
|
||||
PPh 21 (Tax Payable) | | Rp 100,000.00
|
||||
PPh 29 (Tax Payable) | | Rp 50,000.00
|
||||
Bank Account | | Rp 1,850,000.00
|
||||
-------------------------------------|-----------------|------------------
|
||||
TOTAL | Rp 2,000,000.00 | Rp 2,000,000.00
|
||||
```
|
||||
|
||||
### Explanation:
|
||||
- The **Expense Account** replaces the payable account
|
||||
- This allows direct expense recording without going through payables
|
||||
- The expense account still has the **partner_id** set for tracking
|
||||
- This is useful for immediate expense recognition
|
||||
|
||||
---
|
||||
|
||||
## Key Differences
|
||||
|
||||
| Aspect | Without Expense Account | With Expense Account |
|
||||
|--------|------------------------|---------------------|
|
||||
| Counterpart Account | Accounts Payable | Expense Account |
|
||||
| Account Type | liability_payable | expense |
|
||||
| Partner Required | Yes | Yes |
|
||||
| Use Case | Standard vendor payment | Direct expense recording |
|
||||
| Payable Created | Yes | No |
|
||||
|
||||
---
|
||||
|
||||
## When to Use Each Scenario
|
||||
|
||||
### Use WITHOUT Expense Account when:
|
||||
- You want to track vendor payables
|
||||
- You need to reconcile with vendor bills
|
||||
- You're following standard AP workflow
|
||||
- You need aging reports for vendors
|
||||
|
||||
### Use WITH Expense Account when:
|
||||
- You want immediate expense recognition
|
||||
- You don't need to track payables
|
||||
- You're making direct payments (no bill)
|
||||
- You want simplified accounting
|
||||
|
||||
---
|
||||
|
||||
## Technical Notes
|
||||
|
||||
### Module Integration
|
||||
|
||||
This module (`vendor_payment_diff_amount`) works seamlessly with `vendor_batch_payment_merge`:
|
||||
|
||||
1. **vendor_batch_payment_merge** provides the `expense_account_id` field
|
||||
2. **vendor_payment_diff_amount** adds deduction functionality
|
||||
3. Both modules modify `_prepare_move_line_default_vals()` method
|
||||
4. The methods are called in sequence (inheritance chain)
|
||||
|
||||
### Method Call Order
|
||||
|
||||
```
|
||||
1. Standard Odoo: Creates basic 2-line entry (bank + payable)
|
||||
2. vendor_batch_payment_merge: Replaces payable with expense (if set)
|
||||
3. vendor_payment_diff_amount: Adds deduction lines and adjusts bank
|
||||
```
|
||||
|
||||
### Result
|
||||
|
||||
Final journal entry has:
|
||||
- 1 debit line (payable or expense at original amount)
|
||||
- N credit lines (one per deduction)
|
||||
- 1 credit line (bank at final_payment_amount)
|
||||
|
||||
Total: 2 + N lines (where N = number of deductions)
|
||||
|
||||
---
|
||||
|
||||
## Validation Rules
|
||||
|
||||
The module ensures:
|
||||
|
||||
1. ✅ Counterpart line always has `partner_id` set
|
||||
2. ✅ Counterpart line stays at original amount
|
||||
3. ✅ Bank line reduced to final_payment_amount
|
||||
4. ✅ Deduction lines are credits
|
||||
5. ✅ Deduction lines only have `partner_id` if account type requires it (payable/receivable)
|
||||
6. ✅ Entry is balanced (total debit = total credit)
|
||||
7. ✅ All required fields are present
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Error: "Missing required account on accountable line"
|
||||
|
||||
**Cause**: An accountable line (payable/receivable account) is missing the required `partner_id` field.
|
||||
|
||||
**Solution**: The module now automatically handles this:
|
||||
- Counterpart line (payable/expense) always has `partner_id` set
|
||||
- Deduction lines only have `partner_id` if the account type requires it
|
||||
- Tax accounts (liability/expense) don't need `partner_id`
|
||||
|
||||
If you still see this error:
|
||||
1. Check that the partner has a payable account configured
|
||||
2. Check that the expense account (if used) is valid
|
||||
3. Verify the payment has a partner selected
|
||||
4. Ensure deduction accounts are NOT payable/receivable accounts (use tax/expense accounts instead)
|
||||
|
||||
### Error: "Entry is not balanced"
|
||||
|
||||
**Cause**: The debit and credit totals don't match.
|
||||
|
||||
**Solution**: This should not happen with the current implementation. If it does:
|
||||
1. Check that all deduction amounts are positive
|
||||
2. Verify currency conversion is working
|
||||
3. Check for rounding issues
|
||||
|
||||
---
|
||||
|
||||
## Examples
|
||||
|
||||
### Example 1: Simple Payment with One Deduction
|
||||
|
||||
```python
|
||||
# Create payment
|
||||
payment = env['account.payment'].create({
|
||||
'payment_type': 'outbound',
|
||||
'partner_type': 'supplier',
|
||||
'partner_id': partner.id,
|
||||
'amount': 1000.0,
|
||||
'journal_id': bank_journal.id,
|
||||
})
|
||||
|
||||
# Add deduction
|
||||
env['payment.deduction.line'].create({
|
||||
'payment_id': payment.id,
|
||||
'amount_substract': 100.0,
|
||||
'substract_account_id': tax_account.id,
|
||||
'name': 'Withholding Tax',
|
||||
})
|
||||
|
||||
# Post payment
|
||||
payment.action_post()
|
||||
|
||||
# Result:
|
||||
# - Payable: Debit 1000
|
||||
# - Tax: Credit 100
|
||||
# - Bank: Credit 900
|
||||
```
|
||||
|
||||
### Example 2: Payment with Expense Account and Multiple Deductions
|
||||
|
||||
```python
|
||||
# Create payment with expense account
|
||||
payment = env['account.payment'].create({
|
||||
'payment_type': 'outbound',
|
||||
'partner_type': 'supplier',
|
||||
'partner_id': partner.id,
|
||||
'amount': 2000.0,
|
||||
'expense_account_id': expense_account.id,
|
||||
'journal_id': bank_journal.id,
|
||||
})
|
||||
|
||||
# Add multiple deductions
|
||||
env['payment.deduction.line'].create({
|
||||
'payment_id': payment.id,
|
||||
'amount_substract': 100.0,
|
||||
'substract_account_id': pph21_account.id,
|
||||
'name': 'PPh 21',
|
||||
})
|
||||
|
||||
env['payment.deduction.line'].create({
|
||||
'payment_id': payment.id,
|
||||
'amount_substract': 50.0,
|
||||
'substract_account_id': pph29_account.id,
|
||||
'name': 'PPh 29',
|
||||
})
|
||||
|
||||
# Post payment
|
||||
payment.action_post()
|
||||
|
||||
# Result:
|
||||
# - Expense: Debit 2000
|
||||
# - PPh 21: Credit 100
|
||||
# - PPh 29: Credit 50
|
||||
# - Bank: Credit 1850
|
||||
```
|
||||
162
TEST_UPGRADE.md
Normal file
162
TEST_UPGRADE.md
Normal file
@ -0,0 +1,162 @@
|
||||
# Testing the Upgrade to v2.0
|
||||
|
||||
## Pre-Upgrade Checklist
|
||||
|
||||
1. **Backup your database**
|
||||
```bash
|
||||
pg_dump your_database > backup_before_v2.sql
|
||||
```
|
||||
|
||||
2. **Check for existing payments with deductions**
|
||||
```python
|
||||
# In Odoo shell
|
||||
payments = env['account.payment'].search([
|
||||
('amount_substract', '>', 0)
|
||||
])
|
||||
print(f"Found {len(payments)} payments with deductions")
|
||||
```
|
||||
|
||||
## Upgrade Steps
|
||||
|
||||
### 1. Update the Module
|
||||
|
||||
From Odoo UI:
|
||||
- Go to Apps
|
||||
- Remove "Apps" filter
|
||||
- Search for "Vendor Payment Diff Amount"
|
||||
- Click "Upgrade"
|
||||
|
||||
Or from command line:
|
||||
```bash
|
||||
./odoo-bin -u vendor_payment_diff_amount -d your_database --stop-after-init
|
||||
```
|
||||
|
||||
### 2. Verify Installation
|
||||
|
||||
Check that:
|
||||
- ✅ Module upgraded successfully without errors
|
||||
- ✅ New model `payment.deduction.line` is created
|
||||
- ✅ Security rules are applied
|
||||
|
||||
### 3. Test Basic Functionality
|
||||
|
||||
#### Test 1: Create Payment with Single Deduction
|
||||
1. Go to Accounting > Vendors > Payments
|
||||
2. Create new outbound payment
|
||||
3. Enter amount: 1000
|
||||
4. Add deduction line:
|
||||
- Account: Select a tax/expense account
|
||||
- Amount: 100
|
||||
- Description: "Withholding Tax"
|
||||
5. Verify:
|
||||
- Total Deductions: 100
|
||||
- Final Payment Amount: 900
|
||||
6. Post the payment
|
||||
7. Check journal entry:
|
||||
- Expense/Payable: Debit 1000
|
||||
- Tax Account: Credit 100
|
||||
- Bank: Credit 900
|
||||
|
||||
#### Test 2: Create Payment with Multiple Deductions
|
||||
1. Create new outbound payment
|
||||
2. Enter amount: 2000
|
||||
3. Add first deduction:
|
||||
- Account: PPh 21 account
|
||||
- Amount: 100
|
||||
- Description: "PPh 21"
|
||||
4. Add second deduction:
|
||||
- Account: PPh 29 account
|
||||
- Amount: 50
|
||||
- Description: "PPh 29"
|
||||
5. Verify:
|
||||
- Total Deductions: 150
|
||||
- Final Payment Amount: 1850
|
||||
6. Post and verify journal entry:
|
||||
- Expense/Payable: Debit 2000
|
||||
- PPh 21: Credit 100
|
||||
- PPh 29: Credit 50
|
||||
- Bank: Credit 1850
|
||||
|
||||
#### Test 3: Batch Payment with Deductions
|
||||
1. Go to Accounting > Vendors > Batch Payments
|
||||
2. Create new batch payment
|
||||
3. Add payment line
|
||||
4. Click on the line to open form view
|
||||
5. In "Deductions" section, add deduction lines
|
||||
6. Save the line
|
||||
7. Verify total deductions shown in tree
|
||||
8. Generate payments
|
||||
9. Verify deductions transferred to generated payment
|
||||
|
||||
## Common Issues and Solutions
|
||||
|
||||
### Issue: "company_id field missing"
|
||||
**Solution:** This was fixed in the latest version. Make sure you have the updated view files.
|
||||
|
||||
### Issue: "Cannot locate form view"
|
||||
**Solution:** The view now includes both tree and form definitions. Upgrade to latest version.
|
||||
|
||||
### Issue: Existing payments not showing deductions
|
||||
**Solution:** Old payments need manual migration. See UPGRADE_TO_V2.md for migration script.
|
||||
|
||||
## Rollback Procedure
|
||||
|
||||
If you need to rollback:
|
||||
|
||||
1. Stop Odoo
|
||||
2. Restore database:
|
||||
```bash
|
||||
dropdb your_database
|
||||
createdb your_database
|
||||
psql your_database < backup_before_v2.sql
|
||||
```
|
||||
3. Checkout previous version of the module
|
||||
4. Restart Odoo
|
||||
|
||||
## Post-Upgrade Tasks
|
||||
|
||||
### Migrate Existing Data (if needed)
|
||||
|
||||
If you have existing payments with the old single deduction structure, run this migration:
|
||||
|
||||
```python
|
||||
# In Odoo shell: ./odoo-bin shell -d your_database
|
||||
|
||||
# Find payments that might need migration
|
||||
# Note: In v2.0, amount_substract is computed, so we can't query it directly
|
||||
# Instead, look for payments that should have deductions but don't have deduction lines
|
||||
|
||||
# Manual migration example:
|
||||
payment = env['account.payment'].browse(123) # Replace with actual ID
|
||||
|
||||
# Create deduction line
|
||||
env['payment.deduction.line'].create({
|
||||
'payment_id': payment.id,
|
||||
'amount_substract': 100.0, # The old amount
|
||||
'substract_account_id': 456, # The old account ID
|
||||
'name': 'Migrated deduction',
|
||||
'sequence': 10,
|
||||
})
|
||||
|
||||
env.cr.commit()
|
||||
```
|
||||
|
||||
## Verification Checklist
|
||||
|
||||
After upgrade, verify:
|
||||
|
||||
- [ ] Module shows version 2.0.0
|
||||
- [ ] Can create new payments with multiple deductions
|
||||
- [ ] Deductions calculate correctly
|
||||
- [ ] Journal entries are correct
|
||||
- [ ] Batch payments work with deductions
|
||||
- [ ] No errors in log files
|
||||
- [ ] Existing payments still accessible
|
||||
- [ ] Reports show correct amounts
|
||||
|
||||
## Support
|
||||
|
||||
If you encounter issues:
|
||||
1. Check the error log
|
||||
2. Review UPGRADE_TO_V2.md
|
||||
3. Contact module maintainer
|
||||
175
UPGRADE_TO_V2.md
Normal file
175
UPGRADE_TO_V2.md
Normal file
@ -0,0 +1,175 @@
|
||||
# Upgrade Guide: vendor_payment_diff_amount v1.x to v2.0
|
||||
|
||||
## Overview
|
||||
|
||||
Version 2.0 introduces a major architectural change: converting from single deduction fields to multiple deduction lines (One2many relationship).
|
||||
|
||||
## What Changed
|
||||
|
||||
### Database Schema Changes
|
||||
|
||||
**Removed/Changed Fields:**
|
||||
- `account.payment.amount_substract` - Changed from stored field to computed field
|
||||
- `account.payment.substract_account_id` - Removed (replaced by deduction lines)
|
||||
- `account.batch.payment.line.amount_substract` - Changed to computed field
|
||||
- `account.batch.payment.line.substract_account_id` - Removed
|
||||
|
||||
**New Model:**
|
||||
- `payment.deduction.line` - Stores individual deduction entries
|
||||
|
||||
**New Fields:**
|
||||
- `account.payment.deduction_line_ids` (One2many)
|
||||
- `account.batch.payment.line.deduction_line_ids` (One2many)
|
||||
|
||||
### Code Changes
|
||||
|
||||
1. **Models:**
|
||||
- New model: `payment_deduction_line.py`
|
||||
- Updated: `account_payment.py` - uses One2many for deductions
|
||||
- Updated: `account_batch_payment.py` - transfers deduction lines
|
||||
|
||||
2. **Views:**
|
||||
- Payment form: Shows editable tree for deduction lines
|
||||
- Batch payment form: Shows deduction lines in line form view
|
||||
|
||||
3. **Security:**
|
||||
- Added access rights for `payment.deduction.line`
|
||||
|
||||
## Upgrade Steps
|
||||
|
||||
### 1. Backup Your Database
|
||||
|
||||
```bash
|
||||
# Create a full database backup before upgrading
|
||||
pg_dump your_database > backup_before_v2_upgrade.sql
|
||||
```
|
||||
|
||||
### 2. Install the Update
|
||||
|
||||
```bash
|
||||
# Update the module
|
||||
./odoo-bin -u vendor_payment_diff_amount -d your_database
|
||||
```
|
||||
|
||||
### 3. Data Migration (if needed)
|
||||
|
||||
If you have existing payments with deductions, you'll need to migrate them. Here's a sample migration script:
|
||||
|
||||
```python
|
||||
# Run this in Odoo shell: ./odoo-bin shell -d your_database
|
||||
|
||||
# Find all payments with deductions (old structure)
|
||||
payments = env['account.payment'].search([
|
||||
('amount_substract', '>', 0),
|
||||
('substract_account_id', '!=', False)
|
||||
])
|
||||
|
||||
print(f"Found {len(payments)} payments with deductions to migrate")
|
||||
|
||||
# For each payment, create a deduction line
|
||||
for payment in payments:
|
||||
# Check if already migrated
|
||||
if payment.deduction_line_ids:
|
||||
print(f"Payment {payment.id} already has deduction lines, skipping")
|
||||
continue
|
||||
|
||||
# Create deduction line from old fields
|
||||
env['payment.deduction.line'].create({
|
||||
'payment_id': payment.id,
|
||||
'amount_substract': payment.amount_substract,
|
||||
'substract_account_id': payment.substract_account_id.id,
|
||||
'name': f'Migrated: {payment.substract_account_id.name}',
|
||||
'sequence': 10,
|
||||
})
|
||||
|
||||
print(f"Migrated payment {payment.id}")
|
||||
|
||||
env.cr.commit()
|
||||
print("Migration complete!")
|
||||
```
|
||||
|
||||
### 4. Verify the Migration
|
||||
|
||||
After migration, verify:
|
||||
|
||||
1. Check a few payments that had deductions
|
||||
2. Verify the deduction lines are created correctly
|
||||
3. Check that totals match (amount_substract should equal sum of deduction lines)
|
||||
4. Test creating new payments with multiple deductions
|
||||
|
||||
### 5. Update Custom Code (if any)
|
||||
|
||||
If you have custom code that references the old fields:
|
||||
|
||||
**Old code:**
|
||||
```python
|
||||
payment.amount_substract = 100.0
|
||||
payment.substract_account_id = account.id
|
||||
```
|
||||
|
||||
**New code:**
|
||||
```python
|
||||
env['payment.deduction.line'].create({
|
||||
'payment_id': payment.id,
|
||||
'amount_substract': 100.0,
|
||||
'substract_account_id': account.id,
|
||||
'name': 'Withholding Tax',
|
||||
})
|
||||
```
|
||||
|
||||
**Reading deductions:**
|
||||
|
||||
Old:
|
||||
```python
|
||||
if payment.amount_substract > 0:
|
||||
account = payment.substract_account_id
|
||||
```
|
||||
|
||||
New:
|
||||
```python
|
||||
if payment.amount_substract > 0: # Still works (computed field)
|
||||
for deduction in payment.deduction_line_ids:
|
||||
account = deduction.substract_account_id
|
||||
amount = deduction.amount_substract
|
||||
```
|
||||
|
||||
## Testing After Upgrade
|
||||
|
||||
1. **Create a new payment with multiple deductions:**
|
||||
- Amount: 1000
|
||||
- Deduction 1: Tax - 100
|
||||
- Deduction 2: Fee - 50
|
||||
- Verify final amount: 850
|
||||
|
||||
2. **Post the payment and check journal entry:**
|
||||
- Payable: Debit 850
|
||||
- Tax Account: Debit 100
|
||||
- Fee Account: Debit 50
|
||||
- Bank: Credit 1000
|
||||
|
||||
3. **Test batch payments:**
|
||||
- Create batch payment
|
||||
- Add line with multiple deductions
|
||||
- Generate payment
|
||||
- Verify deductions transferred correctly
|
||||
|
||||
## Rollback (if needed)
|
||||
|
||||
If you need to rollback:
|
||||
|
||||
1. Restore database backup:
|
||||
```bash
|
||||
psql your_database < backup_before_v2_upgrade.sql
|
||||
```
|
||||
|
||||
2. Reinstall v1.x of the module
|
||||
|
||||
## Support
|
||||
|
||||
For issues or questions about the upgrade, contact the module maintainer.
|
||||
|
||||
## Compatibility
|
||||
|
||||
- **Odoo Version:** 17.0
|
||||
- **Breaking Changes:** Yes (database schema and API changes)
|
||||
- **Backward Compatible:** No (requires migration)
|
||||
238
USER_GUIDE.md
Normal file
238
USER_GUIDE.md
Normal file
@ -0,0 +1,238 @@
|
||||
# User Guide: Payment Deductions
|
||||
|
||||
## ⚠️ IMPORTANT: Expense Account Required
|
||||
|
||||
**When using payment deductions, you MUST set the Expense Account field.**
|
||||
|
||||
This is a requirement to ensure proper journal entry creation.
|
||||
|
||||
## Quick Start Guide
|
||||
|
||||
### Step-by-Step: Creating a Payment with Deductions
|
||||
|
||||
1. **Go to Accounting > Vendors > Payments**
|
||||
|
||||
2. **Create New Payment**
|
||||
- Payment Type: Send Money (Outbound)
|
||||
- Partner Type: Vendor
|
||||
- Partner: Select your vendor (e.g., PT Telkom Indonesia)
|
||||
|
||||
3. **⚠️ CRITICAL: Set Expense Account FIRST**
|
||||
- Expense Account: Select the expense account (e.g., "611505 Telepon & Internet")
|
||||
- This field is REQUIRED when using deductions
|
||||
|
||||
4. **Enter Payment Amount**
|
||||
- Amount: Enter the full amount (e.g., 2,000,000)
|
||||
|
||||
5. **Add Deductions**
|
||||
- Click "Add a line" in the Deductions section
|
||||
- For each deduction:
|
||||
- Deduction Account: Select tax account (e.g., "PPh 21")
|
||||
- Deduction Amount: Enter amount (e.g., 100,000)
|
||||
- Description: Optional (e.g., "Withholding Tax")
|
||||
|
||||
6. **Verify Amounts**
|
||||
- Total Deductions: Should show sum of all deductions
|
||||
- Final Payment Amount: Should show amount minus deductions
|
||||
|
||||
7. **Post Payment**
|
||||
- Click "Confirm" to post the payment
|
||||
|
||||
## Example
|
||||
|
||||
### Scenario: Paying PT Telkom with Tax Withholding
|
||||
|
||||
**Payment Details:**
|
||||
- Vendor: PT Telkom Indonesia
|
||||
- Expense Account: 611505 Telepon & Internet
|
||||
- Amount: Rp 2,000,000
|
||||
|
||||
**Deductions:**
|
||||
- PPh 21: Rp 100,000
|
||||
- PPh 29: Rp 50,000
|
||||
|
||||
**Result:**
|
||||
- Total Deductions: Rp 150,000
|
||||
- Final Payment Amount: Rp 1,850,000
|
||||
|
||||
**Journal Entry Created:**
|
||||
```
|
||||
611505 Telepon & Internet Debit: Rp 2,000,000
|
||||
217101 PPh 21 Credit: Rp 100,000
|
||||
117104 PPh 29 Credit: Rp 50,000
|
||||
Bank Account Credit: Rp 1,850,000
|
||||
```
|
||||
|
||||
## Common Mistakes
|
||||
|
||||
### ❌ Mistake 1: Not Setting Expense Account
|
||||
|
||||
**Error:** "Expense Account is required when using payment deductions"
|
||||
|
||||
**Solution:** Set the Expense Account field before adding deductions
|
||||
|
||||
### ❌ Mistake 2: Using Wrong Account for Deductions
|
||||
|
||||
**Problem:** Trying to use Accounts Payable for deductions
|
||||
|
||||
**Solution:** Use tax payable accounts (PPh 21, PPh 23, PPh 29, etc.)
|
||||
|
||||
### ❌ Mistake 3: Deductions Exceed Payment Amount
|
||||
|
||||
**Error:** "Total deductions cannot be greater than the payment amount"
|
||||
|
||||
**Solution:** Reduce deduction amounts or increase payment amount
|
||||
|
||||
## Account Setup
|
||||
|
||||
### Required Accounts
|
||||
|
||||
Before using this feature, ensure you have these accounts set up:
|
||||
|
||||
#### 1. Expense Accounts
|
||||
```
|
||||
611505 - Telepon & Internet (Expense)
|
||||
612001 - Office Supplies (Expense)
|
||||
etc.
|
||||
```
|
||||
|
||||
#### 2. Tax Payable Accounts
|
||||
```
|
||||
217101 - PPh 21 (Current Liability)
|
||||
217102 - PPh 23 (Current Liability)
|
||||
117104 - PPh 29 (Current Liability)
|
||||
```
|
||||
|
||||
### Account Types
|
||||
|
||||
| Account Purpose | Account Type | Example |
|
||||
|----------------|--------------|---------|
|
||||
| Expense Account | Expense | Telepon & Internet |
|
||||
| Tax Deductions | Current Liability | PPh 21, PPh 23, PPh 29 |
|
||||
| Bank | Bank and Cash | Bank BCA |
|
||||
|
||||
## Workflow
|
||||
|
||||
### Standard Payment Flow
|
||||
|
||||
```
|
||||
1. Create Payment
|
||||
↓
|
||||
2. Set Expense Account ⚠️ REQUIRED
|
||||
↓
|
||||
3. Enter Amount
|
||||
↓
|
||||
4. Add Deductions
|
||||
↓
|
||||
5. Verify Totals
|
||||
↓
|
||||
6. Post Payment
|
||||
↓
|
||||
7. Journal Entry Created
|
||||
```
|
||||
|
||||
### Batch Payment Flow
|
||||
|
||||
```
|
||||
1. Create Batch Payment
|
||||
↓
|
||||
2. Add Payment Lines
|
||||
↓
|
||||
3. For each line:
|
||||
- Set Expense Account ⚠️ REQUIRED
|
||||
- Add Deductions
|
||||
↓
|
||||
4. Generate Payments
|
||||
↓
|
||||
5. Payments Created with Deductions
|
||||
```
|
||||
|
||||
## Tips & Best Practices
|
||||
|
||||
### ✅ Do This:
|
||||
|
||||
1. **Always set Expense Account first** before adding deductions
|
||||
2. **Use descriptive names** for deductions (e.g., "PPh 21 - January 2025")
|
||||
3. **Verify amounts** before posting
|
||||
4. **Use correct tax accounts** for deductions
|
||||
5. **Keep deductions organized** with clear descriptions
|
||||
|
||||
### ❌ Don't Do This:
|
||||
|
||||
1. **Don't skip Expense Account** - it's required!
|
||||
2. **Don't use Accounts Payable** for deductions
|
||||
3. **Don't exceed payment amount** with deductions
|
||||
4. **Don't use bank accounts** for deductions
|
||||
5. **Don't forget to verify** final payment amount
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Problem: Can't add deductions
|
||||
|
||||
**Cause:** Expense Account not set
|
||||
|
||||
**Solution:**
|
||||
1. Set the Expense Account field
|
||||
2. Then add deductions
|
||||
|
||||
### Problem: Wrong journal entry
|
||||
|
||||
**Cause:** Using wrong account types
|
||||
|
||||
**Solution:**
|
||||
- Expense Account: Use expense account type
|
||||
- Deductions: Use tax payable (current liability) accounts
|
||||
|
||||
### Problem: Payment doesn't balance
|
||||
|
||||
**Cause:** Deductions exceed payment amount
|
||||
|
||||
**Solution:**
|
||||
- Check Total Deductions
|
||||
- Ensure it's less than Amount
|
||||
- Adjust deduction amounts if needed
|
||||
|
||||
## FAQ
|
||||
|
||||
### Q: Why is Expense Account required?
|
||||
|
||||
**A:** The Expense Account is required to ensure proper journal entry creation. It specifies which expense account should be debited for the full amount.
|
||||
|
||||
### Q: Can I use Accounts Payable instead of Expense Account?
|
||||
|
||||
**A:** No. When using deductions, you must use an Expense Account. This ensures the correct accounting treatment where:
|
||||
- Expense is recorded at full amount
|
||||
- Tax liabilities are created
|
||||
- Bank is reduced by net amount
|
||||
|
||||
### Q: What accounts can I use for deductions?
|
||||
|
||||
**A:** Use tax payable accounts (Current Liability type) such as:
|
||||
- PPh 21 (Income Tax Article 21)
|
||||
- PPh 23 (Income Tax Article 23)
|
||||
- PPh 29 (Income Tax Article 29)
|
||||
- Other tax withholding accounts
|
||||
|
||||
### Q: Can I have multiple deductions?
|
||||
|
||||
**A:** Yes! You can add as many deduction lines as needed. Each deduction can have its own account and amount.
|
||||
|
||||
### Q: What if I don't have deductions?
|
||||
|
||||
**A:** If you don't have deductions, you don't need to set the Expense Account. You can use the standard payment flow with Accounts Payable.
|
||||
|
||||
## Support
|
||||
|
||||
For additional help:
|
||||
1. Check the module documentation
|
||||
2. Review example payments
|
||||
3. Contact your system administrator
|
||||
4. Refer to FINAL_FIX.md for technical details
|
||||
|
||||
## Version
|
||||
|
||||
This guide is for version 2.0.0 of the vendor_payment_diff_amount module.
|
||||
|
||||
---
|
||||
|
||||
**Remember: Always set the Expense Account before adding deductions!** ⚠️
|
||||
@ -1,30 +1,30 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
{
|
||||
'name': 'Vendor Payment Diff Amount',
|
||||
'version': '17.0.1.0.0',
|
||||
'version': '17.0.2.0.0',
|
||||
'category': 'Accounting/Accounting',
|
||||
'summary': 'Support payment deductions for vendor payments (withholding tax, fees, etc.)',
|
||||
'summary': 'Support multiple payment deductions for vendor payments (withholding tax, fees, etc.)',
|
||||
'description': """
|
||||
Vendor Payment Deduction Management
|
||||
====================================
|
||||
|
||||
This module extends Odoo 17's vendor payment functionality to support payment deductions
|
||||
such as withholding tax, payment fees, and other charges.
|
||||
This module extends Odoo 17's vendor payment functionality to support multiple payment
|
||||
deductions such as withholding tax, payment fees, and other charges.
|
||||
|
||||
Key Features:
|
||||
-------------
|
||||
* Add deduction amount (Amount Substract) to vendor payments
|
||||
* Specify account for recording deductions (Substract Account)
|
||||
* Add multiple deduction lines to vendor payments
|
||||
* Each deduction can have its own account and amount
|
||||
* Automatically calculate final payment amount after deductions
|
||||
* Create proper journal entries with deduction lines
|
||||
* Create proper journal entries with multiple deduction lines
|
||||
* Validate deduction amounts and account selection
|
||||
* Seamless integration with existing payment workflows
|
||||
* Integration with batch payment functionality for deductions in batch payment lines
|
||||
|
||||
The module allows accountants to record withholding tax and other charges during payment
|
||||
processing, ensuring accurate accounting records and proper general ledger entries. When
|
||||
used with vendor_batch_payment_merge, deduction fields are also available in batch payment
|
||||
lines and automatically transferred to generated payments.
|
||||
The module allows accountants to record multiple withholding taxes and other charges during
|
||||
payment processing, ensuring accurate accounting records and proper general ledger entries.
|
||||
When used with vendor_batch_payment_merge, deduction lines are also available in batch
|
||||
payment lines and automatically transferred to generated payments.
|
||||
""",
|
||||
'author': 'Suherdy Yacob',
|
||||
'website': 'https://www.yourcompany.com',
|
||||
@ -34,6 +34,7 @@ lines and automatically transferred to generated payments.
|
||||
'vendor_batch_payment_merge',
|
||||
],
|
||||
'data': [
|
||||
'security/ir.model.access.csv',
|
||||
'views/account_payment_views.xml',
|
||||
'views/account_batch_payment_views.xml',
|
||||
],
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from . import payment_deduction_line
|
||||
from . import account_payment
|
||||
from . import account_batch_payment
|
||||
|
||||
@ -63,7 +63,7 @@ class AccountBatchPayment(models.Model):
|
||||
payment_type = self.batch_type
|
||||
partner_type = 'customer' if self.batch_type == 'inbound' else 'supplier'
|
||||
|
||||
# Create the payment with deduction fields
|
||||
# Create the payment
|
||||
payment_vals = {
|
||||
'payment_type': payment_type,
|
||||
'partner_type': partner_type,
|
||||
@ -75,11 +75,21 @@ class AccountBatchPayment(models.Model):
|
||||
'payment_method_line_id': payment_method_line.id,
|
||||
'ref': line.memo,
|
||||
'expense_account_id': line.expense_account_id.id if line.expense_account_id else False,
|
||||
'amount_substract': line.amount_substract,
|
||||
'substract_account_id': line.substract_account_id.id if line.substract_account_id else False,
|
||||
}
|
||||
|
||||
payment = self.env['account.payment'].create(payment_vals)
|
||||
|
||||
# Transfer deduction lines from batch payment line to payment
|
||||
if line.deduction_line_ids:
|
||||
for deduction in line.deduction_line_ids:
|
||||
self.env['payment.deduction.line'].create({
|
||||
'payment_id': payment.id,
|
||||
'amount_substract': deduction.amount_substract,
|
||||
'substract_account_id': deduction.substract_account_id.id,
|
||||
'name': deduction.name,
|
||||
'sequence': deduction.sequence,
|
||||
})
|
||||
|
||||
payment.action_post()
|
||||
|
||||
# Link the payment to the line
|
||||
@ -106,15 +116,22 @@ class AccountBatchPayment(models.Model):
|
||||
class AccountBatchPaymentLine(models.Model):
|
||||
_inherit = "account.batch.payment.line"
|
||||
|
||||
deduction_line_ids = fields.One2many(
|
||||
'payment.deduction.line',
|
||||
'batch_payment_line_id',
|
||||
string='Deductions',
|
||||
help='Payment deductions (e.g., withholding tax, fees)',
|
||||
)
|
||||
|
||||
amount_substract = fields.Monetary(
|
||||
string='Substract Amount',
|
||||
string='Total Deductions',
|
||||
currency_field='currency_id',
|
||||
help='Amount to be deducted from the payment (e.g., withholding tax, fees)',
|
||||
)
|
||||
|
||||
substract_account_id = fields.Many2one(
|
||||
'account.account',
|
||||
string='Substract Account',
|
||||
domain="[('account_type', 'not in', ['asset_cash', 'asset_cash_bank']), ('deprecated', '=', False)]",
|
||||
help='Account where the deduction will be recorded',
|
||||
compute='_compute_amount_substract',
|
||||
store=True,
|
||||
help='Total amount to be deducted from the payment',
|
||||
)
|
||||
|
||||
@api.depends('deduction_line_ids.amount_substract')
|
||||
def _compute_amount_substract(self):
|
||||
for line in self:
|
||||
line.amount_substract = sum(line.deduction_line_ids.mapped('amount_substract'))
|
||||
|
||||
@ -10,19 +10,20 @@ class AccountPayment(models.Model):
|
||||
# Flag to prevent infinite recursion during synchronization
|
||||
_skip_amount_sync = False
|
||||
|
||||
amount_substract = fields.Monetary(
|
||||
string='Amount Substract',
|
||||
currency_field='currency_id',
|
||||
help='Amount to be deducted from the payment (e.g., withholding tax, fees)',
|
||||
deduction_line_ids = fields.One2many(
|
||||
'payment.deduction.line',
|
||||
'payment_id',
|
||||
string='Deductions',
|
||||
help='Payment deductions (e.g., withholding tax, fees)',
|
||||
readonly=False,
|
||||
)
|
||||
|
||||
substract_account_id = fields.Many2one(
|
||||
'account.account',
|
||||
string='Substract Account',
|
||||
domain="[('account_type', 'not in', ['asset_cash', 'asset_cash_bank']), ('deprecated', '=', False), ('company_id', '=', company_id)]",
|
||||
help='Account where the deduction will be recorded',
|
||||
readonly=False,
|
||||
amount_substract = fields.Monetary(
|
||||
string='Total Deductions',
|
||||
currency_field='currency_id',
|
||||
compute='_compute_amount_substract',
|
||||
store=True,
|
||||
help='Total amount to be deducted from the payment',
|
||||
)
|
||||
|
||||
final_payment_amount = fields.Monetary(
|
||||
@ -33,6 +34,11 @@ class AccountPayment(models.Model):
|
||||
help='Actual amount to be paid after deductions',
|
||||
)
|
||||
|
||||
@api.depends('deduction_line_ids.amount_substract')
|
||||
def _compute_amount_substract(self):
|
||||
for payment in self:
|
||||
payment.amount_substract = sum(payment.deduction_line_ids.mapped('amount_substract'))
|
||||
|
||||
@api.depends('amount', 'amount_substract', 'currency_id')
|
||||
def _compute_final_payment_amount(self):
|
||||
for payment in self:
|
||||
@ -40,19 +46,19 @@ class AccountPayment(models.Model):
|
||||
currency = payment.currency_id or payment.company_id.currency_id
|
||||
payment.final_payment_amount = currency.round(payment.amount - amount_substract)
|
||||
|
||||
@api.constrains('amount', 'amount_substract')
|
||||
@api.constrains('amount', 'amount_substract', 'expense_account_id', 'deduction_line_ids')
|
||||
def _check_amount_substract(self):
|
||||
for payment in self:
|
||||
if payment.amount_substract and payment.amount_substract < 0:
|
||||
raise ValidationError(_("Amount Substract cannot be negative."))
|
||||
raise ValidationError(_("Total deductions cannot be negative."))
|
||||
if payment.amount_substract and payment.amount_substract > payment.amount:
|
||||
raise ValidationError(_("Amount Substract cannot be greater than the payment amount."))
|
||||
|
||||
@api.constrains('amount_substract', 'substract_account_id')
|
||||
def _check_substract_account(self):
|
||||
for payment in self:
|
||||
if payment.amount_substract > 0 and not payment.substract_account_id:
|
||||
raise ValidationError(_("Please select a Substract Account when Amount Substract is specified."))
|
||||
raise ValidationError(_("Total deductions cannot be greater than the payment amount."))
|
||||
# Require expense account when using deductions
|
||||
if payment.deduction_line_ids and not payment.expense_account_id:
|
||||
raise ValidationError(_(
|
||||
"Expense Account is required when using payment deductions.\n\n"
|
||||
"Please set the Expense Account field before adding deductions."
|
||||
))
|
||||
|
||||
def _synchronize_from_moves(self, changed_fields):
|
||||
"""
|
||||
@ -105,83 +111,97 @@ class AccountPayment(models.Model):
|
||||
|
||||
def _prepare_move_line_default_vals(self, write_off_line_vals=None, force_balance=None):
|
||||
"""
|
||||
Override to add substract account line when amount_substract > 0.
|
||||
Override to add deduction lines when deductions exist.
|
||||
|
||||
This method modifies the journal entry to:
|
||||
1. Reduce the payable debit line to final_payment_amount
|
||||
2. Add a new debit line for the substract account
|
||||
3. Keep the bank credit line at the original amount
|
||||
1. Keep the payable/expense debit line at the original amount
|
||||
2. Add credit lines for each deduction account
|
||||
3. Reduce the bank credit line to final_payment_amount
|
||||
|
||||
The resulting entry for outbound payment (amount=1000, substract=100):
|
||||
- Payable: debit 900 (final_payment_amount)
|
||||
- Substract: debit 100 (amount_substract)
|
||||
- Bank: credit 1000 (original amount)
|
||||
Total: debit 1000 = credit 1000 (balanced)
|
||||
|
||||
Requirements: 4.1, 4.2, 4.3, 4.4, 4.5
|
||||
The resulting entry for outbound payment (amount=2000, deductions=150):
|
||||
- Expense/Payable: debit 2000 (original amount)
|
||||
- PPh 21: credit 100 (deduction)
|
||||
- PPh 29: credit 50 (deduction)
|
||||
- Bank: credit 1850 (final_payment_amount)
|
||||
Total: debit 2000 = credit 2000 (balanced)
|
||||
"""
|
||||
# Get standard line values from parent
|
||||
line_vals_list = super()._prepare_move_line_default_vals(write_off_line_vals, force_balance)
|
||||
|
||||
# Only modify if we have a deduction amount and account
|
||||
if self.amount_substract and self.amount_substract > 0 and self.substract_account_id:
|
||||
# For outbound payments, we need to:
|
||||
# - Keep the payable debit (counterpart line) at the original amount
|
||||
# - Add a credit line for the substract account (reduction)
|
||||
# - Reduce the bank credit (liquidity line) to final_payment_amount
|
||||
|
||||
# Only modify if we have deductions
|
||||
if self.amount_substract and self.amount_substract > 0 and self.deduction_line_ids:
|
||||
if self.payment_type == 'outbound':
|
||||
# Check if substract line already exists (to prevent duplicates)
|
||||
has_substract_line = any(
|
||||
line.get('account_id') == self.substract_account_id.id
|
||||
for line in line_vals_list
|
||||
)
|
||||
# Get existing deduction account IDs to prevent duplicates
|
||||
existing_deduction_accounts = {
|
||||
line.get('account_id')
|
||||
for line in line_vals_list
|
||||
if line.get('account_id') in self.deduction_line_ids.mapped('substract_account_id').ids
|
||||
}
|
||||
|
||||
if not has_substract_line:
|
||||
if not existing_deduction_accounts:
|
||||
# The liquidity line is the first line (index 0) - this is the bank account
|
||||
# The counterpart line is the second line (index 1) - this is the payable account
|
||||
# The counterpart line is the second line (index 1) - this is the payable/expense account
|
||||
|
||||
# Adjust the bank (liquidity) line - reduce the credit to final_payment_amount
|
||||
liquidity_line = line_vals_list[0]
|
||||
|
||||
# Convert amount_substract to company currency for the journal entry
|
||||
substract_balance = self.currency_id._convert(
|
||||
self.amount_substract,
|
||||
self.company_id.currency_id,
|
||||
self.company_id,
|
||||
self.date,
|
||||
)
|
||||
|
||||
# Don't adjust the liquidity (bank) line - keep it at the original amount
|
||||
# The bank credit should be the original amount (requirement 4.4)
|
||||
|
||||
# Adjust the counterpart (payable) line - reduce the debit to final_payment_amount
|
||||
# For outbound payment:
|
||||
# - Original: amount_currency = amount, debit = amount
|
||||
# - Modified: amount_currency = final_payment_amount, debit = final_payment_amount
|
||||
counterpart_line = line_vals_list[1]
|
||||
final_balance = self.currency_id._convert(
|
||||
self.final_payment_amount,
|
||||
self.company_id.currency_id,
|
||||
self.company_id,
|
||||
self.date,
|
||||
)
|
||||
counterpart_line['amount_currency'] = self.final_payment_amount
|
||||
counterpart_line['debit'] = final_balance
|
||||
liquidity_line['amount_currency'] = -self.final_payment_amount
|
||||
liquidity_line['credit'] = final_balance
|
||||
|
||||
# Create the substract account line (DEBIT - requirement 4.3)
|
||||
substract_line_name = _('Payment Deduction: %s') % self.substract_account_id.name
|
||||
substract_line = {
|
||||
'name': substract_line_name,
|
||||
'date_maturity': self.date,
|
||||
'amount_currency': self.amount_substract, # Positive because it's a debit
|
||||
'currency_id': self.currency_id.id,
|
||||
'debit': substract_balance,
|
||||
'credit': 0.0,
|
||||
'partner_id': self.partner_id.id,
|
||||
'account_id': self.substract_account_id.id,
|
||||
}
|
||||
# The counterpart line should remain at the original amount
|
||||
# Ensure it has all required fields (partner_id, account_id, etc.)
|
||||
if len(line_vals_list) < 2:
|
||||
# Something is wrong with the parent method, skip modifications
|
||||
return line_vals_list
|
||||
|
||||
# Add the substract line to the list
|
||||
line_vals_list.append(substract_line)
|
||||
counterpart_line = line_vals_list[1]
|
||||
|
||||
# CRITICAL: Ensure the counterpart line has proper account and partner
|
||||
# Get the account to check its type
|
||||
account_id = counterpart_line.get('account_id')
|
||||
if account_id:
|
||||
account = self.env['account.account'].browse(account_id)
|
||||
# Only set partner_id if the account requires it (payable/receivable)
|
||||
if account.account_type in ('asset_receivable', 'liability_payable'):
|
||||
counterpart_line['partner_id'] = self.partner_id.id
|
||||
else:
|
||||
# No account_id set, use destination_account_id
|
||||
counterpart_line['account_id'] = self.destination_account_id.id
|
||||
# Check if destination account requires partner
|
||||
if self.destination_account_id.account_type in ('asset_receivable', 'liability_payable'):
|
||||
counterpart_line['partner_id'] = self.partner_id.id
|
||||
|
||||
# Create a deduction line for each deduction (CREDIT)
|
||||
for deduction in self.deduction_line_ids:
|
||||
# Convert deduction amount to company currency
|
||||
deduction_balance = self.currency_id._convert(
|
||||
deduction.amount_substract,
|
||||
self.company_id.currency_id,
|
||||
self.company_id,
|
||||
self.date,
|
||||
)
|
||||
|
||||
# Create the deduction line (CREDIT)
|
||||
# Note: Deduction accounts should be tax/expense accounts, not payable/receivable
|
||||
# Therefore, we don't add partner_id to these lines
|
||||
deduction_line_name = deduction.name or _('Payment Deduction: %s') % deduction.substract_account_id.name
|
||||
deduction_line = {
|
||||
'name': deduction_line_name,
|
||||
'date_maturity': self.date,
|
||||
'amount_currency': -deduction.amount_substract, # Negative for credit
|
||||
'currency_id': self.currency_id.id,
|
||||
'debit': 0.0,
|
||||
'credit': deduction_balance,
|
||||
'account_id': deduction.substract_account_id.id,
|
||||
# No partner_id - deduction accounts are typically tax/expense accounts
|
||||
}
|
||||
|
||||
# Add the deduction line to the list
|
||||
line_vals_list.append(deduction_line)
|
||||
|
||||
return line_vals_list
|
||||
|
||||
79
models/payment_deduction_line.py
Normal file
79
models/payment_deduction_line.py
Normal file
@ -0,0 +1,79 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from odoo import models, fields, api, _
|
||||
from odoo.exceptions import ValidationError
|
||||
|
||||
|
||||
class PaymentDeductionLine(models.Model):
|
||||
_name = 'payment.deduction.line'
|
||||
_description = 'Payment Deduction Line'
|
||||
_order = 'sequence, id'
|
||||
|
||||
sequence = fields.Integer(string='Sequence', default=10)
|
||||
payment_id = fields.Many2one(
|
||||
'account.payment',
|
||||
string='Payment',
|
||||
ondelete='cascade',
|
||||
index=True,
|
||||
)
|
||||
batch_payment_line_id = fields.Many2one(
|
||||
'account.batch.payment.line',
|
||||
string='Batch Payment Line',
|
||||
ondelete='cascade',
|
||||
index=True,
|
||||
)
|
||||
company_id = fields.Many2one(
|
||||
'res.company',
|
||||
compute='_compute_company_currency',
|
||||
store=True,
|
||||
readonly=True,
|
||||
)
|
||||
currency_id = fields.Many2one(
|
||||
'res.currency',
|
||||
compute='_compute_company_currency',
|
||||
store=True,
|
||||
readonly=True,
|
||||
)
|
||||
|
||||
@api.depends('payment_id.company_id', 'payment_id.currency_id',
|
||||
'batch_payment_line_id.currency_id')
|
||||
def _compute_company_currency(self):
|
||||
for line in self:
|
||||
if line.payment_id:
|
||||
line.company_id = line.payment_id.company_id
|
||||
line.currency_id = line.payment_id.currency_id
|
||||
elif line.batch_payment_line_id:
|
||||
line.company_id = line.batch_payment_line_id.batch_payment_id.journal_id.company_id
|
||||
line.currency_id = line.batch_payment_line_id.currency_id
|
||||
else:
|
||||
line.company_id = self.env.company
|
||||
line.currency_id = self.env.company.currency_id
|
||||
amount_substract = fields.Monetary(
|
||||
string='Deduction Amount',
|
||||
currency_field='currency_id',
|
||||
required=True,
|
||||
help='Amount to be deducted from the payment (e.g., withholding tax, fees)',
|
||||
)
|
||||
substract_account_id = fields.Many2one(
|
||||
'account.account',
|
||||
string='Deduction Account',
|
||||
required=True,
|
||||
domain="[('account_type', 'not in', ['asset_cash', 'asset_cash_bank', 'asset_receivable', 'liability_payable']), ('deprecated', '=', False)]",
|
||||
help='Account where the deduction will be recorded (use tax payable or expense accounts, NOT payable/receivable accounts)',
|
||||
)
|
||||
name = fields.Char(
|
||||
string='Description',
|
||||
help='Optional description for this deduction',
|
||||
)
|
||||
|
||||
@api.constrains('amount_substract')
|
||||
def _check_amount_substract(self):
|
||||
for line in self:
|
||||
if line.amount_substract <= 0:
|
||||
raise ValidationError(_("Deduction amount must be greater than zero."))
|
||||
|
||||
@api.onchange('substract_account_id')
|
||||
def _onchange_substract_account_id(self):
|
||||
"""Auto-fill description based on account name if not set"""
|
||||
if self.substract_account_id and not self.name:
|
||||
self.name = self.substract_account_id.name
|
||||
3
security/ir.model.access.csv
Normal file
3
security/ir.model.access.csv
Normal file
@ -0,0 +1,3 @@
|
||||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_payment_deduction_line_user,payment.deduction.line.user,model_payment_deduction_line,account.group_account_invoice,1,1,1,1
|
||||
access_payment_deduction_line_manager,payment.deduction.line.manager,model_payment_deduction_line,account.group_account_manager,1,1,1,1
|
||||
|
@ -1,13 +1,49 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<!-- Add deduction lines field to batch payment line tree view -->
|
||||
<record id="view_batch_payment_form_inherit_diff_amount" model="ir.ui.view">
|
||||
<field name="name">account.batch.payment.form.inherit.diff.amount</field>
|
||||
<field name="model">account.batch.payment</field>
|
||||
<field name="inherit_id" ref="vendor_batch_payment_merge.view_batch_payment_form_inherit"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='direct_payment_line_ids']/tree/field[@name='expense_account_id']" position="after">
|
||||
<field name="amount_substract"/>
|
||||
<field name="substract_account_id"/>
|
||||
<!-- Replace the tree view with one that includes a form view for deduction lines -->
|
||||
<xpath expr="//field[@name='direct_payment_line_ids']" position="replace">
|
||||
<field name="direct_payment_line_ids">
|
||||
<tree editable="bottom">
|
||||
<field name="partner_id" domain="parent.batch_type == 'outbound' and [('supplier_rank', '>', 0)] or [('customer_rank', '>', 0)]" options="{'no_create': True}"/>
|
||||
<field name="amount" sum="Total"/>
|
||||
<field name="expense_account_id"/>
|
||||
<field name="amount_substract" sum="Total Deductions" optional="show"/>
|
||||
<field name="memo"/>
|
||||
<field name="date"/>
|
||||
<field name="payment_id" readonly="1"/>
|
||||
</tree>
|
||||
<form>
|
||||
<group>
|
||||
<group name="payment_info">
|
||||
<field name="partner_id" domain="parent.batch_type == 'outbound' and [('supplier_rank', '>', 0)] or [('customer_rank', '>', 0)]"/>
|
||||
<field name="amount"/>
|
||||
<field name="currency_id" invisible="1"/>
|
||||
<field name="expense_account_id"/>
|
||||
<field name="memo"/>
|
||||
<field name="date"/>
|
||||
<field name="payment_id" readonly="1"/>
|
||||
</group>
|
||||
</group>
|
||||
<group string="Deductions" name="deductions">
|
||||
<field name="deduction_line_ids" nolabel="1" context="{'default_currency_id': currency_id}">
|
||||
<tree editable="bottom">
|
||||
<field name="sequence" widget="handle"/>
|
||||
<field name="substract_account_id" required="1"/>
|
||||
<field name="name" placeholder="Description (optional)"/>
|
||||
<field name="amount_substract" required="1" sum="Total"/>
|
||||
<field name="currency_id" column_invisible="1"/>
|
||||
</tree>
|
||||
</field>
|
||||
<field name="amount_substract" readonly="1"/>
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
@ -6,22 +6,32 @@
|
||||
<field name="inherit_id" ref="account.view_account_payment_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<div name="amount_div" position="after">
|
||||
<label for="amount_substract" string="Amount Substract"
|
||||
<label for="deduction_line_ids" string="Deductions"
|
||||
invisible="payment_type != 'outbound'"/>
|
||||
<field name="deduction_line_ids"
|
||||
invisible="payment_type != 'outbound'"
|
||||
readonly="state != 'draft'"
|
||||
nolabel="1">
|
||||
<tree editable="bottom">
|
||||
<field name="sequence" widget="handle"/>
|
||||
<field name="substract_account_id" required="1"/>
|
||||
<field name="name" placeholder="Description (optional)"/>
|
||||
<field name="amount_substract" required="1" sum="Total Deductions"/>
|
||||
<field name="currency_id" column_invisible="1"/>
|
||||
<field name="company_id" column_invisible="1"/>
|
||||
</tree>
|
||||
</field>
|
||||
|
||||
<label for="amount_substract" string="Total Deductions"
|
||||
invisible="payment_type != 'outbound'"/>
|
||||
<div class="o_row" invisible="payment_type != 'outbound'">
|
||||
<field name="amount_substract"
|
||||
widget="monetary"
|
||||
options="{'currency_field': 'currency_id'}"
|
||||
readonly="state != 'draft'"
|
||||
force_save="1"/>
|
||||
</div>
|
||||
<label for="substract_account_id" string="Substract Account"
|
||||
invisible="payment_type != 'outbound'"/>
|
||||
<div class="o_row" invisible="payment_type != 'outbound'">
|
||||
<field name="substract_account_id"
|
||||
readonly="state != 'draft'"
|
||||
readonly="1"
|
||||
force_save="1"/>
|
||||
</div>
|
||||
|
||||
<label for="final_payment_amount" string="Final Payment Amount"
|
||||
invisible="payment_type != 'outbound'"/>
|
||||
<div class="o_row" invisible="payment_type != 'outbound'">
|
||||
|
||||
Loading…
Reference in New Issue
Block a user