OpenXE/www/plugins/sepa/SepaXmlCreator.php
2021-05-21 08:49:41 +02:00

429 lines
14 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
/*
* SepaXmlCreator - by Thomas Schiffler.de
* http://www.ThomasSchiffler.de/2013_09/code-schnipsel/sepa-sammeluberweisung-xml-datei-mit-php-erstellen
*
* Copyright (c) 2013 Thomas Schiffler (http://www.ThomasSchiffler.de
* GPL (http://www.opensource.org/licenses/gpl-license.php) license.
*
*/
class SepaBuchung{
var $end2end, $iban, $bic, $kontoinhaber, $verwendungszweck, $amount;
// Mandatsinformationen für Lastschriften
var $mandatId, $mandatDatum, $mandatAenderung;
function __construct() {
$this->end2end = "NOTPROVIDED";
}
function setEnd2End($end2end) {
$this->end2end = $this->normalizeString($end2end);
}
function setIban($iban) {
$this->iban = str_replace(' ','',$iban);
}
function setBic($bic) {
$this->bic = $bic;
}
function setName($name) {
$this->kontoinhaber = $this->normalizeString($name);
}
function setVerwendungszweck($verwendungszweck) {
$this->verwendungszweck = $this->normalizeString($verwendungszweck);
}
function setBetrag($betrag) {
$this->amount = $betrag;
}
/*
* Methode zum Setzen des Mandates - notwendig beim Generieren von Lastschriften. Wenn gewünscht kann
* nur die Mandats-ID gesetzt werden, hierbei wird das aktuelle Tagesdatum als Datum der Mandatserteilung
* genommen. Das Datum ist im Format (YYYY-mm-dd - bsp. 2013-11-02 zu übergeben)
*
* @param String $id
* @param String $mandatDatum
* @param boolean $mandatAenderung - true wenn das Mandat seit letzer Erteilung geändert wurde
*/
function setMandat($id, $mandatDatum = null, $mandatAenderung = true) {
$this->mandatId = $id;
$this->mandatAenderung = $mandatAenderung;
if (!isset($mandatDatum)) {
$this->mandatDatum = date('Y-m-d', time());
} else {
$this->mandatDatum = $mandatDatum;
}
}
function normalizeString($input) {
// Only below characters can be used within the XML tags according the guideline.
// a b c d e f g h i j k l m n o p q r s t u v w x y z
// A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
// 0 1 2 3 4 5 6 7 8 9
// / - ? : ( ) . , +
// Space
//
// Create a normalized array and cleanup the string $XMLText for unexpected characters in names
$normalizeChars = array(
'Á'=>'A', 'À'=>'A', 'Â'=>'A', 'Ã'=>'A', 'Å'=>'A', 'Ä'=>'Ae', 'Æ'=>'AE', 'Ç'=>'C',
'É'=>'E', 'È'=>'E', 'Ê'=>'E', 'Ë'=>'E', 'Í'=>'I', 'Ì'=>'I', 'Î'=>'I', 'Ï'=>'I', 'Ð'=>'Eth',
'Ñ'=>'N', 'Ó'=>'O', 'Ò'=>'O', 'Ô'=>'O', 'Õ'=>'O', 'Ö'=>'O', 'Ø'=>'O',
'Ú'=>'U', 'Ù'=>'U', 'Û'=>'U', 'Ü'=>'Ue', 'Ý'=>'Y',
'á'=>'a', 'à'=>'a', 'â'=>'a', 'ã'=>'a', 'å'=>'a', 'ä'=>'ae', 'æ'=>'ae', 'ç'=>'c',
'é'=>'e', 'è'=>'e', 'ê'=>'e', 'ë'=>'e', 'í'=>'i', 'ì'=>'i', 'î'=>'i', 'ï'=>'i', 'ð'=>'eth',
'ñ'=>'n', 'ó'=>'o', 'ò'=>'o', 'ô'=>'o', 'õ'=>'o', 'ö'=>'oe', 'ø'=>'o',
'ú'=>'u', 'ù'=>'u', 'û'=>'u', 'ü'=>'ue', 'ý'=>'y',
'ß'=>'ss', 'þ'=>'thorn', 'ÿ'=>'y',
'&'=>'u.', '@'=>'at', '#'=>'h', '$'=>'s', '%'=>'perc', '^'=>'-','*'=>'-'
);
$output = strtr($input, $normalizeChars);
return $output;
}
}
class SepaXmlCreator {
var $buchungssaetze = array();
var $accountName, $accountIban, $accountBic;
var $offset = 0, $fixedDate;
var $waehrung = "EUR";
// Mode = 1 -> Überweisung / Mode = 2 -> Basislastschrift
var $mode = 1;
var $isFirst = true;
// Gläubiger-ID
var $glaeubigerId;
// XML-Errors
private $xmlerrors;
function setDebitorValues($name, $iban, $bic) {
trigger_error('Use setAccountValues($name, $iban, $bic) instead', E_USER_DEPRECATED);
$this->setAccountValues($name, $iban, $bic);
}
function setAccountValues($name, $iban, $bic) {
$this->accountName = $name;
$this->accountIban = $iban;
$this->accountBic = $bic;
}
function setGlaeubigerId($glaeubigerId) {
$this->glaeubigerId = $glaeubigerId;
}
function setCurrency($currency) {
$this->waehrung = $currency;
}
function addBuchung($buchungssatz) {
array_push($this->buchungssaetze, $buchungssatz);
}
function setAusfuehrungOffset($offset) {
$this->offset = $offset;
}
function setAusfuehrungDatum($datum) {
$this->fixedDate = $datum;
}
function generateSammelueberweisungXml() {
// Set Mode = 1 -> Sammelüberweisung
$this->mode = 1;
return $this->getGeneratedXml();
}
function generateBasislastschriftXml() {
// Set Mode = 2 -> Basislastschrift
$this->mode = 2;
return $this->getGeneratedXml();
}
function setIsFolgelastschrift() {
$this->isFirst = false;
}
function getGeneratedXml() {
$dom = new DOMDocument('1.0', 'utf-8');
// Build Document-Root
$document = $dom->createElement('Document');
if ($this->mode == 2) {
$document->setAttribute('xmlns', 'urn:iso:std:iso:20022:tech:xsd:pain.008.002.02');
$document->setAttribute('xsi:schemaLocation', 'urn:iso:std:iso:20022:tech:xsd:pain.008.002.02 pain.008.002.02.xsd');
} else {
$document->setAttribute('xmlns', 'urn:iso:std:iso:20022:tech:xsd:pain.001.002.03');
$document->setAttribute('xsi:schemaLocation', 'urn:iso:std:iso:20022:tech:xsd:pain.001.002.03 pain.001.002.03.xsd');
}
$document->setAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance');
$dom->appendChild($document);
// Build Content-Root
if ($this->mode == 2) {
$content = $dom->createElement('CstmrDrctDbtInitn');
} else {
$content = $dom->createElement('CstmrCdtTrfInitn');
}
$document->appendChild($content);
// Build Header
$header = $dom->createElement('GrpHdr');
$content->appendChild($header);
$creationTime = time();
// Msg-ID
$header->appendChild($dom->createElement('MsgId', $this->accountBic . '00' . date('YmdHis', $creationTime)));
$header->appendChild($dom->createElement('CreDtTm', date('Y-m-d', $creationTime) . 'T' . date('H:i:s', $creationTime) . '.000Z'));
$header->appendChild($dom->createElement('NbOfTxs', count($this->buchungssaetze)));
$header->appendChild($initatorName = $dom->createElement('InitgPty'));
$initatorName->appendChild($dom->createElement('Nm', $this->accountName));
// PaymentInfo
$paymentInfo = $dom->createElement('PmtInf');
$content->appendChild($paymentInfo);
$paymentInfo->appendChild($dom->createElement('PmtInfId', 'PMT-ID0-' . date('YmdHis', $creationTime)));
switch ($this->mode) {
case 2:
// 2 = Basislastschrift
$paymentInfo->appendChild($dom->createElement('PmtMtd', 'DD'));
break;
default:
// Default / 1 = Überweisung
$paymentInfo->appendChild($dom->createElement('PmtMtd', 'TRF'));
break;
}
$paymentInfo->appendChild($dom->createElement('BtchBookg', 'false'));
$paymentInfo->appendChild($dom->createElement('NbOfTxs', count($this->buchungssaetze)));
$paymentInfo->appendChild($dom->createElement('CtrlSum', number_format($this->getUmsatzsumme(), 2, '.', '')));
$paymentInfo->appendChild($tmp1 = $dom->createElement('PmtTpInf'));
$tmp1->appendChild($tmp2 = $dom->createElement('SvcLvl'));
$tmp2->appendChild($dom->createElement('Cd', 'SEPA'));
if ($this->mode == 2) {
// zusätzliche Attribute für Lastschriften
$tmp1->appendChild($tmp2 = $dom->createElement('LclInstrm'));
$tmp2->appendChild($dom->createElement('Cd', 'CORE'));
if ($this->isFirst) {
$tmp1->appendChild($dom->createElement('SeqTp', 'FRST'));
} else {
$tmp1->appendChild($dom->createElement('SeqTp', 'RCUR'));
}
}
// Ausführungsdatum berechnen
if (isset($this->fixedDate)) {
$ausfuehrungsdatum = $this->fixedDate;
} else {
$ausfuehrungszeit = $creationTime;
if ($this->offset > 0) {
$ausfuehrungszeit = $ausfuehrungszeit + (24 * 3600 * $this->offset);
}
$ausfuehrungsdatum = date('Y-m-d', $ausfuehrungszeit);
}
if ($this->mode == 2) {
$paymentInfo->appendChild($dom->createElement('ReqdColltnDt', $ausfuehrungsdatum));
} else {
$paymentInfo->appendChild($dom->createElement('ReqdExctnDt', $ausfuehrungsdatum));
}
// eigene Account-Daten Daten
if ($this->mode == 2) {
$paymentInfo->appendChild($tmp1 = $dom->createElement('Cdtr'));
} else {
$paymentInfo->appendChild($tmp1 = $dom->createElement('Dbtr'));
}
$tmp1->appendChild($dom->createElement('Nm', $this->accountName));
if ($this->mode == 2) {
$paymentInfo->appendChild($tmp1 = $dom->createElement('CdtrAcct'));
} else {
$paymentInfo->appendChild($tmp1 = $dom->createElement('DbtrAcct'));
}
$tmp1->appendChild($tmp2 = $dom->createElement('Id'));
$tmp2->appendChild($dom->createElement('IBAN', $this->accountIban));
if ($this->mode == 2) {
$paymentInfo->appendChild($tmp1 = $dom->createElement('CdtrAgt'));
} else {
$paymentInfo->appendChild($tmp1 = $dom->createElement('DbtrAgt'));
}
$tmp1->appendChild($tmp2 = $dom->createElement('FinInstnId'));
$tmp2->appendChild($dom->createElement('BIC', $this->accountBic));
$paymentInfo->appendChild($dom->createElement('ChrgBr', 'SLEV'));
if ($this->mode == 2) {
$paymentInfo->appendChild($tmp1 = $dom->createElement('CdtrSchmeId'));
$tmp1->appendChild($tmp2 = $dom->createElement('Id'));
$tmp2->appendChild($tmp3 = $dom->createElement('PrvtId'));
$tmp3->appendChild($tmp4 = $dom->createElement('Othr'));
$tmp4->appendChild($dom->createElement('Id', $this->glaeubigerId));
$tmp4->appendChild($tmp5 = $dom->createElement('SchmeNm'));
$tmp5->appendChild($dom->createElement('Prtry', 'SEPA'));
}
// Buchungssätze hinzufügen
foreach ($this->buchungssaetze as $buchungssatz) {
if ($this->mode == 2) {
$paymentInfo->appendChild($buchung = $dom->createElement('DrctDbtTxInf'));
} else {
$paymentInfo->appendChild($buchung = $dom->createElement('CdtTrfTxInf'));
}
// End2End setzen
if (isset($buchungssatz->end2end)) {
$buchung->appendChild($tmp1 = $dom->createElement('PmtId'));
$tmp1->appendChild($dom->createElement('EndToEndId', $buchungssatz->end2end));
}
// Betrag
if ($this->mode == 2) {
$buchung->appendChild($tmp2 = $dom->createElement('InstdAmt', number_format($buchungssatz->amount, 2, '.', '')));
$tmp2->setAttribute('Ccy', $this->waehrung);
} else {
$buchung->appendChild($tmp1 = $dom->createElement('Amt'));
$tmp1->appendChild($tmp2 = $dom->createElement('InstdAmt', number_format($buchungssatz->amount, 2, '.', '')));
$tmp2->setAttribute('Ccy', $this->waehrung);
}
if ($this->mode == 2) {
// Lastschrift -> Mandatsinformationen
$buchung->appendChild($tmp1 = $dom->createElement('DrctDbtTx'));
$tmp1->appendChild($tmp2 = $dom->createElement('MndtRltdInf'));
$tmp2->appendChild($dom->createElement('MndtId', $buchungssatz->mandatId));
$tmp2->appendChild($dom->createElement('DtOfSgntr', $buchungssatz->mandatDatum));
if ($buchungssatz->mandatAenderung) {
$tmp2->appendChild($dom->createElement('AmdmntInd', 'true'));
} else {
$tmp2->appendChild($dom->createElement('AmdmntInd', 'false'));
}
}
// Institut
if ($this->mode == 2) {
$buchung->appendChild($tmp1 = $dom->createElement('DbtrAgt'));
} else {
$buchung->appendChild($tmp1 = $dom->createElement('CdtrAgt'));
}
$tmp1->appendChild($tmp2 = $dom->createElement('FinInstnId'));
$tmp2->appendChild($dom->createElement('BIC', $buchungssatz->bic));
// Inhaber
if ($this->mode == 2) {
$buchung->appendChild($tmp1 = $dom->createElement('Dbtr'));
} else {
$buchung->appendChild($tmp1 = $dom->createElement('Cdtr'));
}
$tmp1->appendChild($dom->createElement('Nm', $buchungssatz->kontoinhaber));
// IBAN
if ($this->mode == 2) {
$buchung->appendChild($tmp1 = $dom->createElement('DbtrAcct'));
} else {
$buchung->appendChild($tmp1 = $dom->createElement('CdtrAcct'));
}
$tmp1->appendChild($tmp2 = $dom->createElement('Id'));
$tmp2->appendChild($dom->createElement('IBAN', $buchungssatz->iban));
if ($this->mode == 2) {
$buchung->appendChild($tmp1 = $dom->createElement('UltmtDbtr'));
$tmp1->appendChild($dom->createElement('Nm', $buchungssatz->kontoinhaber));
}
// Verwendungszweck
if (strlen($buchungssatz->verwendungszweck) > 0) {
$buchung->appendChild($tmp1 = $dom->createElement('RmtInf'));
$tmp1->appendChild($dom->createElement('Ustrd', $buchungssatz->verwendungszweck));
}
}
// XML exportieren
return $dom->saveXML();
}
function getUmsatzsumme() {
$betrag = 0;
foreach ($this->buchungssaetze as $buchungssatz) {
$betrag = $betrag + $buchungssatz->amount;
}
return $betrag;
}
public function validateBasislastschriftXml($xmlfile) {
return $this->validateXML($xmlfile, 'pain.008.002.02.xsd');
}
public function validateUeberweisungXml($xmlfile) {
return $this->validateXML($xmlfile, 'pain.001.002.03.xsd');
}
protected function validateXML($xmlfile, $xsdfile) {
libxml_use_internal_errors(true);
$feed = new DOMDocument();
$result = $feed->load($xmlfile);
if ($result === false) {
$this->xmlerrors[] = "Document is not well formed\n";
}
if (@($feed->schemaValidate(dirname(__FILE__) . '/' . $xsdfile))) {
return true;
} else {
$this->xmlerrors[] = "! Document is not valid:\n";
$errors = libxml_get_errors();
foreach ($errors as $error) {
$this->xmlerrors[] = "---\n" . sprintf("file: %s, line: %s, column: %s, level: %s, code: %s\nError: %s",
basename($error->file),
$error->line,
$error->column,
$error->level,
$error->code,
$error->message
);
}
}
return false;
}
public function printXmlErrors() {
if (!is_array($this->xmlerrors)) return;
foreach ($this->xmlerrors as $error) {
echo $error;
}
}
}
?>