Module: EffectiveMailchimpUser

Extended by:
ActiveSupport::Concern
Defined in:
app/models/concerns/effective_mailchimp_user.rb

Overview

EffectiveMailchimpUser

Mark your user model with effective_mailchimp_user to get a few helpers And user specific point required scores

Defined Under Namespace

Modules: Base, ClassMethods

Instance Method Summary collapse

Instance Method Details

#build_mailchimp_list_member(mailchimp_list:) ⇒ Object

Find or build



182
183
184
185
# File 'app/models/concerns/effective_mailchimp_user.rb', line 182

def build_mailchimp_list_member(mailchimp_list:)
  raise('expected a MailchimpList') unless mailchimp_list.kind_of?(Effective::MailchimpList)
  mailchimp_list_member(mailchimp_list: mailchimp_list) || mailchimp_list_members.build(mailchimp_list: mailchimp_list)
end

#build_mailchimp_list_membersObject

Used by the form to set it up for all lists



192
193
194
195
196
197
198
199
200
# File 'app/models/concerns/effective_mailchimp_user.rb', line 192

def build_mailchimp_list_members
  mailchimp_lists = Effective::MailchimpList.subscribable.sorted.to_a

  mailchimp_lists.each do |mailchimp_list|
    build_mailchimp_list_member(mailchimp_list: mailchimp_list)
  end

  mailchimp_list_members
end

#default_mailchimp_merge_fieldsObject

These are the fields we push to Mailchimp on list_add and list_update Keys can only be 10 characters long



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
# File 'app/models/concerns/effective_mailchimp_user.rb', line 96

def default_mailchimp_merge_fields
  atts = {}

  if respond_to?(:first_name) && respond_to?(:last_name)
    atts.merge!(
      'FNAME': first_name,
      'LNAME': last_name
    )
  end

  if respond_to?(:addresses)
    address = try(:billing_address) || addresses.last

    atts.merge!(
      'ADDRESS1': address&.address1,
      'ADDRESS2': address&.address2,
      'CITY': address&.city,
      'PROVINCE': address&.province,
      'COUNTRY': address&.country,
      'POSTALCODE': address&.postal_code
    )
  end

  if respond_to?(:membership)
    membership = memberships.first() # Individual or organization membership

    atts.merge!(
      'CATEGORY': membership&.categories&.to_sentence,
      'STATUS': membership&.statuses&.to_sentence,
      'NUMBER': membership&.number,
      'JOINED': membership&.joined_on&.strftime('%F'),
      'FEESPAIDTO': mailchimp_membership_fees_paid_through_period()&.strftime('%F')
    )
  end

  if self.class.respond_to?(:effective_memberships_organization_user?)
    atts.merge!(
      'COMPANY': representatives.map { |rep| rep.organization.to_s }.join(', ').presence,
      'ROLES': representatives.flat_map { |rep| rep.roles }.compact.join(', ').presence,
    )
  end

  atts
end

#mailchimp_cannot_be_subscribed?Boolean

Returns:

  • (Boolean)


164
165
166
# File 'app/models/concerns/effective_mailchimp_user.rb', line 164

def mailchimp_cannot_be_subscribed?
  mailchimp_list_members.any?(&:cannot_be_subscribed?)
end

#mailchimp_last_synced_atObject



187
188
189
# File 'app/models/concerns/effective_mailchimp_user.rb', line 187

def mailchimp_last_synced_at
  mailchimp_list_members.map(&:last_synced_at).compact.min
end

#mailchimp_list_member(mailchimp_list:) ⇒ Object



176
177
178
179
# File 'app/models/concerns/effective_mailchimp_user.rb', line 176

def mailchimp_list_member(mailchimp_list:)
  raise('expected a MailchimpList') unless mailchimp_list.kind_of?(Effective::MailchimpList)
  mailchimp_list_members.find { |mlm| mlm.mailchimp_list_id == mailchimp_list.id }
end

#mailchimp_membership_fees_paid_through_periodObject

Returns the maximum fees_paid_through_period of the membership and any deferred membership_period fees



142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
# File 'app/models/concerns/effective_mailchimp_user.rb', line 142

def mailchimp_membership_fees_paid_through_period
  periods = []

  # Find the fees_paid_through_period from any membership
  if self.class.respond_to?(:effective_memberships_user?) && memberships.present?
    membership = memberships.first() # Individual or organization membership
    periods << membership&.fees_paid_through_period
  end

  # Find the fees_paid_through_period from any deferred membership fees
  fees = if self.class.respond_to?(:effective_memberships_organization_user?) && organizations.present?
    Effective::Fee.deferred.where(owner: [self, organizations])
  else
    Effective::Fee.deferred.where(owner: self)
  end

  periods += fees.select { |fee| fee.membership_period_fee? }.map(&:fees_paid_through_period)

  # Return the maximum fees paid through period
  periods.compact.max
end

#mailchimp_merge_fieldsObject

Intended for app to extend



90
91
92
# File 'app/models/concerns/effective_mailchimp_user.rb', line 90

def mailchimp_merge_fields
  default_mailchimp_merge_fields()
end

#mailchimp_subscribe!(mailchimp_list, subscribed: true, now: false) ⇒ Object

Api method to just subscribe this user to this list right now Pass one list or an Array of lists



56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'app/models/concerns/effective_mailchimp_user.rb', line 56

def mailchimp_subscribe!(mailchimp_list, subscribed: true, now: false)
  mailchimp_lists = Array(mailchimp_list)
  raise('expected a MailchimpList') unless mailchimp_lists.all? { |list| list.kind_of?(Effective::MailchimpList) }

  mailchimp_lists.each do |mailchimp_list|
    member = build_mailchimp_list_member(mailchimp_list: mailchimp_list)
    member.assign_attributes(subscribed: subscribed)
  end

  # For use in a rake task. Run the update right now
  if now
    return mailchimp_update!(only: mailchimp_lists)
  end

  # This sets up the after_commit to run the mailchimp_update! job
  save!
end

#mailchimp_subscribe_to_force_subscribe!Object

Subscribe to force_subscribe lists



274
275
276
277
278
279
# File 'app/models/concerns/effective_mailchimp_user.rb', line 274

def mailchimp_subscribe_to_force_subscribe!
  mailchimp_lists = Effective::MailchimpList.where(force_subscribe: true).to_a
  return unless mailchimp_lists.present?

  mailchimp_subscribe!(mailchimp_lists)
end

#mailchimp_subscribed?(mailchimp_list) ⇒ Boolean

Returns:

  • (Boolean)


45
46
47
48
49
50
51
52
# File 'app/models/concerns/effective_mailchimp_user.rb', line 45

def mailchimp_subscribed?(mailchimp_list)
  raise('expected a MailchimpList') unless mailchimp_lists.all? { |list| list.kind_of?(Effective::MailchimpList) }

  member = mailchimp_list_member(mailchimp_list: mailchimp_list)
  return false if member.blank?

  member.subscribed? && member.synced?
end

#mailchimp_subscribed_interestsObject



172
173
174
# File 'app/models/concerns/effective_mailchimp_user.rb', line 172

def mailchimp_subscribed_interests
  mailchimp_list_members.select(&:subscribed?).flat_map(&:interests)
end

#mailchimp_subscribed_listsObject



168
169
170
# File 'app/models/concerns/effective_mailchimp_user.rb', line 168

def mailchimp_subscribed_lists
  mailchimp_list_members.select(&:subscribed?).map(&:mailchimp_list)
end

#mailchimp_sync!(api: EffectiveMailchimp.api) ⇒ Object

Pulls the current status from Mailchimp API into the Mailchimp List Member objects Run before the mailchimp fields are displayed Only run in the background when a user or admin clicks sync now



205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
# File 'app/models/concerns/effective_mailchimp_user.rb', line 205

def mailchimp_sync!(api: EffectiveMailchimp.api)
  lists = Effective::MailchimpList.sorted.to_a

  mailchimp_with_retries do
    Timeout::timeout(lists.length * 3) do
      lists.each do |mailchimp_list|
        member = build_mailchimp_list_member(mailchimp_list: mailchimp_list)

        list_member = api.list_member(mailchimp_list, email) || {}
        member.assign_mailchimp_attributes(list_member)
      end
    end
  end

  mailchimp_list_members.each do |member|
    list = lists.find { |list| list.id == member.mailchimp_list_id }
    member.mark_for_destruction unless list.present?
  end

  without_mailchimp_update_async { save! }
end

#mailchimp_unsubscribe!(mailchimp_list) ⇒ Object

Api method to just unsubscribe this user to this list right now Pass one list or an Array of lists



76
77
78
79
80
81
82
83
84
85
86
87
# File 'app/models/concerns/effective_mailchimp_user.rb', line 76

def mailchimp_unsubscribe!(mailchimp_list)
  mailchimp_lists = Array(mailchimp_list)
  raise('expected a MailchimpList') unless mailchimp_lists.all? { |list| list.kind_of?(Effective::MailchimpList) }

  mailchimp_lists.each do |mailchimp_list|
    member = build_mailchimp_list_member(mailchimp_list: mailchimp_list)
    member.assign_attributes(subscribed: false)
  end

  # This sets up the after_commit to run the mailchimp_update! job
  save!
end

#mailchimp_update!(api: EffectiveMailchimp.api, only: [], except: []) ⇒ Object

Pushes the current Mailchimp List Member objects to Mailchimp when needed Called in the background after a form submission that changes the user email/last_name/first_name or mailchimp subscriptions



234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
# File 'app/models/concerns/effective_mailchimp_user.rb', line 234

def mailchimp_update!(api: EffectiveMailchimp.api, only: [], except: [])
  return if mailchimp_member_update_blocked?

  mailchimp_list_members.each do |member|
    next if only.present? && Array(only).exclude?(member.mailchimp_list)
    next if except.present? && Array(except).include?(member.mailchimp_list)

    begin
      list_member = if member.mailchimp_id.blank? && member.subscribed?
        api.list_member_add(member)
      elsif member.mailchimp_id.present?
        api.list_member_update(member)
      end

      member.assign_mailchimp_attributes(list_member) if list_member.present?
    rescue MailchimpMarketing::ApiError => e
      message = e.to_s.downcase

      if message.include?("cannot be subscribed") || message.include?("deleted") || message.include?("unsubscribed") || message.include?("archived") || message.include?("cleaned")
        member.assign_mailchimp_cannot_be_subscribed
      elsif message.include?("already a list member") || message.include?("already in this list")
        existing = api.list_member(member.mailchimp_list, member.user.email)
        member.assign_mailchimp_attributes(existing) if existing.present?
      elsif message.include?("could not be found")
        # Nothing to do
      else
        # Nothing to do.
      end

      if defined?(ExceptionNotifier) && !EffectiveMailchimp.silence_api_errors?
        ExceptionNotifier.notify_exception(e, data: { user_id: id || 'nil' })
      end

    end
  end

  without_mailchimp_update_async { save! }
end

#mailchimp_update_async!Object



227
228
229
230
# File 'app/models/concerns/effective_mailchimp_user.rb', line 227

def mailchimp_update_async!
  @mailchimp_member_update_enqueued = true
  EffectiveMailchimpUpdateJob.perform_later(self)
end

#without_mailchimp_update_async(&block) ⇒ Object



281
282
283
284
285
286
287
288
289
290
291
292
# File 'app/models/concerns/effective_mailchimp_user.rb', line 281

def without_mailchimp_update_async(&block)
  raise('expected a block') unless block_given?

  before = @mailchimp_member_update_enqueued

  begin
    @mailchimp_member_update_enqueued = true
    yield
  ensure
    @mailchimp_member_update_enqueued = before
  end
end