JPK.php 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041
  1. <?php
  2. Lib::loadClass('RouteBase');
  3. Lib::loadClass('ProcesHelper');
  4. class Route_UrlAction_JPK extends RouteBase {
  5. private $REFERER, $LAST_REFERER;
  6. private $JPK, $BO;
  7. private $NIPerrors = array();
  8. private $JPK_VAT_Wariant = null;
  9. private $tns = [
  10. 2 => "http://jpk.mf.gov.pl/wzor/2016/10/26/10261/",
  11. 3 => "http://jpk.mf.gov.pl/wzor/2017/11/13/1113/",
  12. ];
  13. public function handleAuth() {
  14. if (!User::logged()) {
  15. throw new HttpException('Unauthorized', 401);
  16. }
  17. $this->LAST_REFERER = $_SERVER['HTTP_REFERER'];
  18. if (($this->REFERER=V::get('REFERER','',$_POST))=='') $this->REFERER = $_SERVER['HTTP_REFERER'];
  19. try {
  20. if (!($ID_JPK = V::get('ID_JPK',0,$_GET,'int'))) throw new Exception("Błąd parametru");
  21. if ($result = DB::getPDO()->fetchall("select * from JPK where ID='{$ID_JPK}'")) $this->JPK = $result[0];
  22. else throw new Exception("Dostęp zabroniony");
  23. if ($result = DB::getPDO()->fetchall("select * from BILLING_OWNER where ID='{$this->JPK['ID_BILLING_OWNER']}'")) $this->BO = $result[0];
  24. else throw new Exception("Błąd spójności danych");
  25. if ($this->JPK['A_STATUS'] != 'WAITING') {
  26. if (!$this->JPK['MONTH']) throw new Exception("Błąd daty w rekordzie JPK_VAT");
  27. $year = date("Y", strtotime($this->JPK['MONTH']));
  28. if ($year < 2018) $this->JPK_VAT_Wariant = 2;
  29. else $this->JPK_VAT_Wariant = 3;
  30. }
  31. } catch (Exception $e) {
  32. SE_Layout::gora();
  33. SE_Layout::menu();
  34. SE_Layout::alert('danger',$e->getMessage());
  35. ?>
  36. <div class="container" style="text-align:center">
  37. <a href="<?=$this->REFERER?>" class="btn btn-primary">Powrót</a>
  38. </div>
  39. <?php
  40. SE_Layout::dol();
  41. die();
  42. }
  43. }
  44. private function initialize() {
  45. SE_Layout::gora();
  46. SE_Layout::menu();
  47. try {
  48. if (V::get('action','',$_POST) == 'initialize') {
  49. $month = V::get('MONTH','',$_POST);
  50. $purpose = V::get('PURPOSE','',$_POST);
  51. if (!preg_match("/^[[:digit:]]{4}-[[:digit:]]{2}$/",$month)) throw new Exception("błędny format daty (YYYY-MM)");
  52. switch ($purpose) {
  53. case "1":
  54. $lastMonth = DB::getPDO()->fetchValue("select max(MONTH) from JPK where ID_BILLING_OWNER='{$this->JPK['ID_BILLING_OWNER']}' and TYPE='{$this->JPK['TYPE']}' and PURPOSE='1'");
  55. if (strtotime($month) <= strtotime($lastMonth)) throw new Exception("błędny miesiąc (deklaracja z tego okresu lub późniejszego już istnieje)");
  56. break;
  57. case "2":
  58. $JPKexists = DB::getPDO()->fetchValue("select ID from JPK where ID_BILLING_OWNER='{$this->JPK['ID_BILLING_OWNER']}' and TYPE='{$this->JPK['TYPE']}' and MONTH='{$month}' and PURPOSE='1'");
  59. if (!$JPKexists) throw new Exception("brak deklaracji z tego okresu - nie ma czego korygować");
  60. break;
  61. default:
  62. throw new Exception("błędne określenie celu złożenia deklaracji");
  63. }
  64. $sqlObj = new stdClass();
  65. $sqlObj->ID = $this->JPK['ID'];
  66. $sqlObj->A_STATUS = 'NORMAL';
  67. $sqlObj->A_STATUS_INFO = 'W trakcie tworzenia';
  68. $sqlObj->MONTH = $month;
  69. $sqlObj->PURPOSE = $purpose;
  70. $affected = DB::getDB()->UPDATE_OBJ('JPK', $sqlObj);
  71. if ($affected) {
  72. SE_Layout::alert('success','Pomyślnie zainicjalizowano deklarację JPK.');
  73. ?>
  74. <div class="container" style="text-align:center">
  75. <form method="post">
  76. <input type="hidden" name="REFERER" value="<?=$this->REFERER?>"/>
  77. <button type="submit" class="btn btn-primary">Edytuj</button>
  78. <a href="<?=$this->REFERER?>" class="btn btn-default">Powrót</a>
  79. </form>
  80. </div>
  81. <?php
  82. }
  83. else {
  84. SE_Layout::alert('warning','Wystąpił nieznany błąd podczas inicjalizowania deklaracji JPK.');
  85. ?>
  86. <div class="container" style="text-align:center">
  87. <a href="<?=$this->REFERER?>" class="btn btn-primary">Powrót</a>
  88. </div>
  89. <?php
  90. }
  91. } else {
  92. ?>
  93. <div class="container" style="margin-top:20px">
  94. <form class="form-horizontal" method="post">
  95. <legend>Inicjalizacja deklaracji JPK</legend>
  96. <div class="form-group">
  97. <label class="col-sm-3 control-label">Operator</label>
  98. <div class="col-sm-9" style="margin-top:7px;"><?=$this->BO['name1']?></div>
  99. </div>
  100. <div class="form-group">
  101. <label class="col-sm-3 control-label">Typ JPK</label>
  102. <div class="col-sm-9" style="margin-top:7px;"><?=$this->JPK['TYPE']?></div>
  103. </div>
  104. <div class="form-group">
  105. <label class="col-sm-3 control-label">Miesiąc, którego dotyczy deklaracja</label>
  106. <div class="col-sm-2">
  107. <div class="input-group">
  108. <input type="text" id="MONTH" class="form-control se_type-date" name="MONTH" value="2017-01" maxlength="7"/>
  109. <span class="input-group-addon">
  110. <span class="glyphicon glyphicon-calendar"/>
  111. </span>
  112. </input>
  113. </div>
  114. </div>
  115. </div>
  116. <div class="form-group">
  117. <label class="col-sm-3 control-label">Cel złożenia deklaracji za dany okres</label>
  118. <div class="col-sm-3">
  119. <select class="form-control" name="PURPOSE">
  120. <option value="1">Złożenie po raz pierwszy</option>
  121. <option value="2">Korekta</option>
  122. </select>
  123. </div>
  124. </div>
  125. <div class="form-group">
  126. <div class="col-sm-offset-3 col-sm-9">
  127. <button type="submit" class="btn btn-primary" name="action" value="initialize">Zapisz</button>
  128. <a href="<?=$this->REFERER?>" class="btn btn-default">Anuluj</a>
  129. </div>
  130. </div>
  131. <input type="hidden" name="REFERER" value="<?=$this->REFERER?>"/>
  132. </form>
  133. </div>
  134. <script>
  135. jQuery(document.getElementById('MONTH')).parent().datetimepicker({
  136. format: 'YYYY-MM'
  137. , locale: 'pl'
  138. , showTodayButton: false
  139. , minDate: '2017-01-01'
  140. , maxDate: '<?=date("Y-m", strtotime("-1 month"))?>-28'
  141. });
  142. </script>
  143. <?php
  144. }
  145. } catch (Exception $e) {
  146. SE_Layout::alert('danger', "Wystąpił problem z inicjalizacją deklaracji JPK - " . $e->getMessage());
  147. ?>
  148. <div class="container" style="text-align:center">
  149. <a href="<?=$this->REFERER?>" class="btn btn-primary">Powrót</a>
  150. </div>
  151. <?php
  152. }
  153. SE_Layout::dol();
  154. }
  155. private $fieldsDescrJPK_VAT = array(
  156. "KodFormularza" => "Kod formularza",
  157. "WariantFormularza" => "Wariant formularza",
  158. "CelZlozenia" => "Cel złożenia",
  159. "DataWytworzeniaJPK" => "Data wytworzenia JPK",
  160. "DataOd" => "Data od",
  161. "DataDo" => "Data do",
  162. "DomyslnyKodWaluty" => "Waluta",
  163. "KodUrzedu" => "Kod urzędu skarbowego",
  164. "PelnaNazwa" => "Nazwa podmiotu",
  165. "NIP" => "NIP",
  166. "REGON" => "Regon",
  167. "KodKraju" => "Kod kraju",
  168. "Wojewodztwo" => "Województwo",
  169. "Powiat" => "Powiat",
  170. "Gmina" => "Gmina",
  171. "Miejscowosc" => "Miejscowość",
  172. "Ulica" => "Ulica",
  173. "NrDomu" => "Nr domu",
  174. "NrLokalu" => "Nr lokalu",
  175. "KodPocztowy" => "Kod pocztowy",
  176. "Poczta" => "Poczta",
  177. "LiczbaWierszySprzedazy" => "Liczba dokumentów sprzedaży",
  178. "PodatekNalezny" => "Podatek należny",
  179. "LiczbaWierszyZakupow" => "Liczba dokumentów zakupu",
  180. "PodatekNaliczony" => "Podatek naliczony"
  181. );
  182. private static function getNamespaces($xml) {
  183. $ns = $xml->getNamespaces(true);
  184. if (!isset($ns['tns'])) {
  185. if (isset($ns[''])) {
  186. $ns['tns'] = $ns[''];
  187. unset($ns['']);
  188. } else throw new Exception('Błędna struktura namespace');
  189. }
  190. foreach ($ns as $k => $v) $xml->registerXPathNamespace($k, $v);
  191. return $ns;
  192. }
  193. private function showJPK_VAT($xml) {
  194. $ns = self::getNamespaces($xml);
  195. $summaryJPK_VAT = $this->getSummaryJPK_VAT($xml);
  196. $result['KodFormularza'] = $xml->xpath('/tns:JPK/tns:Naglowek/tns:KodFormularza')[0];
  197. $result['WariantFormularza'] = $xml->xpath('/tns:JPK/tns:Naglowek/tns:WariantFormularza')[0];
  198. $result['CelZlozenia'] = $xml->xpath('/tns:JPK/tns:Naglowek/tns:CelZlozenia')[0];
  199. $result['DataWytworzeniaJPK'] = $xml->xpath('/tns:JPK/tns:Naglowek/tns:DataWytworzeniaJPK')[0];
  200. $result['DataOd'] = $xml->xpath('/tns:JPK/tns:Naglowek/tns:DataOd')[0];
  201. $result['DataDo'] = $xml->xpath('/tns:JPK/tns:Naglowek/tns:DataDo')[0];
  202. $result['DomyslnyKodWaluty'] = $xml->xpath('/tns:JPK/tns:Naglowek/tns:DomyslnyKodWaluty')[0];
  203. $result['KodUrzedu'] = $xml->xpath('/tns:JPK/tns:Naglowek/tns:KodUrzedu')[0];
  204. $result['NIP'] = $xml->xpath('/tns:JPK/tns:Podmiot1/tns:IdentyfikatorPodmiotu/etd:NIP')[0];
  205. $result['PelnaNazwa'] = $xml->xpath('/tns:JPK/tns:Podmiot1/tns:IdentyfikatorPodmiotu/etd:PelnaNazwa')[0];
  206. $result['REGON'] = $xml->xpath('/tns:JPK/tns:Podmiot1/tns:IdentyfikatorPodmiotu/etd:REGON')[0];
  207. $result['KodKraju'] = $xml->xpath('/tns:JPK/tns:Podmiot1/tns:AdresPodmiotu/tns:KodKraju')[0];
  208. $result['Wojewodztwo'] = $xml->xpath('/tns:JPK/tns:Podmiot1/tns:AdresPodmiotu/tns:Wojewodztwo')[0];
  209. $result['Powiat'] = $xml->xpath('/tns:JPK/tns:Podmiot1/tns:AdresPodmiotu/tns:Powiat')[0];
  210. $result['Gmina'] = $xml->xpath('/tns:JPK/tns:Podmiot1/tns:AdresPodmiotu/tns:Gmina')[0];
  211. $result['Ulica'] = $xml->xpath('/tns:JPK/tns:Podmiot1/tns:AdresPodmiotu/tns:Ulica')[0];
  212. $result['NrDomu'] = $xml->xpath('/tns:JPK/tns:Podmiot1/tns:AdresPodmiotu/tns:NrDomu')[0];
  213. $result['NrLokalu'] = $xml->xpath('/tns:JPK/tns:Podmiot1/tns:AdresPodmiotu/tns:NrLokalu')[0];
  214. $result['Miejscowosc'] = $xml->xpath('/tns:JPK/tns:Podmiot1/tns:AdresPodmiotu/tns:Miejscowosc')[0];
  215. $result['KodPocztowy'] = $xml->xpath('/tns:JPK/tns:Podmiot1/tns:AdresPodmiotu/tns:KodPocztowy')[0];
  216. $result['Poczta'] = $xml->xpath('/tns:JPK/tns:Podmiot1/tns:AdresPodmiotu/tns:Poczta')[0];
  217. $result['LiczbaWierszySprzedazy'] = $summaryJPK_VAT['LiczbaWierszySprzedazy'] ?: "";
  218. $result['PodatekNalezny'] = $summaryJPK_VAT['LiczbaWierszySprzedazy'] ? number_format($summaryJPK_VAT['PodatekNalezny'], 2, ',', '.'): "";
  219. $result['LiczbaWierszyZakupow'] = $summaryJPK_VAT['LiczbaWierszyZakupow'] ?: "";
  220. $result['PodatekNaliczony'] = $summaryJPK_VAT['LiczbaWierszyZakupow'] ? number_format($summaryJPK_VAT['PodatekNaliczony'], 2, ',', '.'): "";
  221. return $result;
  222. }
  223. private function showTable() {
  224. ?>
  225. <div class="form-group">
  226. <div class="col-sm-12">
  227. <table class="table table-bordered table-hover table-striped">
  228. <thead>
  229. <tr style="text-align:center; background-color:lightgray"><td width="19%"></td><td witdh="27%">Insert</td><td width="27%">L1</td><td width="27%">Dane wynikowe</td></tr>
  230. </thead>
  231. <tbody>
  232. <?php
  233. if ($this->JPK['IN_INSERT']) {
  234. $xmlIN_INSERT = simplexml_load_string($this->JPK['IN_INSERT']);
  235. $IN_INSERT = $this->showJPK_VAT($xmlIN_INSERT);
  236. }
  237. if ($this->JPK['IN_L1']) {
  238. $xmlIN_L1 = simplexml_load_string($this->JPK['IN_L1']);
  239. $IN_L1 = $this->showJPK_VAT($xmlIN_L1);
  240. }
  241. if ($this->JPK['OUT_MERGED']) {
  242. $xmlOUT_MERGED = simplexml_load_string($this->JPK['OUT_MERGED']);
  243. $OUT_MERGED = $this->showJPK_VAT($xmlOUT_MERGED);
  244. }
  245. foreach ($this->fieldsDescrJPK_VAT as $fieldKey => $fieldName) {
  246. echo "<tr><td>{$fieldName}</td><td>";
  247. if ($this->JPK['IN_INSERT']) echo $IN_INSERT[$fieldKey];
  248. echo "</td><td>";
  249. if ($this->JPK['IN_L1']) echo $IN_L1[$fieldKey];
  250. echo "</td><td>";
  251. if ($this->JPK['OUT_MERGED']) echo $OUT_MERGED[$fieldKey];
  252. echo "</td></tr>\n";
  253. }
  254. ?>
  255. </tbody>
  256. </table>
  257. </div>
  258. </div>
  259. <?php
  260. }
  261. private function show() {
  262. if (V::get('action','',$_POST) == "getJPK") {
  263. try {
  264. if (!$this->JPK['OUT_MERGED']) throw new Exception("Błąd danych - nie wygenerowano wynikowego pliku JPK");
  265. $xml = simplexml_load_string($this->JPK['OUT_MERGED']);
  266. $ns = $xml->getNamespaces(true);
  267. $this->validateJPK_VAT($xml);
  268. $fileName = preg_replace("/[: \.]/", "_", "JPK_VAT_{$this->JPK['MONTH']}_" . str_replace('"', '', $xml->Podmiot1->IdentyfikatorPodmiotu->children($ns['etd'])->PelnaNazwa));
  269. $output = $xml->asXml();
  270. header("Content-Type: application/xml");
  271. header("Content-Disposition: attachment; filename={$fileName};");
  272. header("Content-Transfer-Encoding: binary");
  273. header("Content-Length: " . strlen($output));
  274. echo $output;
  275. } catch (Exception $e) {
  276. SE_Layout::gora();
  277. SE_Layout::menu();
  278. SE_Layout::alert('danger', $e->getMessage());
  279. ?>
  280. <div class="container" style="text-align:center">
  281. <form method="post" action="<?=$this->LAST_REFERER?>">
  282. <input type="hidden" name="REFERER" value="<?=$this->REFERER?>"/>
  283. <button type="submit" class="btn btn-primary">Powrót</button>
  284. </form>
  285. </div>
  286. <?php
  287. SE_Layout::dol();
  288. }
  289. } else {
  290. SE_Layout::gora();
  291. SE_Layout::menu();
  292. ?>
  293. <div class="container" style="margin-top:20px">
  294. <form class="form-horizontal" method="post" target="_blank">
  295. <legend>
  296. Podgląd deklaracji JPK :: <?=$this->JPK['TYPE']?> - <?=$this->JPK['MONTH']." (".($this->JPK['PURPOSE'] == 1 ? "pierwsze złożenie" : "korekta").")"?>
  297. <span class="pull-right">
  298. <?=$this->BO['name1']?>
  299. </span>
  300. </legend>
  301. <div class="form-group">
  302. <div class="form-group">
  303. <div class="col-sm-10">
  304. <button type="submit" class="btn-sm btn-primary" name="action" value="getJPK">Pobierz plik JPK</button>
  305. </div>
  306. </div>
  307. <?=$this->showTable();?>
  308. <div class="form-group" style="text-align:center">
  309. <div class="col-sm-12">
  310. <input type="hidden" name="REFERER" value="<?=$this->REFERER?>"/>
  311. <a href="<?=$this->REFERER?>" class="btn btn-default">Powrót</a>
  312. </div>
  313. </div>
  314. </form>
  315. </div>
  316. <?php
  317. SE_Layout::dol();
  318. }
  319. }
  320. private function edit() {
  321. SE_Layout::gora();
  322. SE_Layout::menu();
  323. ?>
  324. <div class="container" style="margin-top:20px">
  325. <form class="form-horizontal" method="post" enctype="multipart/form-data">
  326. <legend>
  327. Edycja deklaracji JPK :: <?=$this->JPK['TYPE']?> - <?=$this->JPK['MONTH']." (".($this->JPK['PURPOSE'] == 1 ? "pierwsze złożenie" : "korekta").")"?>
  328. <span class="pull-right">
  329. <?=$this->BO['name1']?>
  330. </span>
  331. </legend>
  332. <div class="form-group">
  333. <label class="col-sm-3 control-label"><?=($this->JPK['IN_INSERT'] ? "Usuń dane zaimportowane" : "Dodaj plik JPK")?> z pakietu Insert</label>
  334. <?php
  335. if ($this->JPK['IN_INSERT']) {
  336. ?>
  337. <div class="col-sm-9" style="margin-top:3px;">
  338. <button type="submit" class="btn-xs btn-default" name="action" value="delete_insert_jpk">Usuń</button>
  339. </div>
  340. <?php
  341. } else {
  342. ?>
  343. <div class="col-sm-9" style="margin-top:7px;">
  344. <input type="hidden" name="action" value="upload_insert_jpk"/>
  345. <input type="file" name="IN_INSERT" onchange="javascript:this.form.submit();"/>
  346. </div>
  347. <?php
  348. }
  349. ?>
  350. </div>
  351. <div class="form-group">
  352. <label class="col-sm-3 control-label"><?=($this->JPK['IN_L1'] ? "Usuń" : "Pobierz")?> dane z L1</label>
  353. <div class="col-sm-9" style="margin-top:3px;">
  354. <button type="submit" class="btn-xs btn-default" name="action" value=<?=($this->JPK['IN_L1'] ? '"delete_l1_jpk">Usuń' : '"import_l1_jpk">Pobierz')?></button>
  355. </div>
  356. </div>
  357. <?php
  358. if (!($this->JPK['IN_INSERT'] || $this->JPK['IN_L1'])) {
  359. ?>
  360. <div class="form-group">
  361. <label class="col-sm-3 control-label">Reinicjalizuj deklarację</label>
  362. <div class="col-sm-9" style="margin-top:3px;">
  363. <button type="submit" class="btn-xs btn-default" name="action" value="reinitialize">Reinicjalizuj</button>
  364. </div>
  365. </div>
  366. <?php
  367. }
  368. if ($this->JPK['IN_INSERT'] && $this->JPK['IN_L1'] && (!$this->JPK['OUT_MERGED'])) {
  369. ?>
  370. <div class="form-group">
  371. <label class="col-sm-3 control-label">Importuj dane podmiotu z</label>
  372. <div class="col-sm-9" style="margin-top:3px;">
  373. <input type="radio" name="SRC_PODMIOT" value="Insert" checked> Insert<br/>
  374. <input type="radio" name="SRC_PODMIOT" value="L1"> L1
  375. </div>
  376. </div>
  377. <div class="form-group">
  378. <label class="col-sm-3 control-label">Generuj deklarację wynikową</label>
  379. <div class="col-sm-9" style="margin-top:3px;">
  380. <button type="submit" class="btn-xs btn-default" name="action" value="generate_merged_jpk">Generuj</button>
  381. </div>
  382. </div>
  383. <?php
  384. }
  385. if ($this->JPK['OUT_MERGED']) {
  386. ?>
  387. <div class="form-group">
  388. <label class="col-sm-3 control-label">Zamknij deklarację JPK</label>
  389. <div class="col-sm-9" style="margin-top:3px;">
  390. <button type="submit" class="btn-xs btn-default" name="action" value="close_jpk">Zamknij</button>
  391. <p class="help-block">(tej operacji nie można cofnąć)</p>
  392. </div>
  393. </div>
  394. <?php
  395. }
  396. ?>
  397. <?=$this->showTable()?>
  398. <div class="form-group" style="text-align:center">
  399. <div class="col-sm-12">
  400. <input type="hidden" name="REFERER" value="<?=$this->REFERER?>"/>
  401. <input type="hidden" name="_task" value="edit">
  402. <a href="<?=$this->REFERER?>" class="btn btn-primary">Powrót</a>
  403. </div>
  404. </div>
  405. </form>
  406. </div>
  407. <?php
  408. SE_Layout::dol();
  409. }
  410. public function editAction() {
  411. $allowedActions = array("upload_insert_jpk", "delete_insert_jpk", "import_l1_jpk", "delete_l1_jpk", "generate_merged_jpk", "close_jpk", "reinitialize");
  412. if (in_array(($action = V::get('action','',$_POST)), $allowedActions)) $this->$action();
  413. else {
  414. SE_Layout::gora();
  415. SE_Layout::menu();
  416. SE_Layout::alert('danger', "Wykryto abuse! Wysłano informację do administratora.");
  417. ?>
  418. <div class="container" style="text-align:center">
  419. <form method="post" action="<?=$this->LAST_REFERER?>">
  420. <input type="hidden" name="REFERER" value="<?=$this->REFERER?>"/>
  421. <button type="submit" class="btn btn-primary">Powrót</button>
  422. </form>
  423. </div>
  424. <?php
  425. SE_Layout::dol();
  426. }
  427. }
  428. private function getSummaryJPK_VAT($xml) {
  429. $ns = $xml->getNamespaces(true);
  430. $tns = $this->tns[$this->JPK_VAT_Wariant];
  431. if (array_search($tns, $ns) === false) throw new Exception("Błąd struktury pliku XML - błędny namespace");
  432. $PodatekNaleznyFields = array("K_16" => "1", "K_18" => "1", "K_20" => "1", "K_24" => "1", "K_26" => "1", "K_28" => "1",
  433. "K_30" => "1", "K_33" => "1", "K_35" => "1", "K_36" => "1", "K_37" => "1", "K_38" => "-1", "K_39" => "-1");
  434. $PodatekNaliczonyFields = array("K_44" => 1, "K_46" => 1, "K_47" => 1, "K_48" => 1, "K_49" => 1, "K_50" => 1);
  435. $result = array(
  436. "LiczbaWierszySprzedazy" => 0,
  437. "PodatekNalezny" => 0,
  438. "LiczbaWierszyZakupow" => 0,
  439. "PodatekNaliczony" => 0);
  440. foreach ($xml->children($tns)->SprzedazWiersz as $SprzedazWiersz) {
  441. foreach ($PodatekNaleznyFields as $PodatekNaleznyField => $sign) {
  442. if (isset($SprzedazWiersz->children($tns)->$PodatekNaleznyField)) {
  443. $result["PodatekNalezny"] += round((float) $SprzedazWiersz->children($tns)->$PodatekNaleznyField * $sign, 2);
  444. }
  445. }
  446. $result["LiczbaWierszySprzedazy"]++;
  447. }
  448. foreach ($xml->children($tns)->ZakupWiersz as $ZakupWiersz) {
  449. foreach ($PodatekNaliczonyFields as $PodatekNaliczonyField => $sign) {
  450. if (isset($ZakupWiersz->children($tns)->$PodatekNaliczonyField)) {
  451. $result["PodatekNaliczony"] += round((float) $ZakupWiersz->children($tns)->$PodatekNaliczonyField * $sign, 2);
  452. }
  453. }
  454. $result["LiczbaWierszyZakupow"]++;
  455. }
  456. $result["PodatekNalezny"] = round($result["PodatekNalezny"], 2);
  457. $result["PodatekNaliczony"] = round($result["PodatekNaliczony"], 2);
  458. return $result;
  459. }
  460. private function validateJPK_VAT(&$xml) {
  461. $ns = self::getNamespaces($xml);
  462. if ($xml->xpath('/tns:JPK/tns:Naglowek/tns:KodFormularza')[0] != "JPK_VAT") throw new Exception("Błędny typ deklaracji JPK");
  463. if ($xml->xpath('/tns:JPK/tns:Naglowek/tns:WariantFormularza')[0] != $this->JPK_VAT_Wariant) throw new Exception("Błędna wersja deklaracji JPK");
  464. if ($xml->xpath('/tns:JPK/tns:Naglowek/tns:CelZlozenia')[0] != $this->JPK['PURPOSE']) throw new Exception("Niezgodny cel złożenia deklaracji JPK");
  465. if ($xml->xpath('/tns:JPK/tns:Naglowek/tns:DataOd')[0] != ($this->JPK['MONTH'] . "-01")) throw new Exception("Błędna data 'od' deklaracji JPK");
  466. if ($xml->xpath('/tns:JPK/tns:Naglowek/tns:DataDo')[0] != date("Y-m-d", strtotime($xml->xpath('/tns:JPK/tns:Naglowek/tns:DataOd')[0] . " + 1 month - 1 day"))) throw new Exception("Błędna data 'do' deklaracji JPK");
  467. if ($xml->xpath('/tns:JPK/tns:Naglowek/tns:DomyslnyKodWaluty')[0] != "PLN") throw new Exception("Błędna waluta deklaracji JPK");
  468. if (trim(str_replace('-', '', $xml->xpath('/tns:JPK/tns:Podmiot1/tns:IdentyfikatorPodmiotu/etd:NIP')[0])) != trim(str_replace('-', '', $this->BO['nip']))) throw new Exception("Niezgodny NIP podmiotu w deklaracji JPK");
  469. $summaryJPK_VAT = $this->getSummaryJPK_VAT($xml);
  470. if ($summaryJPK_VAT["LiczbaWierszySprzedazy"]) {
  471. if ($xml->xpath('/tns:JPK/tns:SprzedazCtrl/tns:LiczbaWierszySprzedazy')[0] != $summaryJPK_VAT["LiczbaWierszySprzedazy"]) throw new Exception("Brak spójności liczby wierszy sprzedaży w deklaracji JPK");
  472. if (((float) $xml->xpath('/tns:JPK/tns:SprzedazCtrl/tns:PodatekNalezny')[0]) != $summaryJPK_VAT["PodatekNalezny"]) throw new Exception("Brak spójności wartości podatku należnego w deklaracji JPK");
  473. }
  474. if ($summaryJPK_VAT["LiczbaWierszyZakupow"]) {
  475. if ($xml->xpath('/tns:JPK/tns:ZakupCtrl/tns:LiczbaWierszyZakupow')[0] != $summaryJPK_VAT["LiczbaWierszyZakupow"]) throw new Exception("Brak spójności liczby wierszy zakupów w deklaracji JPK");
  476. if (((float) $xml->xpath('/tns:JPK/tns:ZakupCtrl/tns:PodatekNaliczony')[0]) != $summaryJPK_VAT["PodatekNaliczony"]) throw new Exception("Brak spójności wartości podatku naliczonego w deklaracji JPK");
  477. }
  478. set_error_handler(function ($errno, $errstr, $errfile, $errline) {
  479. if ($errno==E_WARNING && (substr_count($errstr,"DOMDocument::loadXML()")>0)) throw new DOMException($errstr);
  480. else return false;
  481. });
  482. try {
  483. $dom = new DOMDocument();
  484. $dom->preserveWhiteSpace = false;
  485. $dom->formatOutput = true;
  486. $dom->loadXML($xml->asXML());
  487. } catch (Exception $e) {
  488. throw new Exception("Błąd parsowania pliku JPK");
  489. }
  490. restore_error_handler();
  491. $xsd = [
  492. 2 => 'Schemat_JPK_VAT(2)_v1-0.xsd',
  493. 3 => 'Schemat_JPK_VAT(3)_v1-1.xsd',
  494. ];
  495. libxml_use_internal_errors(true);
  496. if (!$dom->schemaValidate(APP_PATH_SCHEMA . "/jpk/" . $xsd[$this->JPK_VAT_Wariant])) {
  497. $errors = '';
  498. foreach (libxml_get_errors() as $libxml_error) $errors .= "<br/>{$libxml_error->message}";
  499. throw new Exception("Plik JPK niezgodny ze schematem XSD{$errors}<pre>" . htmlentities($dom->saveXML()) . "</pre>");
  500. }
  501. $xml = simplexml_load_string($dom->saveXML());
  502. }
  503. private function upload_insert_jpk() {
  504. try {
  505. if ($_FILES['IN_INSERT']['type'] != "text/xml") throw new Exception("Błędny plik JPK");
  506. $xml = simplexml_load_file($_FILES['IN_INSERT']['tmp_name']);
  507. $this->validateJPK_VAT($xml);
  508. if ($this->JPK['IN_L1']) $info = "Zaimportowano dane z Insert i L1";
  509. else $info = "Zaimportowano dane z Insert";
  510. $sqlObj = new stdClass();
  511. $sqlObj->ID = $this->JPK['ID'];
  512. $sqlObj->A_STATUS_INFO = $info;
  513. $sqlObj->IN_INSERT = $xml->asXml();
  514. if (!$affected = DB::getDB()->UPDATE_OBJ('JPK', $sqlObj)) throw new Exception("Wystąpił błąd, prawdopodobnie Ten plik JPK został wgrany już wcześniej");
  515. $this->handleAuth();
  516. $this->edit();
  517. } catch (Exception $e) {
  518. SE_Layout::gora();
  519. SE_Layout::menu();
  520. SE_Layout::alert('danger', $e->getMessage());
  521. ?>
  522. <div class="container" style="text-align:center">
  523. <form method="post" action="<?=$this->LAST_REFERER?>">
  524. <input type="hidden" name="REFERER" value="<?=$this->REFERER?>"/>
  525. <button type="submit" class="btn btn-primary">Powrót</button>
  526. </form>
  527. </div>
  528. <?php
  529. SE_Layout::dol();
  530. }
  531. }
  532. private function delete_insert_jpk() {
  533. try {
  534. $info = "Usunięto dane z Insert";
  535. if ($this->JPK['IN_L1']) $info .= " (pozostawiono dane z L1)";
  536. $sqlObj = new stdClass();
  537. $sqlObj->ID = $this->JPK['ID'];
  538. $sqlObj->A_STATUS_INFO = $info;
  539. $sqlObj->IN_INSERT = null;
  540. $sqlObj->OUT_MERGED = null;
  541. if (!$affected = DB::getDB()->UPDATE_OBJ('JPK', $sqlObj)) throw new Exception("Wystąpił nieznany błąd");
  542. $this->handleAuth();
  543. $this->edit();
  544. } catch (Exception $e) {
  545. SE_Layout::gora();
  546. SE_Layout::menu();
  547. SE_Layout::alert('danger', $e->getMessage());
  548. ?>
  549. <div class="container" style="text-align:center">
  550. <form method="post" action="<?=$this->LAST_REFERER?>">
  551. <input type="hidden" name="REFERER" value="<?=$this->REFERER?>"/>
  552. <button type="submit" class="btn btn-primary">Powrót</button>
  553. </form>
  554. </div>
  555. <?php
  556. SE_Layout::dol();
  557. }
  558. }
  559. private function validateNIP($nip_orig, $name, $type) {
  560. $nip = str_replace("-", "", trim($nip_orig));
  561. $error = false;
  562. if ($nip == "" || $nip == "Brak") return true;
  563. $prefix = substr($nip, 0, 2);
  564. if (!is_numeric($prefix)) $nip = substr($nip, 2);
  565. else $prefix = null;
  566. if ($prefix && $prefix != "PL") return true;
  567. if (strlen($nip) != 10 || (!is_numeric($nip))) $error = true;
  568. else {
  569. $control = (($nip[0] * 6 + $nip[1] * 5 + $nip[2] * 7 + $nip[3] * 2 + $nip[4] * 3 + $nip[5] * 4 + $nip[6] * 5 + $nip[7] * 6 + $nip[8] * 7) % 11 ) % 10;
  570. $error = ($control != $nip[9]);
  571. }
  572. if ($error) {
  573. $this->NIPerrors[] = "NIP: {$nip_orig}, nazwa: {$name}, rodzaj dokumentu: {$type}";
  574. return false;
  575. }
  576. return true;
  577. }
  578. private function import_l1_jpk() {
  579. $xmlSchema = <<<EOT
  580. <?xml version="1.0" encoding="UTF-8" standalone="no" ?>
  581. <JPK xmlns="http://jpk.mf.gov.pl/wzor/2016/10/26/10261/" xmlns:etd="http://crd.gov.pl/xml/schematy/dziedzinowe/mf/2016/01/25/eD/DefinicjeTypy/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  582. <Naglowek>
  583. <KodFormularza kodSystemowy="JPK_VAT (2)" wersjaSchemy="1-0">JPK_VAT</KodFormularza>
  584. <WariantFormularza>2</WariantFormularza>
  585. <CelZlozenia></CelZlozenia>
  586. <DataWytworzeniaJPK></DataWytworzeniaJPK>
  587. <DataOd></DataOd>
  588. <DataDo></DataDo>
  589. <DomyslnyKodWaluty>PLN</DomyslnyKodWaluty>
  590. <KodUrzedu></KodUrzedu>
  591. </Naglowek>
  592. <Podmiot1>
  593. <IdentyfikatorPodmiotu>
  594. <etd:NIP></etd:NIP>
  595. <etd:PelnaNazwa></etd:PelnaNazwa>
  596. <etd:REGON></etd:REGON>
  597. </IdentyfikatorPodmiotu>
  598. <AdresPodmiotu>
  599. <KodKraju></KodKraju>
  600. <Wojewodztwo></Wojewodztwo>
  601. <Powiat></Powiat>
  602. <Gmina></Gmina>
  603. <Ulica></Ulica>
  604. <NrDomu></NrDomu>
  605. <NrLokalu></NrLokalu>
  606. <Miejscowosc></Miejscowosc>
  607. <KodPocztowy></KodPocztowy>
  608. <Poczta></Poczta>
  609. </AdresPodmiotu>
  610. </Podmiot1>
  611. </JPK>
  612. EOT;
  613. $queryFVAT = <<<EOT
  614. select
  615. bn.ID as BN_ID,
  616. if (bu.TAXPAYER_ID_BILLING_USERS > 0, concat(bua_tp.P_NAME, if(bua_tp.P_NAME_SECOND='','',concat(' ',bua_tp.P_NAME_SECOND))), concat(bua.P_NAME, if(bua.P_NAME_SECOND='','',concat(' ',bua.P_NAME_SECOND)))) AS NazwaKontrahenta,
  617. if (bu.TAXPAYER_ID_BILLING_USERS > 0, concat(bua_tp.P_ADDRESS_STREET,' ',bua_tp.P_ADDRESS_HOUSE, if(bua_tp.P_ADDRESS_HOME='','',concat('/',bua_tp.P_ADDRESS_HOME)),', ',bua_tp.P_ADDRESS_POST_CODE,' ',bua_tp.P_ADDRESS_CITY), concat(bua.P_ADDRESS_STREET,' ',bua.P_ADDRESS_HOUSE, if(bua.P_ADDRESS_HOME='','',concat('/',bua.P_ADDRESS_HOME)),', ',bua.P_ADDRESS_POST_CODE,' ',bua.P_ADDRESS_CITY)) AS AdresKontrahenta,
  618. bf.SELL_DATE AS 'DataWystawienia',
  619. concat(bn.NUMBER,'/',bn.ID_BILLING_PREFIXES) AS 'DowodSprzedazy',
  620. if (bu.TAXPAYER_ID_BILLING_USERS > 0, if(bua_tp.is_firma=0,'Brak',coalesce(bua_tp.P_NIP,'')), if(bua.is_firma=0,'Brak',coalesce(bua.P_NIP,''))) AS 'NrKontrahenta',
  621. round(bfp.AMMOUNT * bfp.PRICE, 2) as Netto,
  622. round(round(bfp.AMMOUNT * bfp.PRICE, 2) * bfp.VAT/100, 2) as VAT,
  623. bfp.VAT_NAME as 'VAT_NAME'
  624. from BILLING_NUMBERS bn
  625. join BILLS_FVAT bf on bn.ID=bf.ID_BILLING_NUMBERS
  626. join BILLS_FVAT_POS bfp on bf.ID=bfp.ID_BILLS_FVAT
  627. join BILLING_USERS_ADD bua on bua.id_users=bn.ID_BILLING_USERS
  628. join BILLING_USERS bu on bu.ID=bn.ID_BILLING_USERS
  629. left join BILLING_USERS_ADD bua_tp on bu.TAXPAYER_ID_BILLING_USERS = bua_tp.id_users
  630. where bn.ID_BILLING_NUMBERS_TYPE='1' and bf.BILL_DATE like '{$this->JPK['MONTH']}%'
  631. and bu.BILLING_OWNER='{$this->BO['ID']}'
  632. order by bf.BILL_DATE,bn.ID
  633. EOT;
  634. $queryKORV = <<<EOT
  635. select
  636. bn.ID AS BN_ID,
  637. concat(bua.P_NAME, if(bua.P_NAME_SECOND='','',concat(' ',bua.P_NAME_SECOND))) AS NazwaKontrahenta,
  638. concat(bua.P_ADDRESS_STREET,' ',bua.P_ADDRESS_HOUSE, if(bua.P_ADDRESS_HOME='','',concat('/',bua.P_ADDRESS_HOME)),', ',P_ADDRESS_POST_CODE,' ',P_ADDRESS_CITY) AS AdresKontrahenta,
  639. bk.BILL_DATE AS 'DataWystawienia',
  640. bk.SELL_DATE AS 'DataSprzedazy',
  641. concat(bn.NUMBER,'/',bn.ID_BILLING_PREFIXES) AS 'DowodSprzedazy',
  642. if(is_firma=0,'Brak',coalesce(bua.P_NIP,'')) AS 'NrKontrahenta',
  643. bkp.AMMOUNT AS AMMOUNT,
  644. bkp.PRICE AS PRICE,
  645. bkp.VAT AS VAT,
  646. bkp.VAT_NAME AS VAT_NAME,
  647. bkp.N_AMMOUNT AS N_AMMOUNT,
  648. bkp.N_PRICE AS N_PRICE,
  649. bkp.N_VAT AS N_VAT,
  650. bkp.N_VAT_NAME AS N_VAT_NAME,
  651. bkp.TYP_KOREKTY AS TYP_KOREKTY
  652. from BILLING_NUMBERS bn
  653. join BILLS_KORV bk on bn.ID=bk.ID_BILLING_NUMBERS
  654. join BILLS_KORV_POS bkp on bk.ID=bkp.ID_BILLS_FVAT
  655. join BILLING_USERS_ADD bua on bua.id_users=bn.ID_BILLING_USERS
  656. join BILLING_USERS bu on bu.ID=bn.ID_BILLING_USERS
  657. where bn.ID_BILLING_NUMBERS_TYPE='3'
  658. and bk.BILL_DATE like '{$this->JPK['MONTH']}%'
  659. and bkp.TYP_KOREKTY IS NOT NULL
  660. and bu.BILLING_OWNER='{$this->BO['ID']}'
  661. order by bk.BILL_DATE,bn.ID
  662. EOT;
  663. $xmlVAT = [
  664. 'ZW' => ['netto' => ['K_10']],
  665. '0' => ['netto' => ['K_13']],
  666. '7' => ['netto' => ['K_17'], 'vat' => 'K_18'],
  667. '8' => ['netto' => ['K_17'], 'vat' => 'K_18'],
  668. '22' => ['netto' => ['K_19'], 'vat' => 'K_20'],
  669. '23' => ['netto' => ['K_19'], 'vat' => 'K_20'],
  670. 'OO UE' => ['netto' => ['K_11', 'K_12']],
  671. ];
  672. try {
  673. if (DB::getPDO(931)->fetchValue("select sum(c) from (select count(*) as c from BILLS_FVAT where OPEN='y' union select count(*) as c from BILLS_KORV where OPEN='y') as c;")) {
  674. throw new Exception("wykryto niezamknięte faktury lub korekty faktur");
  675. }
  676. $xml = new SimpleXMLElement($xmlSchema);
  677. $ns = $xml->getNamespaces(true);
  678. $xml->Naglowek->CelZlozenia = $this->JPK['PURPOSE'];
  679. $xml->Naglowek->DataWytworzeniaJPK = date("Y-m-d\TH:i:s");
  680. $xml->Naglowek->DataOd = $this->JPK['MONTH'] . "-01";
  681. $xml->Naglowek->DataDo = date("Y-m-d", strtotime($xml->Naglowek->DataOd . "+ 1 month - 1 day"));
  682. if (!($xml->Naglowek->KodUrzedu = $this->BO['kodUrzeduSkarbowego'])) throw new Exception("blędne dane podmiotu - brak kodu urzędu skarbowego");
  683. if (!($xml->Podmiot1->IdentyfikatorPodmiotu->children($ns['etd'])->NIP = trim(str_replace("-", "", $this->BO['nip'])))) throw new Exception("blędne dane podmiotu - brak NIP");
  684. if (!($xml->Podmiot1->IdentyfikatorPodmiotu->children($ns['etd'])->PelnaNazwa = $this->BO['name1'])) throw new Exception("blędne dane podmiotu - brak nazwy podmiotu");
  685. if ($this->BO['name2']) $xml->Podmiot1->IdentyfikatorPodmiotu->children($ns['etd'])->PelnaNazwa .= " " . $this->BO['name2'];
  686. if (!($xml->Podmiot1->IdentyfikatorPodmiotu->children($ns['etd'])->REGON = $this->BO['regon'])) unset($xml->Podmiot1->IdentyfikatorPodmiotu->children($ns['etd'])->REGON);
  687. if (!($xml->Podmiot1->AdresPodmiotu->KodKraju = $this->BO['kodKraju'])) throw new Exception("blędne dane podmiotu - brak kodu kraju");
  688. if (!($xml->Podmiot1->AdresPodmiotu->Wojewodztwo = $this->BO['wojewodztwo'])) unset($xml->Podmiot1->AdresPodmiotu->Wojewodztwo);
  689. if (!($xml->Podmiot1->AdresPodmiotu->Powiat = $this->BO['powiat'])) unset($xml->Podmiot1->AdresPodmiotu->Powiat);
  690. if (!($xml->Podmiot1->AdresPodmiotu->Gmina = $this->BO['gmina'])) unset($xml->Podmiot1->AdresPodmiotu->Gmina);
  691. if (!($xml->Podmiot1->AdresPodmiotu->Ulica = $this->BO['ulica'])) unset($xml->Podmiot1->AdresPodmiotu->Ulica);
  692. if (!($xml->Podmiot1->AdresPodmiotu->NrDomu = $this->BO['numer_dom'])) unset($xml->Podmiot1->AdresPodmiotu->NrDomu);
  693. if (!($xml->Podmiot1->AdresPodmiotu->NrLokalu = $this->BO['numer_pos'])) unset($xml->Podmiot1->AdresPodmiotu->NrLokalu);
  694. if (!($xml->Podmiot1->AdresPodmiotu->Miejscowosc = $this->BO['miasto'])) throw new Exception("blędne dane podmiotu - brak nazwy miejscowości");
  695. if (!($xml->Podmiot1->AdresPodmiotu->KodPocztowy = $this->BO['kod'])) unset($xml->Podmiot1->AdresPodmiotu->KodPocztowy);
  696. if (!($xml->Podmiot1->AdresPodmiotu->Poczta = $this->BO['poczta'])) unset($xml->Podmiot1->AdresPodmiotu->Poczta);
  697. $data = array();
  698. $allVAT = 0;
  699. $result = DB::getPDO(931)->fetchall($queryFVAT);
  700. foreach ($result as $row) {
  701. $data[$row['BN_ID']][0]['NrKontrahenta'] = trim(str_replace("-", "", $row['NrKontrahenta']));
  702. $data[$row['BN_ID']][0]['NazwaKontrahenta'] = $row['NazwaKontrahenta'];
  703. $data[$row['BN_ID']][0]['AdresKontrahenta'] = $row['AdresKontrahenta'];
  704. $data[$row['BN_ID']][0]['DowodSprzedazy'] = $row['DowodSprzedazy'];
  705. $data[$row['BN_ID']][0]['DataWystawienia'] = $row['DataWystawienia'];
  706. if (!in_array($row['VAT_NAME'],array_keys($xmlVAT))) throw new Exception("Problem ze stawką VAT (1) - {$row['VAT_NAME']}");
  707. foreach ($xmlVAT[$row['VAT_NAME']]['netto'] as $netto) $data[$row['BN_ID']][1][$netto] += $row['Netto'];
  708. if ($row['VAT'] > 0) {
  709. if (!isset($xmlVAT[$row['VAT_NAME']]['vat'])) throw new Exception("Problem ze stawką VAT (2) - {$row['VAT_NAME']}");
  710. $data[$row['BN_ID']][1][$xmlVAT[$row['VAT_NAME']]['vat']] += $row['VAT'];
  711. $allVAT += $row['VAT'];
  712. }
  713. }
  714. $result = DB::getPDO(931)->fetchall($queryKORV);
  715. foreach ($result as $row) {
  716. $data[$row['BN_ID']][0]['NrKontrahenta'] = trim(str_replace("-", "", $row['NrKontrahenta']));
  717. $data[$row['BN_ID']][0]['NazwaKontrahenta'] = $row['NazwaKontrahenta'];
  718. $data[$row['BN_ID']][0]['AdresKontrahenta'] = $row['AdresKontrahenta'];
  719. $data[$row['BN_ID']][0]['DowodSprzedazy'] = $row['DowodSprzedazy'];
  720. $data[$row['BN_ID']][0]['DataWystawienia'] = $row['DataWystawienia'];
  721. $data[$row['BN_ID']][0]['DataSprzedazy'] = $row['DataSprzedazy'];
  722. if (!(in_array($row['VAT_NAME'], array_keys($xmlVAT)) && in_array($row['N_VAT_NAME'], array_keys($xmlVAT)))) throw new Exception("Problem ze stawką VAT (3) - {$row['VAT_NAME']}");
  723. if ((($row['VAT'] > 0) && !(isset($xmlVAT[$row['VAT_NAME']]['vat']))) || (($row['N_VAT'] > 0) && !(isset($xmlVAT[$row['N_VAT_NAME']]['vat'])))) throw new Exception("Problem ze stawką VAT (4) - {$row['VAT_NAME']}");
  724. if ($row['VAT_NAME'] == $row['N_VAT_NAME']) {
  725. foreach ($xmlVAT[$row['VAT_NAME']]['netto'] as $netto) $data[$row['BN_ID']][1][$netto] += round($row['AMMOUNT']*$row['PRICE'],2);
  726. if ($row['VAT'] > 0) {
  727. $data[$row['BN_ID']][1][$xmlVAT[$row['VAT_NAME']]['vat']] += round(round($row['AMMOUNT']*$row['PRICE'],2)*$row['VAT']/100,2);
  728. $allVAT += round(round($row['AMMOUNT']*$row['PRICE'],2)*$row['VAT']/100,2);
  729. }
  730. } else {
  731. foreach ($xmlVAT[$row['VAT_NAME']]['netto'] as $netto) $data[$row['BN_ID']][1][$netto] += round($row['N_AMMOUNT']*$row['N_PRICE'],2) + round($row['AMMOUNT']*$row['PRICE'],2);
  732. foreach ($xmlVAT[$row['N_VAT_NAME']]['netto'] as $netto) $data[$row['BN_ID']][1][$netto] -= round($row['N_AMMOUNT']*$row['N_PRICE'],2);
  733. if ($row['VAT'] > 0) {
  734. $data[$row['BN_ID']][1][$xmlVAT[$row['VAT_NAME']]['vat']] += round(round($row['N_AMMOUNT']*$row['N_PRICE'],2)*$row['VAT']/100,2)
  735. + round(round($row['AMMOUNT']*$row['PRICE'],2)*$row['VAT']/100,2);
  736. $allVAT += round(round($row['N_AMMOUNT']*$row['N_PRICE'],2)*$row['VAT']/100,2) + round(round($row['AMMOUNT']*$row['PRICE'],2)*$row['VAT']/100,2);
  737. }
  738. if ($row['N_VAT'] > 0) {
  739. $data[$row['BN_ID']][1][$xmlVAT[$row['N_VAT_NAME']]['vat']] -= round(round($row['N_AMMOUNT']*$row['N_PRICE'],2)*$row['N_VAT']/100,2);
  740. $allVAT -= round(round($row['N_AMMOUNT']*$row['N_PRICE'],2)*$row['N_VAT']/100,2);
  741. }
  742. }
  743. }
  744. ksort($data);
  745. $addCdata = function(&$node, $value) {
  746. $dom_node = dom_import_simplexml($node);
  747. $dom_owner = $dom_node->ownerDocument;
  748. $dom_node->appendChild($dom_owner->createCDATASection($value));
  749. };
  750. $i = 0;
  751. foreach ($data as $pos) {
  752. $this->validateNIP($pos[0]['NrKontrahenta'], $pos[0]['NazwaKontrahenta'], 'Sprzedaż L1');
  753. $x = $xml->addChild('SprzedazWiersz');
  754. $x->addAttribute('typ', 'G');
  755. $x->addChild('LpSprzedazy', ++$i);
  756. ksort($pos[1]);
  757. foreach ($pos as $subpos) foreach ($subpos as $key => $value) {
  758. $x->addChild($key, $value);
  759. if (!strlen($x->$key)) $addCdata($x->$key, $value);
  760. }
  761. }
  762. if ($this->NIPerrors) throw new Exception("Błędne numery NIP:<br/>" . implode("<br/>", $this->NIPerrors));
  763. $xml->SprzedazCtrl->LiczbaWierszySprzedazy = count($data);
  764. $xml->SprzedazCtrl->PodatekNalezny = $allVAT;
  765. $this->validateJPK_VAT($xml);
  766. if ($this->JPK['IN_INSERT']) $info = "Zaimportowano dane z Insert i L1";
  767. else $info = "Zaimportowano dane z L1";
  768. $sqlObj = new stdClass();
  769. $sqlObj->ID = $this->JPK['ID'];
  770. $sqlObj->A_STATUS_INFO = $info;
  771. $sqlObj->IN_L1 = $xml->asXml();
  772. if (!$affected = DB::getDB()->UPDATE_OBJ('JPK', $sqlObj)) throw new Exception("Wystąpił nieznany błąd bazy danych");
  773. $this->handleAuth();
  774. $this->edit();
  775. } catch (Exception $e) {
  776. SE_Layout::gora();
  777. SE_Layout::menu();
  778. SE_Layout::alert('danger', "Błąd w trakcie importu danych z L1. {$e->getMessage()}");
  779. ?>
  780. <div class="container" style="text-align:center">
  781. <form method="post" action="<?=$this->LAST_REFERER?>">
  782. <input type="hidden" name="REFERER" value="<?=$this->REFERER?>"/>
  783. <button type="submit" class="btn btn-primary">Powrót</button>
  784. </form>
  785. </div>
  786. <?php
  787. SE_Layout::dol();
  788. }
  789. }
  790. private function delete_l1_jpk() {
  791. try {
  792. $info = "Usunięto dane z L1";
  793. if ($this->JPK['IN_INSERT']) $info .= " (pozostawiono dane z Insert)";
  794. $sqlObj = new stdClass();
  795. $sqlObj->ID = $this->JPK['ID'];
  796. $sqlObj->A_STATUS_INFO = $info;
  797. $sqlObj->IN_L1 = null;
  798. $sqlObj->OUT_MERGED = null;
  799. if (!$affected = DB::getDB()->UPDATE_OBJ('JPK', $sqlObj)) throw new Exception("Wystąpił nieznany błąd");
  800. $this->handleAuth();
  801. $this->edit();
  802. } catch (Exception $e) {
  803. SE_Layout::gora();
  804. SE_Layout::menu();
  805. SE_Layout::alert('danger', $e->getMessage());
  806. ?>
  807. <div class="container" style="text-align:center">
  808. <form method="post" action="<?=$this->LAST_REFERER?>">
  809. <input type="hidden" name="REFERER" value="<?=$this->REFERER?>"/>
  810. <button type="submit" class="btn btn-primary">Powrót</button>
  811. </form>
  812. </div>
  813. <?php
  814. SE_Layout::dol();
  815. }
  816. }
  817. private static function removeTnsNamespace(&$xml) {
  818. $ns = $xml->getNamespaces(true);
  819. if (isset($ns[''])) return;
  820. if ((!isset($ns['tns']) || isset($ns['xsi']))) throw new Exception("Błędna struktura pliku XML - błędne namespace");
  821. $dom = dom_import_simplexml($xml);
  822. $ns_uri = $dom->lookupNamespaceURI('tns');
  823. $dom->removeAttributeNS($ns_uri, 'tns');
  824. $xml->addAttribute('xmlns', $ns['tns']);
  825. $xml->addAttribute('xmlns:xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance');
  826. $xml = simplexml_load_string($xml->asXML());
  827. }
  828. private function generate_merged_jpk() {
  829. $xmlSchema = <<<EOT
  830. <?xml version="1.0" encoding="UTF-8" standalone="no"?>
  831. <JPK xmlns="http://jpk.mf.gov.pl/wzor/2016/10/26/10261/" xmlns:etd="http://crd.gov.pl/xml/schematy/dziedzinowe/mf/2016/01/25/eD/DefinicjeTypy/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  832. </JPK>
  833. EOT;
  834. $xml_append = function(SimpleXMLElement $to, SimpleXMLElement $from) {
  835. $toDom = dom_import_simplexml($to);
  836. $fromDom = dom_import_simplexml($from);
  837. $toDom->appendChild($toDom->ownerDocument->importNode($fromDom, true));
  838. };
  839. try {
  840. if (!($this->JPK['IN_INSERT'] && $this->JPK['IN_L1'])) throw new Exception("Błąd danych");
  841. $xmlInsert = simplexml_load_string($this->JPK['IN_INSERT']);
  842. self::removeTnsNamespace($xmlInsert);
  843. $xmlL1 = simplexml_load_string($this->JPK['IN_L1']);
  844. $xml = simplexml_load_string($xmlSchema);
  845. $tns = $this->tns[$this->JPK_VAT_Wariant];
  846. switch (V::get('SRC_PODMIOT','',$_POST)) {
  847. case "Insert":
  848. $xml_append($xml, $xmlInsert->children($tns)->Naglowek);
  849. $xml_append($xml, $xmlInsert->children($tns)->Podmiot1);
  850. break;
  851. case "L1":
  852. $xml_append($xml, $xmlL1->children($tns)->Naglowek);
  853. $xml_append($xml, $xmlL1->children($tns)->Podmiot1);
  854. break;
  855. default:
  856. throw new Exception("Błąd formularza");
  857. }
  858. $xml->Naglowek->DataWytworzeniaJPK = date("Y-m-d\TH:i:s");
  859. $i = 0;
  860. foreach ($xmlInsert->SprzedazWiersz as $sprzedazWiersz) {
  861. $this->validateNIP($sprzedazWiersz->NrKontrahenta, $sprzedazWiersz->NazwaKontrahenta, "Sprzedaż Insert");
  862. $sprzedazWiersz->LpSprzedazy = ++$i;
  863. $xml_append($xml, $sprzedazWiersz);
  864. }
  865. foreach ($xmlL1->SprzedazWiersz as $sprzedazWiersz) {
  866. $this->validateNIP($sprzedazWiersz->NrKontrahenta, $sprzedazWiersz->NazwaKontrahenta, "Sprzedaż L1");
  867. $sprzedazWiersz->LpSprzedazy = ++$i;
  868. $xml_append($xml, $sprzedazWiersz);
  869. }
  870. $xml->addChild("SprzedazCtrl");
  871. $i = 0;
  872. foreach ($xmlInsert->ZakupWiersz as $zakupWiersz) {
  873. $this->validateNIP($zakupWiersz->NrDostawcy, $zakupWiersz->NazwaDostawcy, "Zakup Insert");
  874. $zakupWiersz->LpZakupu = ++$i;
  875. $xml_append($xml, $zakupWiersz);
  876. }
  877. foreach ($xmlL1->ZakupWiersz as $zakupWiersz) {
  878. $this->validateNIP($zakupWiersz->NrDostawcy, $zakupWiersz->NazwaDostawcy, "Zakup L1");
  879. $zakupWiersz->LpZakupu = ++$i;
  880. $xml_append($xml, $zakupWiersz);
  881. }
  882. $xml->addChild("ZakupCtrl");
  883. if ($this->NIPerrors) throw new Exception("Błędne numery NIP:<br/>" . implode("<br/>", $this->NIPerrors));
  884. $sumaryJPK_VAT = $this->getSummaryJPK_VAT($xml);
  885. $xml->SprzedazCtrl->LiczbaWierszySprzedazy = $sumaryJPK_VAT['LiczbaWierszySprzedazy'];
  886. $xml->SprzedazCtrl->PodatekNalezny = $sumaryJPK_VAT['PodatekNalezny'];
  887. $xml->ZakupCtrl->LiczbaWierszyZakupow = $sumaryJPK_VAT['LiczbaWierszyZakupow'];
  888. $xml->ZakupCtrl->PodatekNaliczony = $sumaryJPK_VAT['PodatekNaliczony'];
  889. $this->validateJPK_VAT($xml);
  890. $sqlObj = new stdClass();
  891. $sqlObj->ID = $this->JPK['ID'];
  892. $sqlObj->A_STATUS_INFO = "Wygenerowano wynikowy plik JPK";
  893. $sqlObj->OUT_MERGED = $xml->asXml();
  894. if (!$affected = DB::getDB()->UPDATE_OBJ('JPK', $sqlObj)) throw new Exception("Wystąpił nieznany błąd bazy danych");
  895. $this->handleAuth();
  896. $this->edit();
  897. } catch (Exception $e) {
  898. SE_Layout::gora();
  899. SE_Layout::menu();
  900. SE_Layout::alert('danger', $e->getMessage());
  901. ?>
  902. <div class="container" style="text-align:center">
  903. <form method="post" action="<?=$this->LAST_REFERER?>">
  904. <input type="hidden" name="REFERER" value="<?=$this->REFERER?>"/>
  905. <button type="submit" class="btn btn-primary">Powrót</button>
  906. </form>
  907. </div>
  908. <?php
  909. SE_Layout::dol();
  910. }
  911. }
  912. private function close_jpk() {
  913. try {
  914. $sqlObj = new stdClass();
  915. $sqlObj->ID = $this->JPK['ID'];
  916. $sqlObj->A_STATUS = 'OFF_HARD';
  917. $sqlObj->A_STATUS_INFO = "Zamknięto deklarację JPK";
  918. if (!$affected = DB::getDB()->UPDATE_OBJ('JPK', $sqlObj)) throw new Exception("Wystąpił nieznany błąd bazy danych");
  919. $this->handleAuth();
  920. $this->show();
  921. } catch (Exception $e) {
  922. SE_Layout::gora();
  923. SE_Layout::menu();
  924. SE_Layout::alert('danger', $e->getMessage());
  925. ?>
  926. <div class="container" style="text-align:center">
  927. <form method="post" action="<?=$this->LAST_REFERER?>">
  928. <input type="hidden" name="REFERER" value="<?=$this->REFERER?>"/>
  929. <button type="submit" class="btn btn-primary">Powrót</button>
  930. </form>
  931. </div>
  932. <?php
  933. SE_Layout::dol();
  934. }
  935. }
  936. private function reinitialize() {
  937. $sqlObj = new stdClass();
  938. $sqlObj->ID = $this->JPK['ID'];
  939. $sqlObj->A_STATUS = 'WAITING';
  940. $sqlObj->A_STATUS_INFO = "Oczekuje na inicjalizację";
  941. $sqlObj->MONTH = "NULL";
  942. $sqlObj->PURPOSE = "NULL";
  943. DB::getDB()->UPDATE_OBJ('JPK', $sqlObj);
  944. $this->initialize();
  945. }
  946. public function defaultAction() {
  947. switch ($this->JPK['A_STATUS']) {
  948. case "WAITING":
  949. $this->initialize();
  950. break;
  951. case "NORMAL":
  952. $this->edit();
  953. break;
  954. case "OFF_HARD":
  955. $this->show();
  956. break;
  957. default:
  958. SE_Layout::alert('danger', "Błędny status rekordu.");
  959. }
  960. }
  961. }