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

Whether the document has at least one resolvable contact point to be
transmitted to — gates the queue_for_transmission state event.

Returns:

  • (Boolean)


43
44
45
# File 'app/concerns/models/accounting_document_transmittable.rb', line 43

def can_be_transmitted?
  transmission_contact_points.any?
end

#fallback_notification_channel_typeString

Fallback NotificationChannel type used when the document's own channel
type isn't configured on the customer — the shared invoices channel.

Returns:

  • (String)

    NotificationChannel::INVOICES



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

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)


76
77
78
# File 'app/concerns/models/accounting_document_transmittable.rb', line 76

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>)


67
68
69
# File 'app/concerns/models/accounting_document_transmittable.rb', line 67

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:



86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'app/concerns/models/accounting_document_transmittable.rb', line 86

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)


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

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)


159
160
161
162
# File 'app/concerns/models/accounting_document_transmittable.rb', line 159

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)


148
149
150
151
# File 'app/concerns/models/accounting_document_transmittable.rb', line 148

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:



138
139
140
# File 'app/concerns/models/accounting_document_transmittable.rb', line 138

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)


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

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:



113
114
115
116
117
118
119
120
121
122
123
# File 'app/concerns/models/accounting_document_transmittable.rb', line 113

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