MigrationData.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445
  1. <?php
  2. /**
  3. * Created by PhpStorm.
  4. * User: Giancarlo
  5. * Date: 19/09/2018
  6. * Time: 12:10
  7. */
  8. namespace Modules\Dimatec;
  9. use DB\SQL;
  10. // DB2 Connection
  11. define('DB2DSN', "odbc:Driver={iSeries Access ODBC Driver};DefaultLibraries=SMEDAT_DIM;SYSTEM=");
  12. define('DB2UID', 'icam');
  13. define('DB2PWD', 'icam');
  14. // MAV DB Connection
  15. define('MAVDBDSN', "sqlsrv:Database=icamdbstore;Encrypt=false;TrustServerCertificate=false;Server=");
  16. define('MAVDBUID', 'sa');
  17. define('MAVDBPWD', 'sa');
  18. class MigrationData
  19. {
  20. const STATUS_NEW = 0;
  21. CONST STATUS_PENDING = 50;
  22. CONST STATUS_DONE = 80;
  23. /** @var SQL $dbHandle DB2 */
  24. private $dbHandle;
  25. /** @var SQL $dbHandle MSSQL Server */
  26. private $dbMAVHandle;
  27. /** @var \SoapClient $soapClient MAV client */
  28. private $soapClient;
  29. // SOAPACTION
  30. private $soapAction = 'http://servizi_xchange.org/ImportLists';
  31. // Internal variables
  32. private $finalXml;
  33. private $listXml;
  34. // The ids of current articles to move from DB2 to MAV
  35. private $db2RowsId = [];
  36. public function ClearCachedIDs()
  37. {
  38. global $System;
  39. $System->getCache()->clear('db2RowsId');
  40. }
  41. /**
  42. * Create the connection client to a SOAP server
  43. * @param string $serverAddress IP Address
  44. * @throws \Exception
  45. */
  46. public function SoapConnector(string $serverAddress)
  47. {
  48. global $frameworkUtils;
  49. if ($frameworkUtils->isServerAlive($serverAddress, 80, 2) > 0)
  50. throw new \Exception('Magazzino Verticale non raggiungibile');
  51. $this->soapClient = new \SoapClient("http://$serverAddress/servizi_xchange.asmx?wsdl", array(
  52. 'trace' => true,
  53. 'exceptions' => true,
  54. 'cache_wsdl' => false,
  55. ));
  56. }
  57. /**
  58. * Get all new missions from DB2 without status 0
  59. * @param string $operationType
  60. */
  61. public function selectAvailableMissions(string $operationType)
  62. {
  63. $filter = $this->fixOperationTypeValue($operationType);
  64. $this->db2RowsId = array_column($this->query("SELECT MXIDDM FROM SMEDAT_DIM.INTMAV0F WHERE $filter AND MXSTAT=0"), 'MXIDDM');
  65. }
  66. /**
  67. * Set mission status on AS400
  68. * @param $listaId
  69. */
  70. public function InitializeMissionsToPending($listaId)
  71. {
  72. $ids = join(", ", $this->db2RowsId);
  73. $this->query("UPDATE SMEDAT_DIM.INTMAV0F SET MXSTAT=" . MigrationData::STATUS_PENDING . ", MXNOLS='$listaId' WHERE MXIDDM IN ($ids)");
  74. }
  75. /**
  76. * Set all missions in STATUS_PENDING status as STATUS_DONE
  77. */
  78. public function RollbackPendingMissionsToNew()
  79. {
  80. // Stranamente se non facci oquesto count pdostatement genera un server error 500 intrappabile!!
  81. $pendingCount = count($this->query('SELECT * FROM SMEDAT_DIM.INTMAV0F WHERE MXSTAT=' . MigrationData::STATUS_PENDING));
  82. if ($pendingCount > 0) {
  83. $this->query(
  84. "UPDATE SMEDAT_DIM.INTMAV0F SET MXSTAT=" . MigrationData::STATUS_NEW . " WHERE MXSTAT=" . MigrationData::STATUS_PENDING
  85. );
  86. }
  87. }
  88. /**
  89. * @param string $labelId
  90. * @param string $articleCode
  91. * @param string $commessa
  92. */
  93. public function MarkMissionDone(string $labelId, string $articleCode, string $commessa)
  94. {
  95. $this->query(
  96. "UPDATE SMEDAT_DIM.INTMAV0F SET MXSTAT=" . MigrationData::STATUS_DONE . " WHERE MXNCON='$labelId' AND MXCORD='$commessa' AND MXARTI='$articleCode' AND MXSTAT=" . MigrationData::STATUS_PENDING
  97. );
  98. }
  99. /**
  100. * Set barcode on all missions cached by 'selectAvailableMissions'
  101. * @param string $labelId
  102. * @param string $commessa filter
  103. */
  104. public function SetMissionsBarcodes(string $labelId, string $commessa)
  105. {
  106. $this->query("UPDATE SMEDAT_DIM.INTMAV0F SET MXNCON='$labelId' WHERE MXCORD='$commessa'");
  107. }
  108. /**
  109. * MAV DB constructor.
  110. */
  111. public function MAVDatabaseConnector()
  112. {
  113. global $f3;
  114. $this->dbMAVHandle = new SQL(
  115. MAVDBDSN . $f3->get('VERTICALSTORAGE.MV_ADDRESS'),
  116. MAVDBUID, MAVDBPWD,
  117. array(\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION));
  118. }
  119. /**
  120. * PDO constructor.
  121. */
  122. public function DB2Connector()
  123. {
  124. global $f3;
  125. $this->dbHandle = new SQL(
  126. DB2DSN . $f3->get('VERTICALSTORAGE.DB2_ADDRESS'),
  127. 'icam', 'icam',
  128. array(\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION));
  129. }
  130. /**
  131. * @param $sql
  132. * @return array
  133. */
  134. public function query($sql)
  135. {
  136. return $this->dbHandle->exec($sql);
  137. }
  138. /**
  139. * @param $result
  140. * @return int row count
  141. */
  142. public function toCSV($result): int
  143. {
  144. $count = 0;
  145. foreach($result as $key => $value) {
  146. $arr = [];
  147. array_map(function ($v) use (&$arr) {
  148. $arr[] = str_pad(ltrim(rtrim($v)), 5, ' ');
  149. }, $value);
  150. echo join('|', $arr);
  151. echo PHP_EOL;
  152. $count++;
  153. }
  154. return $count;
  155. }
  156. private function soapAddHead(string $extCode, string $operation, string $name, string $description)
  157. {
  158. $this->listXml .= <<<EOF
  159. <ser:ListHead>
  160. <ser:external_list_code>$extCode</ser:external_list_code>
  161. <ser:operation_type>VISUALIZZAZIONE</ser:operation_type>
  162. <ser:operation>$operation</ser:operation>
  163. <ser:name>$name</ser:name>
  164. <ser:description>$description</ser:description>
  165. <ser:user_id>sa</ser:user_id>
  166. </ser:ListHead>
  167. EOF;
  168. }
  169. private function soapAddArticle(string $id, int $quantity, $description, $color)
  170. {
  171. $this->listXml .= <<<EOF
  172. <ser:ListDetail>
  173. <ser:item_id>$id</ser:item_id>
  174. <ser:quantity>$quantity</ser:quantity>
  175. <ser:description>$description</ser:description>
  176. <ser:color>$color</ser:color>
  177. </ser:ListDetail>
  178. EOF;
  179. }
  180. /**
  181. * Send to as400 a list of all articles contained into MAV
  182. * @param $data
  183. * @return bool
  184. */
  185. public function copyAllToAS400($data): bool
  186. {
  187. $this->dbHandle->exec("TRUNCATE TABLE SMEDAT_DIM.INTMUB0F");
  188. foreach($data as $key => $value) {
  189. $this->dbHandle->exec("INSERT INTO SMEDAT_DIM.INTMUB0F (UXSTAT, UXCOAP, UXQTGC, UXQTMA) VALUES (10, '${value['UXCOAP']}', ${value['UXQTGC']}, ${value['UXQTMA']})");
  190. }
  191. }
  192. /**
  193. * Per comodità questa funzione serve per interpretare meglio il campo MXTIPM, indica solamente il valore 'C' come Carico, e scarico stringa vuota o spazio
  194. *
  195. * @param string $operation
  196. * @return string
  197. */
  198. private function fixOperationTypeValue(string $operation)
  199. {
  200. return ($operation == 'CARICO') ? "MXTIPM == 'C'" : "MXTIPM <> 'C'";
  201. }
  202. /**
  203. * Ritorna la query di massificazione (raggruppamento delle quantità per codice articolo e prebolla) dalla tabella INTMAVOF
  204. *
  205. * @param string $operationType values: 'CARICO' or 'SCARICO'
  206. * @return string
  207. */
  208. public function strQueryMassificata(string $operationType): string
  209. {
  210. $filter = $this->fixOperationTypeValue($operationType);
  211. $status = MigrationData::STATUS_NEW;
  212. return <<<EOF
  213. SELECT MXCORD, MXARTI, MXDESC, MXRIFC, MXBCOD, SUM(MXQTMI) AS QTY
  214. FROM SMEDAT_DIM.INTMAV0F
  215. WHERE $filter AND MXSTAT=$status
  216. GROUP BY MXARTI, MXCORD, MXDESC, MXRIFC, MXBCOD
  217. ORDER BY MXCORD, MXARTI
  218. EOF;
  219. }
  220. /**
  221. * Ritorna la query di massificazione (raggruppamento delle quantità per codice articolo ignorando la prebolla) dalla tabella INTMAVOF
  222. *
  223. * @param string $operationType values: 'CARICO' or 'SCARICO'
  224. * @return string
  225. */
  226. public function strQueryPerMAV(string $operationType): string
  227. {
  228. $filter = $this->fixOperationTypeValue($operationType);
  229. $status = MigrationData::STATUS_NEW;
  230. return <<<EOF
  231. SELECT MXARTI, MXDESC, SUM(MXQTMI) AS QTY
  232. FROM (SELECT * FROM SMEDAT_DIM.INTMAV0F ORDER BY MXCORD) AS tbl
  233. WHERE $filter AND MXSTAT={$status}
  234. GROUP BY MXARTI, MXDESC
  235. EOF;
  236. }
  237. /**
  238. * Query da eseguire sul database di OM-Link, ottiene una lista massificata per quantità articolo, UDS e ordinata per esso
  239. *
  240. * @return string
  241. */
  242. public function strQueryMassificazioneByUDS(): string
  243. {
  244. return <<<EOF
  245. SELECT `uds`, `barcode`, `descrizione`, SUM(`qta_prelevare`) AS `qta`
  246. FROM `distinte`
  247. WHERE `deleted`=0
  248. GROUP BY `barcode`
  249. ORDER BY `uds`
  250. EOF;
  251. }
  252. /**
  253. * Compile xml soap from $data
  254. *
  255. * @param string $operationType values: 'CARICO' or 'SCARICO'
  256. * @param iterable $data
  257. * @return string return id list
  258. */
  259. public function soapCompileFrom(iterable $data, string $operationType): string
  260. {
  261. $idList = 'ID-' . uniqid();
  262. $dateTime = date("d/m/Y H:i:s");
  263. $operationType = $operationType == 'CARICO' ? 'CARICO' : 'SCARICO';
  264. foreach($data as $row) {
  265. // List Head
  266. $this->soapAddHead($idList, $operationType, "Lista di $operationType da as400 del $dateTime", '');
  267. $descArti = trim($row['descrizione']); // trim($row['commessa']) . ' ' . trim(substr($row['desccliente'], 7)) . ' ' . trim($row['descrizione']);
  268. // List Article
  269. $this->soapAddArticle($row['barcode'], $row['qta_prelevare'], $descArti, $row['color']);
  270. }
  271. $this->finalXml = <<<EOF
  272. <?xml version="1.0" encoding="utf-8"?>
  273. <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ser="http://servizi_xchange.org/">
  274. <soapenv:Header/>
  275. <soapenv:Body>
  276. <ser:ImportLists>
  277. <ser:InputLists>
  278. <ser:ListToImport>
  279. $this->listXml
  280. </ser:ListToImport>
  281. </ser:InputLists>
  282. <ser:Output_Type>1</ser:Output_Type>
  283. </ser:ImportLists>
  284. </soapenv:Body>
  285. </soapenv:Envelope>
  286. EOF;
  287. return $idList;
  288. }
  289. /**
  290. * Send xml to SoapService of ICAM
  291. * @param $xmlSoap
  292. * @return bool true if successful
  293. */
  294. public function sendToIcam(): bool
  295. {
  296. global $f3;
  297. $ws_url = 'http://' . $f3->get('VERTICALSTORAGE.MV_ADDRESS') . '/servizi_xchange.asmx';
  298. $ret = $this->soapClient->__doRequest($this->finalXml, $ws_url, $this->soapAction, SOAP_1_1);
  299. return boolval($ret);
  300. }
  301. /**
  302. * Prepara la distinta da importare sul database di OM-Link
  303. *
  304. * @param $dataRows
  305. * @param array $uds
  306. * @return array
  307. */
  308. public function prepareDistinta($dataRows, array $uds)
  309. {
  310. global $f3;
  311. $colors = range(1, 10);
  312. $ret = [];
  313. $idUtente = $f3->get('USER')->id;
  314. $cols = array_column($uds, 'item_id');
  315. foreach($dataRows as $count => $data) {
  316. $color = array_shift($colors);
  317. array_push($colors, $color);
  318. $container_id = '';
  319. $colId = array_search(trim($data['MXARTI']), $cols);
  320. if ($colId !== false)
  321. $container_id = $uds[$colId]['container_id'];
  322. $ret[] = [
  323. 'idUtente' => $idUtente,
  324. 'origine' => $data['MXUBIC'],
  325. 'consegna' => $data['MXIDDM'],
  326. 'commessa' => trim($data['MXCORD']), // Codice prebolla
  327. 'desccliente' => trim(substr($data['MXRIFC'], 7)),
  328. 'barcode' => trim($data['MXARTI']),
  329. 'codcliente' => trim($data['MXBCOD']),
  330. 'descrizione' => trim($data['MXDESC']),
  331. 'qta_prelevare' => $data['QTY'],
  332. 'qta_mancante' => 0,
  333. 'color' => $color,
  334. 'uds' => $container_id // posizione UDS
  335. ];
  336. }
  337. // Sort menus buy 'order' option
  338. usort($ret, function ($obj1, $obj2) {
  339. return $obj1['uds'] <=> $obj2['uds'];
  340. });
  341. return $ret;
  342. }
  343. /**
  344. * Importa la distinta sul database di OM-Link
  345. *
  346. * @param array $data
  347. */
  348. public function saveDistinta(array $data)
  349. {
  350. global $f3;
  351. $distinta = new SQL\Mapper($f3->get('DB'), 'distinte');
  352. foreach($data as $row) {
  353. $distinta->reset();
  354. $distinta->copyfrom($row);
  355. $distinta->save();
  356. }
  357. }
  358. /**
  359. * Get all UDS positions of MAV articles
  360. * @return array
  361. */
  362. public function getUDSs(): array
  363. {
  364. return $this->dbMAVHandle->exec('SELECT item_id, container_id, subcontainer_id from dbo.vw_item_positions');
  365. }
  366. /**
  367. * Transfer product list from MAV to as400
  368. *
  369. * @return int count
  370. */
  371. public function transferFromMAV_as400(): int
  372. {
  373. $this->dbHandle->query("DELETE FROM SMEDAT_DIM.INTMUB0F");
  374. $mavArticles = $this->dbMAVHandle->query('SELECT item_id AS UXCOAP, max_load_unit AS UXQTMA, position_quantity AS UXQTGC, container_id AS UXLOCN FROM vw_item_positions');
  375. $count = 0;
  376. foreach($mavArticles as $key => $value) {
  377. $success = $this->dbHandle->query(
  378. "INSERT INTO SMEDAT_DIM.INTMUB0F (UXSTAT, UXCOAP, UXQTGC, UXQTMA, UXLOCN) VALUES (10, '${value['UXCOAP']}', ${value['UXQTGC']}, ${value['UXQTMA']}, '${value['UXLOCN']}')"
  379. );
  380. if ($success === FALSE) {
  381. return -1;
  382. }
  383. $count++;
  384. }
  385. return $count;
  386. }
  387. }