Module: Models::AccountingDocumentTransmittable

Extended by:
ActiveSupport::Concern
Included in:
CreditMemo, Invoice, StatementOfAccount
Defined in:
app/concerns/models/accounting_document_transmittable.rb

Overview

Mixin shared by Invoice, CreditMemo and StatementOfAccount that
manages the document's transmission_state state machine and resolves
the Customer's NotificationChannel / ContactPoint to use when
transmitting to JDE / EDI / email. Centralises the
customer → billing-customer → fallback-channel lookup chain.

Instance Method Summary collapse

Instance Method Details

#can_be_transmitted?Boolean

Returns:

  • (Boolean)


39
40
41
# File 'app/concerns/models/accounting_document_transmittable.rb', line 39

def can_be_transmitted?
  transmission_contact_points.any?
end

#fallback_notification_channel_typeObject

If credit_memos or statement_of_accounts notification channel is not set up, fall back to the invoices notification channel.



52
53
54
# File 'app/concerns/models/accounting_document_transmittable.rb', line 52

def fallback_notification_channel_type
  NotificationChannel::INVOICES
end

#notification_channel_sort_orderString

SQL ORDER BY fragment that sorts NotificationChannel rows so the
document's own type comes first, then the fallback, then anything
else. Used when transmitting to multiple channels in deterministic order.

Returns:

  • (String)


69
70
71
# File 'app/concerns/models/accounting_document_transmittable.rb', line 69

def notification_channel_sort_order
  "CASE notification_type when '#{own_notification_channel_type}' then 1 when '#{fallback_notification_channel_type}' then 2 else 3 end, id"
end

#notification_channel_typesArray<String>

Both notification-channel types this document will look up against,
in preference order — own type, then invoices fallback.

Returns:

  • (Array<String>)


60
61
62
# File 'app/concerns/models/accounting_document_transmittable.rb', line 60

def notification_channel_types
  [own_notification_channel_type, fallback_notification_channel_type]
end

#notification_channelsActiveRecord::Relation<NotificationChannel>, Array

Resolves the set of NotificationChannels to transmit through —
walks customer / billing-customer with own-type then fallback-type,
honouring fallback_enabled on billing-customer channels, and
returns [] when nothing is configured.

Returns:



79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'app/concerns/models/accounting_document_transmittable.rb', line 79

def notification_channels
  # notification_channel.notification_type could be: invoices, credit_memos, statement_of_accounts
  # if the customer has matching notification channels set up, use them
  # next try the billing customer for matching notification channels
  # next try the customer for the fallback notification channels
  # next try the billing customer for fallback notification channels
  # else return empty array
  if customer.notification_channels.where(notification_type: own_notification_channel_type).any?
    customer.notification_channels.where(notification_type: own_notification_channel_type)
  elsif billing_customer && billing_customer.notification_channels.fallback_enabled.where(notification_type: own_notification_channel_type).any?
    billing_customer.notification_channels.fallback_enabled.where(notification_type: own_notification_channel_type)
  elsif customer.notification_channels.where(notification_type: fallback_notification_channel_type).any?
    customer.notification_channels.where(notification_type: fallback_notification_channel_type)
  elsif billing_customer && billing_customer.notification_channels.fallback_enabled.where(notification_type: fallback_notification_channel_type).any?
    billing_customer.notification_channels.fallback_enabled.where(notification_type: fallback_notification_channel_type)
  else
    []
  end
end

#own_notification_channel_typeString

NotificationChannel type matching the document class
(invoices, credit_memos, statement_of_accounts).

Returns:

  • (String)


47
48
49
# File 'app/concerns/models/accounting_document_transmittable.rb', line 47

def own_notification_channel_type
  self.class.to_s.underscore.pluralize
end

#post_communication_exception_hook(_params = {}) ⇒ Boolean

Communication-pipeline hook — fired when send fails to advance the
transmission state machine into exception so it can be retried or
surfaced in the queue UI.

Parameters:

  • _params (Hash) (defaults to: {})

    ignored

Returns:

  • (Boolean)


152
153
154
155
# File 'app/concerns/models/accounting_document_transmittable.rb', line 152

def post_communication_exception_hook(_params = {})
  # Mark document as transmitted after communication is sent
  transmission_exception
end

#post_communication_sent_hook(_params = {}) ⇒ Boolean

Communication-pipeline hook — fired by the Communication after
successful send to advance the transmission state machine into
transmitted.

Parameters:

  • _params (Hash) (defaults to: {})

    ignored

Returns:

  • (Boolean)


141
142
143
144
# File 'app/concerns/models/accounting_document_transmittable.rb', line 141

def post_communication_sent_hook(_params = {})
  # Mark document as transmitted after communication is sent
  transmit
end

#primary_transmission_contactParty?

The Party that owns the primary transmission contact point —
the human/company the document will be transmitted to.

Returns:



131
132
133
# File 'app/concerns/models/accounting_document_transmittable.rb', line 131

def primary_transmission_contact
  transmission_contact_points.first&.party
end

#primary_transmission_contact_point_idInteger?

Convenience id of the first contact point in
#transmission_contact_points — used by form selects so the rep
sees the resolved transmission target pre-selected.

Returns:

  • (Integer, nil)


123
124
125
# File 'app/concerns/models/accounting_document_transmittable.rb', line 123

def primary_transmission_contact_point_id
  transmission_contact_points.first&.id
end

#transmission_contact_pointsArray<ContactPoint>, ActiveRecord::Relation<ContactPoint>

ContactPoints the document will actually be sent to — derived
from #notification_channels, falling back to the customer's
preferred transmittable contact point for homeowner / direct-pro
profiles that don't bother configuring channels. Empty array when
nothing usable is configured.

Returns:



106
107
108
109
110
111
112
113
114
115
116
# File 'app/concerns/models/accounting_document_transmittable.rb', line 106

def transmission_contact_points
  if notification_channels.present?
    # if the customer has an invoice notification channel set up, use that
    ContactPoint.where(id: notification_channels.collect(&:contact_point_id).compact).transmittable
  elsif billing_customer&.profile && (billing_customer.profile.homeowner? || billing_customer.profile.direct_pro?)
    # it's a homeowner, so just use their preferred contact point
    customer.contact_points.transmittable.any? ? [customer.contact_points.transmittable.first] : []
  else
    []
  end
end