NAME

Business::CAMT - ISO20022 Cash Management (CAMT) messages

SYNOPSIS

my $camt = Business::CAMT->new;
my $msg  = $camt->read($file|$xml);
print $msg->toPerl;
print $msg->toJSON;

my $message = $camt->create('053.001.02', $data);
$camt->write('out.xml', $message);
$message->write('out.xml');   # same

DESCRIPTION

Use this module to manage CAMT messages, which are ISO20022 standard "Cash Management" messages as produced in banking. For instance, CAMT.053 is produced by banks and consumed by accountancies, showing transactions in bank-accounts. See https://www.iso20022.org.

At the moment, this module can be used to read and write the XML message files, perfectly validated and predictable. It is intended to also support abstraction in interpreting and constructing the content.

However, I need a sponsor to make that happen. Contact the author for support. Please. I would also like to include a CAMT.053 to CSV and MT-940 converter, v.v. Please hire me.

METHODS

Constructors

Business::CAMT->new(%options)

Create a new CAMT processing object.

Reuse this object to avoid recompilation of the message processor, which is pretty expensive.

-Option       --Default
 big_numbers    false
 long_tagnames  false
 match_schema   'NEWER'
big_numbers => BOOLEAN

Set to a true value when your accounts run into the billions. This will enable Math::BigFloat to be used, which is slower and memory hungry.

long_tagnames => BOOLEAN

The schemas are derived from an UML specifications which uses clear and readible long names for relations and attributes. But, someone with a poor sense of optimization removed most of the vowels from these tags while translating the UML into an XSD. When set to true, this option will give you the nice long names in Perl.

match_schema => $rule

Sets the default $rule how to handle messages which have namespaces which do not match the schemas contained in the module release.

See matchSchema() for the available $rule values. See the DETAILS section about the namespace versioning horrors.

Accessors

$obj->schemas()

Returns the XML::Compile::Schema object, which collects the compiled message XSDs. The XSDs get automatically loaded when messages are encountered which need them.

Read and Write messages

$obj->create($type, $data, %options)

Create a new message, to be written later. The $data is the content of the message, in a structure as can be found in the example templates.

The $type is either in the form camt.053.001.02 or 053.001.02.

example: of create

my $camt = Business::CAMT->new(...);
my $msg  = $camt->create('053.001.02', \%data);
$msg->write('file.xml');
$obj->fromHASH(\%data, %options)

Create a Business::CAMT::Message object of the given type. It is not checked whether the type schema exists until an attempt is made to write the message.

-Option--Default
 type    <required>
type => VERSION

Something like camt.053.001.02 or 053.001.02.

$obj->read($file|$xml, %options)

Pass a $file name, an $xml document or an $xml element. Returned is a HASH blessed in class 'Business::CAMT::CAMnr', for instance Business::CAMT::CAMT053.

-Option      --Default
 match_schema  new(match_schema)
match_schema => $rule
$obj->write($file, $message, %options)

Write a constructed $message (an extension of Business::CAMT::Message) to a file in XML format. The message can also be written as JSON or Perl data-structure, via the message itself.

example: writing a message

my $message = $camt->create('053.001.02', $data);
$camt->write('out.xml', $message);
$message->write('out.xml');   # same

Helper methods

You would rarely (or never) need to use these methods in your programs: they support the reader and writer function.

$obj->fullname2tagTable()

Translates long and understandable names into (silly) abbreviated tags.

$obj->knownVersions( [$set] )

Returns a sorted LIST with all schema versions which are included in this distribution. When the $set is specified (like 053.001), then only those are reported.

$obj->matchSchema($set, $version, %options)

Find the available schema version for the $set (like '053.001') to interpret a message with $version (like '02').

-Option--Default
 rule    new(match_schema)
rule => 'EXACT'|'NEWER'|'NEWEST'|'ANY'|CODE

When EXACT, only the precise version is acceptable. NEWER will fall back to the closest newer version. When no exact match, NEWEST returns the highest available version, but must be newer. Most generous is ANY, which falls back to the newest available version even when it is older than the message version.

You may also pass a CODE reference, which is called with the $set, the requested schema, and a sorted ARRAY of available versions. It must return one of the available versions or undef (no compatible version).

$obj->schemaReader($set, $version, $ns)

Produces a CODE which can be called with an XML message, to get it transformed into a Perl data-structure. In this case, the $set and $version have to be known already; method read() figures that out by itself.

$obj->schemaWriter($set, $version, $ns)
$obj->tag2fullnameTable()

Returns a table which translates the (silly) abbreviations used in the XML tags into readable names. Good names make it easier to understand the handling code and is less error-prone.

DETAILS

In this chapter, you find some background information and implementation tips.

Examples

The release contains a examples/ directory. In that directory, you with find a show script and some xml files. Run the script with a file, to see what this module has to offer. For example:

cd Business-CAMT-0.01/
examples/show examples/danskeci.com/camt053_dk_example.xml /tmp/a.xml

The script (this module) auto-detects the CAMT type which is found in the XML message. Play with the script to see how changes affect the output.

Templates

In our GitHub repository, you find a templates/ directory which contains a structural dump of each of the Perl data structure which is produced (for read()) or consumed (for write, to be implemented) by this module.

Be sure you understand anonymous HASHes and ARRAYs in Perl well, when you start playing. Do not forget that code gets more readible when you use practical reference variables.

On GitHub, you will also find a templates-long/ directory full of examples. This demonstrates what option new(long_tagnames) does: it will make the Perl datastructures readible.

Implementation issues

XML namespaces

The idea behind XML namespaces to include schema versioning is fundamentally flawed. The CAMT files form no exception in this broken XML concept. Of course, schema versions are mainly backwards compatible, so why not design your versioning with that in mind?

This module bends the namespace use to hide these design mistakes into flexible code. Without full knowledge about existing and future versions of the schemas, there is a powerfull configuration setting with matchSchema().

Please consider to contribute discovered incompatibility issues to this module, to hide them where possible.

Tag abbreviations

XML is very verbose anyway, so it really does not help to abbreviate tags leaving some vowels out. This makes it harder to read messages and code. It increases the chance on stupid typos in the code.

When you set new(long_tagnames), then your Perl structure will use longer, understandable names: it gets easy to understand the message without reading the documentation. This improves maintenance on the long run.

This option will be applied both on read() and write(). Of course, the templates will show you how it works: see the templates-long/ directory in the github repository.

No common types

Each schema is separate, although their type definitions are overlapping. It is not guaranteed that equal types will stay that way over time. This may cause instable code.

Probably, these issues will not emerge because the schema files are generated from a central UML model. However: small changes in the data structure will cause multiple schemas to change to a new version.

A better setup would be:

  • a schema for base types, like "Amount"

  • a schema for more complex (reused) structures

  • a schema per message, which composes the complex structures

Missed chances on XML

The way these schema's got generated, make them very low in using more powerful XML schema features. Those features would have helped the stability of the "interface" which these messages implement a lot. Done this way, XML is not much better than JSON. To be honest, the schemas are littered by missed chances.

The messages are designed with an UML tool, which means: limited to the features of that tool and hindering the view on the quality of the schema. This leads to structures like:

<Bal>
  <Tp>
    <CdOrPrtry>
       <Cd>OPBD</Cd>
    </CdOrPrtry>
  </Tp>
  <Amt Ccy="SEK">500000</Amt>
  <CdtDbtInd>CRDT</CdtDbtInd>
  <Dt>
    <Dt>2010-10-15</Dt>
  </Dt>
</Bal>

In Perl, this leads to (long_tagnames on)

Balance => {
  Type => {
    CodeOrProperty => {
      Code => 'OPBD',
    }
  },
  Amount => {
    _ => '500000',
    Currency => 'SEK',
  },
  CreditDebitInd => 'CRDT',
  Date => {
    Date => '2010-10-15',
  },
}

The XML schema, when designed as XML schema, could have looked like

<OpeningBook Date="2010-10-15CEST">
  <Credit Currency="SEK">500000.00</Credit>
</OpeningBook>

The use of group'ed elements and substitutionGroup's would have made messages so much clearer and easier. Even simple constructs as extension and restriction of complexType's are not used. It would have reduced the message size much further than by leaving out the vowels from tags, as the example shows.

But more importantly: this hinders backward compatibility in the message evaluation a lot! Using XML features better would result in better maintainable applications. Much better.

SEE ALSO

This module is part of Business-CAMT distribution version 0.13, built on December 02, 2024. Website: http://perl.overmeer.net/CPAN/

LICENSE

Copyrights 2024 by [Mark Overmeer <markov@cpan.org>]. For other contributors see ChangeLog.

This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. See http://dev.perl.org/licenses/

1 POD Error

The following errors were encountered while parsing the POD:

Around line 126:

Deleting unknown formatting code T<>