From cca358b590db29ac5e95b02a81f61ed391e9b8e4 Mon Sep 17 00:00:00 2001 From: Suherdy Yacob Date: Mon, 27 Oct 2025 13:41:17 +0700 Subject: [PATCH] fix some bugs in reconcile process --- README.md | 4 + ...ccount_bank_statement_line.cpython-312.pyc | Bin 2577 -> 1840 bytes models/account_bank_statement_line.py | 10 +- views/bank_statement_line_views.xml | 8 +- .../bank_reconcile_wizard.cpython-312.pyc | Bin 6131 -> 5086 bytes wizards/bank_reconcile_wizard.py | 89 +++++------------- 6 files changed, 33 insertions(+), 78 deletions(-) diff --git a/README.md b/README.md index 38284b2..258f3da 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,8 @@ This Odoo 17 module enhances the bank reconciliation process by providing a stre - Wizard-based interface for selecting journal entries to reconcile with - Individual line processing for precise control - Automatic journal entry creation for reconciliation transactions +- Intelligent automatic reconciliation of journal entry lines with created entries +- Proper account matching for accurate reconciliation ### 3. Smart Filtering - "Hide Reconciled" filter to focus on unreconciled lines @@ -73,6 +75,8 @@ No additional configuration is required after installation. The module works wit 1. **Lines not hiding when filter applied**: Ensure the `is_reconciled` computed field is properly stored in the database 2. **Reconciliation errors**: Verify that journal entries have proper account mappings 3. **Performance issues**: For large datasets, use the filter to reduce the number of displayed lines +4. **Automatic reconciliation not working**: Check that journal entry lines have matching accounts and sufficient balances for reconciliation +5. **Reconciliation journal created but not properly linked**: Verify that the reconciliation process is correctly matching accounts between the bank line and journal entry line ### Support For issues or feature requests, please contact your Odoo administrator or module developer. diff --git a/models/__pycache__/account_bank_statement_line.cpython-312.pyc b/models/__pycache__/account_bank_statement_line.cpython-312.pyc index 60382d9408dce615ccbf7c7cc7835791061df1bf..a9bdbf902334a7b76809362e93a4233de8632d5f 100644 GIT binary patch delta 373 zcmbOzvVo89G%qg~0}y;?{GZXsI+1UYDkF#s1fRu##B_#KhA74qhA5^K#wg|#rWS@M zmP%$#mdW~z=9?EWuV>@}DHjGQmzf;RDlN~$5X_*-=%>kei#<2LEHyqe1;}K{$;?YF z2C1BUh$(~T7KcqvVs27OqFt5OWJ6}j$sgF|CrhviiHQPL6mtWK28IJE$8!$mTyzTh z%rH5EZ716;mb}E=)X8G(ri{{)ec07_Z?P1o=A;#YR2T6~u46Z16qvk`J&uh7WXAHz zq8u44L6>ENC%16evkL*m{4`l7pW@IrQ~|PAG8BP?iUdFeNCTK)1u}|xfJ6(!4St;l zkIyX9tXxGxlUq5RJvBj!;Cg@_$jwhF%}KQ@(gjL@JXS0RBt9@RGBVz0P`SvUa+g8% V3!5Ax*Nn3HH8X3zG60!i{Q##JSOEY4 delta 1064 zcmZuv%WD%s9G=-nwvA0&?EA^qMZ>B6v<+Gz2C*WNl7=)pHi_BYc6J+0h)slo zJ$PukVD;n!!D>ASp1kSFst1!+sVpM>6D+}tLUm@7wp1P1Z+`pD_nY5qUQ}jlD?d0K zc0ksh_Z#6JAzS$<+g6?)C&WBJzy~GZVCg2JF1bH?-g#C%{=A3$`d2zeX561E+SgekE)YLZn#ao; zxBy)=of`5L&J&>Xh?4#9RcgI40S~z1paKj5C*#HRkvSQwaJ-w^5Z94Sqk|N2JwaoP zz0}o4xxEB3;I;lX^(M7^W-50%l9MM^g73Z{i(`T|WsLgPr0G;0RfMX09$Q%5UrTt+PlRIK$8m=3GH{|_fz*$KL9Z;;U7|S1lRxo diff --git a/models/account_bank_statement_line.py b/models/account_bank_statement_line.py index 20ad70f..5e941bb 100644 --- a/models/account_bank_statement_line.py +++ b/models/account_bank_statement_line.py @@ -5,14 +5,6 @@ from odoo.exceptions import UserError class AccountBankStatementLine(models.Model): _inherit = 'account.bank.statement.line' - is_reconciled = fields.Boolean(string='Is Reconciled', compute='_compute_is_reconciled', store=True) - - @api.depends('move_id') - def _compute_is_reconciled(self): - """Compute whether the bank line has been reconciled""" - for line in self: - line.is_reconciled = bool(line.move_id and 'Reconciliation:' in line.move_id.name) - def action_reconcile_selected_lines(self): """Open the reconciliation wizard for selected lines""" # Get the selected records from the context @@ -26,7 +18,7 @@ class AccountBankStatementLine(models.Model): 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 and 'Reconciliation:' in line.move_id.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.") diff --git a/views/bank_statement_line_views.xml b/views/bank_statement_line_views.xml index 19e688b..68eb1ef 100644 --- a/views/bank_statement_line_views.xml +++ b/views/bank_statement_line_views.xml @@ -37,14 +37,14 @@ account.bank.statement.line.tree account.bank.statement.line - + - + @@ -60,6 +60,7 @@ + @@ -69,6 +70,7 @@ + @@ -91,7 +93,7 @@ - + diff --git a/wizards/__pycache__/bank_reconcile_wizard.cpython-312.pyc b/wizards/__pycache__/bank_reconcile_wizard.cpython-312.pyc index 1cf366f468cf71b89867f2afcfb282944136da46..a87a9ca4b0f18eed120efebcdc2d5a5659119024 100644 GIT binary patch delta 1325 zcmZuwU2NM_6u!1&*G}v>KX%geCymmnZ927Ce%3)LOzlc(wXLHBP3klVY3wRa(*(Kc z-;}95Agz6&t?olB4J4j;;ek~=>L*T?ss z^PTS=pL2W~{juNqjUdrUK94ik2s@3e6najN;b&AQ{G@FLQmnUU z61)`z;5JbKc@78uTPpC2Ha{HXM2=Ey8j%7K8cuKru*-4AL+f4y))}m1tUBP5qsvF? zK6J3Sg-mfNUC@f^3W?6}YsVz90C_$RzvX9{K9tEF5`NIu?oo&U^5=1CPX&$%K}fQa ztwQ8kSQVNZJN(WWa8P%_N2Fp?XoZG*f)D=0N*GC22zbvabM(?A%7bs7B&J9x^fL!a zLKj*N-T|;nVGuv2J;P$Y9Ww8NjkdmjxSk7PTOrTbp1a20;zHq=D?w8gD({6Au>*!g zI)DrFA5rWG!N410kCV#dTKz3>SL_ULlZ%Anc%S{0Xqj)@DmGo_zz$il-9n~(C+7AM zV3XhEdjSFF(Qbp92kS&cfFrIKVc9i6>&=>f=;{|OT2U9Yvc+U|Rnf}uf$L>|_9=Js z28_gwJbfF++(}30A*~k6`ew7q zuV!tU48{#lrlafakHXHg3emkH>4VR}bgS?x9-u&`GSG7&8->jKrnmOfB)+;ilOWHP8x1Pv+n+ zQqL9-Jl?(WdN^r@FB;*CW_ZE~Pt@ZtnehoDK5;x(i%%VDW^mX*t9$rl{C`}vAhrh+ z)#Q|!ylf;d*OGH5dNuJzwJY_QquV_VK)bySQ3yC6JG|%Yr@-rSY}*_cp)%~lcG-ybJ56|WvO4>H}$RRaI zN|5XB-j6lI9W`B}hHLZ(*I0uFy!@oW5Q6;3CH=m_qoRI!!8^r+uXu9GMa@Pei%qAC znPpg)vqUc(^Yt;2W;bBY7bG6QJH8V}pf8*T``~r|>mApy4-ZtcXBIoQTvApG>MME* Y9{aoeDT0s>`^=80(GmR(;8PR)7w>;(PXGV_ delta 2393 zcmZuzU2NOd6~34HBSlh@Ey=PiS)wh+w&KJ}ZNqU|$FowHn_Gv z#pGjKH+j$X6xqf4$)-EtT*jpijL4r{9Y4>pH2lF)#v0$W=qM*N*Z1ZRaAPgo&K*KX z9n-u`pKN~x(HL^k(LY{hbVkP(q+O%QSVMN`%v(ry>KLT!ZAWvnm+*FAAo@%cp|TCs zwr0@1S+~)|$t3ILSeeV>d6aOIW9+rce`!*g?aVB^9po5XTZcjX7-4h`a(ku=_QqNZ zr{f%Bp&t;KsUd3V195pj zG3)_yh4WQLrt-y1I$xR|nR-qsD9abr=@A+e0r4O7?Te@yUocYhp9OyV#QXM-_#3?0 zKMwl;N;LhKV!ils*FsTC=cUu>!Z|6QEhtj@d~vCum87A|$%K?i7Yap9QkFA{B1_s? zMamVI)B*%31x;OPyFUaXm<0KX-8Iaqe%M}hQV|4EbI8i+tX6YoR7Hl_mRAaDH}%Fz z4;PuSs~r^O-`;zX=CRnwqt>R;{1$0`O%rD+6lC3oB$1=sAzUYKa-)@4+>A~d(MdBp zZA7QnqM4ih=IkkB_LMoBF=jJWHhi1+tZJsW*YNhP^L_6=y~YpRmf}Wy;by>0&99~A z*W(N8(n3|}+3-r$_{5rb;&w-@+V@y>>PYpmx$0cGj!*^vgn{V_o~P41^HVzY{)`c} z5DFcqO51UU{F!^&-2t`vssP2oyx|OZekt6mRUMO?u7J?22B=9)JE-%aZDVhshsqA! zA>(tW;MqBJd)awaD7y-FSh-;3)NN%JE>1_}b$1{lGf{ff>f7N3 zRfcSG?Ih24iT1b9+l&mS%2;>O5Vy{P0zGB{b~&iS1&$zxb*^RaC%+K94!7>k1&L3L zzzyU=u;}j0(WG_^8E|xK@|hsowt)1l)EOFZfQtPzfKO+%Y_YI-p;*#t_R^AEtT`^J zSpZH^H+v?VhqWTtxYkW2M2jNSM<}4Z$rBa_S!_}BwV+Lw5P&5rz!{CFQS-G(qX`f# zQfdJ_4RUJf!nWI@!gna2u zR_HS+{S7`B@OtV_)RQzL2aL#pD%*9}i6XJ-(dUy$qvBgT>ERDtDbeX(`2It8{H6s)zF|B+HHh( z*KLgCzKa-+ue*PU3twNj4p|@OT>|$`E zEnXd%FxnM{^fh3?f~DnbtfYR|LqI>zeN9O{3Yo>Y)5~!GlyC7hqeOlCqwN6 zyGFsI(y!(XWYu}&1=0U5Disd6O8+3G_Rn1b$NsH7Kf)yCKi2&$_0zVn;5ByYd{JJ? eE7Ph>KJZ6ES1=A 1: - total_bank_amount = sum(abs(line.amount) for line in self.bank_line_ids) - if total_bank_amount > journal_line_amount: - raise UserError(f"Total bank line amounts ({total_bank_amount}) cannot exceed the journal entry line amount ({journal_line_amount}).") - # 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) @@ -56,76 +49,40 @@ class BankReconcileWizard(models.TransientModel): def _reconcile_single_line(self, bank_line, journal_entry_line): """Reconcile a single bank line with a journal entry line""" - # Get the account from the journal entry line that will be on the opposite side - reconcile_account = journal_entry_line.account_id - # Use the individual bank line amount for each line - reconcile_amount = abs(bank_line.amount) - - # According to requirement #5: if the bank line is debit, - # then the new journal entry after reconcile will have that bank account in debit - bank_account = bank_line.journal_id.default_account_id - bank_line_amount = bank_line.amount - - # Determine if the bank line is debit (positive) or credit (negative) - if bank_line_amount >= 0: # Bank line is debit (money coming in) - # Bank account should be debited (requirement #5) - debit_account = bank_account - # The account from the selected journal entry line goes to credit (requirement #6) - credit_account = reconcile_account - else: # Bank line is credit (money going out) - # Bank account should be credited - credit_account = bank_account - # The account from the selected journal entry line goes to debit - debit_account = reconcile_account - - # Set the amounts - make sure they are balanced - debit_amount = reconcile_amount - credit_amount = reconcile_amount - - # Create a new journal entry for reconciliation with lines - reconciling_move = self.env['account.move'].create({ + # 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': debit_account.id, - 'debit': debit_amount, - 'credit': 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': credit_account.id, - 'debit': 0, - 'credit': credit_amount, - 'name': f'Bank Reconciliation: {bank_line.name or ""}', - }) - ] + '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, }) - # Post the reconciling journal entry - reconciling_move.action_post() - - # Link the bank line to the reconciling move - bank_line.sudo().write({ - 'move_id': reconciling_move.id, - }) - - # Mark the bank line as reconciled in a separate operation - bank_line.sudo().write({ - 'is_reconciled': True, - }) - - # Try to reconcile the selected journal entry line with the corresponding line in the reconciling move - # Find the line in the reconciling move that has the same account as the journal entry line - reconciling_line = reconciling_move.line_ids.filtered(lambda l: l.account_id.id == reconcile_account.id and l.credit > 0) - - # Try to reconcile the journal entry line with our reconciling line - if reconciling_line: + # Find the corresponding line in the new move and reconcile with the journal entry line + move_line = move.line_ids.filtered(lambda l: l.account_id.id == journal_entry_line.account_id.id) + if move_line: try: - (journal_entry_line + reconciling_line).reconcile() + (journal_entry_line + move_line).reconcile() except: - # If reconcile fails, we'll just link the moves - pass \ No newline at end of file + pass