<commit_before>module Backend
  class CompaniesController < Backend::BaseController
    def edit
      Preference.check!
      @company = Entity.of_company
    end

    def update
      ActiveRecord::Base.transaction do
        # Update company
        @company = Entity.of_company
        @company.update_attributes(permitted_params[:entity])
        @company.nature = :organization
        @company.save!
        # Update preferences
        params[:preferences].each do |key, data|
          preference = Preference.get!(key)
          preference.reload
          if key == 'currency'
            gc = GlobalCurrency.new(preference.value)
            if preference.value.to_s != data[:value]
              rate = params[:currency_change_rate].to_i
              raise 'Cannot proceed with null rate' if rate.zero?
              gc.convert_to(data[:value], rate: rate)
            end
          end
          if preference.value != data[:value]
            old_value = preference.value
            preference.value = data[:value]
            preference.save!
            preference_changed(preference, old_value, data[:value])
          end
        end
      end
      render :edit
    end

    protected

      def permitted_params
        params.permit!
      end

      # Called after each change in a preference when updating the company
      # @param [Preference] preference
      # @param [Object] old_value
      # @param [Object] new_value
      def preference_changed(preference, old_value, new_value)
        account_number_digits_changed(old_value.to_i, new_value.to_i) if preference.name == "account_number_digits"
      end

      # Called after each change of the preference :account_number:digits when updating the company
      # @param [Integer] old_value
      # @param [Integer] new_value
      def account_number_digits_changed(old_value, new_value)
        return if JournalEntry.any?

        n = Accountancy::AccountNumberNormalizer.build(standard_length: new_value)

        errors = Account.where.not(nature: "auxiliary")
                        .map { |acc| normalize_account(acc, normalizer: n) }
                        .select(&:is_some?)
                        .map(&:get)

        if errors.any?
          notify_error_now(
            :accounts_cannot_be_truncated_to_preference,
            accounts: errors.map(&:number).join(', '),
            preference: errors.first.standard_length,
            count: errors.size
          )

          raise ActiveRecord::Rollback
        end
      end

      # @todo use a Result type when available
      # @param [Account] account
      # @param [Accountancy::AccountNumberNormalizer] normalizer
      # @return [Maybe<Accountancy::AccountNumberNormalizer::NormalizationError>]
      def normalize_account(account, normalizer:)
        account.update(number: normalizer.normalize!(account.number))
        None()
      rescue Accountancy::AccountNumberNormalizer::NormalizationError => e
        return Some(e)
      end
  end
end
<commit_msg>Fix preference comparison to avoid trigger account normalization when account number length is not changed<commit_after>module Backend
  class CompaniesController < Backend::BaseController
    def edit
      Preference.check!
      @company = Entity.of_company
    end

    def update
      ActiveRecord::Base.transaction do
        # Update company
        @company = Entity.of_company
        @company.update_attributes(permitted_params[:entity])
        @company.nature = :organization
        @company.save!
        # Update preferences
        params[:preferences].each do |key, data|
          preference = Preference.get!(key)
          preference.reload
          if key == 'currency'
            gc = GlobalCurrency.new(preference.value)
            if preference.value.to_s != data[:value]
              rate = params[:currency_change_rate].to_i
              raise 'Cannot proceed with null rate' if rate.zero?
              gc.convert_to(data[:value], rate: rate)
            end
          end
          # This is a nasty hack to use the type coercion of Preference in order to be able to compare values from the form and values inside the Preferences
          old_value = preference.value
          preference.value = data[:value]

          if old_value != preference.value # Here, preference.value is the 'new value'
            preference.save!
            preference_changed(preference, preference.value)
          end
        end
      end
      render :edit
    end

    protected

      def permitted_params
        params.permit!
      end

      # Called after each change in a preference when updating the company
      # @param [Preference] preference
      # @param [Object] new_value
      def preference_changed(preference, new_value)
        account_number_digits_changed(new_value.to_i) if preference.name == "account_number_digits"
      end

      # Called after each change of the preference :account_number:digits when updating the company
      # @param [Integer] new_value
      def account_number_digits_changed(new_value)
        return if JournalEntry.any?

        n = Accountancy::AccountNumberNormalizer.build(standard_length: new_value)

        errors = Account.where.not(nature: "auxiliary")
                        .map { |acc| normalize_account(acc, normalizer: n) }
                        .select(&:is_some?)
                        .map(&:get)

        if errors.any?
          notify_error_now(
            :accounts_cannot_be_truncated_to_preference,
            accounts: errors.map(&:number).join(', '),
            preference: errors.first.standard_length,
            count: errors.size
          )

          raise ActiveRecord::Rollback
        end
      end

      # @todo use a Result type when available
      # @param [Account] account
      # @param [Accountancy::AccountNumberNormalizer] normalizer
      # @return [Maybe<Accountancy::AccountNumberNormalizer::NormalizationError>]
      def normalize_account(account, normalizer:)
        account.update(number: normalizer.normalize!(account.number))
        None()
      rescue Accountancy::AccountNumberNormalizer::NormalizationError => e
        return Some(e)
      end
  end
end

{'fraction_non_alphanumeric': 0.07972994695386594, 'fraction_numerical': 0.0, 'mean_word_length': 2.3007957559681698, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3740851', 'n_tokens_mistral': 1637, 'n_tokens_neox': 1602, 'n_words': 414}