@@ -451,3 +451,129 @@ def test_reconcile_with_writeoff_today(self):
451451 )
452452 self .assertEqual (len (writeoff_line ), 1 )
453453 self .assertEqual (writeoff_line .date , fields .Date .today ())
454+
455+ def test_reconcile_with_writeoff_currency_opposite_signs (self ):
456+ """Test write-off when company and foreign residuals have opposite signs."""
457+ self .env .ref ("base.group_multi_currency" ).users |= self .env .user
458+ self .company .currency_id = self .env .ref ("base.EUR" )
459+ usd = self .env .ref ("base.USD" )
460+ usd .active = True
461+
462+ inv_date = fields .Date .today () - timedelta (days = 10 )
463+ pay_date = fields .Date .today () - timedelta (days = 1 )
464+
465+ # Create currency rates
466+ self .env ["res.currency.rate" ].create (
467+ [
468+ {
469+ "name" : inv_date ,
470+ "currency_id" : usd .id ,
471+ "rate" : 1.2 ,
472+ "company_id" : self .company .id ,
473+ },
474+ {
475+ "name" : pay_date ,
476+ "rate" : 1.25 ,
477+ "currency_id" : usd .id ,
478+ "company_id" : self .company .id ,
479+ },
480+ {
481+ "name" : fields .Date .today (),
482+ "rate" : 1.25 ,
483+ "currency_id" : usd .id ,
484+ "company_id" : self .company .id ,
485+ },
486+ ]
487+ )
488+
489+ # Create invoice and payment with opposing residual signs
490+ common_ref = "INV-PAY-OPPOSITE-SIGNS"
491+ invoice = self .init_invoice (
492+ move_type = "out_invoice" ,
493+ partner = self .partner_a ,
494+ currency = usd ,
495+ amounts = [100 ],
496+ invoice_date = inv_date ,
497+ post = True ,
498+ )
499+ invoice .ref = common_ref
500+
501+ payment = self .env ["account.payment" ].create (
502+ {
503+ "partner_type" : "customer" ,
504+ "payment_type" : "inbound" ,
505+ "partner_id" : self .partner_a .id ,
506+ "destination_account_id" : self .company_data [
507+ "default_account_receivable"
508+ ].id ,
509+ "amount" : 100.10 ,
510+ "currency_id" : usd .id ,
511+ "journal_id" : self .bank_journal .id ,
512+ "date" : pay_date ,
513+ "ref" : common_ref ,
514+ }
515+ )
516+ payment .action_post ()
517+
518+ # Create and run mass reconciliation
519+ mass_rec = self .mass_rec_obj .create (
520+ {
521+ "name" : "mass_reconcile_currency_writeoff_opposite" ,
522+ "account" : self .company_data ["default_account_receivable" ].id ,
523+ "reconcile_method" : [
524+ (
525+ 0 ,
526+ 0 ,
527+ {
528+ "name" : "mass.reconcile.advanced.ref" ,
529+ "account_lost_id" : self .company_data [
530+ "default_account_expense"
531+ ].id ,
532+ "account_profit_id" : self .company_data [
533+ "default_account_revenue"
534+ ].id ,
535+ "journal_id" : self .company_data ["default_journal_misc" ].id ,
536+ "write_off" : 3.50 ,
537+ "date_base_on" : "newest" ,
538+ },
539+ )
540+ ],
541+ }
542+ )
543+ existing_moves = self .env ["account.move" ].search (
544+ [("journal_id" , "=" , self .company_data ["default_journal_misc" ].id )]
545+ )
546+ mass_rec .run_reconcile ()
547+
548+ # Validate write-off move
549+ writeoff_move = self .env ["account.move" ].search (
550+ [
551+ ("journal_id" , "=" , self .company_data ["default_journal_misc" ].id ),
552+ ("id" , "not in" , existing_moves .ids ),
553+ ]
554+ )
555+ self .assertEqual (
556+ len (writeoff_move ), 1 , "Exactly one write-off move should exist"
557+ )
558+ self .assertEqual (
559+ writeoff_move .currency_id , usd , "USD should be the write-off currency"
560+ )
561+
562+ pl_line = writeoff_move .line_ids .filtered (
563+ lambda ml : ml .account_id == self .company_data ["default_account_expense" ]
564+ )
565+ receivable_line = writeoff_move .line_ids .filtered (
566+ lambda ml : ml .account_id == self .company_data ["default_account_receivable" ]
567+ )
568+
569+ # Check amounts (0.10 USD residual, 3.25 EUR residual)
570+ self .assertAlmostEqual (pl_line .debit , 3.25 , 2 , "Expense line debit (EUR)" )
571+ self .assertAlmostEqual (
572+ pl_line .amount_currency , 0.10 , 2 , "Expense line USD amount"
573+ )
574+ self .assertAlmostEqual (
575+ receivable_line .credit , 3.25 , 2 , "Receivable line credit (EUR)"
576+ )
577+ self .assertAlmostEqual (
578+ receivable_line .amount_currency , - 0.10 , 2 , "Receivable line USD amount"
579+ )
0 commit comments