InvoiceOperations.php 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. <?php
  2. namespace NavOnlineInvoice;
  3. use Exception;
  4. class InvoiceOperations {
  5. const MAX_INVOICE_COUNT = 100;
  6. const COMPRESSION_LEVEL = 1;
  7. protected $invoices;
  8. protected $compression;
  9. /**
  10. * Az automatikusan felismert technicalAnnulment értéke az első hozzáadott számla alapján.
  11. * `null` esetén még nincs számla hozzáadva
  12. *
  13. * @var bool|null
  14. */
  15. protected $detectedTechnicalAnnulment = null;
  16. protected $index;
  17. protected $schemaValidation = true;
  18. /**
  19. * Számlákat (számla műveleteket) összefogó objektum (collection) készítése
  20. *
  21. * @param boolean $compression gzip tömörítés alkalmazása, részletek: NAV dokumentáció, 1.6.5 Tömörítés és méretkorlát
  22. */
  23. function __construct($compression = false) {
  24. $this->invoices = array();
  25. $this->index = 1;
  26. $this->compression = $compression;
  27. }
  28. /**
  29. * Számla hozzáadásakor ellenőrizze az XML adatot a DATA sémával szemben
  30. *
  31. * @param boolean $flag
  32. */
  33. public function useDataSchemaValidation($flag = true) {
  34. $this->schemaValidation = $flag;
  35. }
  36. /**
  37. * Számla ('szakmai XML') hozzáadása
  38. *
  39. * @param \SimpleXMLElement $xml Számla adatai (szakmai XML)
  40. * @param string [$operation = "CREATE"] Számlaművelet Enum(CREATE, MODIFY, STORNO, ANNUL)
  41. * @param string [$electronicInvoiceHash = null] Számla SHA3-512 hash értéke elektronikus számla esetén. Ha completenessIndicator=true, akkor itt null-t kell átadni.
  42. * @return int A beszúrt művelet sorszáma (index)
  43. * @throws \Exception
  44. */
  45. public function add(\SimpleXMLElement $xml, $operation = "CREATE", $electronicInvoiceHash = null) {
  46. // XSD validálás
  47. if ($this->schemaValidation) {
  48. $xsdFile = $operation === "ANNUL" ? Config::getAnnulmentXsdFilename() : Config::getDataXsdFilename();
  49. Xsd::validate($xml->asXML(), $xsdFile);
  50. }
  51. // Számlák maximum számának ellenőrzése
  52. if (count($this->invoices) > self::MAX_INVOICE_COUNT) {
  53. throw new Exception("Maximum " . self::MAX_INVOICE_COUNT . " számlát lehet egyszerre elküldeni!");
  54. }
  55. // Technical annulment flag beállítása és ellenőrzése
  56. $this->detectTechnicalAnnulment($operation);
  57. $completenessIndicator = $this->isComplete($xml);
  58. if ($completenessIndicator and $electronicInvoiceHash) {
  59. throw new Exception("completenessIndicator=true esetén az electronicInvoiceHash értékét a nav-online-invoice modul számolja automatikusan, így ezt a paramétert üresen kell hagyni!");
  60. }
  61. $invoiceBase64Data = $this->convertXml($xml);
  62. if ($completenessIndicator) {
  63. $electronicInvoiceHash = Util::sha3_512($invoiceBase64Data);
  64. }
  65. $idx = $this->index;
  66. $this->index++;
  67. $this->invoices[] = array(
  68. "index" => $idx,
  69. "operation" => $operation,
  70. "invoice" => $invoiceBase64Data,
  71. "electronicInvoiceHash" => $electronicInvoiceHash,
  72. );
  73. return $idx;
  74. }
  75. /**
  76. * A felismert technicalAnnulment értékének lekérdezése.
  77. * Ha még nem adtunk hozzá számlát, akkor hibát fog dobni.
  78. *
  79. * @return bool technicalAnnulment
  80. * @throws Exception
  81. */
  82. public function isTechnicalAnnulment() {
  83. if (!$this->invoices) {
  84. throw new Exception("Még nincs számla hozzáadva, így a technicalAnnulment értéke nem megállapítható!");
  85. }
  86. return $this->detectedTechnicalAnnulment;
  87. }
  88. protected function detectTechnicalAnnulment($operation) {
  89. $currentFlag = ($operation === 'ANNUL');
  90. // Ha még nincs beállítva, akkor beállítjuk
  91. if (is_null($this->detectedTechnicalAnnulment)) {
  92. $this->detectedTechnicalAnnulment = $currentFlag;
  93. }
  94. // Ha a korábban beállított nem egyezik az aktuálissal, akkor hiba dobása (NAV nem fogadja el)
  95. if ($this->detectedTechnicalAnnulment !== $currentFlag) {
  96. throw new Exception("Az egyszerre feladott számlák nem tartalmazhatnak vegyesen ANNUL, illetve ettől eltérő operation értéket!");
  97. }
  98. }
  99. public function getInvoices() {
  100. return $this->invoices;
  101. }
  102. /**
  103. * Utoljára hozzáadott számla electronicInvoiceHash értékét adja vissza.
  104. * Ez lehet paraméterben átadott, vagy completenessIndicator=true esetén a modul által számolt hash.
  105. *
  106. * @return string
  107. */
  108. public function getLastInvoiceHash() {
  109. if (!$this->invoices) {
  110. return null;
  111. }
  112. $lastInvoice = $this->invoices[count($this->invoices) - 1];
  113. return $lastInvoice['electronicInvoiceHash'];
  114. }
  115. public function isCompressed() {
  116. return $this->compression;
  117. }
  118. /**
  119. * XML objektum konvertálása base64-es szöveggé
  120. * @param \SimpleXMLElement $xml
  121. * @return string
  122. */
  123. protected function convertXml(\SimpleXMLElement $xml) {
  124. $xml = $xml->asXML();
  125. if ($this->compression) {
  126. $xml = gzencode($xml, self::COMPRESSION_LEVEL);
  127. }
  128. return base64_encode($xml);
  129. }
  130. protected function isComplete(\SimpleXMLElement $xml) {
  131. return (string)$xml->completenessIndicator === 'true';
  132. }
  133. /**
  134. * Egy darab számla XML-t átadva visszaad egy InvoiceOperations példányt,
  135. * amit a Reporter::manageInvoice metódusa fogad paraméterben
  136. *
  137. * @param \SimpleXMLElement $xml
  138. * @param string $operation
  139. * @param boolean $compression gzip tömörítés alkalmazása, részletek: NAV dokumentáció, 1.6.5 Tömörítés és méretkorlát
  140. * @return InvoiceOperations
  141. */
  142. public static function convertFromXml($xml, $operation, $compression = false) {
  143. $invoiceOperations = new self($compression);
  144. $invoiceOperations->useDataSchemaValidation();
  145. $invoiceOperations->add($xml, $operation);
  146. return $invoiceOperations;
  147. }
  148. /**
  149. * Számla dekódolása (base64 és opcionálisan gzip)
  150. *
  151. * @param string $base64data
  152. * @param boolean $isCompressed
  153. * @return \SimpleXMLElement
  154. */
  155. public static function convertToXml($base64data, $isCompressed = false) {
  156. $isCompressed = ($isCompressed === true or (string)$isCompressed === 'true');
  157. $data = base64_decode($base64data);
  158. if ($isCompressed) {
  159. $data = gzdecode($data);
  160. }
  161. return simplexml_load_string($data);
  162. }
  163. }