Class: Camt::Parser
Instance Attribute Summary collapse
-
#file ⇒ Object
Returns the value of attribute file.
Instance Method Summary collapse
- #get_balance_type_node(node, balance_type) ⇒ Object
- #get_end_balance(node) ⇒ Object
- #get_party_values(node) ⇒ Object
- #get_start_balance(node) ⇒ Object
- #get_transfer_type(node) ⇒ Object
- #parse(file) ⇒ Object
- #parse_amount(node) ⇒ Object
- #parse_message(node) ⇒ Object
- #parse_Ntry(node) ⇒ Object
- #parse_Stmt(node) ⇒ Object
- #parse_TxDtls(node) ⇒ Object
Instance Attribute Details
#file ⇒ Object
Returns the value of attribute file.
4 5 6 |
# File 'lib/camt/parser.rb', line 4 def file @file end |
Instance Method Details
#get_balance_type_node(node, balance_type) ⇒ Object
6 7 8 9 10 |
# File 'lib/camt/parser.rb', line 6 def get_balance_type_node node, balance_type # :param node: BkToCstmrStmt/Stmt/Bal node # :param balance type: one of 'OPBD', 'PRCD', 'ITBD', 'CLBD' return node.at("./Bal/Tp/CdOrPrtry/Cd[text()='#{balance_type}']/../../..") end |
#get_end_balance(node) ⇒ Object
34 35 36 37 38 39 40 41 42 43 |
# File 'lib/camt/parser.rb', line 34 def get_end_balance(node) # Find the (only) balance node with code ClosingBalance, or # the second (and last) balance node with code InterimBalance in # the case of continued pagination. # # :param node: BkToCstmrStmt/Stmt/Bal node balance_type_node = nil ['CLBD', 'ITBD'].detect{|code| balance_type_node = get_balance_type_node(node, code) } parse_amount balance_type_node end |
#get_party_values(node) ⇒ Object
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 |
# File 'lib/camt/parser.rb', line 86 def get_party_values node # Determine to get either the debtor or creditor party node # and extract the available data from it values = {} party_type = node.at('../../CdtDbtInd').text == 'CRDT' ? 'Dbtr' : 'Cdtr' party_node = node.at("./RltdPties/#{party_type}") account_node = node.at("./RltdPties/#{party_type}Acct/Id") bic_node = node.at("./RltdAgts/#{party_type}Agt/FinInstnId/BIC") if party_node values[:remote_owner] = party_node.at('./Nm').try(:text) values[:remote_owner_country] = party_node.at('./PstlAdr/Ctry').try(:text) values[:remote_owner_address] = party_node.at('./PstlAdr/AdrLine').try(:text) end if account_node values[:remote_account] = account_node.at('./IBAN').try(:text) values[:remote_account] ||= account_node.at('./Othr/Id').try(:text) values[:remote_bank_bic] = bic_node.text if bic_node end return values end |
#get_start_balance(node) ⇒ Object
22 23 24 25 26 27 28 29 30 31 32 |
# File 'lib/camt/parser.rb', line 22 def get_start_balance(node) # Find the (only) balance node with code OpeningBalance, or # the only one with code 'PreviousClosingBalance' # or the first balance node with code InterimBalance in # the case of preceeding pagination. # # :param node: BkToCstmrStmt/Stmt/Bal node balance_type_node = nil ['OPBD', 'PRCD', 'ITBD'].detect{|code| balance_type_node = get_balance_type_node(node, code) } parse_amount balance_type_node end |
#get_transfer_type(node) ⇒ Object
67 68 69 70 71 |
# File 'lib/camt/parser.rb', line 67 def get_transfer_type node # Map properietary codes from BkTxCd/Prtry/Cd. # :param node: BkTxCd/Prtry node { proprietary_code: node.at('./Cd').text, proprietary_issuer: node.at('./Issr').text } if node end |
#parse(file) ⇒ Object
167 168 169 170 171 |
# File 'lib/camt/parser.rb', line 167 def parse file self.file = file file.doc.remove_namespaces! file.doc.xpath('//BkToCstmrStmt').map{|node| node } end |
#parse_amount(node) ⇒ Object
12 13 14 15 16 17 18 19 20 |
# File 'lib/camt/parser.rb', line 12 def parse_amount(node) # Parse an element that contains both Amount and CreditDebitIndicator # # :return: signed amount # :returntype: float sign = node.at('./CdtDbtInd').text == 'DBIT' ? -1 : 1 return sign * node.at('./Amt').text.to_f end |
#parse_message(node) ⇒ Object
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 |
# File 'lib/camt/parser.rb', line 138 def node group_header_node = node.at('./GrpHdr') group_header = GroupHeader.new group_header. = group_header_node.at('./MsgId').text group_header.created_at = Time.parse(group_header_node.at('./CreDtTm').text) group_header.additional_info = group_header_node.at('./AddtlInf').try(:text) if recipient_node = group_header_node.at('./MsgRcpt') group_header.recipient = { name: recipient_node.at('./Nm').try(:text), postal_address: recipient_node.at('./PstlAdr').try(:text), identification: recipient_node.at('./Id').try(:text), country_of_residence: recipient_node.at('./CtryOfRes').try(:text), contact_details: recipient_node.at('./CtctDtls').try(:text) } end if pagination_node = group_header_node.at('./MsgPgntn') group_header.pagination = { page: pagination_node.at('./PgNb').text, last_page: (pagination_node.at('./LastPgInd').text == 'true') } end = Message.new .group_header = group_header .statements = node.xpath('./Stmt').map{|node| parse_Stmt node } end |
#parse_Ntry(node) ⇒ Object
73 74 75 76 77 78 79 80 81 82 83 84 |
# File 'lib/camt/parser.rb', line 73 def parse_Ntry node # :param node: Ntry node transaction = Transaction.new transaction.execution_date = node.at('./BookgDt/Dt | ./BookgDt/DtTm').text transaction.effective_date = node.at('./ValDt/Dt | ./ValDt/DtTm').text transaction.transfer_type = get_transfer_type(node.at('./BkTxCd/Prtry')) transaction.transferred_amount = parse_amount(node) transaction.transaction_details = node.xpath('.//NtryDtls//TxDtls').map{ |node| parse_TxDtls(node) } transaction end |
#parse_Stmt(node) ⇒ Object
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
# File 'lib/camt/parser.rb', line 45 def parse_Stmt node # Parse a single Stmt node. # # Be sure to craft a unique, but short enough statement identifier, # as it is used as the basis of the generated move lines' names # which overflow when using the full IBAN and CAMT statement id. statement = Statement.new statement.id = node.at('./Id').text statement.electronic_sequence_number = node.at('./ElctrncSeqNb').text statement.created_at = Time.parse(node.at('./CreDtTm').text) statement.local_account = node.at('./Acct/Id').text.strip statement.local_currency = node.at('./Acct/Ccy').text statement.date = Time.parse(node.at('./Ntry[1]/ValDt/Dt | ./Ntry[1]/ValDt/DtTm').text) statement.start_balance = get_start_balance(node) statement.end_balance = get_end_balance(node) statement.transactions = node.xpath('./Ntry').map{ |node| parse_Ntry(node) } statement end |
#parse_TxDtls(node) ⇒ Object
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 |
# File 'lib/camt/parser.rb', line 112 def parse_TxDtls node # Parse a single TxDtls node transaction_details = {} if (unstructured = node.xpath('./RmtInf/Ustrd')).any? transaction_details[:messages] = unstructured.map(&:text) end if (structured = node.xpath('./RmtInf/Strd/CdtrRefInf/Ref | ./Refs/EndToEndId')).any? transaction_details[:references] = structured.map(&:text) end if mandate_identifier = node.at('./Refs/MndtId').try(:text) transaction_details[:mandate_identifier] = mandate_identifier end if reason = node.at('./RtrInf/Rsn/Cd').try(:text) reason_language = Camt::Reasons.keys.include?(file.country_code) ? file.country_code : 'EN' transaction_details[:reason] = { code: reason, description: Camt::Reasons[reason_language][reason] } end transaction_details[:party] = get_party_values node transaction_details end |