Class: SourceReconciliation

Inherits:
ApplicationRecord show all
Defined in:
app/models/source_reconciliation.rb

Overview

One record's operational source moved back to its acquisition source, and
what it moved from.

Written by SourceReconciliationWorker before each correction, so the sweep
is reversible per record and per run — see the migration for why neither
update_columns nor update! gives that on its own at this scale.

Constant Summary collapse

RECORD_TYPES =

The three record types Campaign#synchronize_source overwrites.

%w[Order Opportunity Invoice].freeze

Constants included from Models::Schedulable

Models::Schedulable::SIMPLE_FORM_OPTIONS

Instance Attribute Summary collapse

Belongs to collapse

Class Method Summary collapse

Methods inherited from ApplicationRecord

ransackable_associations, ransackable_attributes, ransackable_scopes, ransortable_attributes, #to_relation

Methods included from Models::Schedulable

config

Methods included from Models::AfterCommittable

#after_commit

Methods included from Models::EventPublishable

#publish_event

Instance Attribute Details

#record_idInteger

Primary key of the corrected record, within #record_type.

Returns:

  • (Integer)


31
# File 'app/models/source_reconciliation.rb', line 31

validates :record_id, presence: true

#record_typeString

One of RECORD_TYPES; hand-rolled polymorphism, since all three reverse
identically.

Returns:

  • (String)


26
# File 'app/models/source_reconciliation.rb', line 26

validates :record_type, presence: true, inclusion: { in: RECORD_TYPES }

Class Method Details

.for_batchActiveRecord::Relation<SourceReconciliation>

A relation of SourceReconciliations that are for batch. Active Record Scope

Returns:

See Also:



33
# File 'app/models/source_reconciliation.rb', line 33

scope :for_batch, ->(batch_id) { where(batch_id: batch_id) }

.revert!(batch_id) ⇒ Integer

Puts a run's records back where they were.

Reverts by writing from_source_id back, and only where the record still
holds the value this run gave it — anything changed since is someone else's
decision and is left alone rather than silently overwritten, which is the
mistake this whole exercise is undoing.

Parameters:

  • batch_id (String)

Returns:

  • (Integer)

    records restored



44
45
46
47
48
49
50
51
52
53
54
55
# File 'app/models/source_reconciliation.rb', line 44

def self.revert!(batch_id)
  for_batch(batch_id).group_by(&:record_type).sum do |record_type, entries|
    model = record_type.constantize
    # Grouped by the value being restored, so a run reverts in a handful of
    # statements rather than one per record — 92k round trips would take
    # longer than the sweep it is undoing.
    entries.group_by(&:from_source_id).sum do |from_source_id, group|
      model.where(id: group.map(&:record_id), source_id: group.map(&:to_source_id))
           .update_all(source_id: from_source_id)
    end
  end
end

Instance Method Details

#from_sourceSource?

The source the record held before the sweep — the campaign's. Nullable
because a record may have carried no source at all.

Returns:



16
# File 'app/models/source_reconciliation.rb', line 16

belongs_to :from_source, class_name: 'Source', optional: true

#to_sourceSource?

The acquisition source the sweep restored it to.

Returns:



20
# File 'app/models/source_reconciliation.rb', line 20

belongs_to :to_source, class_name: 'Source', optional: true