<commit_before># -*- encoding : utf-8 -*-
module Deal
  SHOKOU = '(諸口)'

  module EntriesAssociationExtension
    def build(*args)
      record = super
      proxy_association.owner.copy_deal_info(record)
    end

    def not_marked
      find_all{|e| !e.marked_for_destruction?}
    end

  end

  attr_accessor :summary_mode # unified なら統一モードとして summary= で統一上書き。それ以外なら summary= を無視する

  def self.included(base)
    base.accepts_nested_attributes_for :debtor_entries, :creditor_entries, :allow_destroy => true
    base.before_validation :copy_deal_info_to_entries, :set_creditor_to_entries, :set_unified_summary
    base.before_save :adjust_entry_line_numbers
    base.before_update :destroy_marked_entries

    base.class_eval do
      # 単一記入では creditor に金額が指定されないことへの調整。
      # 変更時のentryの同定に金額を使うため、nested_attributesによる代入前に、金額を推測して補完したい。
      # また、携帯対応のためJavaScript前提（金額補完をクライアントサーバだけで完成する）にしたくない。
      def assign_attributes(deal_attributes = {})
        return super unless deal_attributes && deal_attributes[:debtor_entries_attributes] && deal_attributes[:creditor_entries_attributes]

        debtor_attributes = deal_attributes[:debtor_entries_attributes]
        creditor_attributes = deal_attributes[:creditor_entries_attributes]
        debtor_attributes = debtor_attributes.values if debtor_attributes.kind_of?(Hash)
        creditor_attributes = creditor_attributes.values if creditor_attributes.kind_of?(Hash)

        # 借方と借り方に有効なデータが１つだけあるとき
        if debtor_attributes.find_all{|v| v[:account_id]}.size == 1 && creditor_attributes.find_all{|v| v[:account_id]}.size == 1
          # 貸方に金額データがなければ補完する
          creditor = creditor_attributes.detect{|v| v[:account_id]}
          if !creditor[:amount] && !creditor[:reversed_amount]
            debtor = debtor_attributes.detect{|v| v[:account_id]}
            debtor_amount = debtor[:reversed_amount] ? (Entry::Base.parse_amount(debtor[:reversed_amount]).to_i * -1) : Entry::Base.parse_amount(debtor[:amount]).to_i
            creditor[:amount] = (debtor_amount * -1).to_s
            # この creditor は deal_attributes にあるものを直接書き換える
          end
        end

        super
      end
      alias_method :attributes=, :assign_attributes # NOTE: Rails 4.0.2 これをやらないとattributes=が古いままとなる

      [:debtor, :creditor].each do |side|
        define_method :"#{side}_entries_attributes_with_account_care=" do |attributes|
          # 金額も口座IDも摘要も入っていないentry情報は無視する
          attributes = attributes.values if attributes.kind_of?(Hash)
          attributes.reject!{|value| value[:amount].blank? && value[:reversed_amount].blank? && value[:account_id].blank? && value[:summary].blank?}

          # 更新時は必ずしも ID ではなく、内容で既存のデータと紐づける
          unless new_record?
            old_entries = Array.new(send(:"#{side}_entries", true))

            # attirbutes の中と引き当てていく
            matched_old_entries = []
            matched_new_entries = []
            old_entries.each do |old|
              if matched_hash = attributes.detect{|new_entry_hash| old.matched_with_attributes?(new_entry_hash) }
                matched_hash[:id] = old.id.to_s # IDを付け替える
                matched_old_entries << old
                matched_new_entries << matched_hash
              end
            end
            not_matched_new_entries = attributes - matched_new_entries
            not_matched_old_entries = old_entries - matched_old_entries

            # 引き当てられなかったhashからは :id をなくす
            # これにより、account_id の変更を防ぐ
            not_matched_new_entries.each do |hash|
              hash[:id] = nil # shallow copyにより attributes 内のhashが直接更新される
            end

            # 引き当てられなかったold entriesを削除予定にする
            # 現在の関連のなかの該当オブジェクトにマークする
            not_matched_old_entries.each do |old|
              e = send(:"#{side}_entries").detect{|e| e.id == old.id}
              raise "Could not find entry for 'old'" unless e
              e.mark_for_destruction
            end
          end

          # もとの（空は削除された）attributesを渡す。更新時は中のハッシュのidが加工された状態。
          send(:"#{side}_entries_attributes_without_account_care=", attributes)
        end

        alias_method_chain :"#{side}_entries_attributes=", :account_care
      end
    end

  end

  def complex?
    debtor_entries.not_marked.size > 1 || creditor_entries.not_marked.size > 1
  end

  def simple?
    !complex?
  end

  def debtor_amount
    nil if debtor_entries.detect{|e| e.amount.nil? }
    debtor_entries.inject(0){|value, entry| value += entry.amount.to_i}
  end

  # 借り方勘定名を返す
  def creditor_account_name
    creditor_entries
    creditor_entries.size == 1 ? creditor_entries.first.account.try(:name) : SHOKOU
  end

  # 貸し方勘定名を返す
  def debtor_account_name
    debtor_entries # 一度全部とる
    debtor_entries.size == 1 ? debtor_entries.first.account.try(:name) : SHOKOU
  end

  def load(from)
    self.debtor_entries_attributes = from.debtor_entries.map(&:copyable_attributes) #{|e| {:account_id => e.account_id, :amount => e.amount, :summary => e.summary}}
    self.creditor_entries_attributes = from.creditor_entries.map(&:copyable_attributes) #{|e| {:account_id => e.account_id, :amount => e.amount, :summary => e.summary}}
    self
  end

  def copy_deal_info(entry)
    entry.user_id = user_id
    entry
  end

  def summary_unified?
    summary_mode != 'split' && active_entries.map(&:summary).find_all{|s| !s.blank?}.uniq.size == 1
  end

  def summary=(s)
    @unified_summary = s
  end

  def summary
    @unified_summary || active_entries.detect{|e| e.summary.present?}.try(:summary) || ''
  end

  def active_entries
    changed? ? (debtor_entries + creditor_entries) : readonly_entries
  end
<commit_msg>Fix the bug that summary is not loaded properly in the saved object.<commit_after># -*- encoding : utf-8 -*-
module Deal
  SHOKOU = '(諸口)'

  module EntriesAssociationExtension
    def build(*args)
      record = super
      proxy_association.owner.copy_deal_info(record)
    end

    def not_marked
      find_all{|e| !e.marked_for_destruction?}
    end

  end

  attr_accessor :summary_mode # unified なら統一モードとして summary= で統一上書き。それ以外なら summary= を無視する

  def self.included(base)
    base.accepts_nested_attributes_for :debtor_entries, :creditor_entries, :allow_destroy => true
    base.before_validation :copy_deal_info_to_entries, :set_creditor_to_entries, :set_unified_summary
    base.before_save :adjust_entry_line_numbers
    base.before_update :destroy_marked_entries

    base.class_eval do
      # 単一記入では creditor に金額が指定されないことへの調整。
      # 変更時のentryの同定に金額を使うため、nested_attributesによる代入前に、金額を推測して補完したい。
      # また、携帯対応のためJavaScript前提（金額補完をクライアントサーバだけで完成する）にしたくない。
      def assign_attributes(deal_attributes = {})
        return super unless deal_attributes && deal_attributes[:debtor_entries_attributes] && deal_attributes[:creditor_entries_attributes]

        debtor_attributes = deal_attributes[:debtor_entries_attributes]
        creditor_attributes = deal_attributes[:creditor_entries_attributes]
        debtor_attributes = debtor_attributes.values if debtor_attributes.kind_of?(Hash)
        creditor_attributes = creditor_attributes.values if creditor_attributes.kind_of?(Hash)

        # 借方と借り方に有効なデータが１つだけあるとき
        if debtor_attributes.find_all{|v| v[:account_id]}.size == 1 && creditor_attributes.find_all{|v| v[:account_id]}.size == 1
          # 貸方に金額データがなければ補完する
          creditor = creditor_attributes.detect{|v| v[:account_id]}
          if !creditor[:amount] && !creditor[:reversed_amount]
            debtor = debtor_attributes.detect{|v| v[:account_id]}
            debtor_amount = debtor[:reversed_amount] ? (Entry::Base.parse_amount(debtor[:reversed_amount]).to_i * -1) : Entry::Base.parse_amount(debtor[:amount]).to_i
            creditor[:amount] = (debtor_amount * -1).to_s
            # この creditor は deal_attributes にあるものを直接書き換える
          end
        end

        super
      end
      alias_method :attributes=, :assign_attributes # NOTE: Rails 4.0.2 これをやらないとattributes=が古いままとなる

      [:debtor, :creditor].each do |side|
        define_method :"#{side}_entries_attributes_with_account_care=" do |attributes|
          # 金額も口座IDも摘要も入っていないentry情報は無視する
          attributes = attributes.values if attributes.kind_of?(Hash)
          attributes.reject!{|value| value[:amount].blank? && value[:reversed_amount].blank? && value[:account_id].blank? && value[:summary].blank?}

          # 更新時は必ずしも ID ではなく、内容で既存のデータと紐づける
          unless new_record?
            old_entries = Array.new(send(:"#{side}_entries", true))

            # attirbutes の中と引き当てていく
            matched_old_entries = []
            matched_new_entries = []
            old_entries.each do |old|
              if matched_hash = attributes.detect{|new_entry_hash| old.matched_with_attributes?(new_entry_hash) }
                matched_hash[:id] = old.id.to_s # IDを付け替える
                matched_old_entries << old
                matched_new_entries << matched_hash
              end
            end
            not_matched_new_entries = attributes - matched_new_entries
            not_matched_old_entries = old_entries - matched_old_entries

            # 引き当てられなかったhashからは :id をなくす
            # これにより、account_id の変更を防ぐ
            not_matched_new_entries.each do |hash|
              hash[:id] = nil # shallow copyにより attributes 内のhashが直接更新される
            end

            # 引き当てられなかったold entriesを削除予定にする
            # 現在の関連のなかの該当オブジェクトにマークする
            not_matched_old_entries.each do |old|
              e = send(:"#{side}_entries").detect{|e| e.id == old.id}
              raise "Could not find entry for 'old'" unless e
              e.mark_for_destruction
            end
          end

          # もとの（空は削除された）attributesを渡す。更新時は中のハッシュのidが加工された状態。
          send(:"#{side}_entries_attributes_without_account_care=", attributes)
        end

        alias_method_chain :"#{side}_entries_attributes=", :account_care
      end
    end

  end

  def complex?
    debtor_entries.not_marked.size > 1 || creditor_entries.not_marked.size > 1
  end

  def simple?
    !complex?
  end

  def debtor_amount
    nil if debtor_entries.detect{|e| e.amount.nil? }
    debtor_entries.inject(0){|value, entry| value += entry.amount.to_i}
  end

  # 借り方勘定名を返す
  def creditor_account_name
    creditor_entries
    creditor_entries.size == 1 ? creditor_entries.first.account.try(:name) : SHOKOU
  end

  # 貸し方勘定名を返す
  def debtor_account_name
    debtor_entries # 一度全部とる
    debtor_entries.size == 1 ? debtor_entries.first.account.try(:name) : SHOKOU
  end

  def load(from)
    self.debtor_entries_attributes = from.debtor_entries.map(&:copyable_attributes) #{|e| {:account_id => e.account_id, :amount => e.amount, :summary => e.summary}}
    self.creditor_entries_attributes = from.creditor_entries.map(&:copyable_attributes) #{|e| {:account_id => e.account_id, :amount => e.amount, :summary => e.summary}}
    self
  end

  def copy_deal_info(entry)
    entry.user_id = user_id
    entry
  end

  def summary_unified?
    summary_mode != 'split' && active_entries.map(&:summary).find_all{|s| !s.blank?}.uniq.size == 1
  end

  def summary=(s)
    @unified_summary = s
  end

  def summary
    @unified_summary || active_entries.detect{|e| e.summary.present?}.try(:summary) || ''
  end

  def active_entries
    (debtor_entries.loaded? || creditor_entries.loaded?) ? (debtor_entries.find_all{|e| !e.marked_for_destruction? } + creditor_entries.find_all{|e| !e.marked_for_destruction? }) : readonly_entries
  end

{'fraction_non_alphanumeric': 0.0987308533916849, 'fraction_numerical': 0.00262582056892779, 'mean_word_length': 3.1914893617021276, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 21, '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': '6144815', 'n_tokens_mistral': 4283, 'n_tokens_neox': 4028, 'n_words': 629}