Coder Social home page Coder Social logo

autogiro's Introduction

byrokrat

Autogiro

Packagist Version Build Status Quality Score

Read and write files for the swedish direct debit system autogirot.

For a command line utility that can convert autogiro files to XML see autogiro2xml.

Installation

composer require byrokrat/autogiro

Table of contents

  1. Autogiro specifications
  2. Generating autogiro request files
  3. Parsing autogiro files
  4. Accessing nodes using visitors
  5. Generating XML from node trees
  6. Hacking

Autogiro specifications

This library is developed against the technichal manual (in swedish) of the direct debit system (autogirot) revised 2016-12-13. For later versions of this document see Bankgirocentralen.

Generating autogiro request files

Create a writer by supplying your bankgiro account number and BGC customer number to WriterFactory.

$writer = (new \byrokrat\autogiro\Writer\WriterFactory)->createWriter(
    '123456',
    (new \byrokrat\banking\BankgiroFactory)->createAccount('1111-1119')
);

Perform actions on the writer and generate file.

$writer->deleteMandate('1234567890');
$rawFile = $writer->getContent();
echo $rawFile;

Will output something like:

0120180114AUTOGIRO                                            1234560011111119  
0300111111190000001234567890                                                    

Parsing autogiro files

Create a parser using the ParserFactory.

$factory = new \byrokrat\autogiro\Parser\ParserFactory;
$parser = $factory->createParser();

The created parser will by default parse and validate monetary amounts, account numbers and identification numbers. Opt out of this functionality by using one of the visitor constants:

$factory->createParser(\byrokrat\autogiro\Parser\ParserFactory::VISITOR_IGNORE_OBJECTS);

Parsing a file creates a node object.

use byrokrat\autogiro\Tree\Node;

/** @var Node */
$node = $parser->parse($rawFile);

Accessing special objects

Account, Amount, StateId and Date nodes are nested structures, where child node Object contains constructed php objects. Access using something like:

$money = $node->getChild(Node::AMOUNT)->getObjectValue();

Walking the parse tree

A simpler way of doing this is by using visitors. See below.

Walk the tree by calling hasChild(), getChild() and getChildren().

echo $node->getChild(Node::MANDATE_REQUEST_SECTION)
    ->getChild(Node::DELETE_MANDATE_REQUEST)
    ->getChild(Node::PAYER_NUMBER)
    ->getValue();

Or access all Node::DELETE_MANDATE_REQUEST nodes.

$mandateRequests = $node->getChild(Node::MANDATE_REQUEST_SECTION);

foreach ($mandateRequests->getChildren(Node::DELETE_MANDATE_REQUEST) as $deleteRequest) {
    // process...
}

Trying to access a child that does not exist returns a NullNode.

echo $node->getChild('this-does-not-exist')
    ->getChild('and-neither-does-this')
    ->isNull();

Accessing nodes using visitors

With the use of visitors nodes can be accessed based on name or type.

class MyVisitor extends \byrokrat\autogiro\Visitor\Visitor {
    function beforeDeleteMandateRequest($node) {
        echo "Delete mandate request found!";
    }
}

$visitor = new MyVisitor;

$node->accept($visitor);

This can also be done dynamically.

$visitor = new \byrokrat\autogiro\Visitor\Visitor;

$visitor->before(Node::DELETE_MANDATE_REQUEST, function ($node) {
    echo "Delete mandate request found!";
});

Finding mandate responses

$visitor->before(Node::MANDATE_RESPONSE, function ($node) {
    if ($node->hasChild(Node::CREATED_FLAG)) {
        // Mandate successfully created
    }
    if ($node->hasChild(Node::DELETED_FLAG)) {
        // Mandate successfully deleted
    }
    if ($node->hasChild(Node::ERROR_FLAG)) {
        // Mandate error state
    }
});

Finding payment responses

$visitor->before(Node::SUCCESSFUL_INCOMING_PAYMENT_RESPONSE, function ($node) {
    // successfull payment..
});

$visitor->before(Node::FAILED_INCOMING_PAYMENT_RESPONSE, function ($node) {
    // failed payment..
});

Generating XML from node trees

Using this feature can be very helpful to understand how the parser interprets various layouts.

$xmlWriter = (new \byrokrat\autogiro\Xml\XmlWriterFactory)->createXmlWriter();

echo $xmlWriter->asXml(
    $parser->parse($rawFile)
);

Hacking

With composer installed as composer

make

Or use something like

make COMPOSER_CMD=./composer.phar

autogiro's People

Contributors

hanneskod avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

autogiro's Issues

Implement all autogiro layouts

This issue tracks the current layout implementation status.

Parsing and writing request layouts

  • Writing mandate requests
  • Parsing mandate requests
  • Writing payment requests
  • Parsing payment requests
  • Writing amendment requests
  • Parsing amendment requests

Parsing response layouts

  • Payment responses
  • Mandate responses
  • Rejected payment responses
  • Amendment responses
  • Digital mandate responses
  • Payment registry extract responses
  • Mandate registry extract responses
  • Payment responses in BGMAX format (will not be supported, but should generate an informative error message..)

Remove Enumerator

Use a Visitor instead. The simple readme example can use an anonymous class...

Add Node constants

Use a Nodes interface in the base namespace similarl to Intervals.

Acts as a catalogue of nodes as well as preventing simple misspelling error..

Id and account is not mandatory in mandate responses

In mandate responses, mandate reqords (tc 73) includes an id and an account field. These are not mandatory, and will be 0 filled for certain info and status codes (for example when a mandate has been revoked). Needs to be fixed in parser or validator...

Here is an example. Fake bg. Payer number 1.

012018032299000050501055AG-MEDAVI                                               
73005050105500000000000000010000000000000000000000000000     033320180322       
092018032299000000001                                                           

Use cut operator in Grammar

If there is only one rule mapping a transaction code in Grammar the cut operator can probably be used after the TC to speed up parsing.

No idea to implement before grammar is more or less complete as this can lead buggy behaviour when new rules are added...

Record node tree structure...

The tree structure needs to be solid. Some issues and thoughts...

  • Naming. Should all request nodes start with Request or end with RequestNode? Eg RequestOpeningRecordNode or OpeningRecordRequestNode. (Of course the same goes for response nodes.)

  • Tree. Is the tree to deep? Do we really need Tree/Record/Response? Is not Tree/Response or Tree/Record enough...

  • There is an OpeningRecordNode but it is not generic (not used in both request and response layouts). Putting it in the Tree/Record namespace make it look generic. If there are functionality here that is important lets make it an abstract class.

  • Document all tree changes in UPDATING.md.

Can't parse any of the test files

I've been looking for a way to parse BGC-files and found this package. However none of the test files work. When trying the new format this is the error I get

[byrokrat\autogiro\Exception\ContentException] Tree invalid due to the following issues:
Parser: Syntax error, expecting '01', REQ_OPENING_RECORD, REQ_MANDATE_LAYOUT, REQ_PAYMENT_LAYOUT, REQ_AMENDMENT_LAYOUT, REQUEST_FILE, '01', RESP_MANDATE_OPENING_OLD_RECORD, '01', GENERIC_OPENING_RECORD, RESP_MANDATE_FILE, FILE on line 1

If I remove the following from the test file:

[---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8

I get below error instead

[byrokrat\autogiro\Exception\ContentException] Tree invalid due to the following issues:
Parser: Syntax error, expecting ALPHA-NUMERIC on line 1

Steps to reproduce

  1. Download zip

  2. Add a testfile

<?php
require_once('vendor/autoload.php');
$factory = new \byrokrat\autogiro\Parser\ParserFactory;
$parser = $factory->createParser();
$fileNode = $parser->parse(file_get_contents('tests/ny_layout/autogiro_exempelfil_bet-spec-o-tk_sv.txt'));

Add name as a member of Node

In a parent-child node relationship the child is currently not aware of it's name. Adding name as a member of Node whould make printing the element name when we generate XML a simple thing, and generally makes sense.

This would however mean that name must be known at node creation in parser. A problem when the same node type is used multiple times in the same record. For example INT6 is used repeatedly for record counts in closing nodes. This issue needs to be resolved...

How to store messages

Presently we use a PHP interface. This does not feel optimal. Some other datasource would be better. A simple json collection?

Also there seems to be two ways of noting messages in Messages.php. A blast from the past? Make sure all messages are stored using the same semantics.

Validate record count in response layouts

Response layouts typically contains a closing record that specifies the number of different records in the file (and the summed amounts for transactions). These counts can be validated using a visitor.

A generic CountingVisitor could count all node types and validate the count using a generic Closing record node. The type of node a count refers to could be specified at parse time.

Monetary amounts could possible be validated in the same manner.

Edit: There is now a generic closing record universaly applied.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.