feat: Implement bank statement line selection with total amount display in footer and reconciliation wizard.
This commit is contained in:
parent
5dfc280ed6
commit
d75a96007e
513
README.md
513
README.md
@ -1,262 +1,253 @@
|
|||||||
# Bank Statement Reconciliation Module
|
# Bank Statement Reconciliation Module
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
This module enhances Odoo's bank statement reconciliation functionality by providing an intuitive interface for reconciling bank statement lines with journal entries.
|
This module enhances Odoo's bank statement reconciliation functionality by providing an intuitive interface for reconciling bank statement lines with journal entries.
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
### Core Functionality
|
### Core Functionality
|
||||||
- **Menu Access**: Direct menu to access bank statement lines
|
- **Menu Access**: Direct menu to access bank statement lines
|
||||||
- **Bank Journal Filtering**: Filter statement lines by specific bank journals
|
- **Bank Journal Filtering**: Filter statement lines by specific bank journals
|
||||||
- **Batch Reconciliation**: Select and reconcile multiple bank lines simultaneously
|
- **Batch Reconciliation**: Select and reconcile multiple bank lines simultaneously
|
||||||
- **Journal Entry Matching**: Wizard to select appropriate journal entries for reconciliation
|
- **Journal Entry Matching**: Wizard to select appropriate journal entries for reconciliation
|
||||||
- **Automatic Reconciliation**: Automatic creation of reconciliation journal entries
|
- **Automatic Reconciliation**: Automatic creation of reconciliation journal entries
|
||||||
|
|
||||||
### New Features (v17.0.1.0.0)
|
### New Features (v17.0.1.0.0)
|
||||||
|
|
||||||
#### 1. Total Selected Amount Widget
|
#### 1. Total Selected Amount Widget
|
||||||
|
|
||||||
A dynamic header widget that displays real-time totals when you select multiple bank statement lines in the list view.
|
A dynamic header widget that displays real-time totals when you select multiple bank statement lines in the list view.
|
||||||
|
|
||||||
**Features:**
|
**Features:**
|
||||||
- **Real-time Calculation**: Automatically calculates the sum of selected lines
|
- **Real-time Calculation**: Automatically calculates the sum of selected lines
|
||||||
- **Visual Indicators**:
|
- **Visual Indicators**:
|
||||||
- Green badge for positive amounts
|
- Green badge for positive amounts
|
||||||
- Red badge for negative amounts
|
- Red badge for negative amounts
|
||||||
- **Selection Counter**: Shows how many lines are currently selected
|
- **Selection Counter**: Shows how many lines are currently selected
|
||||||
- **Currency Display**: Shows the currency of selected lines
|
- **Currency Display**: Shows the currency of selected lines
|
||||||
- **Modern UI**: Clean, Bootstrap-styled interface with icons
|
- **Modern UI**: Clean, Bootstrap-styled interface with icons
|
||||||
|
|
||||||
**How to Use:**
|
**How to Use:**
|
||||||
1. Navigate to: `Accounting > Bank Statement Reconciliation > Bank Statement Lines`
|
1. Navigate to: `Bank Statement Reconciliation`
|
||||||
2. Select one or more bank statement lines by clicking the checkboxes
|
2. Select one or more bank statement lines by clicking the checkboxes
|
||||||
3. The header widget will automatically appear showing:
|
3. The footer will showing:
|
||||||
- Number of selected lines
|
- Total amount of selected lines
|
||||||
- Total amount of selected lines
|
|
||||||
- Currency information
|
## Installation
|
||||||
|
|
||||||
**Visual Layout:**
|
1. Copy the module to your Odoo addons directory:
|
||||||
```
|
```bash
|
||||||
┌─────────────────────────────────────────────────────────────┐
|
cp -r bank_statement_reconciliation /path/to/odoo/addons/
|
||||||
│ ☑ Selected Lines: [3] │ 🧮 Total Amount: [1,234.56] USD │
|
```
|
||||||
└─────────────────────────────────────────────────────────────┘
|
|
||||||
```
|
2. Update the addons list:
|
||||||
|
- Go to `Apps` menu
|
||||||
## Installation
|
- Click `Update Apps List`
|
||||||
|
- Search for "Bank Statement Reconciliation"
|
||||||
1. Copy the module to your Odoo addons directory:
|
|
||||||
```bash
|
3. Install the module:
|
||||||
cp -r bank_statement_reconciliation /path/to/odoo/addons/
|
- Click `Install` button
|
||||||
```
|
|
||||||
|
## Configuration
|
||||||
2. Update the addons list:
|
|
||||||
- Go to `Apps` menu
|
No additional configuration is required. The module works out of the box after installation.
|
||||||
- Click `Update Apps List`
|
|
||||||
- Search for "Bank Statement Reconciliation"
|
## Usage
|
||||||
|
|
||||||
3. Install the module:
|
### Reconciling Bank Statement Lines
|
||||||
- Click `Install` button
|
|
||||||
|
1. **Access Bank Statement Lines**
|
||||||
## Configuration
|
- Navigate to: `Accounting > Bank Statement Reconciliation > Bank Statement Lines`
|
||||||
|
|
||||||
No additional configuration is required. The module works out of the box after installation.
|
2. **Filter Lines**
|
||||||
|
- Use the search bar to filter by:
|
||||||
## Usage
|
- Date
|
||||||
|
- Partner
|
||||||
### Reconciling Bank Statement Lines
|
- Journal
|
||||||
|
- Amount (Income/Expense)
|
||||||
1. **Access Bank Statement Lines**
|
|
||||||
- Navigate to: `Accounting > Bank Statement Reconciliation > Bank Statement Lines`
|
3. **Select Lines for Reconciliation**
|
||||||
|
- Check the boxes next to the lines you want to reconcile
|
||||||
2. **Filter Lines**
|
- The total amount widget will show the sum automatically
|
||||||
- Use the search bar to filter by:
|
|
||||||
- Date
|
4. **Initiate Reconciliation**
|
||||||
- Partner
|
- Click the `Action` menu
|
||||||
- Journal
|
- Select `Reconcile Selected Lines`
|
||||||
- Amount (Income/Expense)
|
- OR click the `Reconcile` button in the form view
|
||||||
|
|
||||||
3. **Select Lines for Reconciliation**
|
5. **Match Journal Entries**
|
||||||
- Check the boxes next to the lines you want to reconcile
|
- The wizard will open showing available journal entries
|
||||||
- The total amount widget will show the sum automatically
|
- Select the appropriate journal entry to match
|
||||||
|
- Confirm the reconciliation
|
||||||
4. **Initiate Reconciliation**
|
|
||||||
- Click the `Action` menu
|
## Technical Details
|
||||||
- Select `Reconcile Selected Lines`
|
|
||||||
- OR click the `Reconcile` button in the form view
|
### Module Structure
|
||||||
|
|
||||||
5. **Match Journal Entries**
|
```
|
||||||
- The wizard will open showing available journal entries
|
bank_statement_reconciliation/
|
||||||
- Select the appropriate journal entry to match
|
├── __init__.py
|
||||||
- Confirm the reconciliation
|
├── __manifest__.py
|
||||||
|
├── README.md
|
||||||
## Technical Details
|
├── models/
|
||||||
|
│ ├── __init__.py
|
||||||
### Module Structure
|
│ ├── account_bank_statement_line.py
|
||||||
|
│ ├── bank_statement_line.py
|
||||||
```
|
│ └── bank_statement_selector.py
|
||||||
bank_statement_reconciliation/
|
├── views/
|
||||||
├── __init__.py
|
│ ├── bank_statement_line_views.xml
|
||||||
├── __manifest__.py
|
│ ├── bank_statement_selector_views.xml
|
||||||
├── README.md
|
│ └── menu.xml
|
||||||
├── models/
|
├── wizards/
|
||||||
│ ├── __init__.py
|
│ ├── __init__.py
|
||||||
│ ├── account_bank_statement_line.py
|
│ ├── bank_reconcile_wizard.py
|
||||||
│ ├── bank_statement_line.py
|
│ └── bank_reconcile_wizard_views.xml
|
||||||
│ └── bank_statement_selector.py
|
├── security/
|
||||||
├── views/
|
│ └── ir.model.access.csv
|
||||||
│ ├── bank_statement_line_views.xml
|
└── static/
|
||||||
│ ├── bank_statement_selector_views.xml
|
└── src/
|
||||||
│ └── menu.xml
|
├── js/
|
||||||
├── wizards/
|
│ ├── bank_statement_total_widget.js
|
||||||
│ ├── __init__.py
|
│ ├── bank_statement_list_controller.js
|
||||||
│ ├── bank_reconcile_wizard.py
|
│ └── bank_statement_list_view.js
|
||||||
│ └── bank_reconcile_wizard_views.xml
|
└── xml/
|
||||||
├── security/
|
├── bank_statement_total_widget.xml
|
||||||
│ └── ir.model.access.csv
|
└── bank_statement_list_view.xml
|
||||||
└── static/
|
```
|
||||||
└── src/
|
|
||||||
├── js/
|
### JavaScript Components
|
||||||
│ ├── bank_statement_total_widget.js
|
|
||||||
│ ├── bank_statement_list_controller.js
|
#### BankStatementTotalWidget
|
||||||
│ └── bank_statement_list_view.js
|
- **Type**: OWL Component
|
||||||
└── xml/
|
- **Purpose**: Displays total amount of selected lines
|
||||||
├── bank_statement_total_widget.xml
|
- **Props**:
|
||||||
└── bank_statement_list_view.xml
|
- `resIds`: Array of selected record IDs
|
||||||
```
|
- **Features**:
|
||||||
|
- Reactive state management
|
||||||
### JavaScript Components
|
- Automatic updates on selection change
|
||||||
|
- Currency formatting
|
||||||
#### BankStatementTotalWidget
|
- Visual styling based on amount (positive/negative)
|
||||||
- **Type**: OWL Component
|
|
||||||
- **Purpose**: Displays total amount of selected lines
|
#### BankStatementListController
|
||||||
- **Props**:
|
- **Type**: List Controller Extension
|
||||||
- `resIds`: Array of selected record IDs
|
- **Purpose**: Extends standard list controller with custom functionality
|
||||||
- **Features**:
|
- **Features**:
|
||||||
- Reactive state management
|
- Provides selected records to the widget
|
||||||
- Automatic updates on selection change
|
- Integrates widget into list view layout
|
||||||
- Currency formatting
|
|
||||||
- Visual styling based on amount (positive/negative)
|
### XML Views
|
||||||
|
|
||||||
#### BankStatementListController
|
#### Tree View Enhancement
|
||||||
- **Type**: List Controller Extension
|
- Added `js_class="bank_statement_list"` attribute
|
||||||
- **Purpose**: Extends standard list controller with custom functionality
|
- Enabled multi-edit mode
|
||||||
- **Features**:
|
- Added monetary widget for amount field
|
||||||
- Provides selected records to the widget
|
- Added currency field for proper formatting
|
||||||
- Integrates widget into list view layout
|
- Includes sum totals in footer
|
||||||
|
|
||||||
### XML Views
|
### Dependencies
|
||||||
|
|
||||||
#### Tree View Enhancement
|
- `account`: Core accounting module
|
||||||
- Added `js_class="bank_statement_list"` attribute
|
- `base`: Odoo base module
|
||||||
- Enabled multi-edit mode
|
- `web`: Web framework for JavaScript components
|
||||||
- Added monetary widget for amount field
|
|
||||||
- Added currency field for proper formatting
|
## Customization
|
||||||
- Includes sum totals in footer
|
|
||||||
|
### Modifying the Widget Appearance
|
||||||
### Dependencies
|
|
||||||
|
Edit [`bank_statement_total_widget.xml`](static/src/xml/bank_statement_total_widget.xml) to customize:
|
||||||
- `account`: Core accounting module
|
- Layout
|
||||||
- `base`: Odoo base module
|
- Colors
|
||||||
- `web`: Web framework for JavaScript components
|
- Icons
|
||||||
|
- Styling
|
||||||
## Customization
|
|
||||||
|
### Extending Functionality
|
||||||
### Modifying the Widget Appearance
|
|
||||||
|
To add more calculations or features:
|
||||||
Edit [`bank_statement_total_widget.xml`](static/src/xml/bank_statement_total_widget.xml) to customize:
|
|
||||||
- Layout
|
1. Edit [`bank_statement_total_widget.js`](static/src/js/bank_statement_total_widget.js)
|
||||||
- Colors
|
2. Add new computed properties or methods
|
||||||
- Icons
|
3. Update the template to display new information
|
||||||
- Styling
|
|
||||||
|
Example - Add average calculation:
|
||||||
### Extending Functionality
|
```javascript
|
||||||
|
get averageAmount() {
|
||||||
To add more calculations or features:
|
if (this.state.selectedCount === 0) return 0;
|
||||||
|
return this.state.totalAmount / this.state.selectedCount;
|
||||||
1. Edit [`bank_statement_total_widget.js`](static/src/js/bank_statement_total_widget.js)
|
}
|
||||||
2. Add new computed properties or methods
|
```
|
||||||
3. Update the template to display new information
|
|
||||||
|
## Troubleshooting
|
||||||
Example - Add average calculation:
|
|
||||||
```javascript
|
### Widget Not Appearing
|
||||||
get averageAmount() {
|
|
||||||
if (this.state.selectedCount === 0) return 0;
|
1. **Clear Browser Cache**
|
||||||
return this.state.totalAmount / this.state.selectedCount;
|
- Hard refresh: `Ctrl+Shift+R` (Windows/Linux) or `Cmd+Shift+R` (Mac)
|
||||||
}
|
|
||||||
```
|
2. **Update Assets**
|
||||||
|
- Navigate to: `Settings > Technical > User Interface > Views`
|
||||||
## Troubleshooting
|
- Click `Regenerate Assets Bundles`
|
||||||
|
|
||||||
### Widget Not Appearing
|
3. **Check JavaScript Console**
|
||||||
|
- Press `F12` to open developer tools
|
||||||
1. **Clear Browser Cache**
|
- Look for any JavaScript errors
|
||||||
- Hard refresh: `Ctrl+Shift+R` (Windows/Linux) or `Cmd+Shift+R` (Mac)
|
|
||||||
|
### Incorrect Totals
|
||||||
2. **Update Assets**
|
|
||||||
- Navigate to: `Settings > Technical > User Interface > Views`
|
1. **Verify Currency Settings**
|
||||||
- Click `Regenerate Assets Bundles`
|
- Ensure all selected lines use the same currency
|
||||||
|
- Check currency rounding settings
|
||||||
3. **Check JavaScript Console**
|
|
||||||
- Press `F12` to open developer tools
|
2. **Check Data Integrity**
|
||||||
- Look for any JavaScript errors
|
- Verify amount fields are populated correctly
|
||||||
|
- Check for null or undefined values
|
||||||
### Incorrect Totals
|
|
||||||
|
## Support
|
||||||
1. **Verify Currency Settings**
|
|
||||||
- Ensure all selected lines use the same currency
|
For issues, questions, or contributions:
|
||||||
- Check currency rounding settings
|
- **Author**: Suherdy Yacob
|
||||||
|
- **Version**: 17.0.1.0.0
|
||||||
2. **Check Data Integrity**
|
- **Odoo Version**: 17.0
|
||||||
- Verify amount fields are populated correctly
|
|
||||||
- Check for null or undefined values
|
## Changelog
|
||||||
|
|
||||||
## Support
|
### Version 17.0.1.0.0
|
||||||
|
- Added total selected amount widget in list view header
|
||||||
For issues, questions, or contributions:
|
- Enhanced tree view with monetary formatting
|
||||||
- **Author**: Suherdy Yacob
|
- Improved user experience with visual indicators
|
||||||
- **Version**: 17.0.1.0.0
|
- Added real-time calculation of selected lines
|
||||||
- **Odoo Version**: 17.0
|
- Implemented modern OWL-based JavaScript components
|
||||||
|
|
||||||
## Changelog
|
### Initial Version
|
||||||
|
- Basic bank statement reconciliation functionality
|
||||||
### Version 17.0.1.0.0
|
- Wizard-based reconciliation process
|
||||||
- Added total selected amount widget in list view header
|
- Multi-line selection support
|
||||||
- Enhanced tree view with monetary formatting
|
- Journal entry matching
|
||||||
- Improved user experience with visual indicators
|
|
||||||
- Added real-time calculation of selected lines
|
## License
|
||||||
- Implemented modern OWL-based JavaScript components
|
|
||||||
|
This module follows the same license as Odoo.
|
||||||
### Initial Version
|
|
||||||
- Basic bank statement reconciliation functionality
|
## Screenshots
|
||||||
- Wizard-based reconciliation process
|
|
||||||
- Multi-line selection support
|
### Total Amount Widget in Action
|
||||||
- Journal entry matching
|
When you select multiple bank statement lines, the widget appears at the top showing:
|
||||||
|
- Number of selected items
|
||||||
## License
|
- Total sum with currency
|
||||||
|
- Color-coded amount (green for positive, red for negative)
|
||||||
This module follows the same license as Odoo.
|
|
||||||
|
### List View Enhancements
|
||||||
## Screenshots
|
- Checkboxes for multi-selection
|
||||||
|
- Amount column with monetary formatting
|
||||||
### Total Amount Widget in Action
|
- Footer totals for all visible records
|
||||||
When you select multiple bank statement lines, the widget appears at the top showing:
|
- Clean, modern interface
|
||||||
- Number of selected items
|
|
||||||
- Total sum with currency
|
## Future Enhancements
|
||||||
- Color-coded amount (green for positive, red for negative)
|
|
||||||
|
Planned features for future releases:
|
||||||
### List View Enhancements
|
- [ ] Support for multi-currency reconciliation
|
||||||
- Checkboxes for multi-selection
|
- [ ] Advanced filtering options
|
||||||
- Amount column with monetary formatting
|
- [ ] Reconciliation history tracking
|
||||||
- Footer totals for all visible records
|
- [ ] Export selected lines to Excel
|
||||||
- Clean, modern interface
|
- [ ] Batch operations for common reconciliation patterns
|
||||||
|
|
||||||
## Future Enhancements
|
|
||||||
|
|
||||||
Planned features for future releases:
|
|
||||||
- [ ] Support for multi-currency reconciliation
|
|
||||||
- [ ] Advanced filtering options
|
|
||||||
- [ ] Reconciliation history tracking
|
|
||||||
- [ ] Export selected lines to Excel
|
|
||||||
- [ ] Batch operations for common reconciliation patterns
|
|
||||||
- [ ] AI-powered suggestion for matching entries
|
- [ ] AI-powered suggestion for matching entries
|
||||||
@ -1,2 +1,2 @@
|
|||||||
from . import models
|
from . import models
|
||||||
from . import wizards
|
from . import wizards
|
||||||
@ -1,32 +1,32 @@
|
|||||||
{
|
{
|
||||||
'name': 'Bank Statement Reconciliation',
|
'name': 'Bank Statement Reconciliation',
|
||||||
'version': '17.0.1.0.0',
|
'version': '17.0.1.0.0',
|
||||||
'category': 'Accounting',
|
'category': 'Accounting',
|
||||||
'summary': 'Reconcile bank statement lines with journal entries',
|
'summary': 'Reconcile bank statement lines with journal entries',
|
||||||
'description': """
|
'description': """
|
||||||
This module allows users to reconcile bank statement lines with journal entries.
|
This module allows users to reconcile bank statement lines with journal entries.
|
||||||
Features:
|
Features:
|
||||||
- Menu to access bank statement lines
|
- Menu to access bank statement lines
|
||||||
- Filter by bank journal
|
- Filter by bank journal
|
||||||
- Select multiple bank lines to reconcile
|
- Select multiple bank lines to reconcile
|
||||||
- Wizard to select journal entries for reconciliation
|
- Wizard to select journal entries for reconciliation
|
||||||
- Automatic creation of reconciliation journal entries
|
- Automatic creation of reconciliation journal entries
|
||||||
- Total selected amount widget in list view header
|
- Total selected amount widget in list view header
|
||||||
""",
|
""",
|
||||||
'author': 'Suherdy Yacob',
|
'author': 'Suherdy Yacob',
|
||||||
'depends': [
|
'depends': [
|
||||||
'account',
|
'account',
|
||||||
'base',
|
'base',
|
||||||
'web',
|
'web',
|
||||||
],
|
],
|
||||||
'data': [
|
'data': [
|
||||||
'security/ir.model.access.csv',
|
'security/ir.model.access.csv',
|
||||||
'views/bank_statement_line_views.xml',
|
'views/bank_statement_line_views.xml',
|
||||||
'views/bank_statement_selector_views.xml',
|
'views/bank_statement_selector_views.xml',
|
||||||
'wizards/bank_reconcile_wizard_views.xml',
|
'wizards/bank_reconcile_wizard_views.xml',
|
||||||
'views/menu.xml',
|
'views/menu.xml',
|
||||||
],
|
],
|
||||||
# Tree view includes sum="Total Amount" footer for displaying totals
|
# Tree view includes sum="Total Amount" footer for displaying totals
|
||||||
'installable': True,
|
'installable': True,
|
||||||
'auto_install': False,
|
'auto_install': False,
|
||||||
}
|
}
|
||||||
BIN
__pycache__/__init__.cpython-310.pyc
Normal file
BIN
__pycache__/__init__.cpython-310.pyc
Normal file
Binary file not shown.
@ -1,3 +1,3 @@
|
|||||||
from . import bank_statement_line
|
from . import bank_statement_line
|
||||||
from . import bank_statement_selector
|
from . import bank_statement_selector
|
||||||
from . import account_bank_statement_line
|
from . import account_bank_statement_line
|
||||||
BIN
models/__pycache__/__init__.cpython-310.pyc
Normal file
BIN
models/__pycache__/__init__.cpython-310.pyc
Normal file
Binary file not shown.
BIN
models/__pycache__/account_bank_statement_line.cpython-310.pyc
Normal file
BIN
models/__pycache__/account_bank_statement_line.cpython-310.pyc
Normal file
Binary file not shown.
BIN
models/__pycache__/bank_statement_line.cpython-310.pyc
Normal file
BIN
models/__pycache__/bank_statement_line.cpython-310.pyc
Normal file
Binary file not shown.
BIN
models/__pycache__/bank_statement_selector.cpython-310.pyc
Normal file
BIN
models/__pycache__/bank_statement_selector.cpython-310.pyc
Normal file
Binary file not shown.
@ -1,35 +1,35 @@
|
|||||||
from odoo import models, fields, api
|
from odoo import models, fields, api
|
||||||
from odoo.exceptions import UserError
|
from odoo.exceptions import UserError
|
||||||
|
|
||||||
|
|
||||||
class AccountBankStatementLine(models.Model):
|
class AccountBankStatementLine(models.Model):
|
||||||
_inherit = 'account.bank.statement.line'
|
_inherit = 'account.bank.statement.line'
|
||||||
|
|
||||||
def action_reconcile_selected_lines(self):
|
def action_reconcile_selected_lines(self):
|
||||||
"""Open the reconciliation wizard for selected lines"""
|
"""Open the reconciliation wizard for selected lines"""
|
||||||
# Get the selected records from the context
|
# Get the selected records from the context
|
||||||
active_ids = self.env.context.get('active_ids')
|
active_ids = self.env.context.get('active_ids')
|
||||||
active_model = self.env.context.get('active_model')
|
active_model = self.env.context.get('active_model')
|
||||||
|
|
||||||
if active_model == 'account.bank.statement.line' and active_ids:
|
if active_model == 'account.bank.statement.line' and active_ids:
|
||||||
selected_lines = self.browse(active_ids)
|
selected_lines = self.browse(active_ids)
|
||||||
else:
|
else:
|
||||||
# If called from a single record, use self
|
# If called from a single record, use self
|
||||||
selected_lines = self
|
selected_lines = self
|
||||||
|
|
||||||
# Filter out already reconciled lines by checking if they have a move_id with reconciliation in the name
|
# Filter out already reconciled lines by checking if they have a move_id with reconciliation in the name
|
||||||
unreconciled_lines = selected_lines.filtered(lambda line: not line.move_id)
|
unreconciled_lines = selected_lines.filtered(lambda line: not line.move_id)
|
||||||
|
|
||||||
if not unreconciled_lines:
|
if not unreconciled_lines:
|
||||||
raise UserError("All selected bank statement lines have already been reconciled.")
|
raise UserError("All selected bank statement lines have already been reconciled.")
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'name': 'Select Journal Entry to Reconcile',
|
'name': 'Select Journal Entry to Reconcile',
|
||||||
'type': 'ir.actions.act_window',
|
'type': 'ir.actions.act_window',
|
||||||
'res_model': 'bank.reconcile.wizard',
|
'res_model': 'bank.reconcile.wizard',
|
||||||
'view_mode': 'form',
|
'view_mode': 'form',
|
||||||
'target': 'new',
|
'target': 'new',
|
||||||
'context': {
|
'context': {
|
||||||
'default_bank_line_ids': unreconciled_lines.ids,
|
'default_bank_line_ids': unreconciled_lines.ids,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,53 +1,53 @@
|
|||||||
from odoo import models, fields, api
|
from odoo import models, fields, api
|
||||||
from odoo.exceptions import UserError
|
from odoo.exceptions import UserError
|
||||||
|
|
||||||
|
|
||||||
class BankStatementLine(models.Model):
|
class BankStatementLine(models.Model):
|
||||||
_name = 'bank.statement.line'
|
_name = 'bank.statement.line'
|
||||||
_description = 'Bank Statement Line Selection'
|
_description = 'Bank Statement Line Selection'
|
||||||
|
|
||||||
@api.model
|
@api.model
|
||||||
def default_get(self, fields):
|
def default_get(self, fields):
|
||||||
res = super().default_get(fields)
|
res = super().default_get(fields)
|
||||||
active_model = self.env.context.get('active_model')
|
active_model = self.env.context.get('active_model')
|
||||||
active_ids = self.env.context.get('active_ids')
|
active_ids = self.env.context.get('active_ids')
|
||||||
|
|
||||||
if active_model == 'account.bank.statement.line' and active_ids:
|
if active_model == 'account.bank.statement.line' and active_ids:
|
||||||
statement_lines = self.env['account.bank.statement.line'].browse(active_ids)
|
statement_lines = self.env['account.bank.statement.line'].browse(active_ids)
|
||||||
res['line_ids'] = [(6, 0, statement_lines.ids)]
|
res['line_ids'] = [(6, 0, statement_lines.ids)]
|
||||||
|
|
||||||
return res
|
return res
|
||||||
|
|
||||||
journal_id = fields.Many2one('account.journal', string='Bank Journal',
|
journal_id = fields.Many2one('account.journal', string='Bank Journal',
|
||||||
domain=[('type', '=', 'bank')])
|
domain=[('type', '=', 'bank')])
|
||||||
line_ids = fields.Many2many('account.bank.statement.line', string='Bank Statement Lines')
|
line_ids = fields.Many2many('account.bank.statement.line', string='Bank Statement Lines')
|
||||||
selected_line_ids = fields.Many2many('account.bank.statement.line',
|
selected_line_ids = fields.Many2many('account.bank.statement.line',
|
||||||
'bank_statement_line_rel',
|
'bank_statement_line_rel',
|
||||||
'wizard_id', 'line_id',
|
'wizard_id', 'line_id',
|
||||||
string='Selected Bank Lines')
|
string='Selected Bank Lines')
|
||||||
|
|
||||||
@api.onchange('journal_id')
|
@api.onchange('journal_id')
|
||||||
def _onchange_journal_id(self):
|
def _onchange_journal_id(self):
|
||||||
if self.journal_id:
|
if self.journal_id:
|
||||||
statement_lines = self.env['account.bank.statement.line'].search([
|
statement_lines = self.env['account.bank.statement.line'].search([
|
||||||
('journal_id', '=', self.journal_id.id)
|
('journal_id', '=', self.journal_id.id)
|
||||||
])
|
])
|
||||||
self.line_ids = statement_lines
|
self.line_ids = statement_lines
|
||||||
else:
|
else:
|
||||||
self.line_ids = False
|
self.line_ids = False
|
||||||
|
|
||||||
def action_open_reconcile_wizard(self):
|
def action_open_reconcile_wizard(self):
|
||||||
"""Open the reconciliation wizard"""
|
"""Open the reconciliation wizard"""
|
||||||
if not self.selected_line_ids:
|
if not self.selected_line_ids:
|
||||||
raise UserError("Please select at least one bank statement line to reconcile.")
|
raise UserError("Please select at least one bank statement line to reconcile.")
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'name': 'Select Journal Entry to Reconcile',
|
'name': 'Select Journal Entry to Reconcile',
|
||||||
'type': 'ir.actions.act_window',
|
'type': 'ir.actions.act_window',
|
||||||
'res_model': 'bank.reconcile.wizard',
|
'res_model': 'bank.reconcile.wizard',
|
||||||
'view_mode': 'form',
|
'view_mode': 'form',
|
||||||
'target': 'new',
|
'target': 'new',
|
||||||
'context': {
|
'context': {
|
||||||
'default_bank_line_ids': self.selected_line_ids.ids,
|
'default_bank_line_ids': self.selected_line_ids.ids,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,29 +1,29 @@
|
|||||||
from odoo import models, fields, api
|
from odoo import models, fields, api
|
||||||
|
|
||||||
|
|
||||||
class BankStatementSelector(models.TransientModel):
|
class BankStatementSelector(models.TransientModel):
|
||||||
_name = 'bank.statement.selector'
|
_name = 'bank.statement.selector'
|
||||||
_description = 'Bank Statement Selector'
|
_description = 'Bank Statement Selector'
|
||||||
|
|
||||||
journal_id = fields.Many2one('account.journal',
|
journal_id = fields.Many2one('account.journal',
|
||||||
string='Bank Journal',
|
string='Bank Journal',
|
||||||
domain=[('type', '=', 'bank')],
|
domain=[('type', '=', 'bank')],
|
||||||
required=True)
|
required=True)
|
||||||
|
|
||||||
def action_show_statement_lines(self):
|
def action_show_statement_lines(self):
|
||||||
"""Open the bank statement lines for the selected journal"""
|
"""Open the bank statement lines for the selected journal"""
|
||||||
action = {
|
action = {
|
||||||
'type': 'ir.actions.act_window',
|
'type': 'ir.actions.act_window',
|
||||||
'name': 'Bank Statement Lines',
|
'name': 'Bank Statement Lines',
|
||||||
'res_model': 'account.bank.statement.line',
|
'res_model': 'account.bank.statement.line',
|
||||||
'view_mode': 'tree,form',
|
'view_mode': 'tree,form',
|
||||||
'domain': [('journal_id', '=', self.journal_id.id)],
|
'domain': [('journal_id', '=', self.journal_id.id)],
|
||||||
'context': {
|
'context': {
|
||||||
'search_default_journal_id': self.journal_id.id,
|
'search_default_journal_id': self.journal_id.id,
|
||||||
},
|
},
|
||||||
'views': [
|
'views': [
|
||||||
(self.env.ref('bank_statement_reconciliation.view_account_bank_statement_line_tree').id, 'tree'),
|
(self.env.ref('bank_statement_reconciliation.view_account_bank_statement_line_tree').id, 'tree'),
|
||||||
(self.env.ref('bank_statement_reconciliation.view_account_bank_statement_line_form').id, 'form')
|
(self.env.ref('bank_statement_reconciliation.view_account_bank_statement_line_form').id, 'form')
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
return action
|
return action
|
||||||
@ -1,4 +1,4 @@
|
|||||||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||||
access_bank_statement_line,access_bank_statement_line,model_bank_statement_line,account.group_account_user,1,1,1,1
|
access_bank_statement_line,access_bank_statement_line,model_bank_statement_line,account.group_account_user,1,1,1,1
|
||||||
access_bank_reconcile_wizard,access_bank_reconcile_wizard,model_bank_reconcile_wizard,account.group_account_user,1,1
|
access_bank_reconcile_wizard,access_bank_reconcile_wizard,model_bank_reconcile_wizard,account.group_account_user,1,1
|
||||||
access_bank_statement_selector,access_bank_statement_selector,model_bank_statement_selector,account.group_account_user,1,1,1,1
|
access_bank_statement_selector,access_bank_statement_selector,model_bank_statement_selector,account.group_account_user,1,1,1,1
|
||||||
|
@ -1,29 +1,29 @@
|
|||||||
/** @odoo-module **/
|
/** @odoo-module **/
|
||||||
|
|
||||||
import { ListController } from "@web/views/list/list_controller";
|
import { ListController } from "@web/views/list/list_controller";
|
||||||
import { BankStatementTotalWidget } from "./bank_statement_total_widget";
|
import { BankStatementTotalWidget } from "./bank_statement_total_widget";
|
||||||
import { patch } from "@web/core/utils/patch";
|
import { patch } from "@web/core/utils/patch";
|
||||||
|
|
||||||
patch(ListController.prototype, {
|
patch(ListController.prototype, {
|
||||||
get selectedRecords() {
|
get selectedRecords() {
|
||||||
if (this.props.resModel === "account.bank.statement.line") {
|
if (this.props.resModel === "account.bank.statement.line") {
|
||||||
return this.model.root.selection.map(record => record.resId);
|
return this.model.root.selection.map(record => record.resId);
|
||||||
}
|
}
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
export class BankStatementListController extends ListController {
|
export class BankStatementListController extends ListController {
|
||||||
setup() {
|
setup() {
|
||||||
super.setup();
|
super.setup();
|
||||||
}
|
}
|
||||||
|
|
||||||
get selectedRecords() {
|
get selectedRecords() {
|
||||||
return this.model.root.selection.map(record => record.resId);
|
return this.model.root.selection.map(record => record.resId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BankStatementListController.components = {
|
BankStatementListController.components = {
|
||||||
...ListController.components,
|
...ListController.components,
|
||||||
BankStatementTotalWidget,
|
BankStatementTotalWidget,
|
||||||
};
|
};
|
||||||
@ -1,12 +1,12 @@
|
|||||||
/** @odoo-module **/
|
/** @odoo-module **/
|
||||||
|
|
||||||
import { registry } from "@web/core/registry";
|
import { registry } from "@web/core/registry";
|
||||||
import { listView } from "@web/views/list/list_view";
|
import { listView } from "@web/views/list/list_view";
|
||||||
import { BankStatementListController } from "./bank_statement_list_controller";
|
import { BankStatementListController } from "./bank_statement_list_controller";
|
||||||
|
|
||||||
export const bankStatementListView = {
|
export const bankStatementListView = {
|
||||||
...listView,
|
...listView,
|
||||||
Controller: BankStatementListController,
|
Controller: BankStatementListController,
|
||||||
};
|
};
|
||||||
|
|
||||||
registry.category("views").add("bank_statement_list", bankStatementListView);
|
registry.category("views").add("bank_statement_list", bankStatementListView);
|
||||||
@ -1,81 +1,81 @@
|
|||||||
/** @odoo-module **/
|
/** @odoo-module **/
|
||||||
|
|
||||||
import { Component, useState, onWillStart, onWillUpdateProps } from "@odoo/owl";
|
import { Component, useState, onWillStart, onWillUpdateProps } from "@odoo/owl";
|
||||||
import { registry } from "@web/core/registry";
|
import { registry } from "@web/core/registry";
|
||||||
import { useService } from "@web/core/utils/hooks";
|
import { useService } from "@web/core/utils/hooks";
|
||||||
|
|
||||||
export class BankStatementTotalWidget extends Component {
|
export class BankStatementTotalWidget extends Component {
|
||||||
setup() {
|
setup() {
|
||||||
this.orm = useService("orm");
|
this.orm = useService("orm");
|
||||||
this.state = useState({
|
this.state = useState({
|
||||||
totalAmount: 0,
|
totalAmount: 0,
|
||||||
selectedCount: 0,
|
selectedCount: 0,
|
||||||
currency: null,
|
currency: null,
|
||||||
});
|
});
|
||||||
|
|
||||||
onWillStart(async () => {
|
onWillStart(async () => {
|
||||||
await this.updateTotals();
|
await this.updateTotals();
|
||||||
});
|
});
|
||||||
|
|
||||||
onWillUpdateProps(async (nextProps) => {
|
onWillUpdateProps(async (nextProps) => {
|
||||||
await this.updateTotals(nextProps);
|
await this.updateTotals(nextProps);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateTotals(props = this.props) {
|
async updateTotals(props = this.props) {
|
||||||
const resIds = props.resIds || [];
|
const resIds = props.resIds || [];
|
||||||
|
|
||||||
if (resIds.length === 0) {
|
if (resIds.length === 0) {
|
||||||
this.state.totalAmount = 0;
|
this.state.totalAmount = 0;
|
||||||
this.state.selectedCount = 0;
|
this.state.selectedCount = 0;
|
||||||
this.state.currency = null;
|
this.state.currency = null;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const records = await this.orm.searchRead(
|
const records = await this.orm.searchRead(
|
||||||
"account.bank.statement.line",
|
"account.bank.statement.line",
|
||||||
[["id", "in", resIds]],
|
[["id", "in", resIds]],
|
||||||
["amount", "currency_id"]
|
["amount", "currency_id"]
|
||||||
);
|
);
|
||||||
|
|
||||||
let total = 0;
|
let total = 0;
|
||||||
let currency = null;
|
let currency = null;
|
||||||
|
|
||||||
records.forEach(record => {
|
records.forEach(record => {
|
||||||
total += record.amount || 0;
|
total += record.amount || 0;
|
||||||
if (!currency && record.currency_id) {
|
if (!currency && record.currency_id) {
|
||||||
currency = record.currency_id;
|
currency = record.currency_id;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.state.totalAmount = total;
|
this.state.totalAmount = total;
|
||||||
this.state.selectedCount = records.length;
|
this.state.selectedCount = records.length;
|
||||||
this.state.currency = currency;
|
this.state.currency = currency;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error fetching bank statement totals:", error);
|
console.error("Error fetching bank statement totals:", error);
|
||||||
this.state.totalAmount = 0;
|
this.state.totalAmount = 0;
|
||||||
this.state.selectedCount = 0;
|
this.state.selectedCount = 0;
|
||||||
this.state.currency = null;
|
this.state.currency = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get formattedTotal() {
|
get formattedTotal() {
|
||||||
if (!this.state.currency) {
|
if (!this.state.currency) {
|
||||||
return this.state.totalAmount.toFixed(2);
|
return this.state.totalAmount.toFixed(2);
|
||||||
}
|
}
|
||||||
// Format with currency symbol if available
|
// Format with currency symbol if available
|
||||||
return this.state.totalAmount.toFixed(2);
|
return this.state.totalAmount.toFixed(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
get displayClass() {
|
get displayClass() {
|
||||||
return this.state.totalAmount < 0 ? 'text-danger' : 'text-success';
|
return this.state.totalAmount < 0 ? 'text-danger' : 'text-success';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BankStatementTotalWidget.template = "bank_statement_reconciliation.BankStatementTotalWidget";
|
BankStatementTotalWidget.template = "bank_statement_reconciliation.BankStatementTotalWidget";
|
||||||
BankStatementTotalWidget.props = {
|
BankStatementTotalWidget.props = {
|
||||||
resIds: { type: Array, optional: true },
|
resIds: { type: Array, optional: true },
|
||||||
};
|
};
|
||||||
|
|
||||||
registry.category("view_widgets").add("bank_statement_total_widget", BankStatementTotalWidget);
|
registry.category("view_widgets").add("bank_statement_total_widget", BankStatementTotalWidget);
|
||||||
@ -1,32 +1,32 @@
|
|||||||
/** @odoo-module **/
|
/** @odoo-module **/
|
||||||
|
|
||||||
import { patch } from "@web/core/utils/patch";
|
import { patch } from "@web/core/utils/patch";
|
||||||
import { ListController } from "@web/views/list/list_controller";
|
import { ListController } from "@web/views/list/list_controller";
|
||||||
|
|
||||||
patch(ListController.prototype, {
|
patch(ListController.prototype, {
|
||||||
/**
|
/**
|
||||||
* Compute total amount of selected bank statement lines
|
* Compute total amount of selected bank statement lines
|
||||||
*/
|
*/
|
||||||
get selectedBankLinesTotal() {
|
get selectedBankLinesTotal() {
|
||||||
if (this.props.resModel !== "account.bank.statement.line") {
|
if (this.props.resModel !== "account.bank.statement.line") {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const selection = this.model.root.selection;
|
const selection = this.model.root.selection;
|
||||||
if (!selection || selection.length === 0) {
|
if (!selection || selection.length === 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
let total = 0;
|
let total = 0;
|
||||||
selection.forEach(record => {
|
selection.forEach(record => {
|
||||||
const amount = record.data.amount || 0;
|
const amount = record.data.amount || 0;
|
||||||
total += amount;
|
total += amount;
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
count: selection.length,
|
count: selection.length,
|
||||||
total: total.toFixed(2),
|
total: total.toFixed(2),
|
||||||
currency: selection[0]?.data.currency_id?.[1] || 'IDR'
|
currency: selection[0]?.data.currency_id?.[1] || 'IDR'
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -1,10 +1,10 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<templates xml:space="preserve">
|
<templates xml:space="preserve">
|
||||||
<t t-name="bank_statement_reconciliation.BankStatementListController" t-inherit="web.ListView" t-inherit-mode="extension">
|
<t t-name="bank_statement_reconciliation.BankStatementListController" t-inherit="web.ListView" t-inherit-mode="extension">
|
||||||
<xpath expr="//div[hasclass('o_content')]" position="before">
|
<xpath expr="//div[hasclass('o_content')]" position="before">
|
||||||
<div class="o_bank_statement_header_widget p-3 mx-3" t-if="props.resModel === 'account.bank.statement.line' and selectedRecords.length > 0">
|
<div class="o_bank_statement_header_widget p-3 mx-3" t-if="props.resModel === 'account.bank.statement.line' and selectedRecords.length > 0">
|
||||||
<BankStatementTotalWidget resIds="selectedRecords"/>
|
<BankStatementTotalWidget resIds="selectedRecords"/>
|
||||||
</div>
|
</div>
|
||||||
</xpath>
|
</xpath>
|
||||||
</t>
|
</t>
|
||||||
</templates>
|
</templates>
|
||||||
@ -1,15 +1,15 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<templates xml:space="preserve">
|
<templates xml:space="preserve">
|
||||||
<t t-name="bank_statement_reconciliation.SelectionInfo" t-inherit="web.ListView" t-inherit-mode="extension">
|
<t t-name="bank_statement_reconciliation.SelectionInfo" t-inherit="web.ListView" t-inherit-mode="extension">
|
||||||
<xpath expr="//Layout" position="inside">
|
<xpath expr="//Layout" position="inside">
|
||||||
<t t-set-slot="layout-actions">
|
<t t-set-slot="layout-actions">
|
||||||
<div t-if="model.root.selection.length > 0" class="alert alert-info d-flex align-items-center gap-3 m-2" role="alert">
|
<div t-if="model.root.selection.length > 0" class="alert alert-info d-flex align-items-center gap-3 m-2" role="alert">
|
||||||
<i class="fa fa-info-circle fa-lg"/>
|
<i class="fa fa-info-circle fa-lg"/>
|
||||||
<strong t-esc="model.root.selection.length"/> lines selected
|
<strong t-esc="model.root.selection.length"/> lines selected
|
||||||
<span class="mx-2">|</span>
|
<span class="mx-2">|</span>
|
||||||
Total: <strong t-esc="model.root.selection.reduce((sum, rec) => sum + (rec.data.amount || 0), 0).toFixed(2)"/>
|
Total: <strong t-esc="model.root.selection.reduce((sum, rec) => sum + (rec.data.amount || 0), 0).toFixed(2)"/>
|
||||||
</div>
|
</div>
|
||||||
</t>
|
</t>
|
||||||
</xpath>
|
</xpath>
|
||||||
</t>
|
</t>
|
||||||
</templates>
|
</templates>
|
||||||
@ -1,19 +1,19 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<templates xml:space="preserve">
|
<templates xml:space="preserve">
|
||||||
<t t-name="bank_statement_reconciliation.BankStatementTotalWidget">
|
<t t-name="bank_statement_reconciliation.BankStatementTotalWidget">
|
||||||
<div class="o_bank_statement_total_widget d-flex align-items-center gap-3 px-3 py-2 bg-light border rounded">
|
<div class="o_bank_statement_total_widget d-flex align-items-center gap-3 px-3 py-2 bg-light border rounded">
|
||||||
<div class="d-flex align-items-center gap-2">
|
<div class="d-flex align-items-center gap-2">
|
||||||
<i class="fa fa-check-square-o text-primary" style="font-size: 1.2em;"/>
|
<i class="fa fa-check-square-o text-primary" style="font-size: 1.2em;"/>
|
||||||
<span class="fw-bold">Selected Lines:</span>
|
<span class="fw-bold">Selected Lines:</span>
|
||||||
<span class="badge bg-primary" t-esc="state.selectedCount"/>
|
<span class="badge bg-primary" t-esc="state.selectedCount"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="vr"/>
|
<div class="vr"/>
|
||||||
<div class="d-flex align-items-center gap-2">
|
<div class="d-flex align-items-center gap-2">
|
||||||
<i class="fa fa-calculator text-info" style="font-size: 1.2em;"/>
|
<i class="fa fa-calculator text-info" style="font-size: 1.2em;"/>
|
||||||
<span class="fw-bold">Total Amount:</span>
|
<span class="fw-bold">Total Amount:</span>
|
||||||
<span t-attf-class="badge {{displayClass}} fs-6 px-3" t-esc="formattedTotal"/>
|
<span t-attf-class="badge {{displayClass}} fs-6 px-3" t-esc="formattedTotal"/>
|
||||||
<span t-if="state.currency" class="text-muted small" t-esc="state.currency[1]"/>
|
<span t-if="state.currency" class="text-muted small" t-esc="state.currency[1]"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</t>
|
</t>
|
||||||
</templates>
|
</templates>
|
||||||
@ -1,11 +1,11 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<templates xml:space="preserve">
|
<templates xml:space="preserve">
|
||||||
<t t-name="bank_statement_reconciliation.SelectedAmountBadge" t-inherit="web.ListController" t-inherit-mode="extension">
|
<t t-name="bank_statement_reconciliation.SelectedAmountBadge" t-inherit="web.ListController" t-inherit-mode="extension">
|
||||||
<xpath expr="//div[hasclass('o_cp_action_menus')]" position="before">
|
<xpath expr="//div[hasclass('o_cp_action_menus')]" position="before">
|
||||||
<div t-if="selectedBankLinesTotal" class="badge bg-info text-dark fs-5 px-3 py-2 me-2">
|
<div t-if="selectedBankLinesTotal" class="badge bg-info text-dark fs-5 px-3 py-2 me-2">
|
||||||
<i class="fa fa-calculator me-1"/>
|
<i class="fa fa-calculator me-1"/>
|
||||||
Total: Rp <t t-esc="selectedBankLinesTotal.total"/>
|
Total: Rp <t t-esc="selectedBankLinesTotal.total"/>
|
||||||
</div>
|
</div>
|
||||||
</xpath>
|
</xpath>
|
||||||
</t>
|
</t>
|
||||||
</templates>
|
</templates>
|
||||||
@ -1,109 +1,109 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<odoo>
|
<odoo>
|
||||||
<!-- Action to open the bank statement lines view -->
|
<!-- Action to open the bank statement lines view -->
|
||||||
<record id="action_bank_statement_lines" model="ir.actions.act_window">
|
<record id="action_bank_statement_lines" model="ir.actions.act_window">
|
||||||
<field name="name">Bank Statement Lines</field>
|
<field name="name">Bank Statement Lines</field>
|
||||||
<field name="res_model">account.bank.statement.line</field>
|
<field name="res_model">account.bank.statement.line</field>
|
||||||
<field name="view_mode">tree,form</field>
|
<field name="view_mode">tree,form</field>
|
||||||
<field name="context">{'tree_view_ref': 'bank_statement_reconciliation.view_account_bank_statement_line_tree'}</field>
|
<field name="context">{'tree_view_ref': 'bank_statement_reconciliation.view_account_bank_statement_line_tree'}</field>
|
||||||
<field name="help" type="html">
|
<field name="help" type="html">
|
||||||
<p class="o_view_nocontent_smiling_face">
|
<p class="o_view_nocontent_smiling_face">
|
||||||
Select a bank journal to view its statement lines
|
Select a bank journal to view its statement lines
|
||||||
</p>
|
</p>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<!-- Server action for reconciliation -->
|
<!-- Server action for reconciliation -->
|
||||||
<record id="action_reconcile_bank_lines" model="ir.actions.server">
|
<record id="action_reconcile_bank_lines" model="ir.actions.server">
|
||||||
<field name="name">Reconcile Selected Lines</field>
|
<field name="name">Reconcile Selected Lines</field>
|
||||||
<field name="model_id" ref="account.model_account_bank_statement_line"/>
|
<field name="model_id" ref="account.model_account_bank_statement_line"/>
|
||||||
<field name="binding_model_id" ref="account.model_account_bank_statement_line"/>
|
<field name="binding_model_id" ref="account.model_account_bank_statement_line"/>
|
||||||
<field name="state">code</field>
|
<field name="state">code</field>
|
||||||
<field name="code">
|
<field name="code">
|
||||||
action = {
|
action = {
|
||||||
'name': 'Select Journal Entry to Reconcile',
|
'name': 'Select Journal Entry to Reconcile',
|
||||||
'type': 'ir.actions.act_window',
|
'type': 'ir.actions.act_window',
|
||||||
'res_model': 'bank.reconcile.wizard',
|
'res_model': 'bank.reconcile.wizard',
|
||||||
'view_mode': 'form',
|
'view_mode': 'form',
|
||||||
'target': 'new',
|
'target': 'new',
|
||||||
'context': {
|
'context': {
|
||||||
'default_bank_line_ids': env.context.get('active_ids'),
|
'default_bank_line_ids': env.context.get('active_ids'),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<!-- Tree view for bank statement lines -->
|
<!-- Tree view for bank statement lines -->
|
||||||
<record id="view_account_bank_statement_line_tree" model="ir.ui.view">
|
<record id="view_account_bank_statement_line_tree" model="ir.ui.view">
|
||||||
<field name="name">account.bank.statement.line.tree</field>
|
<field name="name">account.bank.statement.line.tree</field>
|
||||||
<field name="model">account.bank.statement.line</field>
|
<field name="model">account.bank.statement.line</field>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<tree string="Bank Statement Lines" create="0" delete="0" decoration-danger="amount < 0" decoration-muted="move_id and 'Reconciliation:' in move_id.name" multi_edit="1">
|
<tree string="Bank Statement Lines" create="0" delete="0" decoration-danger="amount < 0" decoration-muted="move_id and 'Reconciliation:' in move_id.name" multi_edit="1">
|
||||||
<field name="company_id" column_invisible="True"/>
|
<field name="company_id" column_invisible="True"/>
|
||||||
<field name="currency_id" column_invisible="True"/>
|
<field name="currency_id" column_invisible="True"/>
|
||||||
<field name="suitable_journal_ids" column_invisible="True"/>
|
<field name="suitable_journal_ids" column_invisible="True"/>
|
||||||
<field name="date"/>
|
<field name="date"/>
|
||||||
<field name="name"/>
|
<field name="name"/>
|
||||||
<field name="partner_id"/>
|
<field name="partner_id"/>
|
||||||
<field name="amount" sum="Total Amount" widget="monetary"/>
|
<field name="amount" sum="Total Amount" widget="monetary"/>
|
||||||
<field name="journal_id"/>
|
<field name="journal_id"/>
|
||||||
<field name="statement_id"/>
|
<field name="statement_id"/>
|
||||||
<field name="move_id"/>
|
<field name="move_id"/>
|
||||||
</tree>
|
</tree>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<!-- Form view for bank statement lines -->
|
<!-- Form view for bank statement lines -->
|
||||||
<record id="view_account_bank_statement_line_form" model="ir.ui.view">
|
<record id="view_account_bank_statement_line_form" model="ir.ui.view">
|
||||||
<field name="name">account.bank.statement.line.form</field>
|
<field name="name">account.bank.statement.line.form</field>
|
||||||
<field name="model">account.bank.statement.line</field>
|
<field name="model">account.bank.statement.line</field>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<form string="Bank Statement Line">
|
<form string="Bank Statement Line">
|
||||||
<header>
|
<header>
|
||||||
<button name="action_reconcile_selected_lines" type="object" string="Reconcile" class="btn-primary" invisible="move_id and 'Reconciliation:' in move_id.name"/>
|
<button name="action_reconcile_selected_lines" type="object" string="Reconcile" class="btn-primary" invisible="move_id and 'Reconciliation:' in move_id.name"/>
|
||||||
</header>
|
</header>
|
||||||
<sheet>
|
<sheet>
|
||||||
<group>
|
<group>
|
||||||
<group>
|
<group>
|
||||||
<field name="date"/>
|
<field name="date"/>
|
||||||
<field name="name"/>
|
<field name="name"/>
|
||||||
<field name="ref"/>
|
<field name="ref"/>
|
||||||
</group>
|
</group>
|
||||||
<group>
|
<group>
|
||||||
<field name="amount"/>
|
<field name="amount"/>
|
||||||
<field name="partner_id"/>
|
<field name="partner_id"/>
|
||||||
<field name="journal_id" readonly="1"/>
|
<field name="journal_id" readonly="1"/>
|
||||||
</group>
|
</group>
|
||||||
</group>
|
</group>
|
||||||
<group>
|
<group>
|
||||||
<field name="statement_id"/>
|
<field name="statement_id"/>
|
||||||
<field name="move_id"/>
|
<field name="move_id"/>
|
||||||
<field name="company_id" invisible="1"/>
|
<field name="company_id" invisible="1"/>
|
||||||
</group>
|
</group>
|
||||||
</sheet>
|
</sheet>
|
||||||
</form>
|
</form>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<!-- Search view for bank statement lines -->
|
<!-- Search view for bank statement lines -->
|
||||||
<record id="view_account_bank_statement_line_search" model="ir.ui.view">
|
<record id="view_account_bank_statement_line_search" model="ir.ui.view">
|
||||||
<field name="name">account.bank.statement.line.search</field>
|
<field name="name">account.bank.statement.line.search</field>
|
||||||
<field name="model">account.bank.statement.line</field>
|
<field name="model">account.bank.statement.line</field>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<search>
|
<search>
|
||||||
<field name="name"/>
|
<field name="name"/>
|
||||||
<field name="partner_id"/>
|
<field name="partner_id"/>
|
||||||
<field name="journal_id"/>
|
<field name="journal_id"/>
|
||||||
<field name="date"/>
|
<field name="date"/>
|
||||||
<filter name="positive_amount" string="Income" domain="[('amount', '>', 0)]"/>
|
<filter name="positive_amount" string="Income" domain="[('amount', '>', 0)]"/>
|
||||||
<filter name="negative_amount" string="Expense" domain="[('amount', '<', 0)]"/>
|
<filter name="negative_amount" string="Expense" domain="[('amount', '<', 0)]"/>
|
||||||
<filter name="hide_reconciled" string="Hide Reconciled" domain="[('move_id', 'not ilike', '%Reconciliation:%')]" help="Hide lines that have been reconciled"/>
|
<filter name="hide_reconciled" string="Hide Reconciled" domain="[('move_id', 'not ilike', '%Reconciliation:%')]" help="Hide lines that have been reconciled"/>
|
||||||
<filter name="show_all" string="Show All" domain="[]" help="Show all lines including reconciled"/>
|
<filter name="show_all" string="Show All" domain="[]" help="Show all lines including reconciled"/>
|
||||||
<group expand="0" string="Group By">
|
<group expand="0" string="Group By">
|
||||||
<filter name="group_by_journal" string="Journal" context="{'group_by': 'journal_id'}"/>
|
<filter name="group_by_journal" string="Journal" context="{'group_by': 'journal_id'}"/>
|
||||||
<filter name="group_by_date" string="Date" context="{'group_by': 'date'}"/>
|
<filter name="group_by_date" string="Date" context="{'group_by': 'date'}"/>
|
||||||
</group>
|
</group>
|
||||||
</search>
|
</search>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
</odoo>
|
</odoo>
|
||||||
@ -1,29 +1,29 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<odoo>
|
<odoo>
|
||||||
<!-- Form view for bank statement selector -->
|
<!-- Form view for bank statement selector -->
|
||||||
<record id="view_bank_statement_selector_form" model="ir.ui.view">
|
<record id="view_bank_statement_selector_form" model="ir.ui.view">
|
||||||
<field name="name">bank.statement.selector.form</field>
|
<field name="name">bank.statement.selector.form</field>
|
||||||
<field name="model">bank.statement.selector</field>
|
<field name="model">bank.statement.selector</field>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<form string="Select Bank Journal">
|
<form string="Select Bank Journal">
|
||||||
<group>
|
<group>
|
||||||
<field name="journal_id" options="{'no_create': True}"/>
|
<field name="journal_id" options="{'no_create': True}"/>
|
||||||
</group>
|
</group>
|
||||||
<footer>
|
<footer>
|
||||||
<button name="action_show_statement_lines" type="object" string="Show Statement Lines"
|
<button name="action_show_statement_lines" type="object" string="Show Statement Lines"
|
||||||
class="btn-primary"/>
|
class="btn-primary"/>
|
||||||
<button string="Cancel" class="btn-secondary" special="cancel"/>
|
<button string="Cancel" class="btn-secondary" special="cancel"/>
|
||||||
</footer>
|
</footer>
|
||||||
</form>
|
</form>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<!-- Action to open the bank statement selector -->
|
<!-- Action to open the bank statement selector -->
|
||||||
<record id="action_bank_statement_selector" model="ir.actions.act_window">
|
<record id="action_bank_statement_selector" model="ir.actions.act_window">
|
||||||
<field name="name">Select Bank Journal</field>
|
<field name="name">Select Bank Journal</field>
|
||||||
<field name="res_model">bank.statement.selector</field>
|
<field name="res_model">bank.statement.selector</field>
|
||||||
<field name="view_mode">form</field>
|
<field name="view_mode">form</field>
|
||||||
<field name="target">new</field>
|
<field name="target">new</field>
|
||||||
<field name="view_id" ref="view_bank_statement_selector_form"/>
|
<field name="view_id" ref="view_bank_statement_selector_form"/>
|
||||||
</record>
|
</record>
|
||||||
</odoo>
|
</odoo>
|
||||||
@ -1,15 +1,15 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<odoo>
|
<odoo>
|
||||||
<!-- Top level menu for Bank Statement Reconciliation -->
|
<!-- Top level menu for Bank Statement Reconciliation -->
|
||||||
<menuitem id="menu_bank_statement_root"
|
<menuitem id="menu_bank_statement_root"
|
||||||
name="Bank Statement Reconciliation"
|
name="Bank Statement Reconciliation"
|
||||||
sequence="50"
|
sequence="50"
|
||||||
web_icon="account,static/description/icon.png"
|
web_icon="account,static/description/icon.png"
|
||||||
groups="account.group_account_user"/>
|
groups="account.group_account_user"/>
|
||||||
|
|
||||||
<menuitem id="menu_bank_statement_lines"
|
<menuitem id="menu_bank_statement_lines"
|
||||||
name="Bank Statement Lines"
|
name="Bank Statement Lines"
|
||||||
parent="menu_bank_statement_root"
|
parent="menu_bank_statement_root"
|
||||||
action="action_bank_statement_selector"
|
action="action_bank_statement_selector"
|
||||||
sequence="10"/>
|
sequence="10"/>
|
||||||
</odoo>
|
</odoo>
|
||||||
BIN
wizards/__pycache__/__init__.cpython-310.pyc
Normal file
BIN
wizards/__pycache__/__init__.cpython-310.pyc
Normal file
Binary file not shown.
BIN
wizards/__pycache__/bank_reconcile_wizard.cpython-310.pyc
Normal file
BIN
wizards/__pycache__/bank_reconcile_wizard.cpython-310.pyc
Normal file
Binary file not shown.
@ -1,93 +1,93 @@
|
|||||||
from odoo import models, fields, api
|
from odoo import models, fields, api
|
||||||
from odoo.exceptions import UserError
|
from odoo.exceptions import UserError
|
||||||
|
|
||||||
|
|
||||||
class BankReconcileWizard(models.TransientModel):
|
class BankReconcileWizard(models.TransientModel):
|
||||||
_name = 'bank.reconcile.wizard'
|
_name = 'bank.reconcile.wizard'
|
||||||
_description = 'Bank Reconcile Wizard'
|
_description = 'Bank Reconcile Wizard'
|
||||||
|
|
||||||
bank_line_ids = fields.Many2many('account.bank.statement.line',
|
bank_line_ids = fields.Many2many('account.bank.statement.line',
|
||||||
string='Selected Bank Lines',
|
string='Selected Bank Lines',
|
||||||
readonly=True)
|
readonly=True)
|
||||||
journal_entry_id = fields.Many2one('account.move',
|
journal_entry_id = fields.Many2one('account.move',
|
||||||
string='Journal Entry to Reconcile',
|
string='Journal Entry to Reconcile',
|
||||||
domain=[('state', '=', 'posted')])
|
domain=[('state', '=', 'posted')])
|
||||||
journal_entry_line_id = fields.Many2one('account.move.line',
|
journal_entry_line_id = fields.Many2one('account.move.line',
|
||||||
string='Journal Entry Line to Reconcile',
|
string='Journal Entry Line to Reconcile',
|
||||||
domain="[('move_id', '=', journal_entry_id), ('reconciled', '=', False)]")
|
domain="[('move_id', '=', journal_entry_id), ('reconciled', '=', False)]")
|
||||||
total_bank_line_amount = fields.Float(string='Total Bank Line Amount', compute='_compute_total_bank_line_amount', store=True)
|
total_bank_line_amount = fields.Float(string='Total Bank Line Amount', compute='_compute_total_bank_line_amount', store=True)
|
||||||
|
|
||||||
@api.onchange('journal_entry_id')
|
@api.onchange('journal_entry_id')
|
||||||
def _onchange_journal_entry_id(self):
|
def _onchange_journal_entry_id(self):
|
||||||
"""Reset journal entry line when journal entry changes"""
|
"""Reset journal entry line when journal entry changes"""
|
||||||
if self.journal_entry_id:
|
if self.journal_entry_id:
|
||||||
self.journal_entry_line_id = False
|
self.journal_entry_line_id = False
|
||||||
else:
|
else:
|
||||||
self.journal_entry_line_id = False
|
self.journal_entry_line_id = False
|
||||||
|
|
||||||
|
|
||||||
@api.depends('bank_line_ids')
|
@api.depends('bank_line_ids')
|
||||||
def _compute_total_bank_line_amount(self):
|
def _compute_total_bank_line_amount(self):
|
||||||
"""Compute total amount of selected bank lines"""
|
"""Compute total amount of selected bank lines"""
|
||||||
for record in self:
|
for record in self:
|
||||||
record.total_bank_line_amount = sum(line.amount for line in record.bank_line_ids)
|
record.total_bank_line_amount = sum(line.amount for line in record.bank_line_ids)
|
||||||
|
|
||||||
def action_reconcile(self):
|
def action_reconcile(self):
|
||||||
"""Perform the reconciliation for each selected bank line"""
|
"""Perform the reconciliation for each selected bank line"""
|
||||||
if not self.journal_entry_id:
|
if not self.journal_entry_id:
|
||||||
raise UserError("Please select a journal entry to reconcile.")
|
raise UserError("Please select a journal entry to reconcile.")
|
||||||
|
|
||||||
if not self.journal_entry_line_id:
|
if not self.journal_entry_line_id:
|
||||||
raise UserError("Please select a journal entry line to reconcile.")
|
raise UserError("Please select a journal entry line to reconcile.")
|
||||||
|
|
||||||
# Check if any of the selected bank lines are already reconciled
|
# Check if any of the selected bank lines are already reconciled
|
||||||
for bank_line in self.bank_line_ids:
|
for bank_line in self.bank_line_ids:
|
||||||
if bank_line.move_id and bank_line.move_id.ref and 'Reconciliation:' in bank_line.move_id.ref:
|
if bank_line.move_id and bank_line.move_id.ref and 'Reconciliation:' in bank_line.move_id.ref:
|
||||||
raise UserError(f"Bank statement line '{bank_line.ref}' has already been reconciled and cannot be reconciled again.")
|
raise UserError(f"Bank statement line '{bank_line.ref}' has already been reconciled and cannot be reconciled again.")
|
||||||
|
|
||||||
# Process each selected bank line individually
|
# Process each selected bank line individually
|
||||||
for bank_line in self.bank_line_ids:
|
for bank_line in self.bank_line_ids:
|
||||||
self._reconcile_single_line(bank_line, self.journal_entry_line_id)
|
self._reconcile_single_line(bank_line, self.journal_entry_line_id)
|
||||||
|
|
||||||
|
|
||||||
return {'type': 'ir.actions.act_window_close'}
|
return {'type': 'ir.actions.act_window_close'}
|
||||||
|
|
||||||
def _reconcile_single_line(self, bank_line, journal_entry_line):
|
def _reconcile_single_line(self, bank_line, journal_entry_line):
|
||||||
"""Reconcile a single bank line with a journal entry line"""
|
"""Reconcile a single bank line with a journal entry line"""
|
||||||
|
|
||||||
# Create a journal entry to balance the transaction
|
# Create a journal entry to balance the transaction
|
||||||
# This mimics the standard Odoo reconciliation widget behavior.
|
# This mimics the standard Odoo reconciliation widget behavior.
|
||||||
move = self.env['account.move'].create({
|
move = self.env['account.move'].create({
|
||||||
'journal_id': bank_line.journal_id.id,
|
'journal_id': bank_line.journal_id.id,
|
||||||
'date': bank_line.date,
|
'date': bank_line.date,
|
||||||
'ref': f'Reconciliation: {bank_line.name or "Bank Line"}',
|
'ref': f'Reconciliation: {bank_line.name or "Bank Line"}',
|
||||||
'move_type': 'entry',
|
'move_type': 'entry',
|
||||||
'line_ids': [
|
'line_ids': [
|
||||||
(0, 0, {
|
(0, 0, {
|
||||||
'account_id': bank_line.journal_id.default_account_id.id,
|
'account_id': bank_line.journal_id.default_account_id.id,
|
||||||
'debit': bank_line.amount if bank_line.amount > 0 else 0,
|
'debit': bank_line.amount if bank_line.amount > 0 else 0,
|
||||||
'credit': -bank_line.amount if bank_line.amount < 0 else 0,
|
'credit': -bank_line.amount if bank_line.amount < 0 else 0,
|
||||||
'name': f'Bank Reconciliation: {bank_line.name or ""}',
|
'name': f'Bank Reconciliation: {bank_line.name or ""}',
|
||||||
}),
|
}),
|
||||||
(0, 0, {
|
(0, 0, {
|
||||||
'account_id': journal_entry_line.account_id.id,
|
'account_id': journal_entry_line.account_id.id,
|
||||||
'debit': -bank_line.amount if bank_line.amount < 0 else 0,
|
'debit': -bank_line.amount if bank_line.amount < 0 else 0,
|
||||||
'credit': bank_line.amount if bank_line.amount > 0 else 0,
|
'credit': bank_line.amount if bank_line.amount > 0 else 0,
|
||||||
'name': f'Bank Reconciliation: {journal_entry_line.name or ""}',
|
'name': f'Bank Reconciliation: {journal_entry_line.name or ""}',
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
move.action_post()
|
move.action_post()
|
||||||
|
|
||||||
# Link the bank statement line to the new journal entry
|
# Link the bank statement line to the new journal entry
|
||||||
bank_line.write({
|
bank_line.write({
|
||||||
'move_id': move.id,
|
'move_id': move.id,
|
||||||
})
|
})
|
||||||
|
|
||||||
# Find the corresponding line in the new move and reconcile with the journal entry line
|
# Find the corresponding line in the new move and reconcile with the journal entry line
|
||||||
move_line = move.line_ids.filtered(lambda l: l.account_id.id == journal_entry_line.account_id.id)
|
move_line = move.line_ids.filtered(lambda l: l.account_id.id == journal_entry_line.account_id.id)
|
||||||
if move_line:
|
if move_line:
|
||||||
try:
|
try:
|
||||||
(journal_entry_line + move_line).reconcile()
|
(journal_entry_line + move_line).reconcile()
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|||||||
@ -1,36 +1,36 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<odoo>
|
<odoo>
|
||||||
<!-- Wizard form view -->
|
<!-- Wizard form view -->
|
||||||
<record id="view_bank_reconcile_wizard_form" model="ir.ui.view">
|
<record id="view_bank_reconcile_wizard_form" model="ir.ui.view">
|
||||||
<field name="name">bank.reconcile.wizard.form</field>
|
<field name="name">bank.reconcile.wizard.form</field>
|
||||||
<field name="model">bank.reconcile.wizard</field>
|
<field name="model">bank.reconcile.wizard</field>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<form string="Reconcile Bank Lines">
|
<form string="Reconcile Bank Lines">
|
||||||
<group>
|
<group>
|
||||||
<field name="bank_line_ids" widget="many2many" options="{'no_create': True}" readonly="1"/>
|
<field name="bank_line_ids" widget="many2many" options="{'no_create': True}" readonly="1"/>
|
||||||
</group>
|
</group>
|
||||||
<group>
|
<group>
|
||||||
<field name="total_bank_line_amount" readonly="1"/>
|
<field name="total_bank_line_amount" readonly="1"/>
|
||||||
<field name="journal_entry_id" options="{'no_create': True}"/>
|
<field name="journal_entry_id" options="{'no_create': True}"/>
|
||||||
<field name="journal_entry_line_id"
|
<field name="journal_entry_line_id"
|
||||||
domain="[('move_id', '=', journal_entry_id), ('reconciled', '=', False)]"
|
domain="[('move_id', '=', journal_entry_id), ('reconciled', '=', False)]"
|
||||||
invisible="journal_entry_id == False"/>
|
invisible="journal_entry_id == False"/>
|
||||||
</group>
|
</group>
|
||||||
<footer>
|
<footer>
|
||||||
<button name="action_reconcile" type="object" string="Reconcile"
|
<button name="action_reconcile" type="object" string="Reconcile"
|
||||||
class="btn-primary"
|
class="btn-primary"
|
||||||
invisible="journal_entry_id == False or journal_entry_line_id == False"/>
|
invisible="journal_entry_id == False or journal_entry_line_id == False"/>
|
||||||
<button string="Cancel" class="btn-secondary" special="cancel"/>
|
<button string="Cancel" class="btn-secondary" special="cancel"/>
|
||||||
</footer>
|
</footer>
|
||||||
</form>
|
</form>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<!-- Action to open the wizard -->
|
<!-- Action to open the wizard -->
|
||||||
<record id="action_bank_reconcile_wizard" model="ir.actions.act_window">
|
<record id="action_bank_reconcile_wizard" model="ir.actions.act_window">
|
||||||
<field name="name">Select Journal Entry to Reconcile</field>
|
<field name="name">Select Journal Entry to Reconcile</field>
|
||||||
<field name="res_model">bank.reconcile.wizard</field>
|
<field name="res_model">bank.reconcile.wizard</field>
|
||||||
<field name="view_mode">form</field>
|
<field name="view_mode">form</field>
|
||||||
<field name="target">new</field>
|
<field name="target">new</field>
|
||||||
</record>
|
</record>
|
||||||
</odoo>
|
</odoo>
|
||||||
Loading…
Reference in New Issue
Block a user