MigrationData.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  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. public function MarkMissionDone(string $labelId, string $articleCode, string $commessa)
  76. {
  77. $this->query(
  78. "UPDATE SMEDAT_DIM.INTMAV0F SET MXSTAT=" . MigrationData::STATUS_DONE . " WHERE MXNCON='$labelId' AND MXCORD='$commessa' AND MXARTI='$articleCode' AND MXSTAT=" . MigrationData::STATUS_PENDING
  79. );
  80. }
  81. /**
  82. * Set barcode on all missions cached by 'selectAvailableMissions'
  83. * @param string $labelId
  84. * @param string $commessa filter
  85. */
  86. public function SetMissionsBarcodes(string $labelId, string $commessa)
  87. {
  88. $this->query("UPDATE SMEDAT_DIM.INTMAV0F SET MXNCON='$labelId' WHERE MXCORD='$commessa'");
  89. }
  90. /**
  91. * MAV DB constructor.
  92. */
  93. public function MAVDatabaseConnector()
  94. {
  95. global $f3;
  96. $this->dbMAVHandle = new SQL(
  97. MAVDBDSN . $f3->get('VERTICALSTORAGE.MV_ADDRESS'),
  98. MAVDBUID, MAVDBPWD,
  99. array(\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION));
  100. }
  101. /**
  102. * PDO constructor.
  103. */
  104. public function DB2Connector()
  105. {
  106. global $f3;
  107. $this->dbHandle = new SQL(
  108. DB2DSN . $f3->get('VERTICALSTORAGE.DB2_ADDRESS'),
  109. 'icam', 'icam',
  110. array(\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION));
  111. }
  112. /**
  113. * @param $sql
  114. * @return array
  115. */
  116. public function query($sql)
  117. {
  118. return $this->dbHandle->exec($sql);
  119. }
  120. /**
  121. * @param $result
  122. * @return int row count
  123. */
  124. public function toCSV($result): int
  125. {
  126. $count = 0;
  127. foreach($result as $key => $value) {
  128. $arr = [];
  129. array_map(function ($v) use (&$arr) {
  130. $arr[] = str_pad(ltrim(rtrim($v)), 5, ' ');
  131. }, $value);
  132. echo join('|', $arr);
  133. echo PHP_EOL;
  134. $count++;
  135. }
  136. return $count;
  137. }
  138. private function soapAddHead(string $extCode, string $operation, string $name, string $description)
  139. {
  140. $this->listXml .= <<<EOF
  141. <ser:ListHead>
  142. <ser:external_list_code>$extCode</ser:external_list_code>
  143. <ser:operation_type>VISUALIZZAZIONE</ser:operation_type>
  144. <ser:operation>$operation</ser:operation>
  145. <ser:name>$name</ser:name>
  146. <ser:description>$description</ser:description>
  147. <ser:user_id>sa</ser:user_id>
  148. </ser:ListHead>
  149. EOF;
  150. }
  151. private function soapAddArticle(string $id, int $quantity, $description, $color)
  152. {
  153. $this->listXml .= <<<EOF
  154. <ser:ListDetail>
  155. <ser:item_id>$id</ser:item_id>
  156. <ser:quantity>$quantity</ser:quantity>
  157. <ser:description>$description</ser:description>
  158. <ser:color>$color</ser:color>
  159. </ser:ListDetail>
  160. EOF;
  161. }
  162. /**
  163. * Send to as400 a list of all articles contained into MAV
  164. * @param $data
  165. * @return bool
  166. */
  167. public function copyAllToAS400($data): bool
  168. {
  169. $this->dbHandle->exec("TRUNCATE TABLE SMEDAT_DIM.INTMUB0F");
  170. foreach($data as $key => $value) {
  171. $this->dbHandle->exec("INSERT INTO SMEDAT_DIM.INTMUB0F (UXSTAT, UXCOAP, UXQTGC, UXQTMA) VALUES (10, '${value['UXCOAP']}', ${value['UXQTGC']}, ${value['UXQTMA']})");
  172. }
  173. }
  174. /**
  175. * Per comodità questa funzione serve per interpretare meglio il campo MXTIPM, indica solamente il valore 'C' come Carico, e scarico stringa vuota o spazio
  176. *
  177. * @param string $operation
  178. * @return string
  179. */
  180. private function fixOperationTypeValue(string $operation)
  181. {
  182. return ($operation == 'CARICO') ? "MXTIPM == 'C'" : "MXTIPM <> 'C'";
  183. }
  184. /**
  185. * Ritorna la query di massificazione (raggruppamento delle quantità per codice articolo e prebolla) dalla tabella INTMAVOF
  186. *
  187. * @param string $operationType values: 'CARICO' or 'SCARICO'
  188. * @return string
  189. */
  190. public function strQueryMassificata(string $operationType): string
  191. {
  192. $filter = $this->fixOperationTypeValue($operationType);
  193. $status = MigrationData::STATUS_NEW;
  194. return <<<EOF
  195. SELECT MXCORD, MXARTI, MXDESC, MXRIFC, SUM(MXQTMI) AS QTY
  196. FROM SMEDAT_DIM.INTMAV0F
  197. WHERE $filter AND MXSTAT=$status
  198. GROUP BY MXARTI, MXCORD, MXDESC, MXRIFC
  199. ORDER BY MXCORD, MXARTI
  200. EOF;
  201. }
  202. /**
  203. * Ritorna la query di massificazione (raggruppamento delle quantità per codice articolo ignorando la prebolla) dalla tabella INTMAVOF
  204. *
  205. * @param string $operationType values: 'CARICO' or 'SCARICO'
  206. * @return string
  207. */
  208. public function strQueryPerMAV(string $operationType): string
  209. {
  210. $filter = $this->fixOperationTypeValue($operationType);
  211. $status = MigrationData::STATUS_NEW;
  212. return <<<EOF
  213. SELECT MXARTI, MXDESC, SUM(MXQTMI) AS QTY
  214. FROM (SELECT * FROM SMEDAT_DIM.INTMAV0F ORDER BY MXCORD) AS tbl
  215. WHERE $filter AND MXSTAT={$status}
  216. GROUP BY MXARTI, MXDESC
  217. EOF;
  218. }
  219. /**
  220. * Query da eseguire sul database di OM-Link, ottiene una lista massificata per quantità articolo, UDS e ordinata per esso
  221. *
  222. * @return string
  223. */
  224. public function strQueryMassificazioneByUDS(): string
  225. {
  226. return <<<EOF
  227. SELECT `uds`, `barcode`, `descrizione`, SUM(`qta_prelevare`) AS `qta`
  228. FROM `distinte`
  229. WHERE deleted=0
  230. GROUP BY `barcode`
  231. ORDER BY `uds`
  232. EOF;
  233. }
  234. /**
  235. * Compile xml soap from $data
  236. *
  237. * @param string $operationType values: 'CARICO' or 'SCARICO'
  238. * @param iterable $data
  239. * @return string return id list
  240. */
  241. public function soapCompileFrom(iterable $data, string $operationType): string
  242. {
  243. $idList = 'ID-' . uniqid();
  244. $dateTime = date("d/m/Y H:i:s");
  245. $operationType = $operationType == 'CARICO' ? 'CARICO' : 'SCARICO';
  246. foreach($data as $row) {
  247. // List Head
  248. $this->soapAddHead($idList, $operationType, "Lista di $operationType da as400 del $dateTime", '');
  249. $descArti = trim($row['descrizione']); // trim($row['commessa']) . ' ' . trim(substr($row['codcliente'], 7)) . ' ' . trim($row['descrizione']);
  250. // List Article
  251. $this->soapAddArticle($row['barcode'], $row['qta_prelevare'], $descArti, $row['color']);
  252. }
  253. $this->finalXml = <<<EOF
  254. <?xml version="1.0" encoding="utf-8"?>
  255. <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ser="http://servizi_xchange.org/">
  256. <soapenv:Header/>
  257. <soapenv:Body>
  258. <ser:ImportLists>
  259. <ser:InputLists>
  260. <ser:ListToImport>
  261. $this->listXml
  262. </ser:ListToImport>
  263. </ser:InputLists>
  264. <ser:Output_Type>1</ser:Output_Type>
  265. </ser:ImportLists>
  266. </soapenv:Body>
  267. </soapenv:Envelope>
  268. EOF;
  269. return $idList;
  270. }
  271. /**
  272. * Send xml to SoapService of ICAM
  273. * @param $xmlSoap
  274. * @return bool true if successful
  275. */
  276. public function sendToIcam(): bool
  277. {
  278. global $f3;
  279. $ws_url = 'http://' . $f3->get('VERTICALSTORAGE.MV_ADDRESS') . '/servizi_xchange.asmx';
  280. $ret = $this->soapClient->__doRequest($this->finalXml, $ws_url, $this->soapAction, SOAP_1_1);
  281. return boolval($ret);
  282. }
  283. /**
  284. * Prepara la distinta da importare sul database di OM-Link
  285. *
  286. * @param $dataRows
  287. * @param array $uds
  288. * @return array
  289. */
  290. public function prepareDistinta($dataRows, array $uds)
  291. {
  292. global $f3;
  293. $colors = range(1, 10);
  294. $ret = [];
  295. $idUtente = $f3->get('USER')->id;
  296. $cols = array_column($uds, 'item_id');
  297. foreach($dataRows as $count => $data) {
  298. $color = array_shift($colors);
  299. array_push($colors, $color);
  300. $container_id = '';
  301. $colId = array_search(trim($data['MXARTI']), $cols);
  302. if ($colId !== false)
  303. $container_id = $uds[$colId]['container_id'];
  304. $ret[] = [
  305. 'idUtente' => $idUtente,
  306. 'origine' => $data['MXUBIC'],
  307. 'consegna' => $data['MXIDDM'],
  308. 'commessa' => trim($data['MXCORD']), // Codice prebolla
  309. 'codcliente' => trim(substr($data['MXRIFC'], 7)),
  310. 'barcode' => trim($data['MXARTI']),
  311. 'descrizione' => trim($data['MXDESC']),
  312. 'qta_prelevare' => $data['QTY'],
  313. 'qta_mancante' => 0,
  314. 'color' => $color,
  315. 'uds' => $container_id // posizione UDS
  316. ];
  317. }
  318. // Sort menus buy 'order' option
  319. usort($ret, function ($obj1, $obj2) {
  320. return $obj1['uds'] <=> $obj2['uds'];
  321. });
  322. return $ret;
  323. }
  324. /**
  325. * Importa la distinta sul database di OM-Link
  326. *
  327. * @param array $data
  328. */
  329. public function saveDistinta(array $data)
  330. {
  331. global $f3;
  332. $distinta = new SQL\Mapper($f3->get('DB'), 'distinte');
  333. foreach($data as $row) {
  334. $distinta->reset();
  335. $distinta->copyfrom($row);
  336. $distinta->save();
  337. }
  338. }
  339. /**
  340. * Get all UDS positions of MAV articles
  341. * @return array
  342. */
  343. public function getUDSs(): array
  344. {
  345. return $this->dbMAVHandle->exec('SELECT item_id, container_id, subcontainer_id from dbo.vw_item_positions');
  346. }
  347. /**
  348. * Transfer product list from MAV to as400
  349. *
  350. * @return int count
  351. */
  352. public function transferFromMAV_as400(): int
  353. {
  354. $this->dbHandle->query("TRUNCATE TABLE SMEDAT_DIM.INTMUB0F");
  355. $mavArticles = $this->dbMAVHandle->query('SELECT item_id AS UXCOAP, max_load_unit AS UXQTMA, position_quantity AS UXQTGC FROM vw_item_positions');
  356. $count = 0;
  357. foreach($mavArticles as $key => $value) {
  358. $success = $this->dbHandle->query(
  359. "INSERT INTO SMEDAT_DIM.INTMUB0F (UXSTAT, UXCOAP, UXQTGC, UXQTMA) VALUES (10, '${value['UXCOAP']}', ${value['UXQTGC']}, ${value['UXQTMA']})"
  360. );
  361. if ($success === FALSE) {
  362. return -1;
  363. }
  364. $count++;
  365. }
  366. return $count;
  367. }
  368. }