Class: MOCO::Sync

Inherits:
Object
  • Object
show all
Defined in:
lib/moco/sync.rb

Overview

Match and map projects and tasks between MOCO instances and sync activities

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(source_instance_api, target_instance_api, **args) ⇒ Sync

Returns a new instance of Sync.



12
13
14
15
16
17
18
19
20
21
22
23
24
25
# File 'lib/moco/sync.rb', line 12

def initialize(source_instance_api, target_instance_api, **args)
  @source_api = source_instance_api
  @target_api = target_instance_api
  @project_match_threshold = args.fetch(:project_match_threshold, 0.8)
  @task_match_threshold = args.fetch(:task_match_threshold, 0.45)
  @filters = args.fetch(:filters, {})
  @dry_run = args.fetch(:dry_run, false)

  @project_mapping = {}
  @task_mapping = {}

  fetch_assigned_projects
  build_initial_mappings
end

Instance Attribute Details

#dry_runObject

Returns the value of attribute dry_run.



10
11
12
# File 'lib/moco/sync.rb', line 10

def dry_run
  @dry_run
end

#project_mappingObject (readonly)

Returns the value of attribute project_mapping.



9
10
11
# File 'lib/moco/sync.rb', line 9

def project_mapping
  @project_mapping
end

#project_match_thresholdObject

Returns the value of attribute project_match_threshold.



10
11
12
# File 'lib/moco/sync.rb', line 10

def project_match_threshold
  @project_match_threshold
end

#source_projectsObject (readonly)

Returns the value of attribute source_projects.



9
10
11
# File 'lib/moco/sync.rb', line 9

def source_projects
  @source_projects
end

#target_projectsObject (readonly)

Returns the value of attribute target_projects.



9
10
11
# File 'lib/moco/sync.rb', line 9

def target_projects
  @target_projects
end

#task_mappingObject (readonly)

Returns the value of attribute task_mapping.



9
10
11
# File 'lib/moco/sync.rb', line 9

def task_mapping
  @task_mapping
end

#task_match_thresholdObject

Returns the value of attribute task_match_threshold.



10
11
12
# File 'lib/moco/sync.rb', line 10

def task_match_threshold
  @task_match_threshold
end

Instance Method Details

#sync(&callbacks) ⇒ Object

rubocop:todo Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/moco/sync.rb', line 28

def sync(&callbacks)
  results = []

  source_activities_r = @source_api.get_activities(@filters.fetch(:source, {}))
  target_activities_r = @target_api.get_activities(@filters.fetch(:target, {}))

  source_activities_grouped = source_activities_r.group_by(&:date).transform_values do |activities|
    activities.group_by(&:project)
  end
  target_activities_grouped = target_activities_r.group_by(&:date).transform_values do |activities|
    activities.group_by(&:project)
  end

  source_activities_grouped.each do |date, activities_by_project|
    activities_by_project.each do |project, source_activities|
      target_activities = target_activities_grouped.fetch(date, {}).fetch(@project_mapping[project.id], [])
      next if source_activities.empty? || target_activities.empty?

      matches = calculate_matches(source_activities, target_activities)
      matches.sort_by! { |match| -match[:score] }

      used_source_activities = []
      used_target_activities = []

      matches.each do |match|
        source_activity, target_activity = match[:activity]
        score = match[:score]

        next if used_source_activities.include?(source_activity) || used_target_activities.include?(target_activity)

        best_score = score
        best_match = target_activity
        expected_target_activity = get_expected_target_activity(source_activity)

        case best_score
        when 100
          # 100 - perfect match found, nothing needs doing
          callbacks&.call(:equal, source_activity, expected_target_activity)
        when 60...100
          # >=60 <100 - match with some differences
          expected_target_activity.to_h.except(:id, :user, :customer).each do |k, v|
            best_match.send("#{k}=", v)
          end
          callbacks&.call(:update, source_activity, best_match)
          unless @dry_run
            results << @target_api.update_activity(best_match)
            callbacks&.call(:updated, source_activity, best_match, results.last)
          end
        when 0...60
          # <60 - no good match found, create new entry
          callbacks&.call(:create, source_activity, expected_target_activity)
          unless @dry_run
            results << @target_api.create_activity(expected_target_activity)
            callbacks&.call(:created, source_activity, best_match, results.last)
          end
        end

        used_source_activities << source_activity
        used_target_activities << target_activity
      end
    end
  end
  results
end