From d75a96007e612f3688ff61a404a89233f35162a9 Mon Sep 17 00:00:00 2001 From: "admin.suherdy" Date: Sat, 6 Dec 2025 19:13:17 +0700 Subject: [PATCH] feat: Implement bank statement line selection with total amount display in footer and reconciliation wizard. --- README.md | 513 +++++++++--------- __init__.py | 2 +- __manifest__.py | 62 +-- __pycache__/__init__.cpython-310.pyc | Bin 0 -> 258 bytes models/__init__.py | 4 +- models/__pycache__/__init__.cpython-310.pyc | Bin 0 -> 344 bytes ...ccount_bank_statement_line.cpython-310.pyc | Bin 0 -> 1451 bytes .../bank_statement_line.cpython-310.pyc | Bin 0 -> 2098 bytes .../bank_statement_selector.cpython-310.pyc | Bin 0 -> 1362 bytes models/account_bank_statement_line.py | 68 +-- models/bank_statement_line.py | 104 ++-- models/bank_statement_selector.py | 56 +- security/ir.model.access.csv | 6 +- .../src/js/bank_statement_list_controller.js | 56 +- static/src/js/bank_statement_list_view.js | 22 +- static/src/js/bank_statement_total_widget.js | 160 +++--- static/src/js/selected_amount_badge.js | 62 +-- static/src/xml/bank_statement_list_view.xml | 18 +- .../src/xml/bank_statement_selection_info.xml | 28 +- .../src/xml/bank_statement_total_widget.xml | 36 +- static/src/xml/selected_amount_badge.xml | 20 +- views/bank_statement_line_views.xml | 216 ++++---- views/bank_statement_selector_views.xml | 56 +- views/menu.xml | 28 +- wizards/__pycache__/__init__.cpython-310.pyc | Bin 0 -> 251 bytes .../bank_reconcile_wizard.cpython-310.pyc | Bin 0 -> 3521 bytes wizards/bank_reconcile_wizard.py | 186 +++---- wizards/bank_reconcile_wizard_views.xml | 70 +-- 28 files changed, 882 insertions(+), 891 deletions(-) create mode 100644 __pycache__/__init__.cpython-310.pyc create mode 100644 models/__pycache__/__init__.cpython-310.pyc create mode 100644 models/__pycache__/account_bank_statement_line.cpython-310.pyc create mode 100644 models/__pycache__/bank_statement_line.cpython-310.pyc create mode 100644 models/__pycache__/bank_statement_selector.cpython-310.pyc create mode 100644 wizards/__pycache__/__init__.cpython-310.pyc create mode 100644 wizards/__pycache__/bank_reconcile_wizard.cpython-310.pyc diff --git a/README.md b/README.md index f1a201e..93fe163 100644 --- a/README.md +++ b/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 \ No newline at end of file diff --git a/__init__.py b/__init__.py index 6ed2c21..cf2479f 100644 --- a/__init__.py +++ b/__init__.py @@ -1,2 +1,2 @@ -from . import models +from . import models from . import wizards \ No newline at end of file diff --git a/__manifest__.py b/__manifest__.py index 8de75bd..77b0680 100644 --- a/__manifest__.py +++ b/__manifest__.py @@ -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, } \ No newline at end of file diff --git a/__pycache__/__init__.cpython-310.pyc b/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..172acbafd6827fb5ee05552369d3fa846f3f7a92 GIT binary patch literal 258 zcmYk0L2AP=5Je?BZ9|Bm2j~S%!6K_{LdXe9A-imZq7g{M(gaB+I5+Z9dIfL0$`wi% z9qsyI{=5&v@UdxDjPy1A+IQODCHz-K;Xsq#$bbRwndc|Y3s=O|sUohAtX(`fowR&@ z_6Vj=L@zgYR}s=jThA<(SFt9WSbQp6?8gd=-iS0<6JhK|rSW|5>Z(Ggv2!3k$80fZ z`Y8|)H(Q~Hl+h~y3`v|-xX6@MHr|9RqtSHidZ)6(Af$A`WhuMsI4^fpZ0OCt^h^t~ HHGAcMQk+C` literal 0 HcmV?d00001 diff --git a/models/__init__.py b/models/__init__.py index 96b9f9b..b794ae3 100644 --- a/models/__init__.py +++ b/models/__init__.py @@ -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 \ No newline at end of file diff --git a/models/__pycache__/__init__.cpython-310.pyc b/models/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..02963476487c2473cb6a923546adf96e8c9da27b GIT binary patch literal 344 zcmZ9Hv1-FG5QZh&Eg>Wj=+L1r5HA*)x|EV92!(E5gd!bSMA8LG9{fn{BY7I%!X0nBk6j-g92KBCh)Ck89$(uZf#i z*4}(^vbTJ`JF9S!DXR<~LYB@3pz{5qoWOz37^(H3w8oLF3rm?iwav_8St-^<8j?2_ zZwnXsMlqlVk;Va{nYu}7JRiNfs?cfdtPw9$9x!M$AkZKl9)%uLMz4&)ki_E62%5~+ kS(PmY;c3hzA*BsAOW9qgdG$oa(ZO^1Zz?-%*oN=;FDjp6Y5)KL literal 0 HcmV?d00001 diff --git a/models/__pycache__/account_bank_statement_line.cpython-310.pyc b/models/__pycache__/account_bank_statement_line.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e5e3cc45bde503f10be8bf5fdf03f41b64f35f0d GIT binary patch literal 1451 zcmbVM&5k2A5VqUhoz9R65@KKl2byCzbhMX+!)llXt&mnQAVyqrX*q3&bk=PL+nH>l z>}7Y(JOPK{$Se8EiC37*Qq`RaGYEu)qpDQ7?E3kt+~)ZBh`Y}tY5xV+&o4apvXR<k0@#i$$bw!& zxL@f@de9=!q8)^P9@!6e6o_229iCx2+L4!R$F3nQkz5hji+8ab`9!3z=_@LFA`^Xa zB;FE(UA#zZDvp0ip@8A`;kQevb3d24m6g#|t!nOTqw{sW)5-O|jvXnVvO#$#qegq88)tHhvDtLRZH|81wMcakX;ZG+YRy-54P+50IDlD;syi zFy8m4{M%v7qgZZ2_E_;|D){LM=8p4_k?pg8Yj=S-7<~vO%UjUO7PR8AG8I?u6ok(0 z_VXu7{RJ&%ksng-kk04)Qs!J)$;Bq0N@&z=DN+>Mk1yK35?YOeC9+S^U;P5%A9 zlX81f+kIvZ|I2l)g;{S;+L=7~D!N{W7@FM#rsX=E2sz^`(+R2d3YUQPs!r~hU z3?n2V2IOWIhsE}Bdw3to@XksfG8Y}X?bLMa7_WTvAKgIbE(bPbLpq2CG-g8 literal 0 HcmV?d00001 diff --git a/models/__pycache__/bank_statement_line.cpython-310.pyc b/models/__pycache__/bank_statement_line.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..08f6cb540f63dc5bba84a99df0570de84f82eebd GIT binary patch literal 2098 zcmaJ?OOM<{5bkb2#xpzn-VKBhWRQ4_5FWt+E&)ZLfP_ehSaI>ia$LPTo_Oq`+mp>$ z!-b8MQ~m*m%`tze#f?+`!U`0s+B1_)KzP(WUFGWT`l`MvSDTwXhR+|*{u<2##{MMX z^5dd#6NmmBCt$z}HsLX!h*(UV*x{rTg*)+LkF)O>IN&~F;7UIB&z!ge-Vq!4&v7ps zIL4n;APa5$<6IV?jgwCE0XN;BwN$s1s#HdXm!Hm3&<}ATS z+e?Ep9(QCg?t%wCbWS(~Pn@`inhoee4>q2NxWAP8unAkRjXE#hl-~Ik>^$YL3ww_k zp0W-5aPWx5JCB*m;#~xAXm-C&%lk)lTFZ$n>mTw`Hv9Kb73q~ODoA;q?83ESNS5J| zEM!*aRhfxP*nC_&%b{aj)a;C%^96s(e-#Th7Gvk!1(KY#Bv5h}4mkIP`gq~uKs#`* zvU6|Y;yVvq@D>=BW9Nh~1o$`DLLh+79n(+Ig$FXRDKNdIl!LywmS$NsE9>Y#06ix! z701a01Teu3gO2g^Y$}!60C}9wiaI%wwQ*$mz;v>ztmQ+LNaf#C)v1=opQtf~xxTi(xj?bu~!=s!|ULS@QA@CDF|+FY=VKGHhA-x)C`NP3LM8 z9qi)JTR8Q_7T@B1vBUScE829gvrWm4E`_AoUPX3X%~Y8dP2bYv`&Pn&aO?S0UhprC zOCAn{@pY~8^2GRnzUQT)i<<+xYkiF+l^$?)9bcL^Uc+Xyq-0^br+Jeqz>JxWRp!v_ zw^Wo6+9SzfZF)=Z&@!V;uO1?+hvOR@w)~N7OkKg514qgUK=50Men{R0OI%<_ z*aB9ofp^EkQ19V6>Kabp4!l;Nh$3W}s%&IL4r&7x1EKcG@{p!C*V9#8nS%uLHcHDA znY?tG!l3&&`J%`B+<(z?dZPJ&5UyipQ}bV&UqMXhiIf)cN4Ow#x>FM{%nri=BuY#rSPxjeONJRfD1?P_7@28!oO&ue<%3=4jb&5 zAV~;Ol9*mX0A>ZP`$_W4EG?FAJZpkVkUCTOl;WxABWOI^CTu%sdsuKgE$5$M{w$eI z*NPL=SsJTPXj8D_t9l=v{C~q5rKc`jElkIV&<4qOWW5 z=AF`hao(1#ZnSOBb*-z``OWK(k)4M5mTw#)lKHlvU+cw#^rAAN_?JtV*hH_8gq zXKcY1e3oE-{q5Rt{EHtF$bRGt4uhH4?T6j|+Du#s7=7RWia+Csz{%!=hf8h8?Ocy3 zuJIw~ac!&)0CbP6Y;Nt*AsOC91>URTamrZy!7l|ME5QtjNT zE2`vHkyoq=(*JF$i(L|(^gUh4C~ev3IPf~C?i$BI7Z0sHRWtT6*j9hp#vTd6MEVi2 zg@Kr8`!ptA&n6;D#C;aiEzmzP{}w8}_#}l>&zf>s+PrePf$8V# zc8*w}v#A5;ZhttfR-wgP27u+7UP0sEz)iPpcU5WM0r_$rv6=+23UhaPRDkZnoM3?A z4J0BFoW4_@3Gvr;d7XE-H_j~r0xJb8)PN81EGp*|0E_6B<` F`5U6 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, }; \ No newline at end of file diff --git a/static/src/js/bank_statement_list_view.js b/static/src/js/bank_statement_list_view.js index 84a5970..000a115 100644 --- a/static/src/js/bank_statement_list_view.js +++ b/static/src/js/bank_statement_list_view.js @@ -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); \ No newline at end of file diff --git a/static/src/js/bank_statement_total_widget.js b/static/src/js/bank_statement_total_widget.js index 8af20ed..e208569 100644 --- a/static/src/js/bank_statement_total_widget.js +++ b/static/src/js/bank_statement_total_widget.js @@ -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); \ No newline at end of file diff --git a/static/src/js/selected_amount_badge.js b/static/src/js/selected_amount_badge.js index bd8a3a7..4bfec5c 100644 --- a/static/src/js/selected_amount_badge.js +++ b/static/src/js/selected_amount_badge.js @@ -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' + }; + } }); \ No newline at end of file diff --git a/static/src/xml/bank_statement_list_view.xml b/static/src/xml/bank_statement_list_view.xml index 9cf71cc..1376bb4 100644 --- a/static/src/xml/bank_statement_list_view.xml +++ b/static/src/xml/bank_statement_list_view.xml @@ -1,10 +1,10 @@ - - - - -
- -
-
-
+ + + + +
+ +
+
+
\ No newline at end of file diff --git a/static/src/xml/bank_statement_selection_info.xml b/static/src/xml/bank_statement_selection_info.xml index 1e54796..25c4ceb 100644 --- a/static/src/xml/bank_statement_selection_info.xml +++ b/static/src/xml/bank_statement_selection_info.xml @@ -1,15 +1,15 @@ - - - - - - - - - + + + + + + + + + \ No newline at end of file diff --git a/static/src/xml/bank_statement_total_widget.xml b/static/src/xml/bank_statement_total_widget.xml index d20436a..ab368d7 100644 --- a/static/src/xml/bank_statement_total_widget.xml +++ b/static/src/xml/bank_statement_total_widget.xml @@ -1,19 +1,19 @@ - - - -
-
- - Selected Lines: - -
-
-
- - Total Amount: - - -
-
- + + + +
+
+ + Selected Lines: + +
+
+
+ + Total Amount: + + +
+
+ \ No newline at end of file diff --git a/static/src/xml/selected_amount_badge.xml b/static/src/xml/selected_amount_badge.xml index 9107333..f8889d4 100644 --- a/static/src/xml/selected_amount_badge.xml +++ b/static/src/xml/selected_amount_badge.xml @@ -1,11 +1,11 @@ - - - - -
- - Total: Rp -
-
-
+ + + + +
+ + Total: Rp +
+
+
\ No newline at end of file diff --git a/views/bank_statement_line_views.xml b/views/bank_statement_line_views.xml index 218c8ec..ecbdf6f 100644 --- a/views/bank_statement_line_views.xml +++ b/views/bank_statement_line_views.xml @@ -1,109 +1,109 @@ - - - - - Bank Statement Lines - account.bank.statement.line - tree,form - {'tree_view_ref': 'bank_statement_reconciliation.view_account_bank_statement_line_tree'} - -

- Select a bank journal to view its statement lines -

-
-
- - - - Reconcile Selected Lines - - - 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'), - } - } - - - - - - account.bank.statement.line.tree - account.bank.statement.line - - - - - - - - - - - - - - - - - - - account.bank.statement.line.form - account.bank.statement.line - -
-
-
- - - - - - - - - - - - - - - - - - - -
-
-
- - - - account.bank.statement.line.search - account.bank.statement.line - - - - - - - - - - - - - - - - - + + + + + Bank Statement Lines + account.bank.statement.line + tree,form + {'tree_view_ref': 'bank_statement_reconciliation.view_account_bank_statement_line_tree'} + +

+ Select a bank journal to view its statement lines +

+
+
+ + + + Reconcile Selected Lines + + + 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'), + } + } + + + + + + account.bank.statement.line.tree + account.bank.statement.line + + + + + + + + + + + + + + + + + + + account.bank.statement.line.form + account.bank.statement.line + +
+
+
+ + + + + + + + + + + + + + + + + + + +
+
+
+ + + + account.bank.statement.line.search + account.bank.statement.line + + + + + + + + + + + + + + + + +
\ No newline at end of file diff --git a/views/bank_statement_selector_views.xml b/views/bank_statement_selector_views.xml index 407e2cc..94a5942 100644 --- a/views/bank_statement_selector_views.xml +++ b/views/bank_statement_selector_views.xml @@ -1,29 +1,29 @@ - - - - - bank.statement.selector.form - bank.statement.selector - -
- - - -
-
-
-
-
- - - - Select Bank Journal - bank.statement.selector - form - new - - + + + + + bank.statement.selector.form + bank.statement.selector + +
+ + + +
+
+
+
+
+ + + + Select Bank Journal + bank.statement.selector + form + new + +
\ No newline at end of file diff --git a/views/menu.xml b/views/menu.xml index 87cde3f..d09a2fa 100644 --- a/views/menu.xml +++ b/views/menu.xml @@ -1,15 +1,15 @@ - - - - - - + + + + + + \ No newline at end of file diff --git a/wizards/__pycache__/__init__.cpython-310.pyc b/wizards/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4e7101f48b4a1928d63715cae878d3ed271d307e GIT binary patch literal 251 zcmYjLu?oU46iljv2!$?wfm4?RCl?XFKm<3J5c2{JHhCpUk@`peQdcJzKR_Hz6~u#g z$Gze1FwdtX;czDr3Xq0WP4JM?liqi+Ru*CorKp4oieo+ zXLFGrwq@26KSW%KA1C?Hv*8t5%|lyh4;|~I!sEuuMmnaD8Q{AvRw)QUa|Fc2lB+gE uv=RVa;GeD#Wz<%?_-i#X8g%?y9k>w2nJ5Hnx_+{<2yLy`!`v_oD##l-B}YyG literal 0 HcmV?d00001 diff --git a/wizards/__pycache__/bank_reconcile_wizard.cpython-310.pyc b/wizards/__pycache__/bank_reconcile_wizard.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9e92604e45149ae8ec303fe7a133d3fab7b3fb25 GIT binary patch literal 3521 zcmbVPZEqXL5#GHw9;r9#)wbL=mnMbG*rD7QaDYNK+&XcA!VwJ1ZCVD#;dHYUk3Qbf zdnY?Q&_G%XNKl}^APFFS^k3Sq{nVdOH>fkSccfmT1Vt(A-tO$|%}~l(&XgN!pR+M*-h+#0gu^$clf~Q7z49oa-tcrHLyE2XTN7)f_1>a61?xc zG&?o0cUa5$7w%;(Q#peaM4Tz78;KY)Wd_5j#Z~=}nUEh#naYqDPyTG2+`*Rp9Xr7~ z99YKy-Z8=GSiJ;GcXHtdfveK49vpWYQkt-WlvP;Mlts7z7Y|rx2`<4pewX1g9_eRl`FBC`=DB#dJ5 zX;cIfiq%~tw&jG{eqND@*PAkX75C*J4AcE2Z|hxI9^_&ma2iL6D3*6bEW%uXr#Ih6 zTK1@AC@0Hhla!PD*=d&vtq}z{R^3ewnh}3*t<)9v5qm(i}~mp49v8fE=UV^22m6+|Pxd6N68V^2t4Zpcz_bX??9? zqw}RwsODMyA;&{bel#|)-NlxzV>f1fCSBlT=5sK15ap9m%Pej@6q(2;C-U@(JhH)i z-V@0gde{q+J(1npM!#Y@F|~Ty5^X!WgDWc&arYIIE6DZw#bz%Zh|O%jCnSv8qaaLo z?+k)rkhH_J9l_>a5LP;qYeT<3}ld6Gulu9;L}SGPYOS>L=w9FXN zsYCQbg`_m2wuaqbQRQRj1&Z&pKQYcw1>0e-_%_DJsSsu;qkUaj6gVBLvRlR7s=l=+ z67l&^-hP`T(piizR#)2vzh+>6YtpW#iztQm)o~v?bjDihk%2LK9~`Jf9HHPA zHy;SuP36GLd%~L_yF|T*bWa3f?;KbZS0BV8$V9c|1!uAti{?a_XcyOinpu~E(>oR> z2~wK!n_`t*?oAW4EFT-itqrdiWL^+cEgyNi0_(|CF?c}&UKk`vn&Z-`g*`0QZDr-7 zp(rj#vK@q!=ox)6trJL}`(d17X|3rhBq>^Qi8_s?T2-x;DMeSUP3wj5GrU@2p-U`Q zFpaD_Ws|0y0hel)YLBt(u=T2=*YOeZ#F8FTY6%BgAqtc4(P)Md z4G>@`;X2f`1os=OYa-SDiuK*83?}a$@2I3$@;;498OUu9AD)!4XF&ZM`-s0V$L3-E z2usYEA2y&dHv4A8k2ucF{>*j{9u)Pj*x0(j4(DjsrwrzH@JoMx z(PNso=8KyXqzMFZ89a~TRb5a~-a~p-(@$JovX1^Nnv=~HOueG6ae5zXowD^sC+V)N z;Cq%^VKG*X>b-z>ys|;;M!9lADFDA#5)4GkR*lJ>f-Dx`BS-!cg{ry+AwgKV)wP&O zDx{}s4e6(vO;F65*bxBw99@n56TGYCMI<6tui!@+`fBCzE3TF%TFWQMasAe%+ue$T z!7c>1|4ed8L6a3*=fU$B-6xadM7gd6ZMWu?DUxUU_;ko?C{$jj?tSX6VyBisbc6jk z_m90MFVU*Dex^zVdYLKvxr|WCCT(-OQH)~&sy;0bEnBCjq>EGDATEm>TDkT3xF66u zomswv-G|t+E$kY$!!16~4Q^qcF7Xu{JKtH3gQF!qHvaAY$6c{ZhdXapYzsM;IF7mX zUGd)k?x^k7igJCQpy2ze;rsY6z&=(OU(Ndd)BPZ>R&33JL=aghqaoEZNm;Mzp9IP1 zg8_DB@pAP%#p{?JSh}hy`(B&|x%>qY=o(h;w&xLy 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 diff --git a/wizards/bank_reconcile_wizard_views.xml b/wizards/bank_reconcile_wizard_views.xml index ee25624..4c11199 100644 --- a/wizards/bank_reconcile_wizard_views.xml +++ b/wizards/bank_reconcile_wizard_views.xml @@ -1,36 +1,36 @@ - - - - - bank.reconcile.wizard.form - bank.reconcile.wizard - -
- - - - - - - - -
-
-
-
-
- - - - Select Journal Entry to Reconcile - bank.reconcile.wizard - form - new - + + + + + bank.reconcile.wizard.form + bank.reconcile.wizard + +
+ + + + + + + + +
+
+
+
+
+ + + + Select Journal Entry to Reconcile + bank.reconcile.wizard + form + new +
\ No newline at end of file