Class: LeadItem

Inherits:
ApplicationRecord show all
Includes:
Housekeeping, Shared::IsData
Defined in:
app/models/lead_item.rb

Overview

A LeadItem relates an otu to a lead for the purpose of tracking which otus from an initial set of otus for a key are still under consideration at a particular stage of the key.

Instance Attribute Summary collapse

Class Method Summary collapse

Methods included from Shared::IsData

#errors_excepting, #full_error_messages_excepting, #identical, #is_community?, #is_destroyable?, #is_editable?, #is_in_use?, #is_in_users_projects?, #metamorphosize, #similar

Methods included from Housekeeping

#has_polymorphic_relationship?

Methods inherited from ApplicationRecord

transaction_with_retry

Instance Attribute Details

#lead_idinteger

id of the lead to which otu_id is attached

Returns:

  • (integer)


17
18
19
20
21
22
23
24
25
26
27
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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
# File 'app/models/lead_item.rb', line 17

class LeadItem < ApplicationRecord
  include Housekeeping
  include Shared::IsData

  acts_as_list scope: [:lead_id, :project_id]

  belongs_to :otu, inverse_of: :lead_items
  belongs_to :lead, inverse_of: :lead_items

  has_one :taxon_name, through: :otu

  validates :otu, :lead, presence: true

  def self.batch_add_otus_for_lead(lead_id, otu_ids, project_id, user_id)
    attributes = otu_ids.map { |otu_id|
      {
        otu_id:,
        lead_id:,
        project_id:,
        created_by_id: user_id,
        updated_by_id: user_id
      }
    }

    LeadItem.insert_all(attributes)
  end

  def self.move_items(items_scope, lead)
    items_scope.update_all(lead_id: lead.id)
  end

  # Transfers any items on leaf-node descendants of source to a new lead.
  # @param target [Lead or nil] A lead to add the descendant lead_items to; if
  #   nil a new lead is created.
  # @return [Lead or nil] If items exist, the lead now holding those items.
  def self.consolidate_descendant_items(lead, target = nil)
    # Both lead and lead_item have `position`, which .leaves orders by, so need
    # to remove that.
    items =
      lead.leaves.unscope(:order).joins(:lead_items).pluck('lead_items.id')

    return nil if items.empty?

    items_lead = target || Lead.create!(text:
      'PLACEHOLDER LEAD TO HOLD OTU OPTIONS FROM A DELETED SUBTREE'
    )

    self.move_items(LeadItem.where(id: items), items_lead)

    items_lead
  end

  def self.add_otu_index_for_lead(lead, otu_id, exclusive)
    begin
      Lead.transaction do
        if exclusive
          LeadItem.where(lead_id: lead.sibling_ids, otu_id:).destroy_all
        end

        LeadItem.create!(lead_id: lead.id, otu_id:)
      end
    rescue ActiveRecord::RecordNotDestroyed => e
      lead.errors.add(:base, "Destroy sibling LeadItems failed! '#{e}'")
      return false
    rescue ActiveRecord::RecordInvalid => e
      lead.errors.add(:base, "New LeadItem creation failed! '#{e}'")
      return false
    end

    true
  end

  def self.remove_otu_index_for_lead(lead, otu_id)
    count = LeadItem
      .where(otu_id:, lead_id: lead.self_and_siblings.map(&:id)).count

    if count == 1
      lead.errors.add(:base, "Can't destroy last lead item for otu #{otu_id}!")
      return false
    end

    begin
      LeadItem.where(lead_id: lead.id, otu_id:).destroy_all
    rescue ActiveRecord::RecordNotDestroyed => e
      lead.errors.add(:base, "Destroy LeadItem for lead #{lead.id}, otu #{otu_id} failed! '#{e}'")
      return false
    end

    true
  end

  # @param parent [Lead] With add_new_to_first_child, determines which lead to add
  #   items to
  # @param otu_ids [Array] Which otus to add
  # @param exclusive_otu_ids [Array] Remove these otus from all siblings of the
  #   lead added to
  # @param add_new_to_first_child [Boolean] if true then add lead otus *that
  #   already exist on parent* to parent's first child, otherwise (default) add
  #   all supplied otus to the last available (rightmost) child.
  def self.add_items_to_lead(parent, otu_ids, exclusive_otu_ids, add_new_to_first_child = false)
    if otu_ids.nil? || otu_ids.empty?
      parent.errors.add(:base, 'No otus to add!')
      return false
    elsif parent.children.empty?
      parent.errors.add(:base, 'No lead children to add to!')
      return false
    end

    lead_to_add_to = nil
    if add_new_to_first_child
      lead_to_add_to = parent.children.first
    else
      parent.children.to_a.reverse.each do |c|
        if c.children.exists?
          next
        else
          # We add to the rightmost available child.
          lead_to_add_to ||= c
        end
      end
    end

    if lead_to_add_to.nil?
      parent.errors.add(:base, 'No available lead to add otus to!')
      return false
    end

    # TODO: this is really special-case code for adding items from a matrix,
    # clean things up.
    if add_new_to_first_child
      # Limit to lead items that exist on the right lead.
      otu_ids = otu_ids & parent.children[1].lead_items.pluck(:otu_id)
    end
    existing = lead_to_add_to.lead_items.pluck(:otu_id)
    new_otu_ids = otu_ids - existing
    lead_item_table = LeadItem.arel_table

    LeadItem.transaction do
      begin
        to_be_destroyed = otu_ids.filter_map do |otu_id|
          exclusive_otu_ids.include?(otu_id) ? otu_id : false
        end
        if to_be_destroyed.count > 0
          LeadItem
            .where(lead_id: lead_to_add_to.sibling_ids)
            .where(otu_id: to_be_destroyed)
            .destroy_all
        end

        a = new_otu_ids.map { |id| { lead_id: lead_to_add_to.id, otu_id: id } }
        LeadItem.create!(a)
        return true
      rescue ActiveRecord::RecordNotDestroyed => e
        lead.errors.add(:base, e.to_s)
        byebug
        return false
      rescue ActiveRecord::RecordInvalid => e
        lead.errors.add(:base, e.to_s)
        byebug
        return false
      end
    end

    true
  end

end

#otu_idinteger

id of an otu which should be associated with lead_id

Returns:

  • (integer)


17
18
19
20
21
22
23
24
25
26
27
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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
# File 'app/models/lead_item.rb', line 17

class LeadItem < ApplicationRecord
  include Housekeeping
  include Shared::IsData

  acts_as_list scope: [:lead_id, :project_id]

  belongs_to :otu, inverse_of: :lead_items
  belongs_to :lead, inverse_of: :lead_items

  has_one :taxon_name, through: :otu

  validates :otu, :lead, presence: true

  def self.batch_add_otus_for_lead(lead_id, otu_ids, project_id, user_id)
    attributes = otu_ids.map { |otu_id|
      {
        otu_id:,
        lead_id:,
        project_id:,
        created_by_id: user_id,
        updated_by_id: user_id
      }
    }

    LeadItem.insert_all(attributes)
  end

  def self.move_items(items_scope, lead)
    items_scope.update_all(lead_id: lead.id)
  end

  # Transfers any items on leaf-node descendants of source to a new lead.
  # @param target [Lead or nil] A lead to add the descendant lead_items to; if
  #   nil a new lead is created.
  # @return [Lead or nil] If items exist, the lead now holding those items.
  def self.consolidate_descendant_items(lead, target = nil)
    # Both lead and lead_item have `position`, which .leaves orders by, so need
    # to remove that.
    items =
      lead.leaves.unscope(:order).joins(:lead_items).pluck('lead_items.id')

    return nil if items.empty?

    items_lead = target || Lead.create!(text:
      'PLACEHOLDER LEAD TO HOLD OTU OPTIONS FROM A DELETED SUBTREE'
    )

    self.move_items(LeadItem.where(id: items), items_lead)

    items_lead
  end

  def self.add_otu_index_for_lead(lead, otu_id, exclusive)
    begin
      Lead.transaction do
        if exclusive
          LeadItem.where(lead_id: lead.sibling_ids, otu_id:).destroy_all
        end

        LeadItem.create!(lead_id: lead.id, otu_id:)
      end
    rescue ActiveRecord::RecordNotDestroyed => e
      lead.errors.add(:base, "Destroy sibling LeadItems failed! '#{e}'")
      return false
    rescue ActiveRecord::RecordInvalid => e
      lead.errors.add(:base, "New LeadItem creation failed! '#{e}'")
      return false
    end

    true
  end

  def self.remove_otu_index_for_lead(lead, otu_id)
    count = LeadItem
      .where(otu_id:, lead_id: lead.self_and_siblings.map(&:id)).count

    if count == 1
      lead.errors.add(:base, "Can't destroy last lead item for otu #{otu_id}!")
      return false
    end

    begin
      LeadItem.where(lead_id: lead.id, otu_id:).destroy_all
    rescue ActiveRecord::RecordNotDestroyed => e
      lead.errors.add(:base, "Destroy LeadItem for lead #{lead.id}, otu #{otu_id} failed! '#{e}'")
      return false
    end

    true
  end

  # @param parent [Lead] With add_new_to_first_child, determines which lead to add
  #   items to
  # @param otu_ids [Array] Which otus to add
  # @param exclusive_otu_ids [Array] Remove these otus from all siblings of the
  #   lead added to
  # @param add_new_to_first_child [Boolean] if true then add lead otus *that
  #   already exist on parent* to parent's first child, otherwise (default) add
  #   all supplied otus to the last available (rightmost) child.
  def self.add_items_to_lead(parent, otu_ids, exclusive_otu_ids, add_new_to_first_child = false)
    if otu_ids.nil? || otu_ids.empty?
      parent.errors.add(:base, 'No otus to add!')
      return false
    elsif parent.children.empty?
      parent.errors.add(:base, 'No lead children to add to!')
      return false
    end

    lead_to_add_to = nil
    if add_new_to_first_child
      lead_to_add_to = parent.children.first
    else
      parent.children.to_a.reverse.each do |c|
        if c.children.exists?
          next
        else
          # We add to the rightmost available child.
          lead_to_add_to ||= c
        end
      end
    end

    if lead_to_add_to.nil?
      parent.errors.add(:base, 'No available lead to add otus to!')
      return false
    end

    # TODO: this is really special-case code for adding items from a matrix,
    # clean things up.
    if add_new_to_first_child
      # Limit to lead items that exist on the right lead.
      otu_ids = otu_ids & parent.children[1].lead_items.pluck(:otu_id)
    end
    existing = lead_to_add_to.lead_items.pluck(:otu_id)
    new_otu_ids = otu_ids - existing
    lead_item_table = LeadItem.arel_table

    LeadItem.transaction do
      begin
        to_be_destroyed = otu_ids.filter_map do |otu_id|
          exclusive_otu_ids.include?(otu_id) ? otu_id : false
        end
        if to_be_destroyed.count > 0
          LeadItem
            .where(lead_id: lead_to_add_to.sibling_ids)
            .where(otu_id: to_be_destroyed)
            .destroy_all
        end

        a = new_otu_ids.map { |id| { lead_id: lead_to_add_to.id, otu_id: id } }
        LeadItem.create!(a)
        return true
      rescue ActiveRecord::RecordNotDestroyed => e
        lead.errors.add(:base, e.to_s)
        byebug
        return false
      rescue ActiveRecord::RecordInvalid => e
        lead.errors.add(:base, e.to_s)
        byebug
        return false
      end
    end

    true
  end

end

#project_idInteger

the project ID

Returns:

  • (Integer)


17
18
19
20
21
22
23
24
25
26
27
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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
# File 'app/models/lead_item.rb', line 17

class LeadItem < ApplicationRecord
  include Housekeeping
  include Shared::IsData

  acts_as_list scope: [:lead_id, :project_id]

  belongs_to :otu, inverse_of: :lead_items
  belongs_to :lead, inverse_of: :lead_items

  has_one :taxon_name, through: :otu

  validates :otu, :lead, presence: true

  def self.batch_add_otus_for_lead(lead_id, otu_ids, project_id, user_id)
    attributes = otu_ids.map { |otu_id|
      {
        otu_id:,
        lead_id:,
        project_id:,
        created_by_id: user_id,
        updated_by_id: user_id
      }
    }

    LeadItem.insert_all(attributes)
  end

  def self.move_items(items_scope, lead)
    items_scope.update_all(lead_id: lead.id)
  end

  # Transfers any items on leaf-node descendants of source to a new lead.
  # @param target [Lead or nil] A lead to add the descendant lead_items to; if
  #   nil a new lead is created.
  # @return [Lead or nil] If items exist, the lead now holding those items.
  def self.consolidate_descendant_items(lead, target = nil)
    # Both lead and lead_item have `position`, which .leaves orders by, so need
    # to remove that.
    items =
      lead.leaves.unscope(:order).joins(:lead_items).pluck('lead_items.id')

    return nil if items.empty?

    items_lead = target || Lead.create!(text:
      'PLACEHOLDER LEAD TO HOLD OTU OPTIONS FROM A DELETED SUBTREE'
    )

    self.move_items(LeadItem.where(id: items), items_lead)

    items_lead
  end

  def self.add_otu_index_for_lead(lead, otu_id, exclusive)
    begin
      Lead.transaction do
        if exclusive
          LeadItem.where(lead_id: lead.sibling_ids, otu_id:).destroy_all
        end

        LeadItem.create!(lead_id: lead.id, otu_id:)
      end
    rescue ActiveRecord::RecordNotDestroyed => e
      lead.errors.add(:base, "Destroy sibling LeadItems failed! '#{e}'")
      return false
    rescue ActiveRecord::RecordInvalid => e
      lead.errors.add(:base, "New LeadItem creation failed! '#{e}'")
      return false
    end

    true
  end

  def self.remove_otu_index_for_lead(lead, otu_id)
    count = LeadItem
      .where(otu_id:, lead_id: lead.self_and_siblings.map(&:id)).count

    if count == 1
      lead.errors.add(:base, "Can't destroy last lead item for otu #{otu_id}!")
      return false
    end

    begin
      LeadItem.where(lead_id: lead.id, otu_id:).destroy_all
    rescue ActiveRecord::RecordNotDestroyed => e
      lead.errors.add(:base, "Destroy LeadItem for lead #{lead.id}, otu #{otu_id} failed! '#{e}'")
      return false
    end

    true
  end

  # @param parent [Lead] With add_new_to_first_child, determines which lead to add
  #   items to
  # @param otu_ids [Array] Which otus to add
  # @param exclusive_otu_ids [Array] Remove these otus from all siblings of the
  #   lead added to
  # @param add_new_to_first_child [Boolean] if true then add lead otus *that
  #   already exist on parent* to parent's first child, otherwise (default) add
  #   all supplied otus to the last available (rightmost) child.
  def self.add_items_to_lead(parent, otu_ids, exclusive_otu_ids, add_new_to_first_child = false)
    if otu_ids.nil? || otu_ids.empty?
      parent.errors.add(:base, 'No otus to add!')
      return false
    elsif parent.children.empty?
      parent.errors.add(:base, 'No lead children to add to!')
      return false
    end

    lead_to_add_to = nil
    if add_new_to_first_child
      lead_to_add_to = parent.children.first
    else
      parent.children.to_a.reverse.each do |c|
        if c.children.exists?
          next
        else
          # We add to the rightmost available child.
          lead_to_add_to ||= c
        end
      end
    end

    if lead_to_add_to.nil?
      parent.errors.add(:base, 'No available lead to add otus to!')
      return false
    end

    # TODO: this is really special-case code for adding items from a matrix,
    # clean things up.
    if add_new_to_first_child
      # Limit to lead items that exist on the right lead.
      otu_ids = otu_ids & parent.children[1].lead_items.pluck(:otu_id)
    end
    existing = lead_to_add_to.lead_items.pluck(:otu_id)
    new_otu_ids = otu_ids - existing
    lead_item_table = LeadItem.arel_table

    LeadItem.transaction do
      begin
        to_be_destroyed = otu_ids.filter_map do |otu_id|
          exclusive_otu_ids.include?(otu_id) ? otu_id : false
        end
        if to_be_destroyed.count > 0
          LeadItem
            .where(lead_id: lead_to_add_to.sibling_ids)
            .where(otu_id: to_be_destroyed)
            .destroy_all
        end

        a = new_otu_ids.map { |id| { lead_id: lead_to_add_to.id, otu_id: id } }
        LeadItem.create!(a)
        return true
      rescue ActiveRecord::RecordNotDestroyed => e
        lead.errors.add(:base, e.to_s)
        byebug
        return false
      rescue ActiveRecord::RecordInvalid => e
        lead.errors.add(:base, e.to_s)
        byebug
        return false
      end
    end

    true
  end

end

Class Method Details

.add_items_to_lead(parent, otu_ids, exclusive_otu_ids, add_new_to_first_child = false) ⇒ Object

Parameters:

  • parent (Lead)

    With add_new_to_first_child, determines which lead to add items to

  • otu_ids (Array)

    Which otus to add

  • exclusive_otu_ids (Array)

    Remove these otus from all siblings of the lead added to

  • add_new_to_first_child (Boolean) (defaults to: false)

    if true then add lead otus *that already exist on parent* to parent’s first child, otherwise (default) add all supplied otus to the last available (rightmost) child.



116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
# File 'app/models/lead_item.rb', line 116

def self.add_items_to_lead(parent, otu_ids, exclusive_otu_ids, add_new_to_first_child = false)
  if otu_ids.nil? || otu_ids.empty?
    parent.errors.add(:base, 'No otus to add!')
    return false
  elsif parent.children.empty?
    parent.errors.add(:base, 'No lead children to add to!')
    return false
  end

  lead_to_add_to = nil
  if add_new_to_first_child
    lead_to_add_to = parent.children.first
  else
    parent.children.to_a.reverse.each do |c|
      if c.children.exists?
        next
      else
        # We add to the rightmost available child.
        lead_to_add_to ||= c
      end
    end
  end

  if lead_to_add_to.nil?
    parent.errors.add(:base, 'No available lead to add otus to!')
    return false
  end

  # TODO: this is really special-case code for adding items from a matrix,
  # clean things up.
  if add_new_to_first_child
    # Limit to lead items that exist on the right lead.
    otu_ids = otu_ids & parent.children[1].lead_items.pluck(:otu_id)
  end
  existing = lead_to_add_to.lead_items.pluck(:otu_id)
  new_otu_ids = otu_ids - existing
  lead_item_table = LeadItem.arel_table

  LeadItem.transaction do
    begin
      to_be_destroyed = otu_ids.filter_map do |otu_id|
        exclusive_otu_ids.include?(otu_id) ? otu_id : false
      end
      if to_be_destroyed.count > 0
        LeadItem
          .where(lead_id: lead_to_add_to.sibling_ids)
          .where(otu_id: to_be_destroyed)
          .destroy_all
      end

      a = new_otu_ids.map { |id| { lead_id: lead_to_add_to.id, otu_id: id } }
      LeadItem.create!(a)
      return true
    rescue ActiveRecord::RecordNotDestroyed => e
      lead.errors.add(:base, e.to_s)
      byebug
      return false
    rescue ActiveRecord::RecordInvalid => e
      lead.errors.add(:base, e.to_s)
      byebug
      return false
    end
  end

  true
end

.add_otu_index_for_lead(lead, otu_id, exclusive) ⇒ Object



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'app/models/lead_item.rb', line 69

def self.add_otu_index_for_lead(lead, otu_id, exclusive)
  begin
    Lead.transaction do
      if exclusive
        LeadItem.where(lead_id: lead.sibling_ids, otu_id:).destroy_all
      end

      LeadItem.create!(lead_id: lead.id, otu_id:)
    end
  rescue ActiveRecord::RecordNotDestroyed => e
    lead.errors.add(:base, "Destroy sibling LeadItems failed! '#{e}'")
    return false
  rescue ActiveRecord::RecordInvalid => e
    lead.errors.add(:base, "New LeadItem creation failed! '#{e}'")
    return false
  end

  true
end

.batch_add_otus_for_lead(lead_id, otu_ids, project_id, user_id) ⇒ Object



30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'app/models/lead_item.rb', line 30

def self.batch_add_otus_for_lead(lead_id, otu_ids, project_id, user_id)
  attributes = otu_ids.map { |otu_id|
    {
      otu_id:,
      lead_id:,
      project_id:,
      created_by_id: user_id,
      updated_by_id: user_id
    }
  }

  LeadItem.insert_all(attributes)
end

.consolidate_descendant_items(lead, target = nil) ⇒ Lead or nil

Transfers any items on leaf-node descendants of source to a new lead.

Parameters:

  • target (Lead or nil) (defaults to: nil)

    A lead to add the descendant lead_items to; if nil a new lead is created.

Returns:

  • (Lead or nil)

    If items exist, the lead now holding those items.



52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'app/models/lead_item.rb', line 52

def self.consolidate_descendant_items(lead, target = nil)
  # Both lead and lead_item have `position`, which .leaves orders by, so need
  # to remove that.
  items =
    lead.leaves.unscope(:order).joins(:lead_items).pluck('lead_items.id')

  return nil if items.empty?

  items_lead = target || Lead.create!(text:
    'PLACEHOLDER LEAD TO HOLD OTU OPTIONS FROM A DELETED SUBTREE'
  )

  self.move_items(LeadItem.where(id: items), items_lead)

  items_lead
end

.move_items(items_scope, lead) ⇒ Object



44
45
46
# File 'app/models/lead_item.rb', line 44

def self.move_items(items_scope, lead)
  items_scope.update_all(lead_id: lead.id)
end

.remove_otu_index_for_lead(lead, otu_id) ⇒ Object



89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'app/models/lead_item.rb', line 89

def self.remove_otu_index_for_lead(lead, otu_id)
  count = LeadItem
    .where(otu_id:, lead_id: lead.self_and_siblings.map(&:id)).count

  if count == 1
    lead.errors.add(:base, "Can't destroy last lead item for otu #{otu_id}!")
    return false
  end

  begin
    LeadItem.where(lead_id: lead.id, otu_id:).destroy_all
  rescue ActiveRecord::RecordNotDestroyed => e
    lead.errors.add(:base, "Destroy LeadItem for lead #{lead.id}, otu #{otu_id} failed! '#{e}'")
    return false
  end

  true
end