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