hunk.code_window:     import {ReCaptcha} from "@google_recaptcha/js/recaptcha";
       import session from "web.session";
       import ajax from "@web/legacy/js/core/ajax";
       import publicWidget from "@web/legacy/js/public/public_widget";
       import dom from "@web/legacy/js/core/dom";
       import concurrency from "@web/legacy/js/core/concurrency";
       import { debounce } from "@web/core/utils/timing";
       import { _t } from "@web/core/l10n/translation";
       import { renderToElement } from "@web/core/utils/render";
  
hunk.labels: keep keep keep keep keep replace keep keep keep
hunk.after_edit:     import { delay } from "@web/core/utils/concurrency";
  
hunk.file_path: addons/website/static/src/snippets/s_website_form/000.js
hunk.type: replace
file: # -*- coding: utf-8 -*-
  from odoo import models, fields, api
  from markupsafe import escape
  from odoo.tools.translate import _
  from odoo.exceptions import UserError
  
  
  class AccountMoveReversal(models.TransientModel):
      """
      Account move reversal wizard, it cancel an account move by reversing it.
      """
      _name = 'account.move.reversal'
      _description = 'Account Move Reversal'
      _check_company_auto = True
  
      move_ids = fields.Many2many('account.move', 'account_move_reversal_move', 'reversal_id', 'move_id', domain=[('state', '=', 'posted')])
      new_move_ids = fields.Many2many('account.move', 'account_move_reversal_new_move', 'reversal_id', 'new_move_id')
      date = fields.Date(string='Reversal date', default=fields.Date.context_today)
      reason = fields.Char(string='Reason displayed on Credit Note')
      journal_id = fields.Many2one(
          comodel_name='account.journal',
          string='Journal',
          required=True,
          compute='_compute_journal_id',
          readonly=False,
          store=True,
          check_company=True,
          help='If empty, uses the journal of the journal entry to be reversed.',
      )
      company_id = fields.Many2one('res.company', required=True, readonly=True)
      available_journal_ids = fields.Many2many('account.journal', compute='_compute_available_journal_ids')
      country_code = fields.Char(related='company_id.country_id.code')
  
      # computed fields
      residual = fields.Monetary(compute="_compute_from_moves")
      currency_id = fields.Many2one('res.currency', compute="_compute_from_moves")
      move_type = fields.Char(compute="_compute_from_moves")
  
      @api.depends('move_ids')
      def _compute_journal_id(self):
          for record in self:
              if record.journal_id:
                  record.journal_id = record.journal_id
              else:
                  journals = record.move_ids.journal_id.filtered(lambda x: x.active)
                  record.journal_id = journals[0] if journals else None
  
      @api.depends('move_ids')
      def _compute_available_journal_ids(self):
          for record in self:
              if record.move_ids:
                  record.available_journal_ids = self.env['account.journal'].search([
                      *self.env['account.journal']._check_company_domain(record.company_id),
                      ('type', 'in', record.move_ids.journal_id.mapped('type')),
                  ])
              else:
                  record.available_journal_ids = self.env['account.journal'].search([
                      *self.env['account.journal']._check_company_domain(record.company_id),
                  ])
  
      @api.constrains('journal_id', 'move_ids')
      def _check_journal_type(self):
          for record in self:
              if record.journal_id.type not in record.move_ids.journal_id.mapped('type'):
                  raise UserError(_('Journal should be the same type as the reversed entry.'))
  
      @api.model
      def default_get(self, fields):
          res = super(AccountMoveReversal, self).default_get(fields)
          move_ids = self.env['account.move'].browse(self.env.context['active_ids']) if self.env.context.get('active_model') == 'account.move' else self.env['account.move']
  
          if any(move.state != "posted" for move in move_ids):
              raise UserError(_('You can only reverse posted moves.'))
          if 'company_id' in fields:
              res['company_id'] = move_ids.company_id.root_id.id or self.env.company.id
          if 'move_ids' in fields:
              res['move_ids'] = [(6, 0, move_ids.ids)]
          return res
  
      @api.depends('move_ids')
      def _compute_from_moves(self):
          for record in self:
              move_ids = record.move_ids._origin
              record.residual = len(move_ids) == 1 and move_ids.amount_residual or 0
              record.currency_id = len(move_ids.currency_id) == 1 and move_ids.currency_id or False
              record.move_type = move_ids.move_type if len(move_ids) == 1 else (any(move.move_type in ('in_invoice', 'out_invoice') for move in move_ids) and 'some_invoice' or False)
  
      def _prepare_default_reversal(self, move):
          reverse_date = self.date
          return {
              'ref': _('Reversal of: %(move_name)s, %(reason)s', move_name=move.name, reason=self.reason)
                     if self.reason
                     else _('Reversal of: %s', move.name),
              'date': reverse_date,
              'invoice_date_due': reverse_date,
              'invoice_date': move.is_invoice(include_receipts=True) and (self.date or move.date) or False,
              'journal_id': self.journal_id.id,
              'invoice_payment_term_id': None,
              'invoice_user_id': move.invoice_user_id.id,
              'auto_post': 'at_date' if reverse_date > fields.Date.context_today(self) else 'no',
          }
  
      def reverse_moves(self, is_modify=False):
          self.ensure_one()
          moves = self.move_ids
  
          # Create default values.
          default_values_list = []
          for move in moves:
              default_values_list.append(self._prepare_default_reversal(move))
  
          batches = [
              [self.env['account.move'], [], True],   # Moves to be cancelled by the reverses.
              [self.env['account.move'], [], False],  # Others.
          ]
          for move, default_vals in zip(moves, default_values_list):
              is_auto_post = default_vals.get('auto_post') != 'no'
              is_cancel_needed = not is_auto_post and is_modify
              batch_index = 0 if is_cancel_needed else 1
              batches[batch_index][0] |= move
              batches[batch_index][1].append(default_vals)
  
          # Handle reverse method.
          moves_to_redirect = self.env['account.move']
          for moves, default_values_list, is_cancel_needed in batches:
              new_moves = moves._reverse_moves(default_values_list, cancel=is_cancel_needed)
              moves._message_log_batch(
                  bodies=dict((move.id, escape(_('This entry has been %s')) % reverse._get_html_link(title=_("reversed"))) for move, reverse in zip(moves, new_moves))
              )
  
              if is_modify:
                  moves_vals_list = []
                  for move in moves.with_context(include_business_fields=True):
                      moves_vals_list.append(move.copy_data({'date': self.date})[0])
                  new_moves = self.env['account.move'].create(moves_vals_list)
  
              moves_to_redirect |= new_moves
  
          self.new_move_ids = moves_to_redirect
  
          # Create action.
          action = {
              'name': _('Reverse Moves'),
              'type': 'ir.actions.act_window',
              'res_model': 'account.move',
          }
          if len(moves_to_redirect) == 1:
              action.update({
                  'view_mode': 'form',
                  'res_id': moves_to_redirect.id,
                  'context': {'default_move_type':  moves_to_redirect.move_type},
              })
          else:
              action.update({
                  'view_mode': 'tree,form',
                  'domain': [('id', 'in', moves_to_redirect.ids)],
              })
              if len(set(moves_to_redirect.mapped('move_type'))) == 1:
                  action['context'] = {'default_move_type':  moves_to_redirect.mapped('move_type').pop()}
          return action
  
      def refund_moves(self):
          return self.reverse_moves(is_modify=False)
  
      def modify_moves(self):
          return self.reverse_moves(is_modify=True)
  