diff --git a/README.md b/README.md
new file mode 100644
index 0000000..9c7ee45
--- /dev/null
+++ b/README.md
@@ -0,0 +1,30 @@
+#v11
+This is a php library to read ESR v11 files, Swiss banking payments.
+(BESR/VESR/ESR - Einzahlungsscheine mit Referenznummer einlesen)
+
+## Installation
+
+Add v11 in your composer.json:
+
+```js
+{
+ "require": {
+ "ticketpark/v11": "~0.1"
+ }
+}
+```
+
+Now tell composer to download the bundle by running the command:
+
+``` bash
+$ php composer.phar update ticketpark/v11
+```
+
+## Example
+See [example.php](example/example.php)
+
+
+## License
+This bundle is under the MIT license. See the complete license in the bundle:
+
+[Resources/meta/LICENSE](Resources/meta/LICENSE)
\ No newline at end of file
diff --git a/Resources/docs/specifications/zkb-vesr-handbuch.pdf b/Resources/docs/specifications/zkb-vesr-handbuch.pdf
new file mode 100644
index 0000000..c7a782e
Binary files /dev/null and b/Resources/docs/specifications/zkb-vesr-handbuch.pdf differ
diff --git a/Resources/meta/LICENSE b/Resources/meta/LICENSE
new file mode 100644
index 0000000..bd63d47
--- /dev/null
+++ b/Resources/meta/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2014 Ticketpark GmbH
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished
+to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/Tests/v11/Tests/v11Test.php b/Tests/v11/Tests/v11Test.php
new file mode 100644
index 0000000..d32ff83
--- /dev/null
+++ b/Tests/v11/Tests/v11Test.php
@@ -0,0 +1,150 @@
+assertTrue($v11->validate());
+ }
+
+ public function testValidateTransactions()
+ {
+ $v11 = new v11(array(
+ "002012000002123456000000001291146290519 7500000000000014102414102514102600000000000000000000120",
+ "012012000002123456000000001290507716881 50000008 000014102314102414102400552073900000000000000",
+ "002012000002123456000000001288602003992 2550000000000014102414102414102400000000000000000000000",
+ "002012000002123456000000001290068583973 50000008 000014102314102414102400489435900000000000000",
+ "999012000002999999999999999999999999999000000020050000000000004141027000000120000000004 ",
+ ));
+ $v11->setParticipantIdentifier('123456');
+
+ $this->assertSame('002', $v11->getTransactionRecords()[0]->getTransactionCode()->getTransactionCode());
+ $this->assertSame('credit', $v11->getTransactionRecords()[0]->getTransactionCode()->getTransactionType());
+ $this->assertSame('esr', $v11->getTransactionRecords()[0]->getTransactionCode()->getReceiptType());
+ $this->assertSame('banking', $v11->getTransactionRecords()[0]->getTransactionCode()->getPaymentType());
+
+ $this->assertSame('012000002', $v11->getTransactionRecords()[0]->getBankingAccount());
+ $this->assertSame('123456000000001291146290519', $v11->getTransactionRecords()[0]->getReferenceNumber());
+ $this->assertSame('12345600000000129114629051', $v11->getTransactionRecords()[0]->getReferenceNumberWithoutCheckDigit());
+ $this->assertSame('00000000129114629051', $v11->getTransactionRecords()[0]->getCustomReferenceNumber());
+ $this->assertSame(129114629051, $v11->getTransactionRecords()[0]->getCustomReferenceNumber(true));
+ $this->assertSame(75, $v11->getTransactionRecords()[0]->getAmount());
+ $this->assertSame('0000000000', $v11->getTransactionRecords()[0]->getInternalBankReference());
+ $this->assertSame('2014-10-24', $v11->getTransactionRecords()[0]->getDatePaid()->format('Y-m-d'));
+ $this->assertSame('2014-10-25', $v11->getTransactionRecords()[0]->getDateProcessed()->format('Y-m-d'));
+ $this->assertSame('2014-10-26', $v11->getTransactionRecords()[0]->getDateCreditNote()->format('Y-m-d'));
+ $this->assertSame('000000000', $v11->getTransactionRecords()[0]->getMicrofilmReference());
+ $this->assertSame('0', $v11->getTransactionRecords()[0]->getRejectCode());
+ $this->assertNull($v11->getTransactionRecords()[0]->getDateValuta());
+ $this->assertSame(1.2, $v11->getTransactionRecords()[0]->getFee());
+
+ $this->assertSame('999', $v11->getTotalRecord()->getTransactionCode()->getTransactionCode());
+ $this->assertSame('012000002', $v11->getTotalRecord()->getBankingAccount());
+ $this->assertSame('999999999999999999999999999', $v11->getTotalRecord()->getSortingKey());
+ $this->assertSame(4, $v11->getTotalRecord()->getNumberOfTransactions());
+ $this->assertSame('2014-10-27', $v11->getTotalRecord()->getDateFileCreation()->format('Y-m-d'));
+ $this->assertSame(1.2, $v11->getTotalRecord()->getTotalFees());
+ }
+
+
+ public function testValidateTotalLineTooShort()
+ {
+ $v11 = new v11(array(
+ "002012000002123456000000001291146290519 7500000000000014102414102414102400000000000000000000000",
+ "012012000002123456000000001290507716881 50000008 000014102314102414102400552073900000000000120",
+ "002012000002123456000000001288602003992 2550000000000014102414102414102400000000000000000000000",
+ "002012000002123456000000001290068583973 50000008 000014102314102414102400489435900000000000000",
+ "99901200000299999999999999999999999999900000020050000000000004141027000000120000000004 ",
+ ));
+ $this->assertFalse($v11->validate());
+ $this->assertSame('The total line contains 86 instead of 87 characters', $v11->getError());
+ }
+
+ public function testValidateTotalLineBadTransactionCode()
+ {
+ $v11 = new v11(array(
+ "002012000002123456000000001291146290519 7500000000000014102414102414102400000000000000000000000",
+ "012012000002123456000000001290507716881 50000008 000014102314102414102400552073900000000000120",
+ "002012000002123456000000001288602003992 2550000000000014102414102414102400000000000000000000000",
+ "002012000002123456000000001290068583973 50000008 000014102314102414102400489435900000000000000",
+ "111012000002999999999999999999999999999000000020050000000000004141027000000120000000004 ",
+ ));
+ $this->assertFalse($v11->validate());
+ $this->assertSame('The total line does not contain a valid transaction code', $v11->getError());
+ }
+
+ public function testValidateTotalLineInvalidContents()
+ {
+ $v11 = new v11(array(
+ "002012000002123456000000001291146290519 7500000000000014102414102414102400000000000000000000000",
+ "012012000002123456000000001290507716881 50000008 000014102314102414102400552073900000000000120",
+ "002012000002123456000000001288602003992 2550000000000014102414102414102400000000000000000000000",
+ "002012000002123456000000001290068583973 50000008 000014102314102414102400489435900000000000000",
+ "99901200000299999999999999999999999999900A000020050000000000004141027000000120000000004 ",
+ ));
+ $this->assertFalse($v11->validate());
+ $this->assertSame('The total line contains invalid characters. It may only contain digits and spaces', $v11->getError());
+ }
+
+ public function testValidateTransactionLineTooShort()
+ {
+ $v11 = new v11(array(
+ "002012000002123456000000001291146290519 7500000000000014102414102414102400000000000000000000000",
+ "012012000002123456000000001290507716881 50000008 000014102314102414102400552073900000000000120",
+ "002012000002123456000000001288602003992 255000000000001410241410241410240000000000000000000000",
+ "002012000002123456000000001290068583973 50000008 000014102314102414102400489435900000000000000",
+ "999012000002999999999999999999999999999000000020050000000000004141027000000120000000004 ",
+ ));
+ $this->assertFalse($v11->validate());
+ $this->assertSame('Line number 3 contains 99 instead of 100 characters', $v11->getError());
+ }
+
+ public function testValidateTransactionLineBadTransactionCode()
+ {
+ $v11 = new v11(array(
+ "002012000002123456000000001291146290519 7500000000000014102414102414102400000000000000000000000",
+ "012012000002123456000000001290507716881 50000008 000014102314102414102400552073900000000000120",
+ "007012000002123456000000001288602003992 2550000000000014102414102414102400000000000000000000000",
+ "002012000002123456000000001290068583973 50000008 000014102314102414102400489435900000000000000",
+ "999012000002999999999999999999999999999000000020050000000000004141027000000120000000004 ",
+ ));
+ $this->assertFalse($v11->validate());
+ $this->assertSame('Line number 3 contains does not contain a valid transaction code', $v11->getError());
+ }
+
+ public function testValidateTransactionLineInvalidContents()
+ {
+ $v11 = new v11(array(
+ "002012000002123456000000001291146290519 7500000000000014102414102414102400000000000000000000000",
+ "012012000002123456000000001290507716881 50000008 000014102314102414102400552073900000000000120",
+ "002012000002123456000000001288602003992 255000000A000014102414102414102400000000000000000000000",
+ "002012000002123456000000001290068583973 50000008 000014102314102414102400489435900000000000000",
+ "999012000002999999999999999999999999999000000020050000000000004141027000000120000000004 ",
+ ));
+ $this->assertFalse($v11->validate());
+ $this->assertSame('Line number 3 contains invalid characters. It may only contain digits and spaces', $v11->getError());
+ }
+
+ public function testValidateNotMatchingNumberOfTransactions()
+ {
+ $v11 = new v11(array(
+ "002012000002123456000000001291146290519 7500000000000014102414102414102400000000000000000000000",
+ "012012000002123456000000001290507716881 50000008 000014102314102414102400552073900000000000120",
+ "002012000002123456000000001290068583973 50000008 000014102314102414102400489435900000000000000",
+ "999012000002999999999999999999999999999000000020050000000000004141027000000120000000004 ",
+ ));
+ $this->assertFalse($v11->validate());
+ $this->assertSame('The number of 3 transactions does not match the number of 4 transactions according to the total line', $v11->getError());
+ }
+}
diff --git a/composer.json b/composer.json
new file mode 100644
index 0000000..4df008a
--- /dev/null
+++ b/composer.json
@@ -0,0 +1,17 @@
+{
+ "name": "ticketpark/v11",
+ "type": "library",
+ "description": "A php library to process ESR/BESR v11 files (Swiss payment slips / Einzahlungsscheine mit Referenznummer)",
+ "keywords": ["besr", "esr", "v11", "einzahlungsschein", "payment slip"],
+ "homepage": "https://github.com/Ticketpark/v11",
+ "license": "MIT",
+ "authors": [
+ {"name": "Manuel Reinhard", "email": "manu@sprain.ch"}
+ ],
+ "require": {
+ "php": ">=5.4"
+ },
+ "autoload": {
+ "psr-4": { "Ticketpark\\v11\\": "lib/v11" }
+ }
+}
diff --git a/example/example.php b/example/example.php
new file mode 100644
index 0000000..b85c155
--- /dev/null
+++ b/example/example.php
@@ -0,0 +1,49 @@
+getCustomReferenceNumber() later on.
+$v11->setParticipantIdentifier('123456');
+
+// Set content - by file or array
+#$v11->setFile('/path/to/file/besr.v11');
+$v11->setLines(array(
+ "002012000002123456000000001291146290519 7500000000000014102414102414102400000000000000000000000",
+ "012012000002123456000000001290507716881 50000008 000014102314102414102400552073900000000000120",
+ "002012000002123456000000001288602003992 2550000000000014102414102414102400000000000000000000000",
+ "002012000002123456000000001290068583973 50000008 000014102314102414102400489435900000000000000",
+ "999012000002999999999999999999999999999000000020050000000000004141027000000120000000004 ",
+));
+
+// Validate the contents
+if(!$v11->validate()) {
+ print $v11->getError();
+}
+
+// Get the transaction records - see Ticketpark\v11\Record\TransactionRecord for more methods
+foreach($v11->getTransactionRecords() as $record){
+ var_dump(
+ array(
+ 'Transaction type' => $record->getTransactionCode()->getTransactionType(),
+ 'Payment type' => $record->getTransactionCode()->getPaymentType(),
+ 'Amount' => $record->getSignedAmount(),
+ 'Full Reference number' => $record->getReferenceNumber(),
+ 'Customer numeric reference number' => $record->getCustomReferenceNumber(true),
+ 'Fee' => $record->getFee(),
+ )
+ );
+}
+
+// Get the total record - see Ticketpark\v11\Record\TotalRecord for more methods
+$total = $v11->getTotalRecord();
+var_dump(
+ array(
+ 'Transaction type' => $total->getTransactionCode()->getTransactionType(),
+ 'Amount' => $total->getSignedAmount(),
+ 'Number of transactions' => $total->getNumberOfTransactions(),
+ 'Total Fees' => $total->getTotalFees(),
+ )
+);
diff --git a/lib/v11/Record/TotalRecord.php b/lib/v11/Record/TotalRecord.php
new file mode 100644
index 0000000..df8523e
--- /dev/null
+++ b/lib/v11/Record/TotalRecord.php
@@ -0,0 +1,116 @@
+transactionCode = $transactionCode;
+
+ return $this;
+ }
+
+ public function getTransactionCode()
+ {
+ return $this->transactionCode;
+ }
+
+ public function setBankingAccount($bankingAccount)
+ {
+ $this->bankingAccount = $bankingAccount;
+
+ return $this;
+ }
+
+ public function getBankingAccount()
+ {
+ return $this->bankingAccount;
+ }
+
+ public function setSortingKey($sortingKey)
+ {
+ $this->sortingKey = $sortingKey;
+
+ return $this;
+ }
+
+ public function getSortingKey()
+ {
+ return $this->sortingKey;
+ }
+
+ public function setAmount($amount)
+ {
+ $this->amount = $amount;
+
+ return $this;
+ }
+
+ public function getAmount()
+ {
+ return $this->amount;
+ }
+
+ public function getSignedAmount()
+ {
+ if ($this->getTransactionCode()->getTransactionType() == 'storno') {
+
+ return $this->amount * -1;
+ }
+
+ return $this->amount;
+ }
+
+ public function setNumberOfTransactions($numberOfTransactions)
+ {
+ $this->numberOfTransactions = $numberOfTransactions;
+
+ return $this;
+ }
+
+ public function getNumberOfTransactions()
+ {
+ return $this->numberOfTransactions;
+ }
+
+ public function setDateFileCreation(\DateTime $dateFileCreation = null)
+ {
+ $this->dateFileCreation = $dateFileCreation;
+
+ return $this;
+ }
+
+ public function getDateFileCreation()
+ {
+ return $this->dateFileCreation;
+ }
+
+ public function setTotalFees($totalFees)
+ {
+ $this->totalFees = $totalFees;
+
+ return $this;
+ }
+
+ public function getTotalFees()
+ {
+ return $this->totalFees;
+ }
+}
\ No newline at end of file
diff --git a/lib/v11/Record/TransactionCode/TransactionCode.php b/lib/v11/Record/TransactionCode/TransactionCode.php
new file mode 100644
index 0000000..15d06fc
--- /dev/null
+++ b/lib/v11/Record/TransactionCode/TransactionCode.php
@@ -0,0 +1,32 @@
+transactionCode = $transactionCode;
+
+ return $this;
+ }
+
+ public function getTransactionCode()
+ {
+ return $this->transactionCode;
+ }
+
+ public function setParticipantIdentifier($participantIdentifier)
+ {
+ $this->participantIdentifier = $participantIdentifier;
+
+ return $this;
+ }
+
+ public function getParticipantIdentifier()
+ {
+ return $this->participantIdentifier;
+ }
+
+ public function setBankingAccount($bankingAccount)
+ {
+ $this->bankingAccount = $bankingAccount;
+
+ return $this;
+ }
+
+ public function getBankingAccount()
+ {
+ return $this->bankingAccount;
+ }
+
+ public function setReferenceNumber($referenceNumber)
+ {
+ $this->referenceNumber = $referenceNumber;
+
+ return $this;
+ }
+
+ public function getReferenceNumber()
+ {
+ return $this->referenceNumber;
+ }
+
+ public function getReferenceNumberWithoutCheckDigit()
+ {
+ return substr($this->referenceNumber, 0, -1);
+ }
+
+ public function getCustomReferenceNumber($numeric = false)
+ {
+ $customReferenceNumber = substr($this->getReferenceNumberWithoutCheckDigit(), strlen($this->getParticipantIdentifier()));
+
+ if ($numeric) {
+
+ return $customReferenceNumber * 1;
+ }
+
+ return $customReferenceNumber;
+ }
+
+ public function setAmount($amount)
+ {
+ $this->amount = $amount;
+
+ return $this;
+ }
+
+ public function getAmount()
+ {
+ return $this->amount;
+ }
+
+ public function getSignedAmount()
+ {
+ if ($this->getTransactionCode()->getTransactionType() == 'storno') {
+
+ return $this->amount * -1;
+ }
+
+ return $this->amount;
+ }
+
+ public function setInternalBankReference($internalBankReference)
+ {
+ $this->internalBankReference = $internalBankReference;
+
+ return $this;
+ }
+
+ public function getInternalBankReference()
+ {
+ return $this->internalBankReference;
+ }
+
+ public function setDatePaid(\DateTime $datePaid = null)
+ {
+ $this->datePaid = $datePaid;
+
+ return $this;
+ }
+
+ public function getDatePaid()
+ {
+ return $this->datePaid;
+ }
+
+ public function setDateProcessed(\DateTime $dateProcessed = null)
+ {
+ $this->dateProcessed = $dateProcessed;
+
+ return $this;
+ }
+
+ public function getDateProcessed()
+ {
+ return $this->dateProcessed;
+ }
+
+ public function setDateCreditNote(\DateTime $dateCreditNote = null)
+ {
+ $this->dateCreditNote = $dateCreditNote;
+
+ return $this;
+ }
+
+ public function getDateCreditNote()
+ {
+ return $this->dateCreditNote;
+ }
+
+ public function setMicrofilmReference($microfilmReference)
+ {
+ $this->microfilmReference = $microfilmReference;
+
+ return $this;
+ }
+
+ public function getMicrofilmReference()
+ {
+ return $this->microfilmReference;
+ }
+
+ public function setRejectCode($rejectCode)
+ {
+ $this->rejectCode = $rejectCode;
+
+ return $this;
+ }
+
+ public function getRejectCode()
+ {
+ return $this->rejectCode;
+ }
+
+ public function setDateValuta(\DateTime $dateValuta = null)
+ {
+ $this->dateValuta = $dateValuta;
+
+ return $this;
+ }
+
+ public function getDateValuta()
+ {
+ return $this->dateValuta;
+ }
+
+ public function setFee($fee)
+ {
+ $this->fee = $fee;
+
+ return $this;
+ }
+
+ public function getFee()
+ {
+ return $this->fee;
+ }
+}
\ No newline at end of file
diff --git a/lib/v11/v11.php b/lib/v11/v11.php
new file mode 100644
index 0000000..3301438
--- /dev/null
+++ b/lib/v11/v11.php
@@ -0,0 +1,303 @@
+setLines($contents);
+ } elseif (null !== $contents) {
+ $this->setFile($contents);
+ }
+ }
+
+ public function setParticipantIdentifier($participantIdentifier)
+ {
+ $this->participantIdentifier = $participantIdentifier;
+ }
+
+ public function getParticipantIdentifier()
+ {
+ return $this->participantIdentifier;
+ }
+
+ /**
+ * Get the transaction records
+ *
+ * @return array
+ */
+ public function getTransactionRecords()
+ {
+ $records = array();
+
+ foreach ($this->getTransactionLines() as $line) {
+ $records[] = $this->getTransactionRecord($line);
+ }
+
+ return $records;
+ }
+
+ /**
+ * Get the total record
+ *
+ * @return TotalRecord
+ */
+ public function getTotalRecord()
+ {
+ $record = new TotalRecord();
+ $line = $this->getTotalLine();
+
+ if ($transactionCode = TransactionCodeFactory::create(substr($line, 0, 3))) {
+ $record->setTransactionCode($transactionCode);
+ }
+
+ $record
+ ->setBankingAccount(substr($line, 3, 9))
+ ->setSortingKey(substr($line, 12, 27))
+ ->setAmount(substr($line, 39, 12) / 100)
+ ->setNumberOfTransactions(substr($line, 51, 12) * 1)
+ ->setDateFileCreation($this->createDate(substr($line, 63, 6)))
+ ->setTotalFees((substr($line, 69, 9)) / 100);
+
+ return $record;
+ }
+
+ /**
+ * Set path to file containing v11 contents
+ *
+ * @param string $file
+ */
+ public function setFile($file)
+ {
+ $this->file = $file;
+
+ return $this;
+ }
+
+ /**
+ * Get path to file
+ *
+ * @return string
+ */
+ public function getFile()
+ {
+ return $this->file;
+ }
+
+ /**
+ * Set the raw lines
+ *
+ * @param array $lines
+ */
+ public function setLines(array $lines)
+ {
+ $newLines = array();
+ foreach($lines as $line) {
+ $newLines[] = trim($line);
+ }
+
+ $this->lines = $newLines;
+
+ return $this;
+ }
+
+ /**
+ * Get the raw lines
+ *
+ * @return array
+ */
+ public function getLines()
+ {
+ return $this->lines;
+ }
+
+ /**
+ * Get the raw transaction lines
+ *
+ * @return array
+ */
+ public function getTransactionLines()
+ {
+ return array_slice($this->getLines(), 0, -1);
+ }
+
+ /**
+ * Get the raw total line
+ *
+ * @return string
+ */
+ public function getTotalLine()
+ {
+ $lines = $this->getLines();
+
+ return array_pop($lines);
+ }
+
+ /**
+ * Creates a transaction record
+ *
+ * @param $line
+ * @return Record
+ */
+ protected function getTransactionRecord($line)
+ {
+ $record = new TransactionRecord();
+
+ if ($transactionCode = TransactionCodeFactory::create(substr($line, 0, 3))) {
+ $record->setTransactionCode($transactionCode);
+ }
+
+ $record->setParticipantIdentifier($this->getParticipantIdentifier())
+ ->setBankingAccount(substr($line, 3, 9))
+ ->setReferenceNumber(substr($line, 12, 27))
+ ->setAmount(substr($line, 39, 10) / 100)
+ ->setInternalBankReference(substr($line, 49, 10))
+ ->setDatePaid($this->createDate(substr($line, 59, 6)))
+ ->setDateProcessed($this->createDate(substr($line, 65, 6)))
+ ->setDateCreditNote($this->createDate(substr($line, 71, 6)))
+ ->setMicrofilmReference(substr($line, 77, 9))
+ ->setRejectCode(substr($line, 86, 1))
+ ->setDateValuta($this->createDate(substr($line, 87, 6)))
+ ->setFee((substr($line, 96, 4)) / 100);
+
+ return $record;
+ }
+
+ /**
+ * Validate the v11 contents
+ *
+ * @return bool
+ */
+ public function validate()
+ {
+
+ if (null !== $this->getFile()) {
+ if (is_readable($this->getFile())) {
+ $this->setLines(file($this->getFile(), FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES));
+ } else {
+ $this->setError(sprintf('The provided file %s is not readable', $this->getFile()));
+
+ return false;
+ }
+ }
+
+
+ if (count($this->getLines()) == 0) {
+
+ return true;
+ }
+
+ $lines = $this->getLines();
+
+ // Last line is the total record
+ // It must have 87 characters and only consist of digits and spaces
+ $lastLine = array_pop($lines);
+ if (strlen($lastLine) != 87) {
+ $this->setError(sprintf('The total line contains %s instead of 87 characters', strlen($lastLine)));
+
+ return false;
+ }
+
+ if (!preg_match('/^[\d ]+$/', $lastLine)) {
+ $this->setError('The total line contains invalid characters. It may only contain digits and spaces');
+
+ return false;
+ }
+
+ // Transaction records must have 100 characters and only consist of digits and spaces
+ $i=1;
+ foreach ($lines as $line) {
+ if (strlen($line) != 100) {
+ $this->setError(sprintf('Line number %s contains %s instead of 100 characters', $i, strlen($line)));
+
+ return false;
+ }
+
+ if (!preg_match('/^[\d ]+$/', $line)) {
+ $this->setError(sprintf('Line number %s contains invalid characters. It may only contain digits and spaces', $i));
+
+ return false;
+ }
+
+ $i++;
+ }
+
+ //Number of transactions must match
+ if ($this->getTotalRecord()->getNumberOfTransactions() != count($lines)) {
+ $this->setError(sprintf('The number of %s transactions does not match the number of %s transactions according to the total line', count($lines), $this->getTotalRecord()->getNumberOfTransactions()));
+
+ return false;
+ }
+
+
+ // All records must have a transaction code
+ if (null == $this->getTotalRecord()->getTransactionCode()) {
+ $this->setError(sprintf('The total line does not contain a valid transaction code'));
+
+ return false;
+ }
+
+ $i=1;
+ foreach($this->getTransactionRecords() as $record){
+ if (null == $record->getTransactionCode()) {
+ $this->setError(sprintf('Line number %s contains does not contain a valid transaction code', $i));
+
+ return false;
+ }
+ $i++;
+ }
+
+ return true;
+ }
+
+ /**
+ * Get the last error message
+ *
+ * @return string
+ */
+ public function getError()
+ {
+ return $this->error;
+ }
+
+ /**
+ * Set error message
+ *
+ * @param string $error
+ */
+ protected function setError($error)
+ {
+ $this->error = $error;
+ }
+
+ /**
+ * Converts a 6-character string (YYMMDD) to a DateTime
+ * @param $string
+ * @return \DateTime|null
+ */
+ protected function createDate($string)
+ {
+ if ('000000' == $string) {
+
+ return null;
+ }
+
+ return new \DateTime(substr($string, 0, 2) . '-' . substr($string, 2, 2) . '-' . substr($string, 4, 2));
+ }
+}
\ No newline at end of file
diff --git a/phpunit.xml b/phpunit.xml
new file mode 100644
index 0000000..4386ce8
--- /dev/null
+++ b/phpunit.xml
@@ -0,0 +1,13 @@
+
+
+
+
+ ./Tests
+
+
+
+
+ ./Tests
+
+
+
\ No newline at end of file