Class: SEPA::Message
- Inherits:
-
Object
- Object
- SEPA::Message
- Includes:
- ActiveModel::Validations, SchemaValidation
- Defined in:
- lib/sepa_rator/message.rb
Direct Known Subclasses
Constant Summary collapse
- FAMILY =
Overridden by subclasses; used to resolve profiles via country/version hints.
nil- XML_MAIN_TAG =
Root element inside <Document>. Overridden by subclasses.
nil
Constants included from SchemaValidation
SchemaValidation::SCHEMA_CACHE, SchemaValidation::SCHEMA_CACHE_MUTEX, SchemaValidation::SCHEMA_DIR
Instance Attribute Summary collapse
-
#account ⇒ Object
readonly
Returns the value of attribute account.
-
#grouped_transactions ⇒ Object
readonly
Returns the value of attribute grouped_transactions.
-
#initiation_source_name ⇒ Object
Returns the value of attribute initiation_source_name.
-
#initiation_source_provider ⇒ Object
Returns the value of attribute initiation_source_provider.
-
#profile ⇒ Object
readonly
Returns the value of attribute profile.
Instance Method Summary collapse
-
#add_transaction(options) ⇒ Object
Add a transaction to the message.
-
#amount_total(selected_transactions = transactions) ⇒ BigDecimal
Total amount.
-
#batch_id(transaction_reference) ⇒ Object
Find the PmtInf ID for the batch containing a transaction with the given reference.
- #batches ⇒ Object
- #creation_date_time ⇒ Object
- #creation_date_time=(value) ⇒ Object
-
#initialize(country: nil, version: :latest, profile: nil, **account_options) ⇒ Message
constructor
A new instance of Message.
- #message_identification ⇒ Object
- #message_identification=(value) ⇒ Object
-
#payment_information_identification(group) ⇒ Object
Unique and consecutive identifier for a <PmtInf> block, derived from ‘message_identification` + the group’s position.
-
#to_xml ⇒ String
Generate the SEPA XML document using the profile provided at construction.
-
#transactions ⇒ Array<Transaction>
All transactions across all groups.
Constructor Details
#initialize(country: nil, version: :latest, profile: nil, **account_options) ⇒ Message
Returns a new instance of Message.
48 49 50 51 52 53 54 |
# File 'lib/sepa_rator/message.rb', line 48 def initialize(country: nil, version: :latest, profile: nil, **) @profile = resolve_profile(country: country, version: version, profile: profile) @grouped_transactions = {} @account = account_class.new() validate_account_against_profile!(@account) end |
Instance Attribute Details
#account ⇒ Object (readonly)
Returns the value of attribute account.
13 14 15 |
# File 'lib/sepa_rator/message.rb', line 13 def account @account end |
#grouped_transactions ⇒ Object (readonly)
Returns the value of attribute grouped_transactions.
13 14 15 |
# File 'lib/sepa_rator/message.rb', line 13 def grouped_transactions @grouped_transactions end |
#initiation_source_name ⇒ Object
Returns the value of attribute initiation_source_name.
13 14 15 |
# File 'lib/sepa_rator/message.rb', line 13 def initiation_source_name @initiation_source_name end |
#initiation_source_provider ⇒ Object
Returns the value of attribute initiation_source_provider.
14 15 16 |
# File 'lib/sepa_rator/message.rb', line 14 def initiation_source_provider @initiation_source_provider end |
#profile ⇒ Object (readonly)
Returns the value of attribute profile.
13 14 15 |
# File 'lib/sepa_rator/message.rb', line 13 def profile @profile end |
Instance Method Details
#add_transaction(options) ⇒ Object
Add a transaction to the message. The transaction is validated both against its own ActiveModel rules and against the profile’s ‘accept_transaction` lambda + extra validators.
62 63 64 65 66 67 68 69 70 71 72 |
# File 'lib/sepa_rator/message.rb', line 62 def add_transaction() transaction = transaction_class.new() raise SEPA::ValidationError, transaction.errors..join("\n") unless transaction.valid? validate_transaction_against_profile!(transaction) group = transaction_group(transaction) @grouped_transactions[group] ||= [] @grouped_transactions[group] << transaction @transactions = nil end |
#amount_total(selected_transactions = transactions) ⇒ BigDecimal
Returns total amount.
108 109 110 |
# File 'lib/sepa_rator/message.rb', line 108 def amount_total(selected_transactions = transactions) selected_transactions.sum(&:amount) end |
#batch_id(transaction_reference) ⇒ Object
Find the PmtInf ID for the batch containing a transaction with the given reference.
139 140 141 142 143 144 |
# File 'lib/sepa_rator/message.rb', line 139 def batch_id(transaction_reference) grouped_transactions.each do |group, transactions| return payment_information_identification(group) if transactions.any? { |t| t.reference == transaction_reference } end nil end |
#batches ⇒ Object
146 147 148 |
# File 'lib/sepa_rator/message.rb', line 146 def batches grouped_transactions.keys.map { |group| payment_information_identification(group) } end |
#creation_date_time ⇒ Object
134 135 136 |
# File 'lib/sepa_rator/message.rb', line 134 def creation_date_time @creation_date_time ||= Time.now.iso8601 end |
#creation_date_time=(value) ⇒ Object
125 126 127 128 129 130 131 132 |
# File 'lib/sepa_rator/message.rb', line 125 def creation_date_time=(value) raise ArgumentError, 'creation_date_time must be a string!' unless value.is_a?(String) regex = /[0-9]{4}-[0-9]{2,2}-[0-9]{2,2}(?:\s|T)[0-9]{2,2}:[0-9]{2,2}:[0-9]{2,2}/ raise ArgumentError, "creation_date_time does not match #{regex}!" unless value.match?(regex) @creation_date_time = value end |
#message_identification ⇒ Object
121 122 123 |
# File 'lib/sepa_rator/message.rb', line 121 def @message_identification ||= "MSG/#{SecureRandom.hex(14)}" end |
#message_identification=(value) ⇒ Object
112 113 114 115 116 117 118 119 |
# File 'lib/sepa_rator/message.rb', line 112 def (value) raise ArgumentError, 'message_identification must be a string!' unless value.is_a?(String) regex = %r{\A([A-Za-z0-9]|[+|?/\-:().,'\ ]){1,35}\z} raise ArgumentError, "message_identification does not match #{regex}!" unless value.match?(regex) @message_identification = value end |
#payment_information_identification(group) ⇒ Object
Unique and consecutive identifier for a <PmtInf> block, derived from ‘message_identification` + the group’s position. Invoked by builder stages.
152 153 154 155 156 |
# File 'lib/sepa_rator/message.rb', line 152 def payment_information_identification(group) suffix = "/#{grouped_transactions.keys.index(group) + 1}" max_prefix_length = 35 - suffix.length "#{[0, max_prefix_length]}#{suffix}" end |
#to_xml ⇒ String
Generate the SEPA XML document using the profile provided at construction.
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
# File 'lib/sepa_rator/message.rb', line 84 def to_xml raise SEPA::ValidationError, errors..join("\n") unless valid? # Fail-safe against post-insertion mutations of the account or # transactions (e.g. a caller flipping `currency` after adding). validate_account_against_profile!(@account) transactions.each { |transaction| validate_transaction_against_profile!(transaction) } doc = Nokogiri::XML::Builder.new(encoding: 'UTF-8') do |builder| builder.Document(xml_namespace_attributes) do builder.__send__(self.class::XML_MAIN_TAG) do run_stages(profile.group_header_stages, builder) run_stages(profile.payment_info_stages, builder) end end end validate_final_document!(doc.doc, profile) doc.to_xml end |
#transactions ⇒ Array<Transaction>
Returns all transactions across all groups.
75 76 77 |
# File 'lib/sepa_rator/message.rb', line 75 def transactions @transactions ||= grouped_transactions.values.flatten end |