api.dreamkas.php 99 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406
  1. <?php
  2. /**
  3. * DreamKas service interaction class
  4. */
  5. class DreamKas {
  6. /**
  7. * UbillingConfig object placeholder
  8. *
  9. * @var null
  10. */
  11. protected $ubConfig = null;
  12. /**
  13. * System message helper object placeholder
  14. *
  15. * @var null
  16. */
  17. protected $messages = null;
  18. /**
  19. * UbillingCache instance placeholder
  20. *
  21. * @var null
  22. */
  23. protected $ubCache = null;
  24. /**
  25. * Dreamkas auth token placeholder
  26. *
  27. * @var string
  28. */
  29. protected $authToken = '';
  30. /**
  31. * Placeholder for DREAMKAS_ALWAYS_FISCALIZE_ALL alter.ini option
  32. *
  33. * @var bool
  34. */
  35. protected $alwaysFiscalizeAll = false;
  36. /**
  37. * Placeholder for DREAMKAS_DEFAULT_CASH_MACHINE_ID alter.ini option
  38. *
  39. * @var bool
  40. */
  41. protected $defaultCashMachineID = '';
  42. /**
  43. * Placeholder for DREAMKAS_DEFAULT_TAX_TYPE alter.ini option
  44. *
  45. * @var bool
  46. */
  47. protected $defaultTaxType = '';
  48. /**
  49. * Placeholder for DREAMKAS_NOTIFICATIONS_ENABLED alter.ini option
  50. *
  51. * @var bool
  52. */
  53. protected $notysEnabled = false;
  54. /**
  55. * Caching timeout based on polling interval in seconds.
  56. *
  57. * @var int
  58. */
  59. protected $notysCachingTimeout = 8;
  60. /**
  61. * Plcaeholder for basic and common HTTP headers for Dreamkas connecting and authenticating
  62. *
  63. * @var array
  64. */
  65. protected $basicHTTPHeaders = array();
  66. /**
  67. * Placeholder for all cash machines
  68. *
  69. * @var array
  70. */
  71. protected $cashMachines = array();
  72. /**
  73. * Array containing cash machines IDs => IDs + Names. E.g for selector controls
  74. *
  75. * @var array
  76. */
  77. protected $cashMachines4Selector = array();
  78. /**
  79. * Placeholder for selling positions to services relations
  80. * to be able to distinguish UKV/Inet services when preforming check fiscalization
  81. *
  82. * @var array
  83. */
  84. protected $sellPos2SrvTypeMapping = array();
  85. /**
  86. * Placeholder for all selling positions
  87. *
  88. * @var array
  89. */
  90. protected $sellingPositions = array();
  91. /**
  92. * Array containing selling positions IDs => Names. E.g for selector controls
  93. *
  94. * @var array
  95. */
  96. protected $sellingPositionsIDsNames = array();
  97. /**
  98. * Array containing fiscal operations initiated and stored locally
  99. *
  100. * @var array
  101. */
  102. protected $localFiscalOperations = array();
  103. /**
  104. * Placeholder for all registered webhooks
  105. *
  106. * @var array
  107. */
  108. protected $webhooks = array();
  109. /**
  110. * Contains last error message string
  111. *
  112. * @var string
  113. */
  114. protected $lastErrorMEssage = '';
  115. /**
  116. * Placeholder for DREAMKAS_CACHE_LIFETIME from alter.ini
  117. *
  118. * @var int
  119. */
  120. protected $cacheLifeTime = 1800;
  121. /**
  122. * $dataCahched array from UbillingCache
  123. *
  124. * @var array
  125. */
  126. protected $dataCahched = array();
  127. /**
  128. * Dreamkas to Banksta2 processed relations data with receipts IDs already
  129. *
  130. * @var array
  131. */
  132. protected $bs2RelationsProcessed = array();
  133. /**
  134. * Dreamkas to Banksta2 unprocessed relations data without receipts IDs yet
  135. *
  136. * @var array
  137. */
  138. protected $bs2RelationsUnProcessed = array();
  139. /**
  140. * Dreamkas to Banksta2 relations data with fiscal operation ID as a key and without receipts IDs yet
  141. *
  142. * @var array
  143. */
  144. protected $bs2RelationsUnProcFiscOpKey = array();
  145. /**
  146. * Placeholder for payment types supported by Dreamkas API
  147. *
  148. * @var array
  149. */
  150. protected $paymentTypes = array(
  151. 'CASH' => 'Наличные',
  152. 'CASHLESS' => 'Безналичные',
  153. 'PREPAID' => 'Аванс',
  154. 'CREDIT' => 'Кредит',
  155. 'CONSIDERATION' => 'Встречное предоставление'
  156. );
  157. /**
  158. * Placeholder for taxation systems supported by Dreamkas API
  159. *
  160. * @var array
  161. */
  162. protected $taxTypes = array(
  163. 'DEFAULT' => 'Общая',
  164. 'SIMPLE' => 'Упрощенная доход',
  165. 'SIMPLE_WO' => 'Упрощенная доход минус расход',
  166. 'ENVD' => 'Единый налог на вмененный доход',
  167. 'PATENT' => 'Патентная система налогообложения'
  168. );
  169. /**
  170. * Placeholder for VAT(НДС) types supported by Dreamkas API
  171. *
  172. * @var array
  173. */
  174. protected $taxTypesVAT = array(
  175. 'NDS_NO_TAX' => 'Без НДС',
  176. 'NDS_0' => 'НДС 0%',
  177. 'NDS_10' => 'НДС 10%',
  178. 'NDS_20' => 'НДС 20%',
  179. 'NDS_10_CALCULATED' => 'НДС 10/110%',
  180. 'NDS_20_CALCULATED' => 'НДС 20/120%'
  181. );
  182. const URL_ME = '?module=dreamkas';
  183. const URL_API = 'https://kabinet.dreamkas.ru/api/';
  184. const URL_DREAMKAS_RECEIPTS = '?module=dreamkas&getreceipts=true';
  185. const URL_DREAMKAS_CASHIERS = '?module=dreamkas&getcashiers=true';
  186. const URL_DREAMKAS_OPERATIONS = '?module=dreamkas&getoperations=true';
  187. const URL_DREAMKAS_GOODS = '?module=dreamkas&getgoods=true';
  188. const URL_DREAMKAS_CASH_MACHINES = '?module=dreamkas&getcashmachines=true';
  189. const URL_DREAMKAS_WEBHOOKS = '?module=dreamkas&getwebhookss=true';
  190. const URL_DREAMKAS_RECEIPT_DETAILS = '?module=dreamkas&getreceiptdetails=true';
  191. const URL_DREAMKAS_FORCE_CACHE_UPDATE = '?module=dreamkas&forcecacheupdate=true';
  192. // fiscalize timeout in minutes
  193. const RECEIPT_FISCALIZE_TIMEOUT = '7';
  194. const RECEIPT_PRODUCT_TYPE = 'SERVICE';
  195. const RECEIPT_OPERATION_TYPE = 'SALE';
  196. // Go to:
  197. // https://kabinet.dreamkas.ru/api/#cheki
  198. // and carefully read about the positions array
  199. // and quantity for anything except SCALABLE.
  200. const RECEIPT_QUANTITY_DIVIDER = '1000';
  201. const DREAMKAS_CACHE_KEY = 'DREAMKAS_DATA';
  202. const DREAMKAS_NOTYS_CAHCE_KEY = 'DREAMKAS_NOTIFICATIONS';
  203. public function __construct() {
  204. global $ubillingConfig;
  205. $this->ubConfig = $ubillingConfig;
  206. $this->ubCache = new UbillingCache();
  207. $this->initMessages();
  208. $this->loadOptions();
  209. $this->basicHTTPHeaders = array(
  210. 'Authorization: Bearer ' . $this->authToken,
  211. 'Content-Type: application/json',
  212. 'Cache-Control: no-cache'
  213. );
  214. $thisInstance = $this;
  215. $this->dataCahched = $this->ubCache->getCallback(self::DREAMKAS_CACHE_KEY, function () use ($thisInstance) {
  216. return ($thisInstance->getDataForCache());
  217. }, $this->cacheLifeTime);
  218. $this->cashMachines = (isset($this->dataCahched['cashmachines'])) ? $this->dataCahched['cashmachines'] : array();
  219. $this->sellingPositions = (isset($this->dataCahched['sellingpositions'])) ? $this->dataCahched['sellingpositions'] : array();
  220. $this->getCashMachines4Selector();
  221. $this->getSellPosIDsNames();
  222. $this->getSellPos2SrvTypeMapping();
  223. $this->getBS2RelationsProcessed();
  224. $this->getBS2RelationsUnProcessed();
  225. //$curISOTime = date('Y-m-d\TH:i:s.Z\Z', time());
  226. //$customISOTime = date('Y-m-d\TH:i:s.Z\Z', strtotime('2017-01-25 14:40:46'));
  227. //date('Y-m-d H:i:s', strtotime('2019-06-05T23:59:59.999Z'))
  228. }
  229. /**
  230. * Inits message helper object for further usage
  231. *
  232. * @return void
  233. */
  234. protected function initMessages() {
  235. $this->messages = new UbillingMessageHelper();
  236. }
  237. /**
  238. * Getting an alter.ini options
  239. *
  240. * @return void
  241. */
  242. protected function loadOptions() {
  243. $this->authToken = $this->ubConfig->getAlterParam('DREAMKAS_AUTH_TOKEN');
  244. $this->cacheLifeTime = ($this->ubConfig->getAlterParam('DREAMKAS_CACHE_LIFETIME')) ? $this->ubConfig->getAlterParam('DREAMKAS_CACHE_LIFETIME') : 1800;
  245. $this->defaultCashMachineID = ($this->ubConfig->getAlterParam('DREAMKAS_DEFAULT_CASH_MACHINE_ID')) ? $this->ubConfig->getAlterParam('DREAMKAS_DEFAULT_CASH_MACHINE_ID') : '';
  246. $this->defaultTaxType = ($this->ubConfig->getAlterParam('DREAMKAS_DEFAULT_TAX_TYPE')) ? $this->ubConfig->getAlterParam('DREAMKAS_DEFAULT_TAX_TYPE') : '';
  247. $this->alwaysFiscalizeAll = wf_getBoolFromVar($this->ubConfig->getAlterParam('DREAMKAS_ALWAYS_FISCALIZE_ALL'));
  248. $this->notysEnabled = wf_getBoolFromVar($this->ubConfig->getAlterParam('DREAMKAS_NOTIFICATIONS_ENABLED'));
  249. $this->notysCachingTimeout = ($this->ubConfig->getAlterParam('DREAMKAS_CACHE_CHECK_INTERVAL')) ? $this->ubConfig->getAlterParam('DREAMKAS_CACHE_CHECK_INTERVAL') : 8;
  250. }
  251. /**
  252. * Returns reference to UbillingMessageHelper object
  253. *
  254. * @return object
  255. */
  256. public function getUbMsgHelperInstance() {
  257. return $this->messages;
  258. }
  259. /**
  260. * Returns essential data suitable for caching
  261. *
  262. * @return array
  263. */
  264. public function getDataForCache() {
  265. $cacheArray = array();
  266. $cashiers4Cache = $this->getCashiers();
  267. $sellPos4Cache = $this->getSellingPositions();
  268. $cashMachines4Cache = $this->getCashMachines();
  269. if (!empty($cashiers4Cache)) {
  270. $cacheArray['cashiers'] = $cashiers4Cache;
  271. }
  272. if (!empty($sellPos4Cache)) {
  273. $cacheArray['sellingpositions'] = $sellPos4Cache;
  274. }
  275. if (!empty($sellPos4Cache)) {
  276. $cacheArray['cashmachines'] = $cashMachines4Cache;
  277. }
  278. //$this->updateFiscalOperationsLocalStorage();
  279. return ($cacheArray);
  280. }
  281. /**
  282. * Forcibly updates cached data
  283. */
  284. public function refreshCacheForced() {
  285. $this->ubCache->set(self::DREAMKAS_CACHE_KEY, $this->getDataForCache(), $this->cacheLifeTime);
  286. $this->dataCahched = $this->ubCache->get(self::DREAMKAS_CACHE_KEY, $this->cacheLifeTime);
  287. }
  288. /**
  289. * Returns cashiers array via Dreamkas API
  290. *
  291. * @return mixed
  292. */
  293. protected function getCashiers() {
  294. $urlString = self::URL_API . 'cashiers';
  295. $curl = curl_init();
  296. curl_setopt($curl, CURLOPT_URL, $urlString);
  297. curl_setopt($curl, CURLOPT_HTTPHEADER, $this->basicHTTPHeaders);
  298. curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
  299. $result = curl_exec($curl);
  300. $httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
  301. curl_close($curl);
  302. $result = json_decode($result, true);
  303. if (substr($httpCode, 0, 1) != '2') {
  304. log_register('DREAMKAS getting cashiers error: ' . $this->errorToString($result));
  305. $result = array();
  306. }
  307. return ($result);
  308. }
  309. /**
  310. * Returns cash machines array via Dreamkas API
  311. *
  312. * @return mixed
  313. */
  314. public function getCashMachines($cmID = '') {
  315. $urlString = self::URL_API . 'devices' . ((empty($cmID)) ? '' : '/' . $cmID);
  316. $curl = curl_init();
  317. curl_setopt($curl, CURLOPT_URL, $urlString);
  318. curl_setopt($curl, CURLOPT_HTTPHEADER, $this->basicHTTPHeaders);
  319. curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
  320. $result = curl_exec($curl);
  321. $httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
  322. curl_close($curl);
  323. $tCMArr = json_decode($result, true);
  324. $result = array();
  325. if (!empty($tCMArr)) {
  326. if (substr($httpCode, 0, 1) == '2') {
  327. if (empty($cmID)) {
  328. foreach ($tCMArr as $eachItem) {
  329. $this->cashMachines[$eachItem['id']] = $eachItem;
  330. }
  331. $result = $this->cashMachines;
  332. } else {
  333. $result = $tCMArr;
  334. }
  335. } else {
  336. log_register('DREAMKAS getting cash machines error: ' . $this->errorToString($tCMArr));
  337. }
  338. }
  339. return ($result);
  340. }
  341. /**
  342. * Returns fiscal operations array via Dreamkas API
  343. *
  344. * @return mixed
  345. */
  346. protected function getFiscalOperations($dateFrom = '', $dateTo = '') {
  347. if (!empty($dateFrom) and $dateFrom == $dateTo) {
  348. $dateTo = $dateTo . ' 23:59:59';
  349. } elseif (!empty($dateFrom) and empty($dateTo)) {
  350. $dateTo = $dateFrom . ' 23:59:59';
  351. }
  352. // for now - this is useless, 'cause Dreamkas API doesn't support fiscal operations filtering by time range
  353. // but there is hope it may change in future
  354. $urlParams = empty($dateFrom) ? '' : '?from=' . date('Y-m-d\TH:i:s.Z\Z', strtotime($dateFrom));
  355. $urlParams .= empty($dateTo) ? '' : (empty($dateFrom) ? '?' : '&') . 'to=' . date('Y-m-d\TH:i:s.Z\Z', strtotime($dateTo));
  356. $urlString = self::URL_API . 'operations' . $urlParams;
  357. $curl = curl_init();
  358. curl_setopt($curl, CURLOPT_URL, $urlString);
  359. curl_setopt($curl, CURLOPT_HTTPHEADER, $this->basicHTTPHeaders);
  360. curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
  361. //curl_setopt($curl, CURLOPT_TIMEOUT, 12);
  362. $result = curl_exec($curl);
  363. $httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
  364. curl_close($curl);
  365. $result = json_decode($result, true);
  366. if (substr($httpCode, 0, 1) != '2') {
  367. log_register('DREAMKAS getting fiscal operations error: ' . $this->errorToString($result));
  368. $result = array();
  369. }
  370. return ($result);
  371. }
  372. /**
  373. * Fills $this->localFiscalOperations with fiscal operations initiated and stored locally
  374. *
  375. * @return array
  376. */
  377. protected function getFiscalOperationsLocal($whereClause = '') {
  378. $whereClause = (empty($whereClause)) ? '' : " WHERE " . $whereClause . " ";
  379. $tQuery = "SELECT * FROM `dreamkas_operations`" . $whereClause . " ORDER BY `date_create` DESC";
  380. $tQueryResult = simple_queryall($tQuery);
  381. if (!empty($tQueryResult)) {
  382. $this->localFiscalOperations = array();
  383. foreach ($tQueryResult as $eachRec) {
  384. $this->localFiscalOperations[$eachRec['operation_id']] = $eachRec;
  385. }
  386. }
  387. return ($this->localFiscalOperations);
  388. }
  389. /**
  390. * Returns the actual query body of fiscal operation
  391. *
  392. * @param $operationID
  393. *
  394. * @return string
  395. */
  396. public function getFiscalOperationLocalBody($operationID) {
  397. $tQuery = "SELECT `operation_body` FROM `dreamkas_operations` WHERE `operation_id` = '" . $operationID . "'";
  398. $tQueryResult = simple_queryall($tQuery);
  399. $result = '';
  400. if (!empty($tQueryResult)) {
  401. foreach ($tQueryResult as $eachRec) {
  402. $result = base64_decode($eachRec['operation_body']);
  403. }
  404. }
  405. return ($result);
  406. }
  407. /**
  408. * Returns the all actual data of fiscal operation
  409. *
  410. * @param $operationID
  411. *
  412. * @return false|string
  413. */
  414. public function getFiscalOperationLocalData($operationID) {
  415. $tQuery = "SELECT * FROM `dreamkas_operations` WHERE `operation_id` = '" . $operationID . "'";
  416. $tQueryResult = simple_queryall($tQuery);
  417. $result = '';
  418. if (!empty($tQueryResult)) {
  419. foreach ($tQueryResult as $eachRec) {
  420. $result = $eachRec;
  421. }
  422. }
  423. return ($result);
  424. }
  425. /**
  426. * Simply increments fiscal operation repeats counter
  427. *
  428. * @param $operationID
  429. *
  430. * @return void
  431. */
  432. public function incrFiscalOperationRepeatsCount($operationID) {
  433. $tQuery = "UPDATE `dreamkas_operations` SET `repeat_count` = `repeat_count` + 1 WHERE `operation_id` = '" . $operationID . "'";
  434. nr_query($tQuery);
  435. }
  436. /**
  437. * Returns last error message
  438. *
  439. * @return string
  440. */
  441. public function getLastErrorMessage() {
  442. return ($this->lastErrorMEssage);
  443. }
  444. /**
  445. * Returns selling positions array via Dreamkas API
  446. *
  447. * @return mixed
  448. */
  449. public function getSellingPositions($goodsID = '') {
  450. $urlString = self::URL_API . 'v2/products' . ((empty($goodsID)) ? '' : '/' . $goodsID);
  451. //$urlString = self::URL_API . 'products' . ((empty($goodsID)) ? '' : '/' . $goodsID);
  452. $curl = curl_init();
  453. curl_setopt($curl, CURLOPT_URL, $urlString);
  454. curl_setopt($curl, CURLOPT_HTTPHEADER, $this->basicHTTPHeaders);
  455. curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
  456. $result = curl_exec($curl);
  457. $httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
  458. curl_close($curl);
  459. $tSelPosArr = json_decode($result, true);
  460. $result = array();
  461. if (!empty($tSelPosArr)) {
  462. if (substr($httpCode, 0, 1) == '2') {
  463. if (empty($goodsID)) {
  464. foreach ($tSelPosArr as $eachItem) {
  465. $this->sellingPositions[$eachItem['id']] = $eachItem;
  466. }
  467. $result = $this->sellingPositions;
  468. } else {
  469. $result = $tSelPosArr;
  470. }
  471. } else {
  472. log_register('DREAMKAS getting selling positions error: ' . $this->errorToString($tSelPosArr));
  473. }
  474. }
  475. return ($result);
  476. }
  477. /**
  478. * Returns receipts array via Dreamkas API
  479. *
  480. * @return mixed
  481. */
  482. protected function getReceipts($dateFrom = '', $dateTo = '', $cashDeviceID = '', $limit = 1000) {
  483. if (!empty($dateFrom) and $dateFrom == $dateTo) {
  484. $dateTo = $dateTo . ' 23:59:59';
  485. } elseif (!empty($dateFrom) and empty($dateTo)) {
  486. $dateTo = $dateFrom . ' 23:59:59';
  487. }
  488. $limit = '?limit=' . $limit;
  489. $urlString = self::URL_API . 'receipts' . $limit .
  490. ((empty($dateFrom)) ? '' : '&from=' . date('Y-m-d\TH:i:s.Z\Z', strtotime($dateFrom))) .
  491. ((empty($dateTo)) ? '' : '&to=' . date('Y-m-d\TH:i:s.Z\Z', strtotime($dateTo))) .
  492. ((empty($cashDeviceID)) ? '' : '&devices=' . $cashDeviceID);
  493. $curl = curl_init();
  494. curl_setopt($curl, CURLOPT_URL, $urlString);
  495. curl_setopt($curl, CURLOPT_HTTPHEADER, $this->basicHTTPHeaders);
  496. curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
  497. $result = curl_exec($curl);
  498. $httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
  499. curl_close($curl);
  500. $result = json_decode($result, true);
  501. if (substr($httpCode, 0, 1) != '2') {
  502. log_register('DREAMKAS getting receipts error: ' . $this->errorToString($result));
  503. $result = array();
  504. }
  505. return ($result);
  506. }
  507. /**
  508. * Returns receipt detail info array via Dreamkas API
  509. *
  510. * @return mixed
  511. */
  512. public function getReceiptDetails($receiptID) {
  513. $urlString = self::URL_API . 'receipts/' . $receiptID;
  514. $curl = curl_init();
  515. curl_setopt($curl, CURLOPT_URL, $urlString);
  516. curl_setopt($curl, CURLOPT_HTTPHEADER, $this->basicHTTPHeaders);
  517. curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
  518. $result = curl_exec($curl);
  519. $httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
  520. curl_close($curl);
  521. return (json_decode($result, true));
  522. }
  523. /**
  524. * gets ubilling system key into private key prop
  525. *
  526. * @return string
  527. */
  528. protected function getUBSerial() {
  529. $hostid_q = "SELECT * from `ubstats` WHERE `key`='ubid'";
  530. $hostid = simple_query($hostid_q);
  531. if (!empty($hostid)) {
  532. if (isset($hostid['value'])) {
  533. return ($hostid['value']);
  534. }
  535. }
  536. }
  537. protected function getWebHooks($webhookID = '') {
  538. $urlString = self::URL_API . 'webhooks' . ((empty($webhookID)) ? '' : '/' . $webhookID);
  539. $curl = curl_init();
  540. curl_setopt($curl, CURLOPT_URL, $urlString);
  541. curl_setopt($curl, CURLOPT_HTTPHEADER, $this->basicHTTPHeaders);
  542. curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
  543. $result = curl_exec($curl);
  544. $httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
  545. curl_close($curl);
  546. $tWebHookArr = json_decode($result, true);
  547. $result = array();
  548. if (!empty($tWebHookArr)) {
  549. if (substr($httpCode, 0, 1) == '2') {
  550. if (empty($webhookID)) {
  551. foreach ($tWebHookArr as $eachItem) {
  552. $this->webhooks[$eachItem['id']] = $eachItem;
  553. }
  554. $result = $this->webhooks;
  555. } else {
  556. $result = $tWebHookArr;
  557. }
  558. } else {
  559. log_register('DREAMKAS getting webhooks error: ' . $this->errorToString($tWebHookArr));
  560. }
  561. }
  562. return ($result);
  563. }
  564. /**
  565. * Returns an HTML-code string containing selector control
  566. *
  567. * @return mixed
  568. */
  569. protected function getSelectorWebControl($selectorData, $selectorName, $selectedItem = '', $selectorID = '', $selectorClass = '', $selectorLabel = '', $insBR = false) {
  570. $result = wf_Selector($selectorName, $selectorData, $selectorLabel, $selectedItem, $insBR, true, $selectorID, $selectorClass);
  571. return ($result);
  572. }
  573. /**
  574. * Returns an HTML-code string containing selector control
  575. *
  576. * @param string $selectorID
  577. * @param string $selectorClass
  578. * @param string $title
  579. * @param bool $insBR
  580. *
  581. * @return string
  582. */
  583. public function getTaxTypesVATSelector($selectorID = '', $selectorClass = '', $title = '', $insBR = false, $selectedItem = '') {
  584. $labelTitle = (empty($title)) ? __('Choose VAT tax type') : $title;
  585. $ctrlID = (empty($selectorID)) ? 'DreamkasVATTypeSelector' : $selectorID;
  586. $ctrlClass = (empty($selectorClass)) ? '__DreamkasVATTypeSelector' : $selectorClass;
  587. $result = wf_Selector('drsvattypes', $this->paymentTypes, $labelTitle, $selectedItem, $insBR, true, $ctrlID, $ctrlClass);
  588. return ($result);
  589. }
  590. /**
  591. * Fills up $this->cashMachines4Selector array for further use
  592. *
  593. * @return array
  594. */
  595. protected function getCashMachines4Selector() {
  596. if (empty($this->cashMachines)) {
  597. $this->cashMachines = (isset($this->dataCahched['cashmachines'])) ? $this->dataCahched['cashmachines'] : array();
  598. }
  599. if (!empty($this->cashMachines)) {
  600. foreach ($this->cashMachines as $eachCM) {
  601. $this->cashMachines4Selector[$eachCM['id']] = $eachCM['id'] . ' ' . $eachCM['name'];
  602. }
  603. }
  604. return ($this->cashMachines4Selector);
  605. }
  606. /**
  607. * Fills up $this->sellingPositionsIDsNames array for further use
  608. *
  609. * @return array
  610. */
  611. protected function getSellPosIDsNames() {
  612. if (empty($this->sellingPositions)) {
  613. $this->sellingPositions = (isset($this->dataCahched['sellingpositions'])) ? $this->dataCahched['sellingpositions'] : array();
  614. }
  615. if (!empty($this->sellingPositions)) {
  616. foreach ($this->sellingPositions as $sellingPosition) {
  617. $this->sellingPositionsIDsNames[$sellingPosition['id']] = $sellingPosition['name'];
  618. }
  619. }
  620. return ($this->sellingPositionsIDsNames);
  621. }
  622. /**
  623. * Fills up $this->sellPos2SrvTypeMapping array with services to selling positions mapping
  624. *
  625. * @return void
  626. */
  627. protected function getSellPos2SrvTypeMapping() {
  628. $tQuery = "SELECT * FROM `dreamkas_services_relations`";
  629. $tQueryResult = simple_queryall($tQuery);
  630. if (!empty($tQueryResult)) {
  631. foreach ($tQueryResult as $eachRow) {
  632. $this->sellPos2SrvTypeMapping[$eachRow['service']] = $eachRow;
  633. }
  634. }
  635. }
  636. /**
  637. * Returns Banksta2 record ID from `dreamkas_banksta2_relations` table, if exists
  638. *
  639. * @param $fiscopID
  640. *
  641. * @return int|mixed
  642. */
  643. public function getBS2RecIDbyFiscOpID($fiscopID) {
  644. $result = 0;
  645. if (empty($this->bs2RelationsUnProcFiscOpKey)) {
  646. $this->getBS2RelationsUnProcessed();
  647. }
  648. if (!empty($this->bs2RelationsUnProcFiscOpKey) and isset($this->bs2RelationsUnProcFiscOpKey[$fiscopID])) {
  649. $result = $this->bs2RelationsUnProcFiscOpKey[$fiscopID]['bs2_rec_id'];
  650. }
  651. return($result);
  652. }
  653. /**
  654. * Fills $this->bs2RelationsProcessed placeholder with data
  655. */
  656. protected function getBS2RelationsProcessed() {
  657. $tQuery = "SELECT * FROM `dreamkas_banksta2_relations` WHERE `receipt_id` IS NOT NULL AND `receipt_id` != ''";
  658. $tQueryResult = simple_queryall($tQuery);
  659. if (!empty($tQueryResult)) {
  660. foreach ($tQueryResult as $eachRow) {
  661. $this->bs2RelationsProcessed[$eachRow['bs2_rec_id']] = $eachRow;
  662. }
  663. }
  664. }
  665. /**
  666. * Fills $this->bs2RelationsUnProcessed placeholder with data
  667. */
  668. protected function getBS2RelationsUnProcessed() {
  669. $tQuery = "SELECT * FROM `dreamkas_banksta2_relations` WHERE `receipt_id` IS NULL OR `receipt_id` = ''";
  670. $tQueryResult = simple_queryall($tQuery);
  671. if (!empty($tQueryResult)) {
  672. foreach ($tQueryResult as $eachRow) {
  673. $this->bs2RelationsUnProcessed[$eachRow['bs2_rec_id']] = $eachRow;
  674. $this->bs2RelationsUnProcFiscOpKey[$eachRow['operation_id']] = $eachRow;
  675. }
  676. }
  677. }
  678. /**
  679. * Just inserts a new relational record if a fiscal operation from Banksta2 was made
  680. *
  681. * @param $bs2RecID
  682. * @param $fiscopID
  683. */
  684. protected function setBS2Relations($bs2RecID, $fiscopID, $fiscopReceiptID = '') {
  685. $this->getBS2RelationsUnProcessed();
  686. if (!empty($this->bs2RelationsUnProcessed) and isset($this->bs2RelationsUnProcessed[$bs2RecID])) {
  687. $tQuery = "UPDATE `dreamkas_banksta2_relations` SET
  688. `operation_id` = '" . $fiscopID . "',
  689. `receipt_id` = '" . $fiscopReceiptID . "'
  690. WHERE `bs2_rec_id` = " . $bs2RecID;
  691. } else {
  692. $tQuery = "INSERT INTO `dreamkas_banksta2_relations` (`bs2_rec_id`, `operation_id`, `receipt_id`)
  693. VALUES(" . $bs2RecID . ", '" . $fiscopID . "', '" . $fiscopReceiptID . "')";
  694. }
  695. nr_query($tQuery);
  696. }
  697. /**
  698. * To full fill avidity and greed
  699. *
  700. * @param $ukvUserID
  701. * @param $ukvObject
  702. *
  703. * @return mixed
  704. */
  705. public function getUKVUserData($ukvUserID, $ukvObject) {
  706. return ($ukvObject->getUserData($ukvUserID));
  707. }
  708. /**
  709. * To full fill avidity and greed
  710. *
  711. * @param $login
  712. *
  713. * @return string
  714. */
  715. public function getInetUserMobile($login) {
  716. return (zb_UserGetMobile($login));
  717. }
  718. /**
  719. * To full fill avidity and greed
  720. *
  721. * @param $login
  722. *
  723. * @return string
  724. */
  725. public function getInetUserEmail($login) {
  726. return (zb_UserGetEmail($login));
  727. }
  728. /**
  729. * Checks if sell position is mapped to some or certain service already
  730. *
  731. * @param $goodsID
  732. * @param string $service
  733. *
  734. * @return int|string
  735. */
  736. protected function checkSellPosIsMapped2SrvType($goodsID, $service = '') {
  737. $result = '';
  738. if (empty($this->sellPos2SrvTypeMapping)) {
  739. $this->getSellPos2SrvTypeMapping();
  740. }
  741. if (!empty($this->sellPos2SrvTypeMapping)) {
  742. foreach ($this->sellPos2SrvTypeMapping as $eachSrv => $eachGoodsArr) {
  743. if (empty($service) and $eachGoodsArr['goods_id'] == $goodsID) {
  744. $result = $eachSrv;
  745. break;
  746. }
  747. if ($eachSrv != $service and $eachGoodsArr['goods_id'] == $goodsID) {
  748. $result = $eachSrv;
  749. break;
  750. }
  751. }
  752. }
  753. return ($result);
  754. }
  755. /**
  756. * Maps certain selling position to certain service(Inet or UKV)
  757. *
  758. * @param $service
  759. * @param $goodsID
  760. * @param $goodsName
  761. * @param $goodsType
  762. * @param $goodsPrice
  763. * @param $goodsTax
  764. * @param $goodsVendorCode
  765. *
  766. * @return string
  767. */
  768. public function setSellingPositionSrvType($service, $goodsID, $goodsName, $goodsType, $goodsPrice, $goodsTax, $goodsVendorCode) {
  769. $result = '';
  770. If ($goodsType != self::RECEIPT_PRODUCT_TYPE) {
  771. $result = __('Sell positions of type ' . self::RECEIPT_PRODUCT_TYPE . ' allowed only');
  772. }
  773. $alreadyMappedTo = $this->checkSellPosIsMapped2SrvType($goodsID, $service);
  774. if (!empty($alreadyMappedTo)) {
  775. $result = __('This sell position is already mapped to ' . $alreadyMappedTo);
  776. }
  777. if (empty($result)) {
  778. if (isset($this->sellPos2SrvTypeMapping[$service])) {
  779. $tQuery = "UPDATE `dreamkas_services_relations` SET
  780. `goods_id` = '" . $goodsID . "',
  781. `goods_name` = '" . $goodsName . "',
  782. `goods_type` = '" . $goodsType . "',
  783. `goods_price` = " . $goodsPrice . ",
  784. `goods_tax` = '" . $goodsTax . "',
  785. `goods_vendorcode` = '" . $goodsVendorCode . "'
  786. WHERE `service` = '" . $service . "'
  787. ";
  788. nr_query($tQuery);
  789. log_register('DREAMKAS service ' . $service . ' sell position CHANGED from ' .
  790. $this->sellPos2SrvTypeMapping[$service]['goods_name'] . ' to ' . $goodsName);
  791. } else {
  792. $tQuery = "INSERT INTO `dreamkas_services_relations` (`service`, `goods_id`, `goods_name`, `goods_type`, `goods_price`, `goods_tax`, `goods_vendorcode`)
  793. VALUES ('" . $service . "', '" . $goodsID . "', '" . $goodsName . "', '" . $goodsType . "', " . $goodsPrice . ", '" . $goodsTax . "', '" . $goodsVendorCode . "')";
  794. nr_query($tQuery);
  795. log_register('DREAMKAS service ' . $service . ' sell position SET to ' . $goodsName);
  796. }
  797. }
  798. return ($result);
  799. }
  800. /**
  801. * Deletes certain selling position to service mapping
  802. *
  803. * @param $service
  804. *
  805. * @return void
  806. */
  807. public function delSellingPositionSrvType($service) {
  808. if (!empty($service)) {
  809. $tQuery = "DELETE FROM `dreamkas_services_relations` WHERE `service` = '" . $service . "'";
  810. nr_query($tQuery);
  811. log_register('DREAMKAS service ' . $service . ' sell position DELETED');
  812. }
  813. }
  814. /**
  815. * Converts Dreamkas server error message to string for logging and debugging
  816. *
  817. * @param $errorArr
  818. *
  819. * @return string
  820. */
  821. protected function errorToString($errorArr) {
  822. $errorStr = '';
  823. if (!empty($errorArr)) {
  824. foreach ($errorArr as $eachItem => $eachValue) {
  825. if (strtolower($eachItem) == 'data' and ! empty($eachValue)) {
  826. $tArr = $eachValue['errors'];
  827. foreach ($tArr as $errItem) {
  828. foreach ($errItem as $item => $val) {
  829. if (!empty($item) and ! empty($val)) {
  830. $errorStr .= $item . ': ' . $val . "\n";
  831. }
  832. }
  833. }
  834. } else {
  835. if (!empty($eachItem) and ! empty($eachValue)) {
  836. $errorStr .= $eachItem . ': ' . $eachValue . "\n";
  837. }
  838. }
  839. }
  840. if (empty($errorStr)) {
  841. $errorStr = print_r($errorArr, true);
  842. }
  843. }
  844. $this->putNotificationData2Cache($errorStr, 'error', __('DREAMKAS ERROR'));
  845. $this->lastErrorMEssage = $errorStr;
  846. return ($errorStr);
  847. }
  848. /**
  849. * Check fiscalize preparation routine
  850. *
  851. * @param $cashMachineID
  852. * @param $taxType
  853. * @param $paymentType
  854. * @param array $sellPosIDsPrices SellPosID => array('price' => SellPosPrice, 'quantity' => SellPosQuantity)
  855. * @param array $addUserContacts
  856. *
  857. * @return string/JSON
  858. */
  859. public function prepareCheckFiscalData($cashMachineID, $taxType, $paymentType, $sellPosIDsPrices, $addUserContacts = array()) {
  860. $checkBody = array();
  861. $checkJSON = json_encode(array());
  862. if (!empty($sellPosIDsPrices)) {
  863. $checkBody['deviceId'] = $cashMachineID;
  864. $checkBody['type'] = self::RECEIPT_OPERATION_TYPE;
  865. $checkBody['timeout'] = self::RECEIPT_FISCALIZE_TIMEOUT;
  866. $checkBody['taxMode'] = $taxType;
  867. $checkBody['positions'] = array();
  868. $checkBody['payments'] = array();
  869. $checkBody['attributes'] = array();
  870. $sellPosBody = array();
  871. $sellPaymentsBody = array();
  872. $userContacts = array();
  873. $checkTotal = 0;
  874. // gathering positions body
  875. foreach ($sellPosIDsPrices as $eachID => $each) {
  876. if (isset($this->sellingPositions[$eachID])) {
  877. $tSellPosArr = $this->sellingPositions[$eachID];
  878. $sellPosPrice = (isset($each['price'])) ? $each['price'] : $tSellPosArr['price'];
  879. $sellPosQuantity = (isset($each['quantity'])) ? $each['quantity'] : $tSellPosArr['quantity'] / self::RECEIPT_QUANTITY_DIVIDER;
  880. if (empty($sellPosPrice) and empty($sellPosQuantity)) {
  881. continue;
  882. }
  883. $sellPosBody['name'] = $tSellPosArr['name'];
  884. $sellPosBody['type'] = self::RECEIPT_PRODUCT_TYPE;
  885. $sellPosBody['quantity'] = $sellPosQuantity;
  886. $sellPosBody['price'] = $sellPosPrice;
  887. $sellPosBody['tax'] = $tSellPosArr['tax'];
  888. $sellPaymentsBody['sum'] = $sellPosPrice;
  889. $sellPaymentsBody['type'] = $paymentType;
  890. $checkBody['positions'][] = $sellPosBody;
  891. $checkBody['payments'][] = $sellPaymentsBody;
  892. $checkTotal += $sellPaymentsBody['sum'];
  893. // because Dreamkas API doesn't allow empty phone or e-mail fields
  894. // we need to figure out which of them are not empty and add filled only
  895. if (isset($addUserContacts['phone']) and ! empty($addUserContacts['phone'])) {
  896. $userContacts['phone'] = $addUserContacts['phone'];
  897. }
  898. if (isset($addUserContacts['email']) and ! empty($addUserContacts['email'])) {
  899. $userContacts['email'] = $addUserContacts['email'];
  900. }
  901. if (!empty($userContacts)) {
  902. $checkBody['attributes'] = $userContacts;
  903. }
  904. if (!empty($checkBody['positions'])) {
  905. $checkBody['total'] = array('priceSum' => $checkTotal);
  906. $checkJSON = json_encode($checkBody);
  907. }
  908. } else {
  909. log_register('DREAMKAS CHECK FISCALAZE PREPARATION ERROR: seems specified selling positions ' . $eachID . ' are not found');
  910. }
  911. }
  912. } else {
  913. log_register('DREAMKAS CHECK FISCALAZE PREPARATION ERROR: empty selling positions parameter passed');
  914. }
  915. return ($checkJSON);
  916. }
  917. /**
  918. * Check fiscalizing routine
  919. *
  920. * @param $preparedCheckDataJSON
  921. * @param int $banksta2RecID
  922. * @param string $repeatedFiscopID
  923. *
  924. */
  925. public function fiscalizeCheck($preparedCheckDataJSON, $banksta2RecID = 0, $repeatedFiscopID = '') {
  926. $tmpMessageStr = '';
  927. $tmpMessageType = '';
  928. if (!empty($preparedCheckDataJSON)) {
  929. // getting [total][price] for log
  930. $tArr = json_decode($preparedCheckDataJSON, true);
  931. $checkTotalPrice = (isset($tArr['total']['priceSum'])) ? $tArr['total']['priceSum'] / 100 : '';
  932. $checkEmail = (isset($tArr['attributes']['email'])) ? ' email: [' . $tArr['attributes']['email'] . '] ' : '';
  933. $checkPhone = (isset($tArr['attributes']['phone'])) ? ' phone: [' . $tArr['attributes']['phone'] . '] ' : '';
  934. $urlString = self::URL_API . 'receipts';
  935. $banksta2LogStr = '';
  936. $curl = curl_init();
  937. curl_setopt($curl, CURLOPT_POST, true);
  938. curl_setopt($curl, CURLOPT_URL, $urlString);
  939. curl_setopt($curl, CURLOPT_HTTPHEADER, $this->basicHTTPHeaders);
  940. curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
  941. curl_setopt($curl, CURLOPT_POSTFIELDS, $preparedCheckDataJSON);
  942. $result = curl_exec($curl);
  943. $httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
  944. curl_close($curl);
  945. $result = json_decode($result, true);
  946. if (substr($httpCode, 0, 1) == '2') {
  947. if (isset($result['id']) and isset($result['createdAt']) and strtolower($result['status']) != 'error') {
  948. $operationDate = date('Y-m-d H:i:s', strtotime($result['createdAt']));
  949. $fiscopReceiptID = (isset($result['data']['receiptId'])) ? $result['data']['receiptId'] : '';
  950. $tQuery = "INSERT INTO `dreamkas_operations` (`operation_id`, `date_create`, `status`, `receipt_id`, `operation_body`, `repeated_fiscop_id`)
  951. VALUES ('" . $result['id'] . "', '" . $operationDate . "', '" . $result['status'] . "', '" . $fiscopReceiptID . "', '" . base64_encode($preparedCheckDataJSON) . "', '" . $repeatedFiscopID . "') ";
  952. nr_query($tQuery);
  953. if (!empty($banksta2RecID)) {
  954. $this->setBS2Relations($banksta2RecID, $result['id'], $fiscopReceiptID);
  955. $banksta2LogStr = ' BANKSTA2 record ID: ' . $banksta2RecID;
  956. }
  957. $tmpMessageType = 'info';
  958. $tmpMessageStr = 'DREAMKAS CHECK FISCALAZING: operation added with ID [' . $result['id'] . ']. Check total sum: [' . $checkTotalPrice . ']. Check contacts: ' . $checkPhone . $checkEmail . $banksta2LogStr;
  959. } else {
  960. $tmpMessageType = 'error';
  961. $tmpMessageStr = 'DREAMKAS CHECK FISCALAZING ERROR. Check total sum: [' . $checkTotalPrice . ']. Check contacts: ' . $checkPhone . $checkEmail . ' SERVER ERROR MESSAGE: ' . $this->errorToString($result);
  962. }
  963. } else {
  964. $tmpMessageType = 'error';
  965. $tmpMessageStr = 'DREAMKAS CHECK FISCALAZING ERROR. Check total sum: [' . $checkTotalPrice . ']. Check contacts: ' . $checkPhone . $checkEmail . ' SERVER ERROR MESSAGE: ' . $this->errorToString($result);
  966. }
  967. } else {
  968. $tmpMessageType = 'error';
  969. $tmpMessageStr = 'DREAMKAS CHECK FISCALAZING ERROR: empty prepared check JSON parameter passed';
  970. }
  971. if (!empty($tmpMessageStr)) {
  972. log_register($tmpMessageStr);
  973. $this->putNotificationData2Cache($tmpMessageStr, $tmpMessageType, __('DREAMKAS INFO'));
  974. }
  975. }
  976. protected function updateFiscalOperationsLocalStorage($fopsData = array()) {
  977. $this->getBS2RelationsUnProcessed();
  978. if (empty($fopsData)) {
  979. $fopsData = $this->getFiscalOperations();
  980. }
  981. $fopsDataLocal = $this->getFiscalOperationsLocal("(`status` != 'SUCCESS' and `status` != 'ERROR') or (`status` = 'SUCCESS' and (`receipt_id` IS NULL or `receipt_id` = ''))");
  982. //$fopsDataLocal = $this->getFiscalOperationsLocal("`status` != 'ERROR'");
  983. $fopsBS2Data = $this->bs2RelationsUnProcFiscOpKey;
  984. if (!empty($fopsData)) {
  985. if (!empty($fopsDataLocal)) {
  986. foreach ($fopsData as $eachFiscOp) {
  987. $fiscopID = $eachFiscOp['id'];
  988. $fiscopStatus = $eachFiscOp['status'];
  989. $fiscopDateFinish = (empty($eachFiscOp['completedAt'])) ? '0000-00-00 00:00:00' : date('Y-m-d H:i:s', strtotime($eachFiscOp['completedAt']));
  990. $fiscopErrorCode = (isset($eachFiscOp['data']['error']['code'])) ? $eachFiscOp['data']['error']['code'] : '';
  991. $fiscopErrorMsg = (isset($eachFiscOp['data']['error']['message'])) ? $eachFiscOp['data']['error']['message'] : '';
  992. $fiscopReceiptID = (isset($eachFiscOp['data']['receiptId'])) ? $eachFiscOp['data']['receiptId'] : '';
  993. if (isset($fopsDataLocal[$fiscopID])) {
  994. $tQuery = "UPDATE `dreamkas_operations` SET
  995. `status` = '" . $fiscopStatus . "',
  996. `date_finish` = '" . $fiscopDateFinish . "',
  997. `error_code` = '" . $fiscopErrorCode . "',
  998. `error_message` = '" . $fiscopErrorMsg . "',
  999. `receipt_id` = '" . $fiscopReceiptID . "'
  1000. WHERE `operation_id` = '" . $fiscopID . "'
  1001. ";
  1002. nr_query($tQuery);
  1003. if (isset($fopsBS2Data[$fiscopID])) {
  1004. $tQuery = "UPDATE `dreamkas_banksta2_relations` SET
  1005. `receipt_id` = '" . $fiscopReceiptID . "'
  1006. WHERE `operation_id` = '" . $fiscopID . "'
  1007. ";
  1008. nr_query($tQuery);
  1009. }
  1010. }
  1011. }
  1012. }
  1013. } else {
  1014. log_register('DREAMKAS updating local fiscal operations status FAILED: server returned empty answer');
  1015. }
  1016. }
  1017. /**
  1018. * Returns a special JS function for controls processing on banksta2 payments processing table
  1019. *
  1020. * @return string
  1021. */
  1022. public function get_BS2FiscalizePaymentCtrlsJS() {
  1023. $js = wf_tag('script', false, '', 'type="text/javascript"');
  1024. $js .= '
  1025. function endisFiscalizingControls(checkCtrlID) {
  1026. var controlDisabled = !$(\'#\'+checkCtrlID).is(\':checked\');
  1027. var controlIndex = checkCtrlID.substring(checkCtrlID.indexOf(\'_\') + 1);
  1028. $(\'#DreamkasCashMachineSelector_\'+controlIndex).prop("disabled", controlDisabled);
  1029. $(\'#DreamkasTaxTypeSelector_\'+controlIndex).prop("disabled", controlDisabled);
  1030. $(\'#DreamkasPaymTypeSelector_\'+controlIndex).prop("disabled", controlDisabled);
  1031. $(\'#DreamkasSellPosSelector_\'+controlIndex).prop("disabled", controlDisabled);
  1032. $(\'#FiscalizePaymHidden_\'+controlIndex).val((controlDisabled) ? 0 : 1);
  1033. }
  1034. ';
  1035. $js .= wf_tag('script', true);
  1036. return ($js);
  1037. }
  1038. /**
  1039. * Pushes notifications data to cash for further usage
  1040. *
  1041. * @param $notyBody
  1042. * @param $notyType
  1043. */
  1044. public function putNotificationData2Cache($notyBody, $notyType = 'info', $notyTitle = 'DREAMKAS') {
  1045. $tKey = wf_delimiter();
  1046. $tArr = array();
  1047. if (!empty($notyBody)) {
  1048. $tArr[$tKey] = array('text' => $notyBody, 'type' => $notyType, 'title' => $notyTitle);
  1049. $this->ubCache->set(self::DREAMKAS_NOTYS_CAHCE_KEY, $tArr, $this->notysCachingTimeout);
  1050. }
  1051. }
  1052. /**
  1053. * Returns an HTML form for payment fiscalizing for integration as addition to payment forms
  1054. *
  1055. * @param $serviceType
  1056. * @param $processingBanksta2
  1057. * @param $bankstaRecID
  1058. * @param $bankstaRecProcessed
  1059. *
  1060. * @return string
  1061. */
  1062. public function web_FiscalizePaymentCtrls($serviceType, $processingBanksta2 = false, $bankstaRecID = '', $bankstaRecProcessed = false) {
  1063. $selectSellPositionID = (isset($this->sellPos2SrvTypeMapping[strtolower($serviceType)]['goods_id'])) ? $this->sellPos2SrvTypeMapping[strtolower($serviceType)]['goods_id'] : '';
  1064. $processedClassMark = ($bankstaRecProcessed ? ' __BankstaRecProcessed ' : '');
  1065. if ($processingBanksta2) {
  1066. $cells = wf_TableCell(__('Fiscalize this payment?') . wf_nbsp() .
  1067. wf_CheckInput('fiscalizepayment_' . $bankstaRecID, '', false, $this->alwaysFiscalizeAll, 'FiscalizeManualPaym_' . $bankstaRecID, $processedClassMark), '', 'row2');
  1068. $cells .= wf_TableCell(__('Choose cash machine') . wf_nbsp() .
  1069. $this->getSelectorWebControl($this->cashMachines4Selector, 'drscashmachines_' . $bankstaRecID, $this->defaultCashMachineID, 'DreamkasCashMachineSelector_' . $bankstaRecID, '__DreamkasCashMachineSelector'), '', 'row2', '', '3');
  1070. $cells .= wf_TableCell(__('Choose tax type') . wf_nbsp() .
  1071. $this->getSelectorWebControl($this->taxTypes, 'drstaxtypes_' . $bankstaRecID, $this->defaultTaxType, 'DreamkasTaxTypeSelector_' . $bankstaRecID, '__DreamkasTaxTypeSelector'), '', 'row2', '', '3');
  1072. $cells .= wf_TableCell(__('Choose payment type') . wf_nbsp() .
  1073. $this->getSelectorWebControl($this->paymentTypes, 'drspaymtypes_' . $bankstaRecID, 'CASHLESS', 'DreamkasPaymTypeSelector_' . $bankstaRecID, '__DreamkasPaymTypeSelector'), '', 'row2', '', '3');
  1074. $cells .= wf_TableCell(__('Choose selling position') . wf_nbsp() .
  1075. $this->getSelectorWebControl($this->sellingPositionsIDsNames, 'drssellpos_' . $bankstaRecID, $selectSellPositionID, 'DreamkasSellPosSelector_' . $bankstaRecID, '__DreamkasSellPosSelector'), '', 'row2', '', '3');
  1076. $row = wf_TableRow($cells);
  1077. $form = $row;
  1078. $form .= wf_HiddenInput('dofiscalizepayment_' . $bankstaRecID, '0', 'FiscalizePaymHidden_' . $bankstaRecID);
  1079. $form .= wf_tag('script', false, '', 'type="text/javascript"');
  1080. $form .= '
  1081. $(document).ready(function() {
  1082. endisFiscalizingControls(\'FiscalizeManualPaym_' . $bankstaRecID . '\');
  1083. });
  1084. $(\'#FiscalizeManualPaym_' . $bankstaRecID . '\').change(function() {
  1085. endisFiscalizingControls(\'FiscalizeManualPaym_' . $bankstaRecID . '\');
  1086. });
  1087. ';
  1088. // be sure to call get_BS2FiscalizePaymentCtrlsJS() after banksta2 payments processing table is assembled
  1089. $form .= wf_tag('script', true);
  1090. } else {
  1091. $cells = wf_TableCell(__('Fiscalize this payment?'), '', 'row2');
  1092. $cells .= wf_TableCell(wf_CheckInput('fiscalizepayment', '', false, $this->alwaysFiscalizeAll, 'FiscalizeManualPaym'), '', 'row3');
  1093. $rows = wf_TableRow($cells);
  1094. $cells = wf_TableCell(__('Choose cash machine'), '', 'row2');
  1095. $cells .= wf_TableCell($this->getSelectorWebControl($this->cashMachines4Selector, 'drscashmachines', $this->defaultCashMachineID, 'DreamkasCashMachineSelector', '__DreamkasCashMachineSelector'), '', 'row3');
  1096. $rows .= wf_TableRow($cells);
  1097. $cells = wf_TableCell(__('Choose tax type'), '', 'row2');
  1098. $cells .= wf_TableCell($this->getSelectorWebControl($this->taxTypes, 'drstaxtypes', $this->defaultTaxType, 'DreamkasTaxTypeSelector', '__DreamkasTaxTypeSelector'), '', 'row3');
  1099. $rows .= wf_TableRow($cells);
  1100. $cells = wf_TableCell(__('Choose payment type'), '', 'row2');
  1101. $cells .= wf_TableCell($this->getSelectorWebControl($this->paymentTypes, 'drspaymtypes', 'CASH', 'DreamkasPaymTypeSelector', '__DreamkasPaymTypeSelector'), '', 'row3');
  1102. $rows .= wf_TableRow($cells);
  1103. $cells = wf_TableCell(__('Choose selling position'), '', 'row2');
  1104. $cells .= wf_TableCell($this->getSelectorWebControl($this->sellingPositionsIDsNames, 'drssellpos', $selectSellPositionID, 'DreamkasSellPosSelector', '__DreamkasSellPosSelector'), '', 'row3');
  1105. $rows .= wf_TableRow($cells);
  1106. $table = wf_TableBody($rows, '100%', 0, '');
  1107. $form = $table;
  1108. $form .= wf_HiddenInput('dofiscalizepayment', '0', 'FiscalizeManualPaymHidden');
  1109. $form .= wf_tag('script', false, '', 'type="text/javascript"');
  1110. $form .= '
  1111. $(document).ready(function() {
  1112. endisFiscalizingControls();
  1113. });
  1114. $(\'#FiscalizeManualPaym\').change(function() {
  1115. endisFiscalizingControls();
  1116. });
  1117. function endisFiscalizingControls() {
  1118. var controlDisabled = !$(\'#FiscalizeManualPaym\').is(\':checked\');
  1119. $(\'#DreamkasCashMachineSelector\').prop("disabled", controlDisabled);
  1120. $(\'#DreamkasTaxTypeSelector\').prop("disabled", controlDisabled);
  1121. $(\'#DreamkasPaymTypeSelector\').prop("disabled", controlDisabled);
  1122. $(\'#DreamkasSellPosSelector\').prop("disabled", controlDisabled);
  1123. $(\'#FiscalizeManualPaymHidden\').val((controlDisabled) ? 0 : 1);
  1124. }
  1125. ';
  1126. $form .= wf_tag('script', true);
  1127. }
  1128. return ($form);
  1129. }
  1130. /**
  1131. * Returns table row with payment fiscal data
  1132. *
  1133. * @param $bs2RecID
  1134. *
  1135. * @return string
  1136. */
  1137. public function web_ReceiptDetailsTableRow($bs2RecID) {
  1138. // $row = wf_TableRow('');
  1139. $row = '';
  1140. if (empty($this->bs2RelationsProcessed)) {
  1141. $this->getBS2RelationsProcessed();
  1142. }
  1143. if (isset($this->bs2RelationsProcessed[$bs2RecID]) and ! empty($this->bs2RelationsProcessed[$bs2RecID]['receipt_id'])) {
  1144. $lnkID = wf_InputId();
  1145. $ajaxInfoParams = array('showdetailedrcpt' => $this->bs2RelationsProcessed[$bs2RecID]['receipt_id']);
  1146. $actions = wf_Link('#', wf_img('skins/icon_search_small.gif', __('Show details'), 'vertical-align: middle'), false, '', ' id="' . $lnkID . '" ');
  1147. $actions .= wf_JSAjaxModalOpener(self::URL_ME, $ajaxInfoParams, $lnkID, true);
  1148. $cells = wf_TableCell(__('Fiscal operation ID') . ':' . wf_nbsp(2) . $this->bs2RelationsProcessed[$bs2RecID]['operation_id'], '', '', 'style="border: solid #008a77; border-width: 1px 0 1px 1px; padding: 4px;"', '5');
  1149. $cells .= wf_TableCell(__('Check ID') . ':' . wf_nbsp(2) . $this->bs2RelationsProcessed[$bs2RecID]['receipt_id'] . wf_nbsp(4) . $actions, '', '', 'style="border: solid #008a77; border-width: 1px 1px 1px 0; padding: 4px;"', '5');
  1150. $row = wf_TableRow($cells);
  1151. }
  1152. return ($row);
  1153. }
  1154. public function web_FiscalOperationDetailsTableRow($bs2RecID) {
  1155. $row = '';
  1156. if (empty($this->bs2RelationsUnProcessed)) {
  1157. $this->getBS2RelationsUnProcessed();
  1158. }
  1159. if (isset($this->bs2RelationsUnProcessed[$bs2RecID])) {
  1160. $fiscopID = $this->bs2RelationsUnProcessed[$bs2RecID]['operation_id'];
  1161. $fiscopData = $this->getFiscalOperationLocalData($fiscopID);
  1162. $fiscopStatus = $fiscopData['status'];
  1163. $fiscopDateCreate = $fiscopData['date_create'];
  1164. $cells = wf_TableCell(wf_tag('b', false) . '#' . $bs2RecID . ':' . wf_tag('b', true) . wf_nbsp(4)
  1165. . __('Fiscal operation ID') . ':' . wf_nbsp(2) . $fiscopID
  1166. . wf_nbsp(8) . __('Creation date') . ':' . wf_nbsp(2) . $fiscopDateCreate
  1167. . wf_nbsp(8) . __('Current status') . ':' . wf_nbsp(2) . $fiscopStatus, '', '', 'style="border: solid #b84c04; border-width: 1px; padding: 4px;"', '11');
  1168. $row = wf_TableRow($cells);
  1169. }
  1170. return ($row);
  1171. }
  1172. /**
  1173. * Returns main buttons controls for Dreamkas
  1174. *
  1175. * @return string
  1176. */
  1177. public function web_MainButtonsControls() {
  1178. $cacheLnkID = wf_InputId();
  1179. $controls = wf_Link(self::URL_DREAMKAS_RECEIPTS, wf_img('skins/menuicons/receipt_small_compl.png') . wf_nbsp() . __('Issued checks'), false, 'ubButton') . wf_nbsp(2);
  1180. $controls .= wf_Link(self::URL_DREAMKAS_OPERATIONS, wf_img('skins/icon_note.gif') . wf_nbsp() . __('Fiscal operations'), false, 'ubButton') . wf_nbsp(2);
  1181. $controls .= wf_Link(self::URL_DREAMKAS_GOODS, wf_img_sized('skins/shopping_cart.png', '', '16', '16') . wf_nbsp() . __('Selling positions'), false, 'ubButton') . wf_nbsp(2);
  1182. //$controls.= wf_delimiter(0);
  1183. $controls .= wf_Link(self::URL_DREAMKAS_CASHIERS, wf_img_sized('skins/cashier.png', '', '16', '16') . wf_nbsp() . __('Cashiers'), false, 'ubButton') . wf_nbsp(2);
  1184. $controls .= wf_Link(self::URL_DREAMKAS_CASH_MACHINES, wf_img_sized('skins/cash_machine.png', '', '16', '16') . wf_nbsp() . __('Cash machines'), false, 'ubButton');
  1185. $controls .= wf_delimiter();
  1186. $controls .= wf_Link(self::URL_DREAMKAS_WEBHOOKS, wf_img_sized('skins/ymaps/globe.png', '', '16', '16') . wf_nbsp() . __('Webhooks'), false, 'ubButton');
  1187. $controls .= wf_Link('#', wf_img('skins/refresh.gif') . ' ' . __('Refresh cache data'), false, 'ubButton', 'id="' . $cacheLnkID . '"');
  1188. $controls .= wf_JSAjaxModalOpener(self::URL_ME, array('dreamkasforcecacheupdate' => 'true'), $cacheLnkID, true);
  1189. return ($controls);
  1190. }
  1191. /**
  1192. * Returns a companion to fiscal operation form HTML form for fiscal operation data filtering
  1193. *
  1194. * @return string
  1195. */
  1196. public function web_FiscalOperationsFilter() {
  1197. $formID = wf_InputId();
  1198. $ajaxUrlStr = self::URL_ME . '&foperationslistajax=true';
  1199. $jqdtId = 'jqdt_' . md5($ajaxUrlStr);
  1200. $dateFrom = (ubRouting::checkGet('fopsdatefrom', false) ? ubRouting::get('fopsdatefrom') : date('Y-m-d', strtotime(curdate() . "-1 day")));
  1201. $dateTo = (ubRouting::checkGet('fopsdateto', false) ? ubRouting::get('fopsdateto') : curdate());
  1202. // filter controls for dates
  1203. $inputs = wf_DatePickerPreset('fopsdatefrom', $dateFrom);
  1204. $inputs .= __('Creation date from') . wf_nbsp(3);
  1205. $inputs .= wf_DatePickerPreset('fopsdateto', $dateTo);
  1206. $inputs .= __('Creation date to') . wf_nbsp(4);
  1207. $inputs .= wf_SubmitClassed(true, 'ubButton', '', __('Show'));
  1208. $inputs .= wf_tag('script', false, '', 'type="text/javascript"');
  1209. $inputs .= '
  1210. $(\'#' . $formID . '\').submit(function(evt) {
  1211. evt.preventDefault();
  1212. var FrmData = $(\'#' . $formID . '\').serialize();
  1213. $(\'#' . $jqdtId . '\').DataTable().ajax.url(\'' . $ajaxUrlStr . '\' + \'&\' + FrmData).load();
  1214. $(\'#' . $jqdtId . '\').DataTable().ajax.url(\'' . $ajaxUrlStr . '\');
  1215. });
  1216. ';
  1217. $inputs .= wf_tag('script', true);
  1218. $form = wf_Form('', 'POST', $inputs, 'glamour', '', $formID) . wf_delimiter(0);
  1219. return ($form);
  1220. }
  1221. /**
  1222. * Returns a companion to receipts form HTML form for receipts data filtering
  1223. *
  1224. * @return string
  1225. */
  1226. public function web_ReceiptsFilter() {
  1227. $formID = wf_InputId();
  1228. $ajaxUrlStr = self::URL_ME . '&receiptslistajax=true';
  1229. $jqdtId = 'jqdt_' . md5($ajaxUrlStr);
  1230. // filter controls for dates, cash ids and so on
  1231. $inputs = wf_DatePicker('rcptdatefrom');
  1232. $inputs .= __('Date from') . wf_nbsp(3);
  1233. $inputs .= wf_DatePicker('rcptdateto');
  1234. $inputs .= __('Date to') . wf_nbsp(4);
  1235. $inputs .= wf_TextInput('rcptmaxcount', __('Number of checks to get (1000 max)'), '1000', false, '4', 'digits');
  1236. $inputs .= wf_nbsp(3);
  1237. $inputs .= wf_TextInput('rcptdeviceid', __('Cash machine ID'), '', false, '4', 'digits');
  1238. $inputs .= wf_nbsp(3);
  1239. $inputs .= wf_SubmitClassed(true, 'ubButton', '', __('Show'));
  1240. $inputs .= wf_tag('script', false, '', 'type="text/javascript"');
  1241. $inputs .= '
  1242. $(\'#' . $formID . '\').submit(function(evt) {
  1243. evt.preventDefault();
  1244. var FrmData = $(\'#' . $formID . '\').serialize();
  1245. $(\'#' . $jqdtId . '\').DataTable().ajax.url(\'' . $ajaxUrlStr . '\' + \'&\' + FrmData).load();
  1246. $(\'#' . $jqdtId . '\').DataTable().ajax.url(\'' . $ajaxUrlStr . '\');
  1247. });
  1248. ';
  1249. $inputs .= wf_tag('script', true);
  1250. $form = wf_Form('', 'POST', $inputs, 'glamour', '', $formID) . wf_delimiter(0);
  1251. return ($form);
  1252. }
  1253. public function web_WebhooksForm() {
  1254. $lnkId = wf_InputId();
  1255. $addServiceJS = wf_tag('script', false, '', 'type="text/javascript"');
  1256. $addServiceJS .= wf_JSAjaxModalOpener(self::URL_ME, array('whcreate' => 'true'), $lnkId, false, 'POST');
  1257. $addServiceJS .= wf_tag('script', true);
  1258. show_window(__('Webhooks'), wf_Link('#', web_add_icon() . ' ' .
  1259. __('Add webhook'), false, 'ubButton', 'id="' . $lnkId . '"') .
  1260. wf_delimiter() . $addServiceJS . $this->renderWebhooksJQDT()
  1261. );
  1262. }
  1263. /**
  1264. * JSON for cashiers JQDT
  1265. */
  1266. public function renderCashiersListJSON() {
  1267. $cashiersData = (isset($this->dataCahched['cashiers'])) ? $this->dataCahched['cashiers'] : array();
  1268. $json = new wf_JqDtHelper();
  1269. if (!empty($cashiersData)) {
  1270. $data = array();
  1271. foreach ($cashiersData as $eachCashier) {
  1272. $data[] = $eachCashier['tabNumber'];
  1273. $data[] = $eachCashier['name'];
  1274. $data[] = $eachCashier['inn'];
  1275. $data[] = empty($eachCashier['deviceId']) ? '-' : $eachCashier['deviceId'];
  1276. $json->addRow($data);
  1277. unset($data);
  1278. }
  1279. }
  1280. $json->getJson();
  1281. }
  1282. /**
  1283. * JQDT for cashiers list form
  1284. *
  1285. * @return string
  1286. */
  1287. public function renderCashiersJQDT() {
  1288. $ajaxUrlStr = self::URL_ME . '&cashiersslistajax=true';
  1289. $columns = array();
  1290. $opts = '"order": [[ 0, "desc" ]],
  1291. "columnDefs": [ {"targets": "_all", "className": "dt-center"} ]';
  1292. $columns[] = __('Tab number');
  1293. $columns[] = __('Name');
  1294. $columns[] = __('INN');
  1295. $columns[] = __('Cash machine ID');
  1296. return (wf_JqDtLoader($columns, $ajaxUrlStr, false, __('Cashiers'), 100, $opts));
  1297. }
  1298. /**
  1299. * JSON for cash machines JQDT
  1300. */
  1301. public function renderCashMachinesListJSON() {
  1302. $cashMachinesData = (isset($this->dataCahched['cashmachines'])) ? $this->dataCahched['cashmachines'] : array();
  1303. $json = new wf_JqDtHelper();
  1304. if (!empty($cashMachinesData)) {
  1305. $data = array();
  1306. foreach ($cashMachinesData as $eachCM) {
  1307. $data[] = $eachCM['id'];
  1308. $data[] = ($eachCM['isOnline']) ? web_green_led() : web_red_led();
  1309. $data[] = $eachCM['name'];
  1310. $data[] = $eachCM['modelCode'];
  1311. $data[] = $eachCM['modelName'];
  1312. $data[] = date('Y-m-d H:i:s', strtotime($eachCM['kktExpireDate']));
  1313. $lnkID = wf_InputId();
  1314. $ajaxInfoParams = array('showdetailedCM' => $eachCM['id']);
  1315. $actions = wf_Link('#', wf_img('skins/icon_search_small.gif', __('Show details')), false, '', ' id="' . $lnkID . '" ');
  1316. $actions .= wf_JSAjaxModalOpener(self::URL_ME, $ajaxInfoParams, $lnkID, true);
  1317. $data[] = $actions;
  1318. $json->addRow($data);
  1319. unset($data);
  1320. }
  1321. }
  1322. $json->getJson();
  1323. }
  1324. /**
  1325. * JQDT for cash machines list form
  1326. *
  1327. * @return string
  1328. */
  1329. public function renderCashMachinesJQDT() {
  1330. $ajaxUrlStr = self::URL_ME . '&cashmachineslistajax=true';
  1331. $columns = array();
  1332. $opts = '"order": [[ 0, "desc" ]],
  1333. "columnDefs": [ {"targets": "_all", "className": "dt-center"} ]';
  1334. $columns[] = __('Cash machine ID');
  1335. $columns[] = __('Online');
  1336. $columns[] = __('Cash machine name');
  1337. $columns[] = __('Model code');
  1338. $columns[] = __('Model name');
  1339. $columns[] = __('Registration date expires');
  1340. $columns[] = __('Actions');
  1341. return (wf_JqDtLoader($columns, $ajaxUrlStr, false, __('Cash machines'), 100, $opts));
  1342. }
  1343. /**
  1344. * JSON for selling positions JQDT
  1345. */
  1346. public function renderSellPositionsListJSON() {
  1347. $sellingPositions = (isset($this->dataCahched['sellingpositions'])) ? $this->dataCahched['sellingpositions'] : array();
  1348. $json = new wf_JqDtHelper();
  1349. if (!empty($sellingPositions)) {
  1350. $ajaxURLStr = self::URL_ME . '&goodslistajax=true';
  1351. $JQDTId = 'jqdt_' . md5($ajaxURLStr);
  1352. $data = array();
  1353. foreach ($sellingPositions as $eachItem) {
  1354. $sellPosMapped2Srv = $this->checkSellPosIsMapped2SrvType($eachItem['id']);
  1355. $disableLink = (!empty($sellPosMapped2Srv)) ? 'style="opacity: 0.35; pointer-events: none"' : '';
  1356. $enableDelLnk = (empty($sellPosMapped2Srv)) ? 'style="opacity: 0.35; pointer-events: none"' : '';
  1357. $data[] = empty($eachItem['category']) ? '-' : $eachItem['category'];
  1358. $data[] = $eachItem['name'];
  1359. $data[] = $eachItem['type'];
  1360. $data[] = $eachItem['quantity'];
  1361. $data[] = $eachItem['price'];
  1362. $data[] = (isset($eachItem['barcodes'][0])) ? $eachItem['barcodes'][0] : '';
  1363. $data[] = (isset($eachItem['vendorCodes'][0])) ? $eachItem['vendorCodes'][0] : '';
  1364. $data[] = $eachItem['tax'];
  1365. $data[] = date('Y-m-d H:i:s', strtotime($eachItem['createdAt']));
  1366. $data[] = date('Y-m-d H:i:s', strtotime($eachItem['updatedAt']));
  1367. $data[] = ($sellPosMapped2Srv == 'internet') ? __('Internet') : (($sellPosMapped2Srv == 'ukv') ? __('UKV') : '');
  1368. $infoLnkID = wf_InputId();
  1369. $setInetLnkID = wf_InputId();
  1370. $setUKVLnkID = wf_InputId();
  1371. $delMappingLnkID = wf_InputId();
  1372. $ajaxInfoParams = array('showdetailedGoods' => $eachItem['id']);
  1373. $ajaxDelMappingParams = array('delselpossrvmapping' => 'true', 'servicetype' => $sellPosMapped2Srv);
  1374. $ajaxSetMappingParams = array(
  1375. 'goodsid' => $eachItem['id'],
  1376. 'goodsName' => $eachItem['name'],
  1377. 'goodsType' => $eachItem['type'],
  1378. 'goodsPrice' => $eachItem['price'],
  1379. 'goodsTax' => $eachItem['tax'],
  1380. 'goodsVendorCode' => (isset($eachItem['vendorCodes'][0])) ? $eachItem['vendorCodes'][0] : ''
  1381. );
  1382. $actions = wf_Link('#', wf_img('skins/icon_search_small.gif', __('Show details')), false, '', ' id="' . $infoLnkID . '" ');
  1383. $actions .= wf_Link('#', wf_img('skins/ymaps/globe.png', __('Link to Internet service')), false, '', ' id="' . $setInetLnkID . '" ' . $disableLink);
  1384. $actions .= wf_Link('#', wf_img('skins/menuicons/tv.png', __('Link to UKV service')), false, '', ' id="' . $setUKVLnkID . '" ' . $disableLink);
  1385. $actions .= wf_Link('#', web_delete_icon(__('Delete mapping')), false, '', ' id="' . $delMappingLnkID . '" ' . $enableDelLnk);
  1386. $actions .= wf_tag('script', false, '', 'type="text/javascript"');
  1387. $actions .= wf_JSAjaxModalOpener(self::URL_ME, $ajaxInfoParams, $infoLnkID);
  1388. $actions .= wf_JSAjaxModalOpener(self::URL_ME . '&setselpossrvmapping=internet', $ajaxSetMappingParams, $setInetLnkID, false, 'GET', 'click', false, false, $JQDTId);
  1389. $actions .= wf_JSAjaxModalOpener(self::URL_ME . '&setselpossrvmapping=ukv', $ajaxSetMappingParams, $setUKVLnkID, false, 'GET', 'click', false, false, $JQDTId);
  1390. $actions .= wf_JSAjaxModalOpener(self::URL_ME, $ajaxDelMappingParams, $delMappingLnkID, false, 'GET', 'click', false, false, $JQDTId);
  1391. $actions .= wf_tag('script', true);
  1392. $data[] = $actions;
  1393. $json->addRow($data);
  1394. unset($data);
  1395. }
  1396. }
  1397. $json->getJson();
  1398. }
  1399. /**
  1400. * JQDT for selling positions list form
  1401. *
  1402. * @return string
  1403. */
  1404. public function renderSellPositionsJQDT() {
  1405. $ajaxURLStr = self::URL_ME . '&goodslistajax=true';
  1406. $columns = array();
  1407. $opts = '"order": [[ 1, "asc" ]],
  1408. "columnDefs": [ {"targets": [2, 3, 4, 5, 6, 7, 8, 9, 10, 11], "className": "dt-center"},
  1409. {"targets": [11], "width": "70px"}
  1410. ]';
  1411. $columns[] = __('Category');
  1412. $columns[] = __('Selling position');
  1413. $columns[] = __('Type');
  1414. $columns[] = __('Quantity');
  1415. $columns[] = __('Price');
  1416. $columns[] = __('Barcode');
  1417. $columns[] = __('Vendor code');
  1418. $columns[] = __('Tax type');
  1419. $columns[] = __('Creation date');
  1420. $columns[] = __('Last edit date');
  1421. $columns[] = __('Mapped to service');
  1422. $columns[] = __('Actions');
  1423. return (wf_JqDtLoader($columns, $ajaxURLStr, false, __('Selling positions'), 100, $opts));
  1424. }
  1425. /** OLD
  1426. * JSON for fiscal operations JQDT
  1427. */
  1428. /* public function renderFiscalOperationsListJSON_old($dateFrom = '', $dateTo = '') {
  1429. $fopsData = $this->getFiscalOperations($dateFrom, $dateTo);
  1430. $fopsDataLocal = $this->getFiscalOperationsLocal();
  1431. $json = new wf_JqDtHelper();
  1432. if (!empty($fopsData)) {
  1433. $this->updateFiscalOperationsLocalStorage($fopsData);
  1434. $fopsData = $this->getFiscalOperationsLocal();
  1435. $ajaxURLStr = self::URL_ME . '&foperationslistajax=true';
  1436. $JQDTId = 'jqdt_' . md5($ajaxURLStr);
  1437. $data = array();
  1438. //$fopsData = $fopsData['data'];
  1439. foreach ($fopsData as $eachFOperation) {
  1440. $fiscopID = $eachFOperation['id'];
  1441. $data[] = $fiscopID;
  1442. $data[] = date('Y-m-d H:i:s', strtotime($eachFOperation['createdAt']));
  1443. $data[] = date('Y-m-d H:i:s', strtotime($eachFOperation['completedAt']));
  1444. $data[] = $eachFOperation['status'];
  1445. if (isset($eachFOperation['data']['error'])) {
  1446. $data[] = $eachFOperation['data']['error']['code'];
  1447. $data[] = $eachFOperation['data']['error']['message'];
  1448. } else {
  1449. $data[] = '';
  1450. $data[] = '';
  1451. }
  1452. if (isset($eachFOperation['data']['receiptId'])) {
  1453. $data[] = $eachFOperation['data']['receiptId'];
  1454. } else {
  1455. $data[] = '';
  1456. }
  1457. if (isset($fopsDataLocal[$fiscopID])) {
  1458. $data[] = $fopsDataLocal[$fiscopID]['repeat_count'];
  1459. } else {
  1460. $data[] = '';
  1461. }
  1462. $disableLink = (strtolower($eachFOperation['status']) == 'error') ? '' : 'style="opacity: 0.35; pointer-events: none"';
  1463. $infoLnkID = wf_InputId();
  1464. $repeatOpLnkID = wf_InputId();
  1465. $ajaxInfoParams = array('showdetailedFiscOp' => $fiscopID);
  1466. $ajaxRepeatOpParams = array('repeatFiscOp' => $fiscopID);
  1467. $actions = wf_Link('#', wf_img('skins/icon_search_small.gif', __('Show details')), false, '', ' id="' . $infoLnkID . '" ');
  1468. $actions .= wf_Link('#', wf_img('skins/refresh.gif', __('Repeat this operation')), false, '', ' id="' . $repeatOpLnkID . '" ' . $disableLink);
  1469. $actions .= wf_tag('script', false, '', 'type="text/javascript"');
  1470. $actions .= wf_JSAjaxModalOpener(self::URL_ME, $ajaxInfoParams, $infoLnkID);
  1471. //$actions .= wf_JSAjaxModalOpener(self::URL_ME, $ajaxRepeatOpParams, $repeatOpLnkID, false, 'GET', 'click', false, false, $JQDTId);
  1472. $actions .= wf_JSAjaxModalOpener(self::URL_ME, $ajaxRepeatOpParams, $repeatOpLnkID);
  1473. $actions .= wf_tag('script', true);
  1474. $data[] = $actions;
  1475. $json->addRow($data);
  1476. unset($data);
  1477. }
  1478. }
  1479. $json->getJson();
  1480. } */
  1481. /**
  1482. * JSON for fiscal operations JQDT
  1483. *
  1484. * @param string $dateFrom
  1485. * @param string $dateTo
  1486. */
  1487. public function renderFiscalOperationsListJSON($dateFrom = '', $dateTo = '') {
  1488. $json = new wf_JqDtHelper();
  1489. $whereStr = '';
  1490. if (!empty($dateFrom) and ! empty($dateTo)) {
  1491. $whereStr = " `date_create` BETWEEN '" . $dateFrom . " 00:00:00' AND '" . $dateTo . " 23:59:59' ";
  1492. } elseif (!empty($dateFrom) and empty($dateTo)) {
  1493. $whereStr = " `date_create` >= '" . $dateFrom . " 00:00:00' ";
  1494. } elseif (empty($dateFrom) and ! empty($dateTo)) {
  1495. $whereStr = " `date_create` <= '" . $dateTo . " 23:59:59' ";
  1496. }
  1497. $fopsDataExt = $this->getFiscalOperations($dateFrom, $dateTo);
  1498. if (!empty($fopsDataExt)) {
  1499. $this->updateFiscalOperationsLocalStorage($fopsDataExt);
  1500. }
  1501. $fopsData = $this->getFiscalOperationsLocal($whereStr);
  1502. if (!empty($fopsData)) {
  1503. $ajaxURLStr = self::URL_ME . '&foperationslistajax=true';
  1504. $JQDTId = 'jqdt_' . md5($ajaxURLStr);
  1505. $data = array();
  1506. foreach ($fopsData as $eachFOperation) {
  1507. $fiscopID = $eachFOperation['operation_id'];
  1508. $data[] = $fiscopID;
  1509. $data[] = $eachFOperation['date_create'];
  1510. $data[] = $eachFOperation['date_finish'];
  1511. $data[] = $eachFOperation['status'];
  1512. $data[] = $eachFOperation['error_code'];
  1513. $data[] = $eachFOperation['error_message'];
  1514. $data[] = $eachFOperation['receipt_id'];
  1515. $data[] = $eachFOperation['repeated_fiscop_id'];
  1516. $data[] = $eachFOperation['repeat_count'];
  1517. $disableLink = (strtolower($eachFOperation['status']) == 'error') ? '' : 'style="opacity: 0.35; pointer-events: none"';
  1518. $infoLnkID = wf_InputId();
  1519. $repeatOpLnkID = wf_InputId();
  1520. $ajaxInfoParams = array('showdetailedFiscOp' => $fiscopID);
  1521. $ajaxRepeatOpParams = array('repeatFiscOp' => $fiscopID);
  1522. $actions = wf_Link('#', wf_img('skins/icon_search_small.gif', __('Show details')), false, '', ' id="' . $infoLnkID . '" ');
  1523. $actions .= wf_Link('#', wf_img('skins/refresh.gif', __('Repeat this operation')), false, '', ' id="' . $repeatOpLnkID . '" ' . $disableLink);
  1524. $actions .= wf_tag('script', false, '', 'type="text/javascript"');
  1525. $actions .= wf_JSAjaxModalOpener(self::URL_ME, $ajaxInfoParams, $infoLnkID);
  1526. //$actions .= wf_JSAjaxModalOpener(self::URL_ME, $ajaxRepeatOpParams, $repeatOpLnkID, false, 'GET', 'click', false, false, $JQDTId);
  1527. $actions .= wf_JSAjaxModalOpener(self::URL_ME, $ajaxRepeatOpParams, $repeatOpLnkID);
  1528. $actions .= wf_tag('script', true);
  1529. $data[] = $actions;
  1530. $json->addRow($data);
  1531. unset($data);
  1532. }
  1533. }
  1534. $json->getJson();
  1535. }
  1536. /**
  1537. * JQDT for fiscal operations list form
  1538. *
  1539. * @return string
  1540. */
  1541. public function renderFiscalOperationsJQDT() {
  1542. $ajaxURLStr = self::URL_ME . '&foperationslistajax=true';
  1543. $columns = array();
  1544. $opts = '"order": [[ 1, "desc" ]],
  1545. "columnDefs": [ {"targets": "_all", "className": "dt-center"},
  1546. {"targets": [1, 2], "width": "80px"} ]';
  1547. $columns[] = __('Operation ID');
  1548. $columns[] = __('Creation date');
  1549. $columns[] = __('Completion date');
  1550. $columns[] = __('Status');
  1551. $columns[] = __('Error code');
  1552. $columns[] = __('Error message');
  1553. $columns[] = __('Check ID');
  1554. $columns[] = __('Repeated operation ID');
  1555. $columns[] = __('Repeated tries count');
  1556. $columns[] = __('Actions');
  1557. return (wf_JqDtLoader($columns, $ajaxURLStr, false, __('Fiscal operations'), 100, $opts));
  1558. }
  1559. /**
  1560. * JSON for receipts JQDT
  1561. */
  1562. public function renderReceiptsListJSON($dateFrom = '', $dateTo = '', $cashDeviceID = '', $limit = 1000) {
  1563. $receiptsData = $this->getReceipts($dateFrom, $dateTo, $cashDeviceID, $limit);
  1564. $json = new wf_JqDtHelper();
  1565. if (!empty($receiptsData)) {
  1566. $data = array();
  1567. $receiptsData = $receiptsData['data'];
  1568. foreach ($receiptsData as $eachReceipt) {
  1569. $i = 0;
  1570. $receiptPositions = $eachReceipt['positions'];
  1571. $receiptPayments = $eachReceipt['payments'];
  1572. $receiptPositionsLen = count($receiptPositions);
  1573. $receiptPaymentsLen = count($receiptPayments);
  1574. $data[] = $eachReceipt['deviceId'];
  1575. $data[] = $eachReceipt['shopId'];
  1576. $data[] = $eachReceipt['localDate'];
  1577. $data[] = $eachReceipt['shiftId'];
  1578. $data[] = $eachReceipt['cashier']['name'];
  1579. $data[] = $eachReceipt['number'];
  1580. foreach ($receiptPositions as $postion) {
  1581. $i++;
  1582. if ($receiptPositionsLen == 1 or $receiptPositionsLen == $i) {
  1583. $tmpBR = '';
  1584. } else {
  1585. $tmpBR = wf_delimiter(1);
  1586. }
  1587. $data[] = $postion['name'] . wf_nbsp(2) . '-' . wf_nbsp(2) . ($postion['price'] / 100) . $tmpBR;
  1588. }
  1589. $i = 0;
  1590. foreach ($receiptPayments as $payment) {
  1591. $i++;
  1592. if ($receiptPaymentsLen == 1 or $receiptPaymentsLen == $i) {
  1593. $tmpBR = '';
  1594. } else {
  1595. $tmpBR = wf_delimiter(1);
  1596. }
  1597. $data[] = $payment['type'] . wf_nbsp(2) . '-' . wf_nbsp(2) . ($payment['amount'] / 100) . $tmpBR;
  1598. }
  1599. $data[] = $eachReceipt['amount'] / 100;
  1600. //$data[] = wf_Link(self::URL_DREAMKAS_RECEIPT_DETAILS . $eachReceipt['id'], wf_img('skins/icon_search_small.gif', __('Show details')), false, '');
  1601. $lnkID = wf_InputId();
  1602. $ajaxInfoParams = array('showdetailedrcpt' => $eachReceipt['id']);
  1603. $actions = wf_Link('#', wf_img('skins/icon_search_small.gif', __('Show details')), false, '', ' id="' . $lnkID . '" ');
  1604. $actions .= wf_JSAjaxModalOpener(self::URL_ME, $ajaxInfoParams, $lnkID, true);
  1605. $data[] = $actions;
  1606. $json->addRow($data);
  1607. unset($data);
  1608. }
  1609. }
  1610. $json->getJson();
  1611. }
  1612. /**
  1613. * JQDT for receipts list form
  1614. *
  1615. * @return string
  1616. */
  1617. public function renderReceiptsJQDT() {
  1618. $ajaxURLStr = self::URL_ME . '&receiptslistajax=true';
  1619. $columns = array();
  1620. $opts = '"order": [[ 2, "desc" ]],
  1621. "columnDefs": [ {"targets": "_all", "className": "dt-center"} ]';
  1622. $columns[] = __('Cash machine ID');
  1623. $columns[] = __('Seller ID');
  1624. $columns[] = __('Operation date');
  1625. $columns[] = __('Shift ID');
  1626. $columns[] = __('Cashier');
  1627. $columns[] = __('Check in shift');
  1628. $columns[] = __('Check positions and prices');
  1629. $columns[] = __('Check payments details');
  1630. $columns[] = __('Check total');
  1631. $columns[] = __('Actions');
  1632. return (wf_JqDtLoader($columns, $ajaxURLStr, false, __('Checks'), 100, $opts));
  1633. }
  1634. public function renderWebhooksListJSON() {
  1635. $webhooksData = $this->getWebHooks();
  1636. $json = new wf_JqDtHelper();
  1637. if (!empty($webhooksData)) {
  1638. $ajaxURLStr = self::URL_ME . '&webhookslistajax=true';
  1639. $JQDTId = 'jqdt_' . md5($ajaxURLStr);
  1640. $data = array();
  1641. foreach ($webhooksData as $eachWebhook) {
  1642. $webhookOpts = $eachWebhook['types'];
  1643. $data[] = $eachWebhook['url'];
  1644. $data[] = ($eachWebhook['isActive']) ? web_green_led() : web_red_led();
  1645. foreach ($webhookOpts as $webhookOpt => $eachValue) {
  1646. $data[] = ($eachValue) ? web_green_led() : web_red_led();
  1647. }
  1648. $lnkID = wf_InputId();
  1649. $ajaxInfoParams = array('whedit' => true, 'whid' => $eachWebhook['id']);
  1650. $actions = wf_JSAlert('#', web_delete_icon(), 'Removing this may lead to irreparable results', 'deleteWebhook(\'' . $eachWebhook['id'] . '\', \'' . self::URL_ME . '\', \'delWebhook\', \'' . wf_InputId() . '\')') . wf_nbsp();
  1651. $actions .= wf_Link('#', web_edit_icon(), false, '', 'id="' . $lnkID . '"') . wf_nbsp();
  1652. $actions .= wf_JSAjaxModalOpener(self::URL_ME, $ajaxInfoParams, $lnkID, true, 'POST', 'click', false, false, $JQDTId);
  1653. $data[] = $actions;
  1654. $json->addRow($data);
  1655. unset($data);
  1656. }
  1657. }
  1658. $json->getJson();
  1659. }
  1660. public function renderWebhooksJQDT() {
  1661. $ajaxURLStr = self::URL_ME . '&webhookslistajax=true';
  1662. $JQDTId = 'jqdt_' . md5($ajaxURLStr);
  1663. $errorModalWindowId = wf_InputId();
  1664. $columns = array();
  1665. $opts = '"order": [[ 0, "desc" ]],
  1666. "columnDefs": [ {"targets": [1, 2, 3, 4, 5, 6, 7, 8, 9], "className": "dt-center"},
  1667. {"width": "30%", "className": "dt-head-center jqdt_word_wrap", "targets": [0]},
  1668. ]';
  1669. $columns[] = __('Webhook URL');
  1670. $columns[] = __('Webhook active');
  1671. $columns[] = __('Notify for products');
  1672. $columns[] = __('Notify for devices');
  1673. $columns[] = __('Notify for encashments');
  1674. $columns[] = __('Notify for receipts');
  1675. $columns[] = __('Notify for shifts');
  1676. $columns[] = __('Notify for operations');
  1677. $columns[] = __('Notify for device registrations');
  1678. $columns[] = __('Actions');
  1679. $result = wf_JqDtLoader($columns, $ajaxURLStr, false, __('Webhooks'), 100, $opts);
  1680. $result .= wf_tag('script', false, '', 'type="text/javascript"');
  1681. $result .= wf_JSEmptyFunc();
  1682. $result .= wf_JSElemInsertedCatcherFunc();
  1683. $result .= ' function chekEmptyVal(ctrlClassName) {
  1684. $(document).on("focus keydown", ctrlClassName, function(evt) {
  1685. if ( $(ctrlClassName).css("border-color") == "rgb(255, 0, 0)" ) {
  1686. $(ctrlClassName).val("");
  1687. $(ctrlClassName).css("border-color", "");
  1688. $(ctrlClassName).css("color", "");
  1689. }
  1690. });
  1691. }
  1692. onElementInserted(\'body\', \'.__WHEmptyCheck\', function(element) {
  1693. chekEmptyVal(\'.__WHEmptyCheck\');
  1694. });
  1695. onElementInserted(\'body\', \'.__ChkCtrl\', function(element) {
  1696. makeParamsEncodedBind(\'.__ChkCtrl\');
  1697. });
  1698. $(document).on("submit", ".__WHForm", function(evt) {
  1699. evt.preventDefault();
  1700. var URLParams = $(".__WHURLParams").val();
  1701. var LastURL7Chars = URLParams.substring(URLParams.length - 7);
  1702. if (LastURL7Chars == \'&param=\') {
  1703. alert(\'' . __('Specify at least one notification type') . '\');
  1704. } else {
  1705. // some ugly hack...
  1706. if (empty($(".__WHFullURL").val())) {
  1707. makeParamsEncoded();
  1708. }
  1709. var FrmAction = $(".__WHForm").attr("action");
  1710. var FrmData = $(".__WHForm").serialize() + \'&errfrmid=' . $errorModalWindowId . '\';
  1711. //var modalWindowId = $(".__WHForm").closest(\'div\').attr(\'id\');
  1712. var emptyCheckClass = \'.__WHEmptyCheck\';
  1713. if ( empty( $(emptyCheckClass).val() ) || $(emptyCheckClass).css("border-color") == "rgb(255, 0, 0)" ) {
  1714. $(emptyCheckClass).css("border-color", "red");
  1715. $(emptyCheckClass).css("color", "grey");
  1716. $(emptyCheckClass).val("' . __('Mandatory field') . '");
  1717. } else {
  1718. $.ajax({
  1719. type: "POST",
  1720. url: FrmAction,
  1721. data: FrmData,
  1722. success: function(result) {
  1723. if ( !empty(result) ) {
  1724. $(document.body).append(result);
  1725. $( \'#' . $errorModalWindowId . '\' ).dialog("open");
  1726. } else {
  1727. $(\'#' . $JQDTId . '\').DataTable().ajax.reload();
  1728. //$("[name=swgroupname]").val("");
  1729. if ( $(".__CloseFrmOnSubmitChk").is(\':checked\') ) {
  1730. $( \'#\'+$(".__WHFormModalWindowId").val() ).dialog("close");
  1731. }
  1732. }
  1733. }
  1734. });
  1735. }
  1736. }
  1737. });
  1738. function makeParamsEncodedBind(ctrlClassName) {
  1739. $(document).on("change", ctrlClassName, function(evt) {
  1740. evt.stopPropagation();
  1741. evt.stopImmediatePropagation();
  1742. makeParamsEncoded();
  1743. });
  1744. }
  1745. function makeParamsEncoded() {
  1746. var StaticPart = $(".__WHURLParamsStatic").val();
  1747. var ParamsStr = \'\';
  1748. var ParamsArr = [];
  1749. var ParamsValsStr = \'\';
  1750. var ParamsValsArr = {};
  1751. $(\'[name$="schk"]\').each(function(chkindex, chkelement) {
  1752. var ElemName = $(chkelement).attr("name");
  1753. var ParamName = ElemName.substring(2, ElemName.length - 3);
  1754. if ($(chkelement).is(\':checked\')) {
  1755. ParamsArr.push(ParamName);
  1756. ParamsStr += ParamName;
  1757. }
  1758. ParamsValsArr[ParamName] = $(chkelement).is(\':checked\');
  1759. });
  1760. if (empty(ParamsStr)) {
  1761. $(".__WHURLParams").val(StaticPart);
  1762. $(".__WHFullURL").val(\'\');
  1763. $(".__WHNotifyOpts").val(\'\');
  1764. } else {
  1765. ParamsStr = btoa(JSON.stringify(ParamsArr));
  1766. ParamsValsStr = btoa(JSON.stringify(ParamsValsArr));
  1767. $(".__WHURLParams").val(StaticPart + ParamsStr);
  1768. $(".__WHFullURL").val($(".__WHURLSelf").val() + StaticPart + ParamsStr);
  1769. $(".__WHNotifyOpts").val(ParamsValsStr);
  1770. }
  1771. }
  1772. function deleteWebhook(WHId, ajaxURL, actionName, errFrmId) {
  1773. var ajaxData = \'&\'+ actionName +\'=true&whid=\' + WHId + \'&errfrmid=\' + errFrmId
  1774. $.ajax({
  1775. type: "POST",
  1776. url: ajaxURL,
  1777. data: ajaxData,
  1778. success: function(result) {
  1779. if ( !empty(result) ) {
  1780. $(document.body).append(result);
  1781. $(\'#\'+errFrmId).dialog("open");
  1782. }
  1783. $(\'#' . $JQDTId . '\').DataTable().ajax.reload();
  1784. }
  1785. });
  1786. }
  1787. ';
  1788. $result .= wf_tag('script', true);
  1789. return ($result);
  1790. }
  1791. public function renderWebhookAddForm($modalWindowId) {
  1792. $formId = 'Form_' . wf_InputId();
  1793. $closeFormChkId = 'CloseFrmChkID_' . wf_InputId();
  1794. $immutableURLPart = '/?module=remoteapi&key=' . $this->getUBSerial() . '&action=dreamkas&param=';
  1795. $cells = wf_TableCell(__('URL to your Ubilling instance'), '', '', 'align="center"');
  1796. $rows = wf_TableRow($cells);
  1797. $cells = wf_TableCell(wf_TextInput('whurl', '', '', false, '50', '', '__WHURLSelf __WHEmptyCheck', 'WHURLSelf')
  1798. . wf_delimiter(0) . '<b>+</b>', '', '', 'align="center"');
  1799. $rows .= wf_TableRow($cells);
  1800. $cells = wf_TableCell(__('URL params'), '', '', 'align="center"');
  1801. $rows .= wf_TableRow($cells);
  1802. $cells = wf_TableCell(wf_TextInput('whurlparams', '', $immutableURLPart, true, '100', '', '__WHURLParams', 'WHURLParams', 'readonly'));
  1803. $rows .= wf_TableRow($cells);
  1804. $inputs = wf_TableBody($rows);
  1805. //$inputs.=
  1806. $inputs .= wf_tag('h3') . __('Notify about events') . ':' . wf_tag('h3', true);
  1807. $inputs .= wf_CheckInput('whproductschk', __('Goods'), true, false, 'WHGoodsChk', '__WHGoodsChk __ChkCtrl');
  1808. $inputs .= wf_CheckInput('whdeviceschk', __('Cashmachines'), true, false, 'WHCashmachinesChk', '__WHCashmachinesChk __ChkCtrl');
  1809. $inputs .= wf_CheckInput('whencashmentschk', __('Encashments'), true, false, 'WHEncashmentsChk', '__WHEncashmentsChk __ChkCtrl');
  1810. $inputs .= wf_CheckInput('whreceiptschk', __('Receipts'), true, false, 'WHReceiptsChk', '__WHReceiptsChk __ChkCtrl');
  1811. $inputs .= wf_CheckInput('whshiftschk', __('Shifts'), true, false, 'WHShiftsChk', '__WHShiftsChk __ChkCtrl');
  1812. $inputs .= wf_CheckInput('whoperationschk', __('Operations'), true, false, 'WHOperationsChk', '__WHOperationsChk __ChkCtrl');
  1813. $inputs .= wf_CheckInput('whdeviceRegistrationschk', __('Registration data changes'), true, false, 'WHRegdatachangesChk', '__WHRegdatachangesChk __ChkCtrl');
  1814. $inputs .= wf_delimiter(0);
  1815. $inputs .= wf_CheckInput('whisactive', __('Webhook is active'), true, true, 'WHActiveChk', '__WHActiveChk');
  1816. $inputs .= wf_delimiter(0);
  1817. $inputs .= wf_CheckInput('formclose', __('Close form after operation'), false, true, $closeFormChkId, '__CloseFrmOnSubmitChk');
  1818. $inputs .= wf_HiddenInput('whurlparamsstatic', $immutableURLPart, 'WHURLParamsStatic', '__WHURLParamsStatic');
  1819. $inputs .= wf_HiddenInput('whfullurl', '', 'WHFullURL', '__WHFullURL');
  1820. $inputs .= wf_HiddenInput('whnotifyopts', '', 'WHNotifyOpts', '__WHNotifyOpts');
  1821. $inputs .= wf_HiddenInput('', $modalWindowId, '', '__WHFormModalWindowId');
  1822. $inputs .= wf_HiddenInput('whcreate', 'true');
  1823. $inputs .= wf_delimiter();
  1824. $inputs .= wf_Submit(__('Create'));
  1825. $form = wf_Form(self::URL_ME, 'POST', $inputs, 'glamour __WHForm', '', $formId);
  1826. return ($form);
  1827. }
  1828. public function renderWebhookEditForm($webhookID, $modalWindowId) {
  1829. $webhookData = $this->getWebHooks($webhookID);
  1830. $immutableURLPart = '/?module=remoteapi&key=' . $this->getUBSerial() . '&action=dreamkas&param=';
  1831. $whActive = (empty($webhookData['isActive'])) ? false : true;
  1832. $whURLChunks = (empty($webhookData['url'])) ? array() : explode('?', $webhookData['url']);
  1833. $whNotifyTypes = (isset($webhookData['types'])) ? $webhookData['types'] : array();
  1834. if (empty($whURLChunks)) {
  1835. $whURLPart = '';
  1836. $whParamsPart = $immutableURLPart;
  1837. } else {
  1838. $whURLPart = substr($whURLChunks[0], 0, -1);
  1839. $whParamsPart = '/?' . $whURLChunks[1];
  1840. }
  1841. if (empty($whNotifyTypes)) {
  1842. $whNotifyProducts = false;
  1843. $whNotifyDevices = false;
  1844. $whNotifyEncashments = false;
  1845. $whNotifyReceipts = false;
  1846. $whNotifyShifts = false;
  1847. $whNotifyOperations = false;
  1848. $whNotifyDeviceRegistrations = false;
  1849. } else {
  1850. $whNotifyProducts = (empty($whNotifyTypes['products'])) ? false : true;
  1851. $whNotifyDevices = (empty($whNotifyTypes['devices'])) ? false : true;
  1852. $whNotifyEncashments = (empty($whNotifyTypes['encashments'])) ? false : true;
  1853. $whNotifyReceipts = (empty($whNotifyTypes['receipts'])) ? false : true;
  1854. $whNotifyShifts = (empty($whNotifyTypes['shifts'])) ? false : true;
  1855. $whNotifyOperations = (empty($whNotifyTypes['operations'])) ? false : true;
  1856. $whNotifyDeviceRegistrations = (empty($whNotifyTypes['deviceRegistrations'])) ? false : true;
  1857. }
  1858. $formId = 'Form_' . wf_InputId();
  1859. $closeFormChkId = 'CloseFrmChkID_' . wf_InputId();
  1860. $immutableURLPart = '/?module=remoteapi&key=' . $this->getUBSerial() . '&action=dreamkas&param=';
  1861. $cells = wf_TableCell(__('URL to your Ubilling instance'), '', '', 'align="center"');
  1862. $rows = wf_TableRow($cells);
  1863. $cells = wf_TableCell(wf_TextInput('whurl', '', $whURLPart, false, '50', '', '__WHURLSelf __WHEmptyCheck', 'WHURLSelf')
  1864. . wf_delimiter(0) . '<b>+</b>', '', '', 'align="center"');
  1865. $rows .= wf_TableRow($cells);
  1866. $cells = wf_TableCell(__('URL params'), '', '', 'align="center"');
  1867. $rows .= wf_TableRow($cells);
  1868. $cells = wf_TableCell(wf_TextInput('whurlparams', '', $whParamsPart, true, '100', '', '__WHURLParams', 'WHURLParams', 'readonly'));
  1869. $rows .= wf_TableRow($cells);
  1870. $inputs = wf_TableBody($rows);
  1871. $inputs .= wf_tag('h3') . __('Notify about events') . ':' . wf_tag('h3', true);
  1872. $inputs .= wf_CheckInput('whproductschk', __('Goods'), true, $whNotifyProducts, 'WHGoodsChk', '__WHGoodsChk __ChkCtrl');
  1873. $inputs .= wf_CheckInput('whdeviceschk', __('Cashmachines'), true, $whNotifyDevices, 'WHCashmachinesChk', '__WHCashmachinesChk __ChkCtrl');
  1874. $inputs .= wf_CheckInput('whencashmentschk', __('Encashments'), true, $whNotifyEncashments, 'WHEncashmentsChk', '__WHEncashmentsChk __ChkCtrl');
  1875. $inputs .= wf_CheckInput('whreceiptschk', __('Receipts'), true, $whNotifyReceipts, 'WHReceiptsChk', '__WHReceiptsChk __ChkCtrl');
  1876. $inputs .= wf_CheckInput('whshiftschk', __('Shifts'), true, $whNotifyShifts, 'WHShiftsChk', '__WHShiftsChk __ChkCtrl');
  1877. $inputs .= wf_CheckInput('whoperationschk', __('Operations'), true, $whNotifyOperations, 'WHOperationsChk', '__WHOperationsChk __ChkCtrl');
  1878. $inputs .= wf_CheckInput('whdeviceRegistrationschk', __('Registration data changes'), true, $whNotifyDeviceRegistrations, 'WHRegdatachangesChk', '__WHRegdatachangesChk __ChkCtrl');
  1879. $inputs .= wf_delimiter(0);
  1880. $inputs .= wf_CheckInput('whisactive', __('Webhook is active'), true, $whActive, 'WHActiveChk', '__WHActiveChk');
  1881. $inputs .= wf_delimiter(0);
  1882. $inputs .= wf_CheckInput('formclose', __('Close form after operation'), false, true, $closeFormChkId, '__CloseFrmOnSubmitChk');
  1883. $inputs .= wf_HiddenInput('whurlparamsstatic', $immutableURLPart, 'WHURLParamsStatic', '__WHURLParamsStatic');
  1884. $inputs .= wf_HiddenInput('whfullurl', '', 'WHFullURL', '__WHFullURL');
  1885. $inputs .= wf_HiddenInput('whnotifyopts', '', 'WHNotifyOpts', '__WHNotifyOpts');
  1886. $inputs .= wf_HiddenInput('', $modalWindowId, '', '__WHFormModalWindowId');
  1887. $inputs .= wf_HiddenInput('whedit', 'true');
  1888. $inputs .= wf_HiddenInput('whid', $webhookID);
  1889. $inputs .= wf_delimiter();
  1890. $inputs .= wf_Submit(__('Edit'));
  1891. $form = wf_Form(self::URL_ME, 'POST', $inputs, 'glamour __WHForm', '', $formId);
  1892. return ($form);
  1893. }
  1894. public function createeditdeleteWebhook($whURL, $whActive, $whOpts = '', $whID = '', $whDelete = false) {
  1895. $urlString = self::URL_API . 'webhooks' . ((empty($whID)) ? '' : '/' . $whID);
  1896. $webhookBody = array();
  1897. $errorMsg = '';
  1898. if (empty($whID)) {
  1899. $action = 'ADDITION';
  1900. } elseif (!empty($whID) and ! $whDelete) {
  1901. $action = 'EDITING';
  1902. } elseif (!empty($whID) and $whDelete) {
  1903. $action = 'DELETING';
  1904. }
  1905. if (!empty($whOpts) or ( !empty($whID) and $whDelete)) {
  1906. if (!$whDelete) {
  1907. $whOpts = json_decode(base64_decode($whOpts));
  1908. $webhookBody['url'] = $whURL;
  1909. $webhookBody['isActive'] = $whActive;
  1910. foreach ($whOpts as $whOpt => $eachValue) {
  1911. $webhookBody['types'][$whOpt] = $eachValue;
  1912. }
  1913. $webhookBody = json_encode($webhookBody);
  1914. }
  1915. $curl = curl_init();
  1916. curl_setopt($curl, CURLOPT_POST, true);
  1917. curl_setopt($curl, CURLOPT_URL, $urlString);
  1918. curl_setopt($curl, CURLOPT_HTTPHEADER, $this->basicHTTPHeaders);
  1919. curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
  1920. if (!empty($whID)) {
  1921. if ($whDelete) {
  1922. curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "DELETE");
  1923. } else {
  1924. curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "PATCH");
  1925. }
  1926. }
  1927. if (!$whDelete) {
  1928. curl_setopt($curl, CURLOPT_POSTFIELDS, $webhookBody);
  1929. }
  1930. $result = curl_exec($curl);
  1931. $httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
  1932. curl_close($curl);
  1933. $result = json_decode($result, true);
  1934. if (substr($httpCode, 0, 1) != '2') {
  1935. $errorMsg = 'DREAMKAS WEBHOOK ' . $action . ' ERROR. SERVER ERROR MESSAGE: ' . $this->errorToString($result);
  1936. log_register($errorMsg);
  1937. }
  1938. } else {
  1939. $errorMsg = 'DREAMKAS WEBHOOK ' . $action . ' ERROR: empty webhook options';
  1940. log_register($errorMsg);
  1941. }
  1942. return ($errorMsg);
  1943. }
  1944. public function processWebhookRequest($requestData, $paramSection = '') {
  1945. if (!empty($requestData)) {
  1946. $this->refreshCacheForced();
  1947. $requestData = json_decode($requestData, true);
  1948. $notifyAction = $requestData['action'];
  1949. $notifyType = $requestData['type'];
  1950. $notifyData = $requestData['data'];
  1951. $this->processWebhookChange($notifyType, $notifyAction, $notifyData);
  1952. } else {
  1953. log_register('DREAMKAS WEBHOOK PROCESSING ERROR: empty request data received.');
  1954. }
  1955. }
  1956. protected function processWebhookChange($whType, $whAction, $whData) {
  1957. $logStr = '';
  1958. $logTitle = __('DREAMKAS WEBHOOK') . ' ' . __($whType) . ' [' . __($whAction) . ']' . ' ';
  1959. switch ($whType) {
  1960. case 'PRODUCT':
  1961. $this->getSellPosIDsNames();
  1962. $this->getSellPos2SrvTypeMapping();
  1963. $logStr .= '| [Category]: ' . $whData['category'] . ' | ';
  1964. $logStr .= '[Name]: ' . $whData['name'] . ' | ';
  1965. $logStr .= '[Type]: ' . $whData['type'] . ' | ';
  1966. $logStr .= '[Quantity]: ' . $whData['quantity'] . ' | ';
  1967. $logStr .= '[Price]: ' . $whData['price'] . ' | ';
  1968. $logStr .= (isset($whData['barcodes'][0])) ? '[Barcode]: ' . $whData['barcodes'][0] . ' | ' : '';
  1969. $logStr .= (isset($whData['vendorCodes'][0])) ? '[Vendorcode]: ' . $whData['vendorCodes'][0] . ' | ' : '';
  1970. $logStr .= '[Tax]: ' . $whData['tax'] . ' | ';
  1971. $logStr .= '[Creation date]: ' . date('Y-m-d H:i:s', strtotime($whData['createdAt'])) . ' | ';
  1972. $logStr .= '[Update date]: ' . date('Y-m-d H:i:s', strtotime($whData['updatedAt'])) . ' | ';
  1973. break;
  1974. case 'DEVICE':
  1975. $this->getCashMachines4Selector();
  1976. break;
  1977. case 'ENCASHMENT':
  1978. break;
  1979. case 'SHIFT':
  1980. break;
  1981. case 'RECEIPT':
  1982. $this->updateFiscalOperationsLocalStorage();
  1983. $receiptPositions = $whData['positions'];
  1984. $receiptPayments = $whData['payments'];
  1985. $logStr .= '| [Check ID]: ' . $whData['_id'] . ' | ';
  1986. $logStr .= '[Device ID]: ' . $whData['deviceId'] . ' | ';
  1987. $logStr .= '[Shop ID]: ' . $whData['shopId'] . ' | ';
  1988. $logStr .= '[Local date]: ' . $whData['localDate'] . ' | ';
  1989. $logStr .= '[Shift ID]: ' . $whData['shiftId'] . ' | ';
  1990. $logStr .= '[Cashier]: ' . $whData['cashier']['name'] . ' | ';
  1991. $logStr .= '[Number]: ' . $whData['number'] . ' | ';
  1992. $logStr .= '[Amount]: ' . $whData['amount'] / 100 . ' | ';
  1993. foreach ($receiptPositions as $postion) {
  1994. $logStr .= $postion['name'] . wf_nbsp(2) . '-' . wf_nbsp(2) . ($postion['price'] / 100) . ' | ';
  1995. }
  1996. foreach ($receiptPayments as $payment) {
  1997. $logStr .= $payment['type'] . wf_nbsp(2) . '-' . wf_nbsp(2) . ($payment['amount'] / 100) . ' | ';
  1998. }
  1999. break;
  2000. case 'OPERATION':
  2001. $this->updateFiscalOperationsLocalStorage($whData);
  2002. $logStr .= '| [Creation date]: ' . date('Y-m-d H:i:s', strtotime($whData['createdAt'])) . ' | ';
  2003. $logStr .= '[Completion date]: ' . date('Y-m-d H:i:s', strtotime($whData['completedAt'])) . ' | ';
  2004. $logStr .= '[Status]: ' . $whData['status'] . ' | ';
  2005. $logStr .= (isset($whData['type'])) ? '[Type]: ' . $whData['type'] . ' | ' : '';
  2006. $logStr .= (isset($whData['data']['receiptId'])) ? '[Receipt ID]: ' . $whData['data']['receiptId'] . ' | ' : '';
  2007. $logStr .= (isset($whData['data']['error'])) ? '[Error code]: ' . $whData['data']['error']['code'] . ' | ' : '';
  2008. $logStr .= (isset($whData['data']['error'])) ? '[Error message]: ' . $whData['data']['error']['message'] . ' | ' : '';
  2009. break;
  2010. }
  2011. log_register($logTitle . $logStr);
  2012. $this->putNotificationData2Cache($logStr, 'info', $logTitle);
  2013. }
  2014. }