Module: YDIM::Camt
- Defined in:
- lib/ydim/camt.rb
Overview
Reader for ISO-20022 bank-to-customer statements (camt.052/053/054), as delivered by UBS and the other Swiss banks. This is pure parsing: no DB and no ODBA, so it can run on the client side. The matching of entries against invoices lives in YDIM::Reconciler.
Defined Under Namespace
Classes: Entry, Error, Statement
Class Method Summary collapse
- .dedup(entries) ⇒ Object
-
.entries(path) ⇒ Object
All entries of all statements below path, duplicates included -- the Reconciler drops those, and it can only report how many deliveries were doubled up if it gets to see them.
-
.parse(xml, source = nil) ⇒ Object
Parses one camt document into its Statements.
-
.read(path) ⇒ Object
Reads whatever the bank handed you: a single xml file, a directory of them, or the zip you downloaded from e-banking.
- .read_files(paths) ⇒ Object
- .read_zip(path) ⇒ Object
Class Method Details
.dedup(entries) ⇒ Object
141 142 143 144 145 |
# File 'lib/ydim/camt.rb', line 141 def dedup(entries) seen = {} entries.select { |entry| !seen.key?(entry.dedup_key) \ && seen[entry.dedup_key] = true } end |
.entries(path) ⇒ Object
All entries of all statements below path, duplicates included -- the Reconciler drops those, and it can only report how many deliveries were doubled up if it gets to see them.
138 139 140 |
# File 'lib/ydim/camt.rb', line 138 def entries(path) read(path).flat_map { |stmt| stmt.entries } end |
.parse(xml, source = nil) ⇒ Object
Parses one camt document into its Statements.
125 126 127 128 129 130 131 132 133 134 |
# File 'lib/ydim/camt.rb', line 125 def parse(xml, source = nil) doc = REXML::Document.new(xml) root = doc.root or raise Error, "#{source}: not an XML document" # camt.053.001.02 through .08 differ only in the namespace URI for # everything we read, so take whatever the document declares. ns = { 'c' => root.namespace } REXML::XPath.match(doc, '//c:Stmt | //c:Rpt | //c:Ntfctn', ns).collect { |node| parse_statement(node, ns, source) } end |
.read(path) ⇒ Object
Reads whatever the bank handed you: a single xml file, a directory of them, or the zip you downloaded from e-banking. Returns Statements.
101 102 103 104 105 106 107 108 109 |
# File 'lib/ydim/camt.rb', line 101 def read(path) if File.directory?(path) read_files(Dir[File.join(path, '**', '*.[xX][mM][lL]')].sort) elsif path =~ /\.zip\z/i read_zip(path) else read_files([path]) end end |
.read_files(paths) ⇒ Object
110 111 112 113 114 |
# File 'lib/ydim/camt.rb', line 110 def read_files(paths) paths.flat_map { |path| parse(File.read(path), File.basename(path)) } end |
.read_zip(path) ⇒ Object
115 116 117 118 119 120 121 122 123 |
# File 'lib/ydim/camt.rb', line 115 def read_zip(path) Dir.mktmpdir('ydim-camt') { |dir| unless system('unzip', '-q', '-o', path, '-d', dir) raise Error, "unable to unzip #{path} -- extract it and pass the directory" end read_files(Dir[File.join(dir, '**', '*.[xX][mM][lL]')].sort) } end |